@deepseek-ai/dsh-util-code-language 0.1.7-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.i18n.yaml +25 -0
- package/README.md +50 -0
- package/README.zh.md +50 -0
- package/lib/index.js +269 -0
- package/lib/types/index.d.ts +40 -0
- package/package.json +35 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
|
|
2
|
+
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
|
3
|
+
# After editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/util/code-language/README.md
|
|
5
|
+
/:
|
|
6
|
+
en: cc80317463624b86
|
|
7
|
+
zh: 5acd6caf91ab26cb
|
|
8
|
+
/dsh-util-code-language:
|
|
9
|
+
en: 47e8ee84f77661fe
|
|
10
|
+
zh: 41d4c547ec0d1c07
|
|
11
|
+
/dsh-util-code-language/summary:
|
|
12
|
+
en: 7691b06d9c0f5939
|
|
13
|
+
zh: f11d2272efd6afa1
|
|
14
|
+
/dsh-util-code-language/table-of-contents:
|
|
15
|
+
en: 0af71fd8a7533fed
|
|
16
|
+
zh: 325e8000300b6f03
|
|
17
|
+
/dsh-util-code-language/language-selection:
|
|
18
|
+
en: 320253c948359d9d
|
|
19
|
+
zh: 05e15afc801c0f4a
|
|
20
|
+
/dsh-util-code-language/known-limitations-and-deferred-work:
|
|
21
|
+
en: 18e4dc8978a0dd29
|
|
22
|
+
zh: 6f5715ae89229864
|
|
23
|
+
/dsh-util-code-language/known-limitations-and-deferred-work/dev-note:
|
|
24
|
+
en: cfc7173facebc57c
|
|
25
|
+
zh: 4ea51377d7c9c147
|
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Single file-extension to syntax-highlighting language table shared by the Client code surfaces and the Host read card."
|
|
3
|
+
kind: "package-library"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dsh-util-code-language
|
|
7
|
+
|
|
8
|
+
English | [中文](README.zh.md)
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
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 path to a canonical grammar id case-insensitively; `CODE_HIGHLIGHT_EXTENSIONS` lists every suffix a preview registry can claim. `readLangHintForPath` projects the read card's short ids over the same table, so a suffix a recorded session already holds keeps its persisted value and every other suffix takes its language's short name. The package is browser-safe, stateless, and leaves tokenization to the Client highlighter.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Language selection](#language-selection)
|
|
17
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
18
|
+
- [Dev Note](#dev-note)
|
|
19
|
+
|
|
20
|
+
-----
|
|
21
|
+
|
|
22
|
+
<a id="language-selection"></a>
|
|
23
|
+
## Language selection
|
|
24
|
+
|
|
25
|
+
The table lives in [`src/index.ts`](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.
|
|
26
|
+
|
|
27
|
+
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. CSV maps to `csv`; preview registries place specialized viewers before Code so Spreadsheet remains its default preview. `readLangHintForPath` is a projection over this table: a suffix whose value a recorded session already holds returns that persisted short id, any other suffix returns its language's short name (`powershell` to `ps1`), and an unrecognized suffix returns `undefined` — so the persisted field holds one style, a short name; for `kotlin`, `swift`, `yaml`, `json`, and similar that name is also the grammar id, and the suffixes whose own name is the better label (`tsx`, `tf`, `tfvars`, `gradle`) keep it. 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.
|
|
28
|
+
|
|
29
|
+
-----
|
|
30
|
+
|
|
31
|
+
## Known Limitations and Deferred Work
|
|
32
|
+
|
|
33
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
34
|
+
|
|
35
|
+
- **Extension-only matching** — `languageForPath` reads a suffix, so names recognized without one (`Dockerfile`, `Makefile`, `.gitignore`, `.editorconfig`) stay unlisted. Filename rules are deferred.
|
|
36
|
+
- **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.
|
|
37
|
+
- **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.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
<a id="dev-note"></a>
|
|
41
|
+
### Dev Note
|
|
42
|
+
|
|
43
|
+
<details>
|
|
44
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
45
|
+
|
|
46
|
+
None.
|
|
47
|
+
|
|
48
|
+
</details>
|
|
49
|
+
|
|
50
|
+
**Runtime invariant:** No companion is published. This utility owns no mutable runtime relationship.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Client 代码界面与 Host read 卡片共享的唯一「扩展名 → 语法高亮语言」表。"
|
|
3
|
+
kind: "package-library"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dsh-util-code-language
|
|
7
|
+
|
|
8
|
+
[English](README.md) | 中文
|
|
9
|
+
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
本仓库唯一的「文件扩展名 → 语法高亮语言」表,供 Client 的文档 Code 预览、diff 审阅与 Host read 工具持久化的 `lang` 提示共同使用。`languageForPath` 以大小写不敏感的方式把文件名或路径映射为规范化 grammar id;`CODE_HIGHLIGHT_EXTENSIONS` 列出预览注册可以声明的全部后缀。`readLangHintForPath` 在同一张表上把 read 卡片的短 id 投影出来:已录制的会话已经持有该后缀的值时保持该持久化值不变,其余后缀取该语言的短名。该包可在浏览器使用,不提供 Cordis service,也不持有运行时状态;真正的分词仍由 Client 高亮器负责。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [语言选择](#language-selection)
|
|
17
|
+
- [已知限制与暂缓事项](#known-limitations-and-deferred-work)
|
|
18
|
+
- [开发备注](#dev-note)
|
|
19
|
+
|
|
20
|
+
-----
|
|
21
|
+
|
|
22
|
+
<a id="language-selection"></a>
|
|
23
|
+
## 语言选择
|
|
24
|
+
|
|
25
|
+
表位于 [`src/index.ts`](src/index.ts)。每个键是规范化语言 id——即 Client 高亮器解析的 grammar id;每个值是选中它的、不含点的小写扩展名。`languageForPath(path)` 取路径最后一段的最后一个点之后的文本、转小写后在 `Map` 中查找;使用 `Map` 可避免 `foo.constructor` 这类文件名解析到 `Object.prototype` 成员。未列入表的 dotfile(`.gitignore`)、无扩展名、结尾点、未知后缀都返回 `undefined`,各消费方一律按纯文本渲染;前导点仍算分隔符,因此 `.env` 解析为 `dotenv`。`/` 与 `\` 都算路径分隔符,因此 Windows 路径与 POSIX 路径解析一致。
|
|
26
|
+
|
|
27
|
+
该集合按常见源码、配置、脚本、数据与标记扩展名精选,并非完整语言登记表。没有对应 grammar 的扩展名映射到最接近的 grammar(`properties` 映射到 `ini`,该 grammar 自带 `properties` alias);证书与锁文件扩展名(`pem`、`crt`、`key`、`cer`、`lock`)不列入表。CSV 映射为 `csv`;预览注册表将专用查看器排在 Code 之前,因此 Spreadsheet 仍是它的默认预览。`readLangHintForPath` 在同一张表上做投影:已录制的会话已经持有该后缀的值时返回该持久化短 id,其余后缀返回该语言的短名(`powershell`→`ps1`),无法识别的后缀返回 `undefined`——持久化字段因此只有一种风格,即短名;对 `kotlin`、`swift`、`yaml`、`json` 等语言,短名与 grammar id 相同;而 `tsx`、`tf`、`tfvars`、`gradle` 这些后缀本身的名字更准确,保留其自身名字。消费方若希望 Client 高亮器真正分词,仍取决于该 grammar 已在其中注册——没有加载 grammar 的 id 会按纯文本渲染,而不是报错。
|
|
28
|
+
|
|
29
|
+
-----
|
|
30
|
+
|
|
31
|
+
## 已知限制与暂缓事项
|
|
32
|
+
|
|
33
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
34
|
+
|
|
35
|
+
- **只匹配扩展名**——`languageForPath` 只看后缀,因此 `Dockerfile`、`Makefile`、`.gitignore`、`.editorconfig` 这类靠文件名识别的名称仍不表。文件名规则暂缓。
|
|
36
|
+
- **不做内容嗅探**——扩展名缺失或未知时,即使字节含义明确也按纯文本处理;本表从不读取内容。
|
|
37
|
+
- **精选而非穷举**——本表小于 Shiki 的 grammar 目录与 GitHub linguist;新增语言意味着同时添加扩展名条目与 Client grammar 注册。
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
<a id="dev-note"></a>
|
|
41
|
+
### 开发备注
|
|
42
|
+
|
|
43
|
+
<details>
|
|
44
|
+
<summary>维护者工作上下文——点击展开</summary>
|
|
45
|
+
|
|
46
|
+
无。
|
|
47
|
+
|
|
48
|
+
</details>
|
|
49
|
+
|
|
50
|
+
**运行时不变式:** 不发布伴生入口。这个工具不持有可变运行时关系。
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
//#region lib/types/index.js
|
|
2
|
+
/**
|
|
3
|
+
* Lowercase extension to canonical language id. A Map, not an object: a filename
|
|
4
|
+
* whose extension is an `Object.prototype` key (`foo.constructor`,
|
|
5
|
+
* `foo.__proto__`) must miss instead of resolving the inherited member, which
|
|
6
|
+
* would otherwise reach callers as a non-string language value.
|
|
7
|
+
*/
|
|
8
|
+
const LANGUAGES = new Map(Object.entries({
|
|
9
|
+
typescript: [
|
|
10
|
+
"ts",
|
|
11
|
+
"tsx",
|
|
12
|
+
"mts",
|
|
13
|
+
"cts"
|
|
14
|
+
],
|
|
15
|
+
javascript: [
|
|
16
|
+
"js",
|
|
17
|
+
"jsx",
|
|
18
|
+
"mjs",
|
|
19
|
+
"cjs"
|
|
20
|
+
],
|
|
21
|
+
shellscript: [
|
|
22
|
+
"sh",
|
|
23
|
+
"bash",
|
|
24
|
+
"zsh"
|
|
25
|
+
],
|
|
26
|
+
fish: ["fish"],
|
|
27
|
+
json: [
|
|
28
|
+
"json",
|
|
29
|
+
"jsonc",
|
|
30
|
+
"jsonl",
|
|
31
|
+
"ndjson",
|
|
32
|
+
"ipynb"
|
|
33
|
+
],
|
|
34
|
+
csv: ["csv"],
|
|
35
|
+
python: [
|
|
36
|
+
"py",
|
|
37
|
+
"pyw",
|
|
38
|
+
"pyi"
|
|
39
|
+
],
|
|
40
|
+
ruby: [
|
|
41
|
+
"rb",
|
|
42
|
+
"rake",
|
|
43
|
+
"gemspec"
|
|
44
|
+
],
|
|
45
|
+
go: ["go"],
|
|
46
|
+
rust: ["rs"],
|
|
47
|
+
java: ["java"],
|
|
48
|
+
c: ["c", "h"],
|
|
49
|
+
cpp: [
|
|
50
|
+
"cc",
|
|
51
|
+
"cpp",
|
|
52
|
+
"cxx",
|
|
53
|
+
"hh",
|
|
54
|
+
"hpp",
|
|
55
|
+
"hxx"
|
|
56
|
+
],
|
|
57
|
+
csharp: ["cs"],
|
|
58
|
+
kotlin: ["kt", "kts"],
|
|
59
|
+
swift: ["swift"],
|
|
60
|
+
php: ["php"],
|
|
61
|
+
yaml: ["yaml", "yml"],
|
|
62
|
+
toml: ["toml"],
|
|
63
|
+
ini: [
|
|
64
|
+
"ini",
|
|
65
|
+
"conf",
|
|
66
|
+
"cfg",
|
|
67
|
+
"properties"
|
|
68
|
+
],
|
|
69
|
+
dotenv: ["env"],
|
|
70
|
+
log: ["log"],
|
|
71
|
+
diff: ["diff", "patch"],
|
|
72
|
+
http: ["http"],
|
|
73
|
+
markdown: ["md", "markdown"],
|
|
74
|
+
mdx: ["mdx"],
|
|
75
|
+
rst: ["rst"],
|
|
76
|
+
latex: [
|
|
77
|
+
"tex",
|
|
78
|
+
"sty",
|
|
79
|
+
"cls"
|
|
80
|
+
],
|
|
81
|
+
bibtex: ["bib"],
|
|
82
|
+
asciidoc: ["adoc"],
|
|
83
|
+
html: [
|
|
84
|
+
"html",
|
|
85
|
+
"htm",
|
|
86
|
+
"xhtml"
|
|
87
|
+
],
|
|
88
|
+
css: ["css"],
|
|
89
|
+
scss: ["scss"],
|
|
90
|
+
less: ["less"],
|
|
91
|
+
sql: ["sql"],
|
|
92
|
+
xml: [
|
|
93
|
+
"xml",
|
|
94
|
+
"xsd",
|
|
95
|
+
"xsl",
|
|
96
|
+
"xslt",
|
|
97
|
+
"plist",
|
|
98
|
+
"svg"
|
|
99
|
+
],
|
|
100
|
+
lua: ["lua"],
|
|
101
|
+
bat: ["bat", "cmd"],
|
|
102
|
+
powershell: [
|
|
103
|
+
"ps1",
|
|
104
|
+
"psm1",
|
|
105
|
+
"psd1"
|
|
106
|
+
],
|
|
107
|
+
r: ["r"],
|
|
108
|
+
julia: ["jl"],
|
|
109
|
+
dart: ["dart"],
|
|
110
|
+
scala: ["scala"],
|
|
111
|
+
clojure: [
|
|
112
|
+
"clj",
|
|
113
|
+
"cljs",
|
|
114
|
+
"edn"
|
|
115
|
+
],
|
|
116
|
+
erlang: ["erl", "hrl"],
|
|
117
|
+
elixir: ["ex", "exs"],
|
|
118
|
+
haskell: ["hs"],
|
|
119
|
+
fsharp: [
|
|
120
|
+
"fs",
|
|
121
|
+
"fsi",
|
|
122
|
+
"fsx"
|
|
123
|
+
],
|
|
124
|
+
vb: ["vb"],
|
|
125
|
+
perl: ["pl", "pm"],
|
|
126
|
+
verilog: ["v"],
|
|
127
|
+
"system-verilog": ["sv", "svh"],
|
|
128
|
+
graphql: ["graphql", "gql"],
|
|
129
|
+
proto: ["proto"],
|
|
130
|
+
hcl: [
|
|
131
|
+
"tf",
|
|
132
|
+
"tfvars",
|
|
133
|
+
"hcl"
|
|
134
|
+
],
|
|
135
|
+
nix: ["nix"],
|
|
136
|
+
vue: ["vue"],
|
|
137
|
+
svelte: ["svelte"],
|
|
138
|
+
make: ["makefile", "mk"],
|
|
139
|
+
cmake: ["cmake"],
|
|
140
|
+
groovy: ["gradle", "groovy"]
|
|
141
|
+
}).flatMap(([language, extensions]) => extensions.map((extension) => [extension, language])));
|
|
142
|
+
/** Every recognized filename suffix, one entry each; a document-preview registry uses it to claim Code-rendered bodies. */
|
|
143
|
+
const CODE_HIGHLIGHT_EXTENSIONS = [...LANGUAGES.keys()];
|
|
144
|
+
/**
|
|
145
|
+
* Persisted `lang` values a language-level short id cannot express, keyed by the
|
|
146
|
+
* suffix that produced them. Everything else falls back to
|
|
147
|
+
* {@link SHORT_BY_LANGUAGE}, so only a suffix whose own name is the better label
|
|
148
|
+
* appears here. Each value is the exact string recorded sessions already hold
|
|
149
|
+
* and must not change; the byte-level expectation for every suffix lives in the
|
|
150
|
+
* read consumer's test.
|
|
151
|
+
*/
|
|
152
|
+
const READ_LANG_BY_EXTENSION = new Map([
|
|
153
|
+
["tsx", "tsx"],
|
|
154
|
+
["jsx", "jsx"],
|
|
155
|
+
["tf", "tf"],
|
|
156
|
+
["tfvars", "tfvars"],
|
|
157
|
+
["gradle", "gradle"]
|
|
158
|
+
]);
|
|
159
|
+
/**
|
|
160
|
+
* The short `lang` id the read card persists, keyed by canonical language id.
|
|
161
|
+
* Keys are exactly the languages in {@link LANGUAGE_EXTENSIONS}: where
|
|
162
|
+
* {@link READ_LANG_BY_EXTENSION} does not already fix a suffix's value, this
|
|
163
|
+
* table supplies the language's short name (`powershell` to `ps1`, `hcl` to
|
|
164
|
+
* `tf`, `system-verilog` to `sv`) rather than the grammar id. Keys are canonical
|
|
165
|
+
* ids, not untrusted extensions, so an object lookup cannot reach an
|
|
166
|
+
* `Object.prototype` member the way the extension tables can.
|
|
167
|
+
*/
|
|
168
|
+
const SHORT_BY_LANGUAGE = {
|
|
169
|
+
typescript: "ts",
|
|
170
|
+
javascript: "js",
|
|
171
|
+
shellscript: "sh",
|
|
172
|
+
fish: "fish",
|
|
173
|
+
json: "json",
|
|
174
|
+
csv: "csv",
|
|
175
|
+
python: "py",
|
|
176
|
+
ruby: "rb",
|
|
177
|
+
go: "go",
|
|
178
|
+
rust: "rs",
|
|
179
|
+
java: "java",
|
|
180
|
+
c: "c",
|
|
181
|
+
cpp: "cpp",
|
|
182
|
+
csharp: "cs",
|
|
183
|
+
kotlin: "kotlin",
|
|
184
|
+
swift: "swift",
|
|
185
|
+
php: "php",
|
|
186
|
+
yaml: "yaml",
|
|
187
|
+
toml: "toml",
|
|
188
|
+
ini: "ini",
|
|
189
|
+
dotenv: "env",
|
|
190
|
+
log: "log",
|
|
191
|
+
diff: "diff",
|
|
192
|
+
http: "http",
|
|
193
|
+
markdown: "md",
|
|
194
|
+
mdx: "mdx",
|
|
195
|
+
rst: "rst",
|
|
196
|
+
latex: "tex",
|
|
197
|
+
bibtex: "bib",
|
|
198
|
+
asciidoc: "adoc",
|
|
199
|
+
html: "html",
|
|
200
|
+
css: "css",
|
|
201
|
+
scss: "scss",
|
|
202
|
+
less: "less",
|
|
203
|
+
sql: "sql",
|
|
204
|
+
xml: "xml",
|
|
205
|
+
lua: "lua",
|
|
206
|
+
bat: "bat",
|
|
207
|
+
powershell: "ps1",
|
|
208
|
+
r: "r",
|
|
209
|
+
julia: "jl",
|
|
210
|
+
dart: "dart",
|
|
211
|
+
scala: "scala",
|
|
212
|
+
clojure: "clj",
|
|
213
|
+
erlang: "erl",
|
|
214
|
+
elixir: "ex",
|
|
215
|
+
haskell: "hs",
|
|
216
|
+
fsharp: "fs",
|
|
217
|
+
vb: "vb",
|
|
218
|
+
perl: "pl",
|
|
219
|
+
verilog: "v",
|
|
220
|
+
"system-verilog": "sv",
|
|
221
|
+
graphql: "graphql",
|
|
222
|
+
proto: "proto",
|
|
223
|
+
hcl: "hcl",
|
|
224
|
+
nix: "nix",
|
|
225
|
+
vue: "vue",
|
|
226
|
+
svelte: "svelte",
|
|
227
|
+
make: "make",
|
|
228
|
+
cmake: "cmake",
|
|
229
|
+
groovy: "groovy"
|
|
230
|
+
};
|
|
231
|
+
function extensionForPath(path) {
|
|
232
|
+
const slash = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
233
|
+
const base = path.slice(slash + 1);
|
|
234
|
+
const dot = base.lastIndexOf(".");
|
|
235
|
+
return dot < 0 ? void 0 : base.slice(dot + 1).toLowerCase();
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Derive the syntax-highlighting language from a filename or path, case
|
|
239
|
+
* insensitively. The extension is the text after the last dot of the final path
|
|
240
|
+
* segment; a leading dot is still the separator, so `.env` resolves to `dotenv`
|
|
241
|
+
* while an unlisted dotfile (`.gitignore`) and an extensionless name return
|
|
242
|
+
* `undefined`. Both path separators are recognized, so
|
|
243
|
+
* `C:\\dir\\main.PS1` resolves like `dir/main.ps1`.
|
|
244
|
+
* @param path - decoded filename or path.
|
|
245
|
+
* @returns the canonical language id, or `undefined` for an unrecognized or absent suffix.
|
|
246
|
+
*/
|
|
247
|
+
function languageForPath(path) {
|
|
248
|
+
const extension = extensionForPath(path);
|
|
249
|
+
return extension === void 0 ? void 0 : LANGUAGES.get(extension);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Derive the Host read card's persisted `lang` hint from a read path's
|
|
253
|
+
* extension. The value is the language's short name; for some languages that name
|
|
254
|
+
* is also the grammar id (`kotlin`, `swift`, `java`, `yaml`, `json`), and
|
|
255
|
+
* {@link READ_LANG_BY_EXTENSION} overrides it where the suffix names itself
|
|
256
|
+
* better (`tsx`, `tf`, `gradle`). A suffix a recorded session already holds keeps
|
|
257
|
+
* its persisted value. An unrecognized suffix stays `undefined`, so the card
|
|
258
|
+
* renders as plain text.
|
|
259
|
+
* @param path - the model-facing path the read reported.
|
|
260
|
+
* @returns the persisted language hint, or `undefined` when the extension maps to none.
|
|
261
|
+
*/
|
|
262
|
+
function readLangHintForPath(path) {
|
|
263
|
+
const extension = extensionForPath(path);
|
|
264
|
+
if (extension === void 0) return void 0;
|
|
265
|
+
const canonical = LANGUAGES.get(extension);
|
|
266
|
+
return canonical === void 0 ? void 0 : READ_LANG_BY_EXTENSION.get(extension) ?? SHORT_BY_LANGUAGE[canonical];
|
|
267
|
+
}
|
|
268
|
+
//#endregion
|
|
269
|
+
export { CODE_HIGHLIGHT_EXTENSIONS, languageForPath, readLangHintForPath };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single file-extension to syntax-highlighting language table shared by every
|
|
3
|
+
* code surface: the Client's document Code preview and diff review, and the Host
|
|
4
|
+
* read tool's persisted `lang` hint. Language ids are the grammar ids the Client
|
|
5
|
+
* highlighter's alias table resolves, so a language returned here reaches
|
|
6
|
+
* `highlightLines`/`highlightToHtml` unchanged; a filename outside the table, or
|
|
7
|
+
* one naming a language the highlighter does not register, renders as plain text.
|
|
8
|
+
* The read tool persists a short `lang` id, so {@link readLangHintForPath}
|
|
9
|
+
* projects short ids over this table: a suffix keeps the value a recorded session
|
|
10
|
+
* already holds, and every other suffix persists the language's short name —
|
|
11
|
+
* which for `kotlin`, `swift`, `yaml`, `json`, and similar equals that
|
|
12
|
+
* language's grammar id.
|
|
13
|
+
* @module @deepseek-ai/dsh-util-code-language
|
|
14
|
+
*/
|
|
15
|
+
/** Every recognized filename suffix, one entry each; a document-preview registry uses it to claim Code-rendered bodies. */
|
|
16
|
+
export declare const CODE_HIGHLIGHT_EXTENSIONS: readonly string[];
|
|
17
|
+
/**
|
|
18
|
+
* Derive the syntax-highlighting language from a filename or path, case
|
|
19
|
+
* insensitively. The extension is the text after the last dot of the final path
|
|
20
|
+
* segment; a leading dot is still the separator, so `.env` resolves to `dotenv`
|
|
21
|
+
* while an unlisted dotfile (`.gitignore`) and an extensionless name return
|
|
22
|
+
* `undefined`. Both path separators are recognized, so
|
|
23
|
+
* `C:\\dir\\main.PS1` resolves like `dir/main.ps1`.
|
|
24
|
+
* @param path - decoded filename or path.
|
|
25
|
+
* @returns the canonical language id, or `undefined` for an unrecognized or absent suffix.
|
|
26
|
+
*/
|
|
27
|
+
export declare function languageForPath(path: string): string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Derive the Host read card's persisted `lang` hint from a read path's
|
|
30
|
+
* extension. The value is the language's short name; for some languages that name
|
|
31
|
+
* is also the grammar id (`kotlin`, `swift`, `java`, `yaml`, `json`), and
|
|
32
|
+
* {@link READ_LANG_BY_EXTENSION} overrides it where the suffix names itself
|
|
33
|
+
* better (`tsx`, `tf`, `gradle`). A suffix a recorded session already holds keeps
|
|
34
|
+
* its persisted value. An unrecognized suffix stays `undefined`, so the card
|
|
35
|
+
* renders as plain text.
|
|
36
|
+
* @param path - the model-facing path the read reported.
|
|
37
|
+
* @returns the persisted language hint, or `undefined` when the extension maps to none.
|
|
38
|
+
*/
|
|
39
|
+
export declare function readLangHintForPath(path: string): string | undefined;
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@deepseek-ai/dsh-util-code-language",
|
|
3
|
+
"description": "Single file-extension to syntax-highlighting language table shared by Client code surfaces and the Host read card",
|
|
4
|
+
"version": "0.1.7-rc.2",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/util/code-language"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./src/*": "./src/*",
|
|
22
|
+
"./package.json": "./package.json"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"lib/index.js",
|
|
26
|
+
"lib/types/**/*.d.ts"
|
|
27
|
+
],
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@deepseek-ai/cordis": "~4.0.4"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@deepseek-ai/cordis": "~4.0.4"
|
|
34
|
+
}
|
|
35
|
+
}
|