MCPcopy
hub / github.com/npmx-dev/npmx.dev / highlightCode

Function highlightCode

server/utils/code-highlight.ts:266–334  ·  view source on GitHub ↗
(
  code: string,
  language: string,
  options?: HighlightOptions,
)

Source from the content-addressed store, hash-verified

264 * Each line is wrapped in a span.line for individual line highlighting.
265 */
266export async function highlightCode(
267 code: string,
268 language: string,
269 options?: HighlightOptions,
270): Promise<string> {
271 const shiki = await getShikiHighlighter()
272 const loadedLangs = shiki.getLoadedLanguages()
273
274 // Use Shiki if language is loaded
275 if (loadedLangs.includes(language as never)) {
276 try {
277 let html = shiki.codeToHtml(code, {
278 lang: language,
279 themes: { light: 'github-light', dark: 'github-dark' },
280 defaultColor: 'dark',
281 })
282
283 // Shiki doesn't encode > in text content (e.g., arrow functions)
284 html = escapeRawGt(html)
285
286 // Make import statements clickable for JS/TS languages
287 if (IMPORT_LANGUAGES.has(language)) {
288 html = linkifyModuleSpecifiers(html, {
289 dependencies: options?.dependencies,
290 resolveRelative: options?.resolveRelative,
291 })
292 }
293
294 // Check if Shiki already outputs .line spans (newer versions do)
295 if (html.includes('<span class="line">')) {
296 // Shiki already wraps lines, but they're separated by newlines
297 // We need to remove the newlines since display:block handles line breaks
298 // Replace newlines between </span> and <span class="line"> with nothing
299 return html.replace(/<\/span>\n<span class="line">/g, '</span><span class="line">')
300 }
301
302 // Older Shiki without .line spans - wrap manually
303 const codeMatch = html.match(/<code[^>]*>([\s\S]*)<\/code>/)
304 if (codeMatch?.[1]) {
305 const codeContent = codeMatch[1]
306 const lines = codeContent.split('\n')
307 const wrappedLines = lines
308 .map((line: string, i: number) => {
309 if (i === lines.length - 1 && line === '') return null
310 return `<span class="line">${line}</span>`
311 })
312 .filter((line: string | null): line is string => line !== null)
313 .join('')
314
315 return html.replace(codeMatch[1], wrappedLines)
316 }
317
318 return html
319 } catch {
320 // Fall back to plain
321 }
322 }
323

Callers 1

[...pkg].get.tsFile · 0.85

Calls 3

getShikiHighlighterFunction · 0.85
escapeRawGtFunction · 0.85
linkifyModuleSpecifiersFunction · 0.85

Tested by

no test coverage detected