The document Code preview and the Host read card each owned an extension-to-language table that had drifted: the preview table had 13 extensions the read card lacked, and the two returned different language ids for the same suffix. Both now resolve through the new zero-dependency @deepseek-ai/dsh-util-code-language, which also adds common Windows, config, markup, and language extensions. Every added grammar stays in the lazy set; the boot grammars are unchanged. Fixes #4822
description, kind
| description | kind |
|---|---|
| Single file-extension to syntax-highlighting language table shared by the Client code surfaces and the Host read card. | package-library |
dsh-util-code-language
English | 中文
Summary
The repository's one file-extension to syntax-highlighting language table, shared by the Client's document Code preview and diff review and by the Host read tool's persisted lang hint. languageForPath maps a filename or path to a canonical grammar id case-insensitively, recognizing both path separators and treating a leading dot as the extension separator (.env resolves to dotenv). CODE_HIGHLIGHT_EXTENSIONS lists every recognized suffix for a preview registry. The package is browser-safe, has no Cordis service or runtime state, and leaves the actual tokenization to the Client highlighter.
Table of Contents
Language selection
The table lives in src/index.ts. Each key is a canonical language id — the grammar id the Client highlighter resolves — and each value is the lowercase extensions without the dot that select it. languageForPath(path) takes the text after the last dot of the final path segment, lowercases it, and looks it up in a Map; a Map keeps a filename such as foo.constructor from resolving an Object.prototype member. An unlisted dotfile (.gitignore), an absent extension, a trailing dot, and an unknown suffix all return undefined, which every consumer renders as plain text; a leading dot is still the separator, so .env resolves to dotenv. Both / and \ separate path segments, so a Windows path resolves like a POSIX one.
The set is curated for common source, config, script, data, and markup extensions rather than mirroring a full language registry. Extensions with no matching grammar map to the nearest one (properties to ini, whose registration carries the properties alias); certificate and lock extensions (pem, crt, key, cer, lock) stay unlisted. A consumer that needs the Client highlighter to actually tokenize a language still depends on that grammar being registered there — an id without a loaded grammar renders as plain text rather than failing.
Known Limitations and Deferred Work
- Extension-only matching —
languageForPathreads a suffix, so names recognized without one (Dockerfile,Makefile,.gitignore,.editorconfig) stay unlisted. Filename rules are deferred. - No content sniffing — a file with an absent or unknown extension stays plain text even when its bytes are unambiguous; the table never inspects content.
- Curated, not exhaustive — the table is smaller than Shiki's grammar catalog and GitHub linguist; adding a language means adding both the extension entry and the Client grammar registration.
Dev Note
Working context for maintainers — click to expand
None.
Runtime invariant: No companion is published. This utility owns no mutable runtime relationship.