Files
claude-code/src/utils/cliHighlight.ts
claude-code-best 299953b0ee fix: 修复 cliHighlight 类型不兼容问题
loadedGetLanguage 返回类型中 name 字段改为可选,匹配 highlight.js
Language 类型中 name 为 string | undefined 的定义。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 20:12:47 +08:00

54 lines
2.1 KiB
TypeScript

// highlight.js's type defs carry `/// <reference lib="dom" />`. SSETransport,
// mcp/client, ssh, dumpPrompts use DOM types (TextDecodeOptions, RequestInfo)
// that only typecheck because the hljs import below pulls lib.dom in.
// tsconfig has lib: ["ESNext"] only — this ref preserves the status quo.
/// <reference lib="dom" />
import { extname } from 'path'
// Static import — dynamic import('highlight.js') fails in Bun --compile mode
// because module resolution points to the internal bunfs binary path.
import hljs from 'highlight.js'
export type CliHighlight = {
highlight: typeof import('cli-highlight').highlight
supportsLanguage: typeof import('cli-highlight').supportsLanguage
}
// One promise shared by Fallback.tsx, markdown.ts, events.ts, getLanguageName.
let cliHighlightPromise: Promise<CliHighlight | null> | undefined
let loadedGetLanguage: ((name: string) => { name?: string } | undefined) | undefined
async function loadCliHighlight(): Promise<CliHighlight | null> {
try {
const cliHighlight = await import('cli-highlight')
// highlight.js CJS interop: `export =` wraps in .default under ESM
const hljsMod = hljs as { getLanguage?: typeof loadedGetLanguage; default?: typeof hljs }
loadedGetLanguage = hljsMod.getLanguage ?? hljsMod.default?.getLanguage
return {
highlight: cliHighlight.highlight,
supportsLanguage: cliHighlight.supportsLanguage,
}
} catch {
return null
}
}
export function getCliHighlightPromise(): Promise<CliHighlight | null> {
cliHighlightPromise ??= loadCliHighlight()
return cliHighlightPromise
}
/**
* eg. "foo/bar.ts" → "TypeScript". Awaits the shared cli-highlight load,
* then reads highlight.js's language registry. All callers are telemetry
* (OTel counter attributes, permission-dialog unary events) — none block
* on this, they fire-and-forget or the consumer already handles Promise<string>.
*/
export async function getLanguageName(file_path: string): Promise<string> {
await getCliHighlightPromise()
const ext = extname(file_path).slice(1)
if (!ext) return 'unknown'
return loadedGetLanguage?.(ext)?.name ?? 'unknown'
}