tree-sitter-ts-highlight-cli 0.1.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/README.md +88 -0
- package/dist/cli.js +277 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +310 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +34 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +275 -0
- package/dist/index.js.map +1 -0
- package/package.json +69 -0
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# tree-sitter-ts-highlight-cli
|
|
2
|
+
|
|
3
|
+
Command-line wrapper for [`tree-sitter-ts-highlight`](https://www.npmjs.com/package/tree-sitter-ts-highlight).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g tree-sitter-ts-highlight-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or run with `npx`:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx tree-sitter-ts-highlight-cli --help
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
hlts [options]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### HTML highlight
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
hlts --input example.ts --language typescript --block --line-numbers > out.html
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### ANSI highlight (terminal)
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
hlts --input example.ts --ansi --line-numbers
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Diff highlight (HTML)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
hlts --diff --old before.ts --new after.ts --view side-by-side > diff.html
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Options
|
|
42
|
+
|
|
43
|
+
- `-i, --input <file>`: input file path (default: stdin)
|
|
44
|
+
- `-o, --output <file>`: output file path (default: stdout)
|
|
45
|
+
- `-l, --language <lang>`: language name or extension
|
|
46
|
+
- `--ansi`: output ANSI-colored text
|
|
47
|
+
- `--diff`: output highlighted HTML diff (requires `--old` and `--new`)
|
|
48
|
+
- `--block`: wrap HTML output in `<pre><code>`
|
|
49
|
+
- `--line-numbers`: include line numbers
|
|
50
|
+
- `--start-line <n>`: set starting line number
|
|
51
|
+
- `--semantic`: enable semantic token enhancement
|
|
52
|
+
- `--theme <name>`: built-in HTML theme name (from `tree-sitter-ts-highlight`)
|
|
53
|
+
- `--old <file>`: old/original file for diff mode
|
|
54
|
+
- `--new <file>`: new/updated file for diff mode
|
|
55
|
+
- `--view <mode>`: `side-by-side` or `inline` (diff mode)
|
|
56
|
+
- `--old-label <label>`: label for old side header
|
|
57
|
+
- `--new-label <label>`: label for new side header
|
|
58
|
+
- `--no-header`: hide diff header row
|
|
59
|
+
- `-h, --help`: show help
|
|
60
|
+
- `-v, --version`: show version
|
|
61
|
+
|
|
62
|
+
## Programmatic API
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { runCli, parseCliArgs } from "tree-sitter-ts-highlight-cli";
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The package also re-exports all public APIs from `tree-sitter-ts-highlight`.
|
|
69
|
+
|
|
70
|
+
### TypeScript types
|
|
71
|
+
|
|
72
|
+
This package also re-exports types from both `tree-sitter-ts-highlight` and `tree-sitter-ts`, so TypeScript libraries can consume those shared types directly:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import type { ThemeDefinition } from "tree-sitter-ts-highlight-cli";
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Test
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm test
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Watch mode:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npm run test:watch
|
|
88
|
+
```
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/run-cli.ts
|
|
4
|
+
import { extname } from "path";
|
|
5
|
+
import {
|
|
6
|
+
getTheme,
|
|
7
|
+
highlight,
|
|
8
|
+
highlightAnsi,
|
|
9
|
+
highlightBlock,
|
|
10
|
+
highlightDiff
|
|
11
|
+
} from "tree-sitter-ts-highlight";
|
|
12
|
+
var VERSION = "0.1.2";
|
|
13
|
+
function createHelpText() {
|
|
14
|
+
return [
|
|
15
|
+
"tree-sitter-ts-highlight-cli",
|
|
16
|
+
"",
|
|
17
|
+
"Usage:",
|
|
18
|
+
" hlts [options]",
|
|
19
|
+
"",
|
|
20
|
+
"Modes:",
|
|
21
|
+
" --ansi Output ANSI-highlighted text for terminals",
|
|
22
|
+
" --diff Output HTML highlighted diff (requires --old and --new)",
|
|
23
|
+
"",
|
|
24
|
+
"Input:",
|
|
25
|
+
" -i, --input <file> Input file path (default: stdin)",
|
|
26
|
+
" -o, --output <file> Output file path (default: stdout)",
|
|
27
|
+
" -l, --language <lang> Language or extension (default: detect from file, else typescript)",
|
|
28
|
+
"",
|
|
29
|
+
"HTML options:",
|
|
30
|
+
" --block Wrap output in <pre><code>",
|
|
31
|
+
" --line-numbers Include line numbers",
|
|
32
|
+
" --start-line <n> Starting line number",
|
|
33
|
+
" --semantic Enable semantic token enhancement",
|
|
34
|
+
" --theme <name> Built-in HTML theme name",
|
|
35
|
+
"",
|
|
36
|
+
"Diff options:",
|
|
37
|
+
" --old <file> Old/original file for diff mode",
|
|
38
|
+
" --new <file> New/updated file for diff mode",
|
|
39
|
+
" --view <mode> side-by-side | inline (default: side-by-side)",
|
|
40
|
+
" --old-label <label> Header label for old side",
|
|
41
|
+
" --new-label <label> Header label for new side",
|
|
42
|
+
" --no-header Hide diff headers",
|
|
43
|
+
"",
|
|
44
|
+
"General:",
|
|
45
|
+
" -h, --help Show help",
|
|
46
|
+
" -v, --version Show version"
|
|
47
|
+
].join("\n");
|
|
48
|
+
}
|
|
49
|
+
function parseCliArgs(args) {
|
|
50
|
+
const options = {
|
|
51
|
+
mode: "html",
|
|
52
|
+
language: "typescript",
|
|
53
|
+
lineNumbers: false,
|
|
54
|
+
semanticHighlighting: false,
|
|
55
|
+
wrapInPre: false,
|
|
56
|
+
diffView: "side-by-side",
|
|
57
|
+
showHeader: true,
|
|
58
|
+
help: false,
|
|
59
|
+
version: false
|
|
60
|
+
};
|
|
61
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
62
|
+
const arg = args[index];
|
|
63
|
+
if (arg === "-h" || arg === "--help") {
|
|
64
|
+
options.help = true;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (arg === "-v" || arg === "--version") {
|
|
68
|
+
options.version = true;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (arg === "--ansi") {
|
|
72
|
+
options.mode = "ansi";
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (arg === "--diff") {
|
|
76
|
+
options.mode = "diff";
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (arg === "--line-numbers") {
|
|
80
|
+
options.lineNumbers = true;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (arg === "--semantic") {
|
|
84
|
+
options.semanticHighlighting = true;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (arg === "--block") {
|
|
88
|
+
options.wrapInPre = true;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (arg === "--no-header") {
|
|
92
|
+
options.showHeader = false;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (arg === "-i" || arg === "--input") {
|
|
96
|
+
options.inputPath = nextValue(args, ++index, arg);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (arg === "-o" || arg === "--output") {
|
|
100
|
+
options.outputPath = nextValue(args, ++index, arg);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (arg === "-l" || arg === "--language") {
|
|
104
|
+
options.language = nextValue(args, ++index, arg);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (arg === "--start-line") {
|
|
108
|
+
const value = nextValue(args, ++index, arg);
|
|
109
|
+
const startLine = Number.parseInt(value, 10);
|
|
110
|
+
if (!Number.isFinite(startLine) || startLine <= 0) {
|
|
111
|
+
throw new Error(`Invalid --start-line value: ${value}`);
|
|
112
|
+
}
|
|
113
|
+
options.startLine = startLine;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (arg === "--theme") {
|
|
117
|
+
options.themeName = nextValue(args, ++index, arg);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (arg === "--old") {
|
|
121
|
+
options.oldPath = nextValue(args, ++index, arg);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (arg === "--new") {
|
|
125
|
+
options.newPath = nextValue(args, ++index, arg);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (arg === "--view") {
|
|
129
|
+
const view = nextValue(args, ++index, arg);
|
|
130
|
+
if (view !== "side-by-side" && view !== "inline") {
|
|
131
|
+
throw new Error(`Invalid --view value: ${view}`);
|
|
132
|
+
}
|
|
133
|
+
options.diffView = view;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (arg === "--old-label") {
|
|
137
|
+
options.oldLabel = nextValue(args, ++index, arg);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (arg === "--new-label") {
|
|
141
|
+
options.newLabel = nextValue(args, ++index, arg);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
145
|
+
}
|
|
146
|
+
return options;
|
|
147
|
+
}
|
|
148
|
+
async function runCli(args, io) {
|
|
149
|
+
try {
|
|
150
|
+
const options = parseCliArgs(args);
|
|
151
|
+
if (options.help) {
|
|
152
|
+
io.stdout.write(`${createHelpText()}
|
|
153
|
+
`);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (options.version) {
|
|
157
|
+
io.stdout.write(`${VERSION}
|
|
158
|
+
`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const renderResult = await render(options, io.stdin);
|
|
162
|
+
if (options.outputPath) {
|
|
163
|
+
const { writeFile } = await import("fs/promises");
|
|
164
|
+
await writeFile(options.outputPath, renderResult, "utf8");
|
|
165
|
+
} else {
|
|
166
|
+
io.stdout.write(renderResult);
|
|
167
|
+
if (!renderResult.endsWith("\n")) {
|
|
168
|
+
io.stdout.write("\n");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
} catch (error) {
|
|
172
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
173
|
+
io.stderr.write(`Error: ${message}
|
|
174
|
+
`);
|
|
175
|
+
io.stderr.write("Use --help to see usage.\n");
|
|
176
|
+
io.exit(1);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async function render(options, stdin) {
|
|
180
|
+
if (options.mode === "diff") {
|
|
181
|
+
if (!options.oldPath || !options.newPath) {
|
|
182
|
+
throw new Error("--diff requires both --old and --new");
|
|
183
|
+
}
|
|
184
|
+
const { readFile } = await import("fs/promises");
|
|
185
|
+
const [oldSource, newSource] = await Promise.all([
|
|
186
|
+
readFile(options.oldPath, "utf8"),
|
|
187
|
+
readFile(options.newPath, "utf8")
|
|
188
|
+
]);
|
|
189
|
+
const language2 = resolveLanguage(options.language, options.newPath);
|
|
190
|
+
return highlightDiff(oldSource, newSource, language2, {
|
|
191
|
+
view: options.diffView,
|
|
192
|
+
semanticHighlighting: options.semanticHighlighting,
|
|
193
|
+
oldLabel: options.oldLabel,
|
|
194
|
+
newLabel: options.newLabel,
|
|
195
|
+
showHeader: options.showHeader,
|
|
196
|
+
classPrefix: "hlts-",
|
|
197
|
+
theme: resolveHtmlTheme(options.themeName)
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
const source = options.inputPath ? await readTextFile(options.inputPath) : await readStdin(stdin);
|
|
201
|
+
const language = resolveLanguage(options.language, options.inputPath);
|
|
202
|
+
if (options.mode === "ansi") {
|
|
203
|
+
return highlightAnsi(source, language, {
|
|
204
|
+
semanticHighlighting: options.semanticHighlighting,
|
|
205
|
+
lineNumbers: options.lineNumbers,
|
|
206
|
+
startLine: options.startLine
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
const htmlOptions = {
|
|
210
|
+
semanticHighlighting: options.semanticHighlighting,
|
|
211
|
+
lineNumbers: options.lineNumbers,
|
|
212
|
+
startLine: options.startLine,
|
|
213
|
+
theme: resolveHtmlTheme(options.themeName)
|
|
214
|
+
};
|
|
215
|
+
if (options.wrapInPre) {
|
|
216
|
+
return highlightBlock(source, language, {
|
|
217
|
+
...htmlOptions,
|
|
218
|
+
language
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return highlight(source, language, htmlOptions);
|
|
222
|
+
}
|
|
223
|
+
async function readTextFile(filePath) {
|
|
224
|
+
const { readFile } = await import("fs/promises");
|
|
225
|
+
return readFile(filePath, "utf8");
|
|
226
|
+
}
|
|
227
|
+
function readStdin(stdin) {
|
|
228
|
+
return new Promise((resolve, reject) => {
|
|
229
|
+
const chunks = [];
|
|
230
|
+
stdin.on("data", (chunk) => {
|
|
231
|
+
if (typeof chunk === "string") {
|
|
232
|
+
chunks.push(Buffer.from(chunk));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
chunks.push(chunk);
|
|
236
|
+
});
|
|
237
|
+
stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
238
|
+
stdin.on("error", reject);
|
|
239
|
+
stdin.resume();
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function resolveLanguage(explicitLanguage, filePath) {
|
|
243
|
+
if (explicitLanguage && explicitLanguage !== "typescript") {
|
|
244
|
+
return explicitLanguage;
|
|
245
|
+
}
|
|
246
|
+
if (!filePath) {
|
|
247
|
+
return explicitLanguage || "typescript";
|
|
248
|
+
}
|
|
249
|
+
const extension = extname(filePath);
|
|
250
|
+
return extension || explicitLanguage || "typescript";
|
|
251
|
+
}
|
|
252
|
+
function resolveHtmlTheme(themeName) {
|
|
253
|
+
if (!themeName) {
|
|
254
|
+
return void 0;
|
|
255
|
+
}
|
|
256
|
+
const theme = getTheme(themeName);
|
|
257
|
+
if (!theme) {
|
|
258
|
+
throw new Error(`Unknown theme: ${themeName}`);
|
|
259
|
+
}
|
|
260
|
+
return theme;
|
|
261
|
+
}
|
|
262
|
+
function nextValue(args, index, flagName) {
|
|
263
|
+
const value = args[index];
|
|
264
|
+
if (!value || value.startsWith("-")) {
|
|
265
|
+
throw new Error(`Missing value for ${flagName}`);
|
|
266
|
+
}
|
|
267
|
+
return value;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// src/cli.ts
|
|
271
|
+
void runCli(process.argv.slice(2), {
|
|
272
|
+
stdin: process.stdin,
|
|
273
|
+
stdout: process.stdout,
|
|
274
|
+
stderr: process.stderr,
|
|
275
|
+
exit: (code) => process.exit(code)
|
|
276
|
+
});
|
|
277
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/run-cli.ts","../src/cli.ts"],"sourcesContent":["import { extname } from \"node:path\";\r\nimport {\r\n getTheme,\r\n highlight,\r\n highlightAnsi,\r\n highlightBlock,\r\n highlightDiff,\r\n} from \"tree-sitter-ts-highlight\";\r\n\r\nexport type CliMode = \"html\" | \"ansi\" | \"diff\";\r\n\r\nexport interface CliOptions {\r\n mode: CliMode;\r\n inputPath?: string;\r\n outputPath?: string;\r\n language: string;\r\n lineNumbers: boolean;\r\n startLine?: number;\r\n semanticHighlighting: boolean;\r\n wrapInPre: boolean;\r\n diffView: \"side-by-side\" | \"inline\";\r\n oldPath?: string;\r\n newPath?: string;\r\n oldLabel?: string;\r\n newLabel?: string;\r\n showHeader: boolean;\r\n themeName?: string;\r\n help: boolean;\r\n version: boolean;\r\n}\r\n\r\ninterface IoLike {\r\n stdin: NodeJS.ReadStream;\r\n stdout: NodeJS.WriteStream;\r\n stderr: NodeJS.WriteStream;\r\n exit: (code: number) => never | void;\r\n}\r\n\r\nconst VERSION = \"0.1.2\";\r\n\r\nexport function createHelpText(): string {\r\n return [\r\n \"tree-sitter-ts-highlight-cli\",\r\n \"\",\r\n \"Usage:\",\r\n \" hlts [options]\",\r\n \"\",\r\n \"Modes:\",\r\n \" --ansi Output ANSI-highlighted text for terminals\",\r\n \" --diff Output HTML highlighted diff (requires --old and --new)\",\r\n \"\",\r\n \"Input:\",\r\n \" -i, --input <file> Input file path (default: stdin)\",\r\n \" -o, --output <file> Output file path (default: stdout)\",\r\n \" -l, --language <lang> Language or extension (default: detect from file, else typescript)\",\r\n \"\",\r\n \"HTML options:\",\r\n \" --block Wrap output in <pre><code>\",\r\n \" --line-numbers Include line numbers\",\r\n \" --start-line <n> Starting line number\",\r\n \" --semantic Enable semantic token enhancement\",\r\n \" --theme <name> Built-in HTML theme name\",\r\n \"\",\r\n \"Diff options:\",\r\n \" --old <file> Old/original file for diff mode\",\r\n \" --new <file> New/updated file for diff mode\",\r\n \" --view <mode> side-by-side | inline (default: side-by-side)\",\r\n \" --old-label <label> Header label for old side\",\r\n \" --new-label <label> Header label for new side\",\r\n \" --no-header Hide diff headers\",\r\n \"\",\r\n \"General:\",\r\n \" -h, --help Show help\",\r\n \" -v, --version Show version\",\r\n ].join(\"\\n\");\r\n}\r\n\r\nexport function parseCliArgs(args: string[]): CliOptions {\r\n const options: CliOptions = {\r\n mode: \"html\",\r\n language: \"typescript\",\r\n lineNumbers: false,\r\n semanticHighlighting: false,\r\n wrapInPre: false,\r\n diffView: \"side-by-side\",\r\n showHeader: true,\r\n help: false,\r\n version: false,\r\n };\r\n\r\n for (let index = 0; index < args.length; index += 1) {\r\n const arg = args[index];\r\n\r\n if (arg === \"-h\" || arg === \"--help\") {\r\n options.help = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"-v\" || arg === \"--version\") {\r\n options.version = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"--ansi\") {\r\n options.mode = \"ansi\";\r\n continue;\r\n }\r\n\r\n if (arg === \"--diff\") {\r\n options.mode = \"diff\";\r\n continue;\r\n }\r\n\r\n if (arg === \"--line-numbers\") {\r\n options.lineNumbers = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"--semantic\") {\r\n options.semanticHighlighting = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"--block\") {\r\n options.wrapInPre = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"--no-header\") {\r\n options.showHeader = false;\r\n continue;\r\n }\r\n\r\n if (arg === \"-i\" || arg === \"--input\") {\r\n options.inputPath = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"-o\" || arg === \"--output\") {\r\n options.outputPath = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"-l\" || arg === \"--language\") {\r\n options.language = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--start-line\") {\r\n const value = nextValue(args, ++index, arg);\r\n const startLine = Number.parseInt(value, 10);\r\n if (!Number.isFinite(startLine) || startLine <= 0) {\r\n throw new Error(`Invalid --start-line value: ${value}`);\r\n }\r\n options.startLine = startLine;\r\n continue;\r\n }\r\n\r\n if (arg === \"--theme\") {\r\n options.themeName = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--old\") {\r\n options.oldPath = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--new\") {\r\n options.newPath = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--view\") {\r\n const view = nextValue(args, ++index, arg);\r\n if (view !== \"side-by-side\" && view !== \"inline\") {\r\n throw new Error(`Invalid --view value: ${view}`);\r\n }\r\n options.diffView = view;\r\n continue;\r\n }\r\n\r\n if (arg === \"--old-label\") {\r\n options.oldLabel = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--new-label\") {\r\n options.newLabel = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n throw new Error(`Unknown argument: ${arg}`);\r\n }\r\n\r\n return options;\r\n}\r\n\r\nexport async function runCli(args: string[], io: IoLike): Promise<void> {\r\n try {\r\n const options = parseCliArgs(args);\r\n\r\n if (options.help) {\r\n io.stdout.write(`${createHelpText()}\\n`);\r\n return;\r\n }\r\n\r\n if (options.version) {\r\n io.stdout.write(`${VERSION}\\n`);\r\n return;\r\n }\r\n\r\n const renderResult = await render(options, io.stdin);\r\n\r\n if (options.outputPath) {\r\n const { writeFile } = await import(\"node:fs/promises\");\r\n await writeFile(options.outputPath, renderResult, \"utf8\");\r\n } else {\r\n io.stdout.write(renderResult);\r\n if (!renderResult.endsWith(\"\\n\")) {\r\n io.stdout.write(\"\\n\");\r\n }\r\n }\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n io.stderr.write(`Error: ${message}\\n`);\r\n io.stderr.write(\"Use --help to see usage.\\n\");\r\n io.exit(1);\r\n }\r\n}\r\n\r\nasync function render(options: CliOptions, stdin: NodeJS.ReadStream): Promise<string> {\r\n if (options.mode === \"diff\") {\r\n if (!options.oldPath || !options.newPath) {\r\n throw new Error(\"--diff requires both --old and --new\");\r\n }\r\n\r\n const { readFile } = await import(\"node:fs/promises\");\r\n const [oldSource, newSource] = await Promise.all([\r\n readFile(options.oldPath, \"utf8\"),\r\n readFile(options.newPath, \"utf8\"),\r\n ]);\r\n\r\n const language = resolveLanguage(options.language, options.newPath);\r\n\r\n return highlightDiff(oldSource, newSource, language, {\r\n view: options.diffView,\r\n semanticHighlighting: options.semanticHighlighting,\r\n oldLabel: options.oldLabel,\r\n newLabel: options.newLabel,\r\n showHeader: options.showHeader,\r\n classPrefix: \"hlts-\",\r\n theme: resolveHtmlTheme(options.themeName),\r\n });\r\n }\r\n\r\n const source = options.inputPath\r\n ? await readTextFile(options.inputPath)\r\n : await readStdin(stdin);\r\n\r\n const language = resolveLanguage(options.language, options.inputPath);\r\n\r\n if (options.mode === \"ansi\") {\r\n return highlightAnsi(source, language, {\r\n semanticHighlighting: options.semanticHighlighting,\r\n lineNumbers: options.lineNumbers,\r\n startLine: options.startLine,\r\n });\r\n }\r\n\r\n const htmlOptions = {\r\n semanticHighlighting: options.semanticHighlighting,\r\n lineNumbers: options.lineNumbers,\r\n startLine: options.startLine,\r\n theme: resolveHtmlTheme(options.themeName),\r\n };\r\n\r\n if (options.wrapInPre) {\r\n return highlightBlock(source, language, {\r\n ...htmlOptions,\r\n language,\r\n });\r\n }\r\n\r\n return highlight(source, language, htmlOptions);\r\n}\r\n\r\nasync function readTextFile(filePath: string): Promise<string> {\r\n const { readFile } = await import(\"node:fs/promises\");\r\n return readFile(filePath, \"utf8\");\r\n}\r\n\r\nfunction readStdin(stdin: NodeJS.ReadStream): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n const chunks: Buffer[] = [];\r\n stdin.on(\"data\", (chunk: Buffer | string) => {\r\n if (typeof chunk === \"string\") {\r\n chunks.push(Buffer.from(chunk));\r\n return;\r\n }\r\n chunks.push(chunk);\r\n });\r\n stdin.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf8\")));\r\n stdin.on(\"error\", reject);\r\n stdin.resume();\r\n });\r\n}\r\n\r\nfunction resolveLanguage(explicitLanguage: string, filePath?: string): string {\r\n if (explicitLanguage && explicitLanguage !== \"typescript\") {\r\n return explicitLanguage;\r\n }\r\n\r\n if (!filePath) {\r\n return explicitLanguage || \"typescript\";\r\n }\r\n\r\n const extension = extname(filePath);\r\n return extension || explicitLanguage || \"typescript\";\r\n}\r\n\r\nfunction resolveHtmlTheme(themeName?: string) {\r\n if (!themeName) {\r\n return undefined;\r\n }\r\n\r\n const theme = getTheme(themeName);\r\n if (!theme) {\r\n throw new Error(`Unknown theme: ${themeName}`);\r\n }\r\n return theme;\r\n}\r\n\r\nfunction nextValue(args: string[], index: number, flagName: string): string {\r\n const value = args[index];\r\n if (!value || value.startsWith(\"-\")) {\r\n throw new Error(`Missing value for ${flagName}`);\r\n }\r\n return value;\r\n}\r\n","import { runCli } from \"./run-cli\";\r\n\r\nvoid runCli(process.argv.slice(2), {\r\n stdin: process.stdin,\r\n stdout: process.stdout,\r\n stderr: process.stderr,\r\n exit: (code) => process.exit(code),\r\n});\r\n"],"mappings":"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","names":["language"]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var index_exports = {};
|
|
33
|
+
__export(index_exports, {
|
|
34
|
+
createHelpText: () => createHelpText,
|
|
35
|
+
parseCliArgs: () => parseCliArgs,
|
|
36
|
+
runCli: () => runCli
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(index_exports);
|
|
39
|
+
|
|
40
|
+
// src/run-cli.ts
|
|
41
|
+
var import_node_path = require("path");
|
|
42
|
+
var import_tree_sitter_ts_highlight = require("tree-sitter-ts-highlight");
|
|
43
|
+
var VERSION = "0.1.2";
|
|
44
|
+
function createHelpText() {
|
|
45
|
+
return [
|
|
46
|
+
"tree-sitter-ts-highlight-cli",
|
|
47
|
+
"",
|
|
48
|
+
"Usage:",
|
|
49
|
+
" hlts [options]",
|
|
50
|
+
"",
|
|
51
|
+
"Modes:",
|
|
52
|
+
" --ansi Output ANSI-highlighted text for terminals",
|
|
53
|
+
" --diff Output HTML highlighted diff (requires --old and --new)",
|
|
54
|
+
"",
|
|
55
|
+
"Input:",
|
|
56
|
+
" -i, --input <file> Input file path (default: stdin)",
|
|
57
|
+
" -o, --output <file> Output file path (default: stdout)",
|
|
58
|
+
" -l, --language <lang> Language or extension (default: detect from file, else typescript)",
|
|
59
|
+
"",
|
|
60
|
+
"HTML options:",
|
|
61
|
+
" --block Wrap output in <pre><code>",
|
|
62
|
+
" --line-numbers Include line numbers",
|
|
63
|
+
" --start-line <n> Starting line number",
|
|
64
|
+
" --semantic Enable semantic token enhancement",
|
|
65
|
+
" --theme <name> Built-in HTML theme name",
|
|
66
|
+
"",
|
|
67
|
+
"Diff options:",
|
|
68
|
+
" --old <file> Old/original file for diff mode",
|
|
69
|
+
" --new <file> New/updated file for diff mode",
|
|
70
|
+
" --view <mode> side-by-side | inline (default: side-by-side)",
|
|
71
|
+
" --old-label <label> Header label for old side",
|
|
72
|
+
" --new-label <label> Header label for new side",
|
|
73
|
+
" --no-header Hide diff headers",
|
|
74
|
+
"",
|
|
75
|
+
"General:",
|
|
76
|
+
" -h, --help Show help",
|
|
77
|
+
" -v, --version Show version"
|
|
78
|
+
].join("\n");
|
|
79
|
+
}
|
|
80
|
+
function parseCliArgs(args) {
|
|
81
|
+
const options = {
|
|
82
|
+
mode: "html",
|
|
83
|
+
language: "typescript",
|
|
84
|
+
lineNumbers: false,
|
|
85
|
+
semanticHighlighting: false,
|
|
86
|
+
wrapInPre: false,
|
|
87
|
+
diffView: "side-by-side",
|
|
88
|
+
showHeader: true,
|
|
89
|
+
help: false,
|
|
90
|
+
version: false
|
|
91
|
+
};
|
|
92
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
93
|
+
const arg = args[index];
|
|
94
|
+
if (arg === "-h" || arg === "--help") {
|
|
95
|
+
options.help = true;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (arg === "-v" || arg === "--version") {
|
|
99
|
+
options.version = true;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (arg === "--ansi") {
|
|
103
|
+
options.mode = "ansi";
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (arg === "--diff") {
|
|
107
|
+
options.mode = "diff";
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (arg === "--line-numbers") {
|
|
111
|
+
options.lineNumbers = true;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (arg === "--semantic") {
|
|
115
|
+
options.semanticHighlighting = true;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (arg === "--block") {
|
|
119
|
+
options.wrapInPre = true;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (arg === "--no-header") {
|
|
123
|
+
options.showHeader = false;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (arg === "-i" || arg === "--input") {
|
|
127
|
+
options.inputPath = nextValue(args, ++index, arg);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (arg === "-o" || arg === "--output") {
|
|
131
|
+
options.outputPath = nextValue(args, ++index, arg);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (arg === "-l" || arg === "--language") {
|
|
135
|
+
options.language = nextValue(args, ++index, arg);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (arg === "--start-line") {
|
|
139
|
+
const value = nextValue(args, ++index, arg);
|
|
140
|
+
const startLine = Number.parseInt(value, 10);
|
|
141
|
+
if (!Number.isFinite(startLine) || startLine <= 0) {
|
|
142
|
+
throw new Error(`Invalid --start-line value: ${value}`);
|
|
143
|
+
}
|
|
144
|
+
options.startLine = startLine;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (arg === "--theme") {
|
|
148
|
+
options.themeName = nextValue(args, ++index, arg);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (arg === "--old") {
|
|
152
|
+
options.oldPath = nextValue(args, ++index, arg);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (arg === "--new") {
|
|
156
|
+
options.newPath = nextValue(args, ++index, arg);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (arg === "--view") {
|
|
160
|
+
const view = nextValue(args, ++index, arg);
|
|
161
|
+
if (view !== "side-by-side" && view !== "inline") {
|
|
162
|
+
throw new Error(`Invalid --view value: ${view}`);
|
|
163
|
+
}
|
|
164
|
+
options.diffView = view;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (arg === "--old-label") {
|
|
168
|
+
options.oldLabel = nextValue(args, ++index, arg);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (arg === "--new-label") {
|
|
172
|
+
options.newLabel = nextValue(args, ++index, arg);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
176
|
+
}
|
|
177
|
+
return options;
|
|
178
|
+
}
|
|
179
|
+
async function runCli(args, io) {
|
|
180
|
+
try {
|
|
181
|
+
const options = parseCliArgs(args);
|
|
182
|
+
if (options.help) {
|
|
183
|
+
io.stdout.write(`${createHelpText()}
|
|
184
|
+
`);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (options.version) {
|
|
188
|
+
io.stdout.write(`${VERSION}
|
|
189
|
+
`);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const renderResult = await render(options, io.stdin);
|
|
193
|
+
if (options.outputPath) {
|
|
194
|
+
const { writeFile } = await import("fs/promises");
|
|
195
|
+
await writeFile(options.outputPath, renderResult, "utf8");
|
|
196
|
+
} else {
|
|
197
|
+
io.stdout.write(renderResult);
|
|
198
|
+
if (!renderResult.endsWith("\n")) {
|
|
199
|
+
io.stdout.write("\n");
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} catch (error) {
|
|
203
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
204
|
+
io.stderr.write(`Error: ${message}
|
|
205
|
+
`);
|
|
206
|
+
io.stderr.write("Use --help to see usage.\n");
|
|
207
|
+
io.exit(1);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async function render(options, stdin) {
|
|
211
|
+
if (options.mode === "diff") {
|
|
212
|
+
if (!options.oldPath || !options.newPath) {
|
|
213
|
+
throw new Error("--diff requires both --old and --new");
|
|
214
|
+
}
|
|
215
|
+
const { readFile } = await import("fs/promises");
|
|
216
|
+
const [oldSource, newSource] = await Promise.all([
|
|
217
|
+
readFile(options.oldPath, "utf8"),
|
|
218
|
+
readFile(options.newPath, "utf8")
|
|
219
|
+
]);
|
|
220
|
+
const language2 = resolveLanguage(options.language, options.newPath);
|
|
221
|
+
return (0, import_tree_sitter_ts_highlight.highlightDiff)(oldSource, newSource, language2, {
|
|
222
|
+
view: options.diffView,
|
|
223
|
+
semanticHighlighting: options.semanticHighlighting,
|
|
224
|
+
oldLabel: options.oldLabel,
|
|
225
|
+
newLabel: options.newLabel,
|
|
226
|
+
showHeader: options.showHeader,
|
|
227
|
+
classPrefix: "hlts-",
|
|
228
|
+
theme: resolveHtmlTheme(options.themeName)
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
const source = options.inputPath ? await readTextFile(options.inputPath) : await readStdin(stdin);
|
|
232
|
+
const language = resolveLanguage(options.language, options.inputPath);
|
|
233
|
+
if (options.mode === "ansi") {
|
|
234
|
+
return (0, import_tree_sitter_ts_highlight.highlightAnsi)(source, language, {
|
|
235
|
+
semanticHighlighting: options.semanticHighlighting,
|
|
236
|
+
lineNumbers: options.lineNumbers,
|
|
237
|
+
startLine: options.startLine
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
const htmlOptions = {
|
|
241
|
+
semanticHighlighting: options.semanticHighlighting,
|
|
242
|
+
lineNumbers: options.lineNumbers,
|
|
243
|
+
startLine: options.startLine,
|
|
244
|
+
theme: resolveHtmlTheme(options.themeName)
|
|
245
|
+
};
|
|
246
|
+
if (options.wrapInPre) {
|
|
247
|
+
return (0, import_tree_sitter_ts_highlight.highlightBlock)(source, language, {
|
|
248
|
+
...htmlOptions,
|
|
249
|
+
language
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
return (0, import_tree_sitter_ts_highlight.highlight)(source, language, htmlOptions);
|
|
253
|
+
}
|
|
254
|
+
async function readTextFile(filePath) {
|
|
255
|
+
const { readFile } = await import("fs/promises");
|
|
256
|
+
return readFile(filePath, "utf8");
|
|
257
|
+
}
|
|
258
|
+
function readStdin(stdin) {
|
|
259
|
+
return new Promise((resolve, reject) => {
|
|
260
|
+
const chunks = [];
|
|
261
|
+
stdin.on("data", (chunk) => {
|
|
262
|
+
if (typeof chunk === "string") {
|
|
263
|
+
chunks.push(Buffer.from(chunk));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
chunks.push(chunk);
|
|
267
|
+
});
|
|
268
|
+
stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
269
|
+
stdin.on("error", reject);
|
|
270
|
+
stdin.resume();
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
function resolveLanguage(explicitLanguage, filePath) {
|
|
274
|
+
if (explicitLanguage && explicitLanguage !== "typescript") {
|
|
275
|
+
return explicitLanguage;
|
|
276
|
+
}
|
|
277
|
+
if (!filePath) {
|
|
278
|
+
return explicitLanguage || "typescript";
|
|
279
|
+
}
|
|
280
|
+
const extension = (0, import_node_path.extname)(filePath);
|
|
281
|
+
return extension || explicitLanguage || "typescript";
|
|
282
|
+
}
|
|
283
|
+
function resolveHtmlTheme(themeName) {
|
|
284
|
+
if (!themeName) {
|
|
285
|
+
return void 0;
|
|
286
|
+
}
|
|
287
|
+
const theme = (0, import_tree_sitter_ts_highlight.getTheme)(themeName);
|
|
288
|
+
if (!theme) {
|
|
289
|
+
throw new Error(`Unknown theme: ${themeName}`);
|
|
290
|
+
}
|
|
291
|
+
return theme;
|
|
292
|
+
}
|
|
293
|
+
function nextValue(args, index, flagName) {
|
|
294
|
+
const value = args[index];
|
|
295
|
+
if (!value || value.startsWith("-")) {
|
|
296
|
+
throw new Error(`Missing value for ${flagName}`);
|
|
297
|
+
}
|
|
298
|
+
return value;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// src/index.ts
|
|
302
|
+
__reExport(index_exports, require("tree-sitter-ts-highlight"), module.exports);
|
|
303
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
304
|
+
0 && (module.exports = {
|
|
305
|
+
createHelpText,
|
|
306
|
+
parseCliArgs,
|
|
307
|
+
runCli,
|
|
308
|
+
...require("tree-sitter-ts-highlight")
|
|
309
|
+
});
|
|
310
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/run-cli.ts"],"sourcesContent":["export {\r\n runCli,\r\n parseCliArgs,\r\n createHelpText,\r\n type CliOptions,\r\n type CliMode,\r\n} from \"./run-cli\";\r\n\r\nexport * from \"tree-sitter-ts-highlight\";\r\nexport type * from \"tree-sitter-ts-highlight\";\r\nexport type * from \"tree-sitter-ts\";\r\n","import { extname } from \"node:path\";\r\nimport {\r\n getTheme,\r\n highlight,\r\n highlightAnsi,\r\n highlightBlock,\r\n highlightDiff,\r\n} from \"tree-sitter-ts-highlight\";\r\n\r\nexport type CliMode = \"html\" | \"ansi\" | \"diff\";\r\n\r\nexport interface CliOptions {\r\n mode: CliMode;\r\n inputPath?: string;\r\n outputPath?: string;\r\n language: string;\r\n lineNumbers: boolean;\r\n startLine?: number;\r\n semanticHighlighting: boolean;\r\n wrapInPre: boolean;\r\n diffView: \"side-by-side\" | \"inline\";\r\n oldPath?: string;\r\n newPath?: string;\r\n oldLabel?: string;\r\n newLabel?: string;\r\n showHeader: boolean;\r\n themeName?: string;\r\n help: boolean;\r\n version: boolean;\r\n}\r\n\r\ninterface IoLike {\r\n stdin: NodeJS.ReadStream;\r\n stdout: NodeJS.WriteStream;\r\n stderr: NodeJS.WriteStream;\r\n exit: (code: number) => never | void;\r\n}\r\n\r\nconst VERSION = \"0.1.2\";\r\n\r\nexport function createHelpText(): string {\r\n return [\r\n \"tree-sitter-ts-highlight-cli\",\r\n \"\",\r\n \"Usage:\",\r\n \" hlts [options]\",\r\n \"\",\r\n \"Modes:\",\r\n \" --ansi Output ANSI-highlighted text for terminals\",\r\n \" --diff Output HTML highlighted diff (requires --old and --new)\",\r\n \"\",\r\n \"Input:\",\r\n \" -i, --input <file> Input file path (default: stdin)\",\r\n \" -o, --output <file> Output file path (default: stdout)\",\r\n \" -l, --language <lang> Language or extension (default: detect from file, else typescript)\",\r\n \"\",\r\n \"HTML options:\",\r\n \" --block Wrap output in <pre><code>\",\r\n \" --line-numbers Include line numbers\",\r\n \" --start-line <n> Starting line number\",\r\n \" --semantic Enable semantic token enhancement\",\r\n \" --theme <name> Built-in HTML theme name\",\r\n \"\",\r\n \"Diff options:\",\r\n \" --old <file> Old/original file for diff mode\",\r\n \" --new <file> New/updated file for diff mode\",\r\n \" --view <mode> side-by-side | inline (default: side-by-side)\",\r\n \" --old-label <label> Header label for old side\",\r\n \" --new-label <label> Header label for new side\",\r\n \" --no-header Hide diff headers\",\r\n \"\",\r\n \"General:\",\r\n \" -h, --help Show help\",\r\n \" -v, --version Show version\",\r\n ].join(\"\\n\");\r\n}\r\n\r\nexport function parseCliArgs(args: string[]): CliOptions {\r\n const options: CliOptions = {\r\n mode: \"html\",\r\n language: \"typescript\",\r\n lineNumbers: false,\r\n semanticHighlighting: false,\r\n wrapInPre: false,\r\n diffView: \"side-by-side\",\r\n showHeader: true,\r\n help: false,\r\n version: false,\r\n };\r\n\r\n for (let index = 0; index < args.length; index += 1) {\r\n const arg = args[index];\r\n\r\n if (arg === \"-h\" || arg === \"--help\") {\r\n options.help = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"-v\" || arg === \"--version\") {\r\n options.version = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"--ansi\") {\r\n options.mode = \"ansi\";\r\n continue;\r\n }\r\n\r\n if (arg === \"--diff\") {\r\n options.mode = \"diff\";\r\n continue;\r\n }\r\n\r\n if (arg === \"--line-numbers\") {\r\n options.lineNumbers = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"--semantic\") {\r\n options.semanticHighlighting = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"--block\") {\r\n options.wrapInPre = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"--no-header\") {\r\n options.showHeader = false;\r\n continue;\r\n }\r\n\r\n if (arg === \"-i\" || arg === \"--input\") {\r\n options.inputPath = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"-o\" || arg === \"--output\") {\r\n options.outputPath = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"-l\" || arg === \"--language\") {\r\n options.language = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--start-line\") {\r\n const value = nextValue(args, ++index, arg);\r\n const startLine = Number.parseInt(value, 10);\r\n if (!Number.isFinite(startLine) || startLine <= 0) {\r\n throw new Error(`Invalid --start-line value: ${value}`);\r\n }\r\n options.startLine = startLine;\r\n continue;\r\n }\r\n\r\n if (arg === \"--theme\") {\r\n options.themeName = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--old\") {\r\n options.oldPath = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--new\") {\r\n options.newPath = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--view\") {\r\n const view = nextValue(args, ++index, arg);\r\n if (view !== \"side-by-side\" && view !== \"inline\") {\r\n throw new Error(`Invalid --view value: ${view}`);\r\n }\r\n options.diffView = view;\r\n continue;\r\n }\r\n\r\n if (arg === \"--old-label\") {\r\n options.oldLabel = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--new-label\") {\r\n options.newLabel = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n throw new Error(`Unknown argument: ${arg}`);\r\n }\r\n\r\n return options;\r\n}\r\n\r\nexport async function runCli(args: string[], io: IoLike): Promise<void> {\r\n try {\r\n const options = parseCliArgs(args);\r\n\r\n if (options.help) {\r\n io.stdout.write(`${createHelpText()}\\n`);\r\n return;\r\n }\r\n\r\n if (options.version) {\r\n io.stdout.write(`${VERSION}\\n`);\r\n return;\r\n }\r\n\r\n const renderResult = await render(options, io.stdin);\r\n\r\n if (options.outputPath) {\r\n const { writeFile } = await import(\"node:fs/promises\");\r\n await writeFile(options.outputPath, renderResult, \"utf8\");\r\n } else {\r\n io.stdout.write(renderResult);\r\n if (!renderResult.endsWith(\"\\n\")) {\r\n io.stdout.write(\"\\n\");\r\n }\r\n }\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n io.stderr.write(`Error: ${message}\\n`);\r\n io.stderr.write(\"Use --help to see usage.\\n\");\r\n io.exit(1);\r\n }\r\n}\r\n\r\nasync function render(options: CliOptions, stdin: NodeJS.ReadStream): Promise<string> {\r\n if (options.mode === \"diff\") {\r\n if (!options.oldPath || !options.newPath) {\r\n throw new Error(\"--diff requires both --old and --new\");\r\n }\r\n\r\n const { readFile } = await import(\"node:fs/promises\");\r\n const [oldSource, newSource] = await Promise.all([\r\n readFile(options.oldPath, \"utf8\"),\r\n readFile(options.newPath, \"utf8\"),\r\n ]);\r\n\r\n const language = resolveLanguage(options.language, options.newPath);\r\n\r\n return highlightDiff(oldSource, newSource, language, {\r\n view: options.diffView,\r\n semanticHighlighting: options.semanticHighlighting,\r\n oldLabel: options.oldLabel,\r\n newLabel: options.newLabel,\r\n showHeader: options.showHeader,\r\n classPrefix: \"hlts-\",\r\n theme: resolveHtmlTheme(options.themeName),\r\n });\r\n }\r\n\r\n const source = options.inputPath\r\n ? await readTextFile(options.inputPath)\r\n : await readStdin(stdin);\r\n\r\n const language = resolveLanguage(options.language, options.inputPath);\r\n\r\n if (options.mode === \"ansi\") {\r\n return highlightAnsi(source, language, {\r\n semanticHighlighting: options.semanticHighlighting,\r\n lineNumbers: options.lineNumbers,\r\n startLine: options.startLine,\r\n });\r\n }\r\n\r\n const htmlOptions = {\r\n semanticHighlighting: options.semanticHighlighting,\r\n lineNumbers: options.lineNumbers,\r\n startLine: options.startLine,\r\n theme: resolveHtmlTheme(options.themeName),\r\n };\r\n\r\n if (options.wrapInPre) {\r\n return highlightBlock(source, language, {\r\n ...htmlOptions,\r\n language,\r\n });\r\n }\r\n\r\n return highlight(source, language, htmlOptions);\r\n}\r\n\r\nasync function readTextFile(filePath: string): Promise<string> {\r\n const { readFile } = await import(\"node:fs/promises\");\r\n return readFile(filePath, \"utf8\");\r\n}\r\n\r\nfunction readStdin(stdin: NodeJS.ReadStream): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n const chunks: Buffer[] = [];\r\n stdin.on(\"data\", (chunk: Buffer | string) => {\r\n if (typeof chunk === \"string\") {\r\n chunks.push(Buffer.from(chunk));\r\n return;\r\n }\r\n chunks.push(chunk);\r\n });\r\n stdin.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf8\")));\r\n stdin.on(\"error\", reject);\r\n stdin.resume();\r\n });\r\n}\r\n\r\nfunction resolveLanguage(explicitLanguage: string, filePath?: string): string {\r\n if (explicitLanguage && explicitLanguage !== \"typescript\") {\r\n return explicitLanguage;\r\n }\r\n\r\n if (!filePath) {\r\n return explicitLanguage || \"typescript\";\r\n }\r\n\r\n const extension = extname(filePath);\r\n return extension || explicitLanguage || \"typescript\";\r\n}\r\n\r\nfunction resolveHtmlTheme(themeName?: string) {\r\n if (!themeName) {\r\n return undefined;\r\n }\r\n\r\n const theme = getTheme(themeName);\r\n if (!theme) {\r\n throw new Error(`Unknown theme: ${themeName}`);\r\n }\r\n return theme;\r\n}\r\n\r\nfunction nextValue(args: string[], index: number, flagName: string): string {\r\n const value = args[index];\r\n if (!value || value.startsWith(\"-\")) {\r\n throw new Error(`Missing value for ${flagName}`);\r\n }\r\n return value;\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,uBAAwB;AACxB,sCAMO;AA+BP,IAAM,UAAU;AAET,SAAS,iBAAyB;AACrC,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ,EAAE,KAAK,IAAI;AACf;AAEO,SAAS,aAAa,MAA4B;AACrD,QAAM,UAAsB;AAAA,IACxB,MAAM;AAAA,IACN,UAAU;AAAA,IACV,aAAa;AAAA,IACb,sBAAsB;AAAA,IACtB,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,SAAS;AAAA,EACb;AAEA,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACjD,UAAM,MAAM,KAAK,KAAK;AAEtB,QAAI,QAAQ,QAAQ,QAAQ,UAAU;AAClC,cAAQ,OAAO;AACf;AAAA,IACJ;AAEA,QAAI,QAAQ,QAAQ,QAAQ,aAAa;AACrC,cAAQ,UAAU;AAClB;AAAA,IACJ;AAEA,QAAI,QAAQ,UAAU;AAClB,cAAQ,OAAO;AACf;AAAA,IACJ;AAEA,QAAI,QAAQ,UAAU;AAClB,cAAQ,OAAO;AACf;AAAA,IACJ;AAEA,QAAI,QAAQ,kBAAkB;AAC1B,cAAQ,cAAc;AACtB;AAAA,IACJ;AAEA,QAAI,QAAQ,cAAc;AACtB,cAAQ,uBAAuB;AAC/B;AAAA,IACJ;AAEA,QAAI,QAAQ,WAAW;AACnB,cAAQ,YAAY;AACpB;AAAA,IACJ;AAEA,QAAI,QAAQ,eAAe;AACvB,cAAQ,aAAa;AACrB;AAAA,IACJ;AAEA,QAAI,QAAQ,QAAQ,QAAQ,WAAW;AACnC,cAAQ,YAAY,UAAU,MAAM,EAAE,OAAO,GAAG;AAChD;AAAA,IACJ;AAEA,QAAI,QAAQ,QAAQ,QAAQ,YAAY;AACpC,cAAQ,aAAa,UAAU,MAAM,EAAE,OAAO,GAAG;AACjD;AAAA,IACJ;AAEA,QAAI,QAAQ,QAAQ,QAAQ,cAAc;AACtC,cAAQ,WAAW,UAAU,MAAM,EAAE,OAAO,GAAG;AAC/C;AAAA,IACJ;AAEA,QAAI,QAAQ,gBAAgB;AACxB,YAAM,QAAQ,UAAU,MAAM,EAAE,OAAO,GAAG;AAC1C,YAAM,YAAY,OAAO,SAAS,OAAO,EAAE;AAC3C,UAAI,CAAC,OAAO,SAAS,SAAS,KAAK,aAAa,GAAG;AAC/C,cAAM,IAAI,MAAM,+BAA+B,KAAK,EAAE;AAAA,MAC1D;AACA,cAAQ,YAAY;AACpB;AAAA,IACJ;AAEA,QAAI,QAAQ,WAAW;AACnB,cAAQ,YAAY,UAAU,MAAM,EAAE,OAAO,GAAG;AAChD;AAAA,IACJ;AAEA,QAAI,QAAQ,SAAS;AACjB,cAAQ,UAAU,UAAU,MAAM,EAAE,OAAO,GAAG;AAC9C;AAAA,IACJ;AAEA,QAAI,QAAQ,SAAS;AACjB,cAAQ,UAAU,UAAU,MAAM,EAAE,OAAO,GAAG;AAC9C;AAAA,IACJ;AAEA,QAAI,QAAQ,UAAU;AAClB,YAAM,OAAO,UAAU,MAAM,EAAE,OAAO,GAAG;AACzC,UAAI,SAAS,kBAAkB,SAAS,UAAU;AAC9C,cAAM,IAAI,MAAM,yBAAyB,IAAI,EAAE;AAAA,MACnD;AACA,cAAQ,WAAW;AACnB;AAAA,IACJ;AAEA,QAAI,QAAQ,eAAe;AACvB,cAAQ,WAAW,UAAU,MAAM,EAAE,OAAO,GAAG;AAC/C;AAAA,IACJ;AAEA,QAAI,QAAQ,eAAe;AACvB,cAAQ,WAAW,UAAU,MAAM,EAAE,OAAO,GAAG;AAC/C;AAAA,IACJ;AAEA,UAAM,IAAI,MAAM,qBAAqB,GAAG,EAAE;AAAA,EAC9C;AAEA,SAAO;AACX;AAEA,eAAsB,OAAO,MAAgB,IAA2B;AACpE,MAAI;AACA,UAAM,UAAU,aAAa,IAAI;AAEjC,QAAI,QAAQ,MAAM;AACd,SAAG,OAAO,MAAM,GAAG,eAAe,CAAC;AAAA,CAAI;AACvC;AAAA,IACJ;AAEA,QAAI,QAAQ,SAAS;AACjB,SAAG,OAAO,MAAM,GAAG,OAAO;AAAA,CAAI;AAC9B;AAAA,IACJ;AAEA,UAAM,eAAe,MAAM,OAAO,SAAS,GAAG,KAAK;AAEnD,QAAI,QAAQ,YAAY;AACpB,YAAM,EAAE,UAAU,IAAI,MAAM,OAAO,aAAkB;AACrD,YAAM,UAAU,QAAQ,YAAY,cAAc,MAAM;AAAA,IAC5D,OAAO;AACH,SAAG,OAAO,MAAM,YAAY;AAC5B,UAAI,CAAC,aAAa,SAAS,IAAI,GAAG;AAC9B,WAAG,OAAO,MAAM,IAAI;AAAA,MACxB;AAAA,IACJ;AAAA,EACJ,SAAS,OAAO;AACZ,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,OAAG,OAAO,MAAM,UAAU,OAAO;AAAA,CAAI;AACrC,OAAG,OAAO,MAAM,4BAA4B;AAC5C,OAAG,KAAK,CAAC;AAAA,EACb;AACJ;AAEA,eAAe,OAAO,SAAqB,OAA2C;AAClF,MAAI,QAAQ,SAAS,QAAQ;AACzB,QAAI,CAAC,QAAQ,WAAW,CAAC,QAAQ,SAAS;AACtC,YAAM,IAAI,MAAM,sCAAsC;AAAA,IAC1D;AAEA,UAAM,EAAE,SAAS,IAAI,MAAM,OAAO,aAAkB;AACpD,UAAM,CAAC,WAAW,SAAS,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC7C,SAAS,QAAQ,SAAS,MAAM;AAAA,MAChC,SAAS,QAAQ,SAAS,MAAM;AAAA,IACpC,CAAC;AAED,UAAMA,YAAW,gBAAgB,QAAQ,UAAU,QAAQ,OAAO;AAElE,eAAO,+CAAc,WAAW,WAAWA,WAAU;AAAA,MACjD,MAAM,QAAQ;AAAA,MACd,sBAAsB,QAAQ;AAAA,MAC9B,UAAU,QAAQ;AAAA,MAClB,UAAU,QAAQ;AAAA,MAClB,YAAY,QAAQ;AAAA,MACpB,aAAa;AAAA,MACb,OAAO,iBAAiB,QAAQ,SAAS;AAAA,IAC7C,CAAC;AAAA,EACL;AAEA,QAAM,SAAS,QAAQ,YACjB,MAAM,aAAa,QAAQ,SAAS,IACpC,MAAM,UAAU,KAAK;AAE3B,QAAM,WAAW,gBAAgB,QAAQ,UAAU,QAAQ,SAAS;AAEpE,MAAI,QAAQ,SAAS,QAAQ;AACzB,eAAO,+CAAc,QAAQ,UAAU;AAAA,MACnC,sBAAsB,QAAQ;AAAA,MAC9B,aAAa,QAAQ;AAAA,MACrB,WAAW,QAAQ;AAAA,IACvB,CAAC;AAAA,EACL;AAEA,QAAM,cAAc;AAAA,IAChB,sBAAsB,QAAQ;AAAA,IAC9B,aAAa,QAAQ;AAAA,IACrB,WAAW,QAAQ;AAAA,IACnB,OAAO,iBAAiB,QAAQ,SAAS;AAAA,EAC7C;AAEA,MAAI,QAAQ,WAAW;AACnB,eAAO,gDAAe,QAAQ,UAAU;AAAA,MACpC,GAAG;AAAA,MACH;AAAA,IACJ,CAAC;AAAA,EACL;AAEA,aAAO,2CAAU,QAAQ,UAAU,WAAW;AAClD;AAEA,eAAe,aAAa,UAAmC;AAC3D,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,aAAkB;AACpD,SAAO,SAAS,UAAU,MAAM;AACpC;AAEA,SAAS,UAAU,OAA2C;AAC1D,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACpC,UAAM,SAAmB,CAAC;AAC1B,UAAM,GAAG,QAAQ,CAAC,UAA2B;AACzC,UAAI,OAAO,UAAU,UAAU;AAC3B,eAAO,KAAK,OAAO,KAAK,KAAK,CAAC;AAC9B;AAAA,MACJ;AACA,aAAO,KAAK,KAAK;AAAA,IACrB,CAAC;AACD,UAAM,GAAG,OAAO,MAAM,QAAQ,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,CAAC,CAAC;AACrE,UAAM,GAAG,SAAS,MAAM;AACxB,UAAM,OAAO;AAAA,EACjB,CAAC;AACL;AAEA,SAAS,gBAAgB,kBAA0B,UAA2B;AAC1E,MAAI,oBAAoB,qBAAqB,cAAc;AACvD,WAAO;AAAA,EACX;AAEA,MAAI,CAAC,UAAU;AACX,WAAO,oBAAoB;AAAA,EAC/B;AAEA,QAAM,gBAAY,0BAAQ,QAAQ;AAClC,SAAO,aAAa,oBAAoB;AAC5C;AAEA,SAAS,iBAAiB,WAAoB;AAC1C,MAAI,CAAC,WAAW;AACZ,WAAO;AAAA,EACX;AAEA,QAAM,YAAQ,0CAAS,SAAS;AAChC,MAAI,CAAC,OAAO;AACR,UAAM,IAAI,MAAM,kBAAkB,SAAS,EAAE;AAAA,EACjD;AACA,SAAO;AACX;AAEA,SAAS,UAAU,MAAgB,OAAe,UAA0B;AACxE,QAAM,QAAQ,KAAK,KAAK;AACxB,MAAI,CAAC,SAAS,MAAM,WAAW,GAAG,GAAG;AACjC,UAAM,IAAI,MAAM,qBAAqB,QAAQ,EAAE;AAAA,EACnD;AACA,SAAO;AACX;;;AD3UA,0BAAc,qCARd;","names":["language"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export * from 'tree-sitter-ts-highlight';
|
|
2
|
+
export * from 'tree-sitter-ts';
|
|
3
|
+
|
|
4
|
+
type CliMode = "html" | "ansi" | "diff";
|
|
5
|
+
interface CliOptions {
|
|
6
|
+
mode: CliMode;
|
|
7
|
+
inputPath?: string;
|
|
8
|
+
outputPath?: string;
|
|
9
|
+
language: string;
|
|
10
|
+
lineNumbers: boolean;
|
|
11
|
+
startLine?: number;
|
|
12
|
+
semanticHighlighting: boolean;
|
|
13
|
+
wrapInPre: boolean;
|
|
14
|
+
diffView: "side-by-side" | "inline";
|
|
15
|
+
oldPath?: string;
|
|
16
|
+
newPath?: string;
|
|
17
|
+
oldLabel?: string;
|
|
18
|
+
newLabel?: string;
|
|
19
|
+
showHeader: boolean;
|
|
20
|
+
themeName?: string;
|
|
21
|
+
help: boolean;
|
|
22
|
+
version: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface IoLike {
|
|
25
|
+
stdin: NodeJS.ReadStream;
|
|
26
|
+
stdout: NodeJS.WriteStream;
|
|
27
|
+
stderr: NodeJS.WriteStream;
|
|
28
|
+
exit: (code: number) => never | void;
|
|
29
|
+
}
|
|
30
|
+
declare function createHelpText(): string;
|
|
31
|
+
declare function parseCliArgs(args: string[]): CliOptions;
|
|
32
|
+
declare function runCli(args: string[], io: IoLike): Promise<void>;
|
|
33
|
+
|
|
34
|
+
export { type CliMode, type CliOptions, createHelpText, parseCliArgs, runCli };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export * from 'tree-sitter-ts-highlight';
|
|
2
|
+
export * from 'tree-sitter-ts';
|
|
3
|
+
|
|
4
|
+
type CliMode = "html" | "ansi" | "diff";
|
|
5
|
+
interface CliOptions {
|
|
6
|
+
mode: CliMode;
|
|
7
|
+
inputPath?: string;
|
|
8
|
+
outputPath?: string;
|
|
9
|
+
language: string;
|
|
10
|
+
lineNumbers: boolean;
|
|
11
|
+
startLine?: number;
|
|
12
|
+
semanticHighlighting: boolean;
|
|
13
|
+
wrapInPre: boolean;
|
|
14
|
+
diffView: "side-by-side" | "inline";
|
|
15
|
+
oldPath?: string;
|
|
16
|
+
newPath?: string;
|
|
17
|
+
oldLabel?: string;
|
|
18
|
+
newLabel?: string;
|
|
19
|
+
showHeader: boolean;
|
|
20
|
+
themeName?: string;
|
|
21
|
+
help: boolean;
|
|
22
|
+
version: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface IoLike {
|
|
25
|
+
stdin: NodeJS.ReadStream;
|
|
26
|
+
stdout: NodeJS.WriteStream;
|
|
27
|
+
stderr: NodeJS.WriteStream;
|
|
28
|
+
exit: (code: number) => never | void;
|
|
29
|
+
}
|
|
30
|
+
declare function createHelpText(): string;
|
|
31
|
+
declare function parseCliArgs(args: string[]): CliOptions;
|
|
32
|
+
declare function runCli(args: string[], io: IoLike): Promise<void>;
|
|
33
|
+
|
|
34
|
+
export { type CliMode, type CliOptions, createHelpText, parseCliArgs, runCli };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
// src/run-cli.ts
|
|
2
|
+
import { extname } from "path";
|
|
3
|
+
import {
|
|
4
|
+
getTheme,
|
|
5
|
+
highlight,
|
|
6
|
+
highlightAnsi,
|
|
7
|
+
highlightBlock,
|
|
8
|
+
highlightDiff
|
|
9
|
+
} from "tree-sitter-ts-highlight";
|
|
10
|
+
var VERSION = "0.1.2";
|
|
11
|
+
function createHelpText() {
|
|
12
|
+
return [
|
|
13
|
+
"tree-sitter-ts-highlight-cli",
|
|
14
|
+
"",
|
|
15
|
+
"Usage:",
|
|
16
|
+
" hlts [options]",
|
|
17
|
+
"",
|
|
18
|
+
"Modes:",
|
|
19
|
+
" --ansi Output ANSI-highlighted text for terminals",
|
|
20
|
+
" --diff Output HTML highlighted diff (requires --old and --new)",
|
|
21
|
+
"",
|
|
22
|
+
"Input:",
|
|
23
|
+
" -i, --input <file> Input file path (default: stdin)",
|
|
24
|
+
" -o, --output <file> Output file path (default: stdout)",
|
|
25
|
+
" -l, --language <lang> Language or extension (default: detect from file, else typescript)",
|
|
26
|
+
"",
|
|
27
|
+
"HTML options:",
|
|
28
|
+
" --block Wrap output in <pre><code>",
|
|
29
|
+
" --line-numbers Include line numbers",
|
|
30
|
+
" --start-line <n> Starting line number",
|
|
31
|
+
" --semantic Enable semantic token enhancement",
|
|
32
|
+
" --theme <name> Built-in HTML theme name",
|
|
33
|
+
"",
|
|
34
|
+
"Diff options:",
|
|
35
|
+
" --old <file> Old/original file for diff mode",
|
|
36
|
+
" --new <file> New/updated file for diff mode",
|
|
37
|
+
" --view <mode> side-by-side | inline (default: side-by-side)",
|
|
38
|
+
" --old-label <label> Header label for old side",
|
|
39
|
+
" --new-label <label> Header label for new side",
|
|
40
|
+
" --no-header Hide diff headers",
|
|
41
|
+
"",
|
|
42
|
+
"General:",
|
|
43
|
+
" -h, --help Show help",
|
|
44
|
+
" -v, --version Show version"
|
|
45
|
+
].join("\n");
|
|
46
|
+
}
|
|
47
|
+
function parseCliArgs(args) {
|
|
48
|
+
const options = {
|
|
49
|
+
mode: "html",
|
|
50
|
+
language: "typescript",
|
|
51
|
+
lineNumbers: false,
|
|
52
|
+
semanticHighlighting: false,
|
|
53
|
+
wrapInPre: false,
|
|
54
|
+
diffView: "side-by-side",
|
|
55
|
+
showHeader: true,
|
|
56
|
+
help: false,
|
|
57
|
+
version: false
|
|
58
|
+
};
|
|
59
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
60
|
+
const arg = args[index];
|
|
61
|
+
if (arg === "-h" || arg === "--help") {
|
|
62
|
+
options.help = true;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (arg === "-v" || arg === "--version") {
|
|
66
|
+
options.version = true;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (arg === "--ansi") {
|
|
70
|
+
options.mode = "ansi";
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (arg === "--diff") {
|
|
74
|
+
options.mode = "diff";
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (arg === "--line-numbers") {
|
|
78
|
+
options.lineNumbers = true;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (arg === "--semantic") {
|
|
82
|
+
options.semanticHighlighting = true;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (arg === "--block") {
|
|
86
|
+
options.wrapInPre = true;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (arg === "--no-header") {
|
|
90
|
+
options.showHeader = false;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (arg === "-i" || arg === "--input") {
|
|
94
|
+
options.inputPath = nextValue(args, ++index, arg);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (arg === "-o" || arg === "--output") {
|
|
98
|
+
options.outputPath = nextValue(args, ++index, arg);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (arg === "-l" || arg === "--language") {
|
|
102
|
+
options.language = nextValue(args, ++index, arg);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (arg === "--start-line") {
|
|
106
|
+
const value = nextValue(args, ++index, arg);
|
|
107
|
+
const startLine = Number.parseInt(value, 10);
|
|
108
|
+
if (!Number.isFinite(startLine) || startLine <= 0) {
|
|
109
|
+
throw new Error(`Invalid --start-line value: ${value}`);
|
|
110
|
+
}
|
|
111
|
+
options.startLine = startLine;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (arg === "--theme") {
|
|
115
|
+
options.themeName = nextValue(args, ++index, arg);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (arg === "--old") {
|
|
119
|
+
options.oldPath = nextValue(args, ++index, arg);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (arg === "--new") {
|
|
123
|
+
options.newPath = nextValue(args, ++index, arg);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (arg === "--view") {
|
|
127
|
+
const view = nextValue(args, ++index, arg);
|
|
128
|
+
if (view !== "side-by-side" && view !== "inline") {
|
|
129
|
+
throw new Error(`Invalid --view value: ${view}`);
|
|
130
|
+
}
|
|
131
|
+
options.diffView = view;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (arg === "--old-label") {
|
|
135
|
+
options.oldLabel = nextValue(args, ++index, arg);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (arg === "--new-label") {
|
|
139
|
+
options.newLabel = nextValue(args, ++index, arg);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
143
|
+
}
|
|
144
|
+
return options;
|
|
145
|
+
}
|
|
146
|
+
async function runCli(args, io) {
|
|
147
|
+
try {
|
|
148
|
+
const options = parseCliArgs(args);
|
|
149
|
+
if (options.help) {
|
|
150
|
+
io.stdout.write(`${createHelpText()}
|
|
151
|
+
`);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (options.version) {
|
|
155
|
+
io.stdout.write(`${VERSION}
|
|
156
|
+
`);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const renderResult = await render(options, io.stdin);
|
|
160
|
+
if (options.outputPath) {
|
|
161
|
+
const { writeFile } = await import("fs/promises");
|
|
162
|
+
await writeFile(options.outputPath, renderResult, "utf8");
|
|
163
|
+
} else {
|
|
164
|
+
io.stdout.write(renderResult);
|
|
165
|
+
if (!renderResult.endsWith("\n")) {
|
|
166
|
+
io.stdout.write("\n");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
} catch (error) {
|
|
170
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
171
|
+
io.stderr.write(`Error: ${message}
|
|
172
|
+
`);
|
|
173
|
+
io.stderr.write("Use --help to see usage.\n");
|
|
174
|
+
io.exit(1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async function render(options, stdin) {
|
|
178
|
+
if (options.mode === "diff") {
|
|
179
|
+
if (!options.oldPath || !options.newPath) {
|
|
180
|
+
throw new Error("--diff requires both --old and --new");
|
|
181
|
+
}
|
|
182
|
+
const { readFile } = await import("fs/promises");
|
|
183
|
+
const [oldSource, newSource] = await Promise.all([
|
|
184
|
+
readFile(options.oldPath, "utf8"),
|
|
185
|
+
readFile(options.newPath, "utf8")
|
|
186
|
+
]);
|
|
187
|
+
const language2 = resolveLanguage(options.language, options.newPath);
|
|
188
|
+
return highlightDiff(oldSource, newSource, language2, {
|
|
189
|
+
view: options.diffView,
|
|
190
|
+
semanticHighlighting: options.semanticHighlighting,
|
|
191
|
+
oldLabel: options.oldLabel,
|
|
192
|
+
newLabel: options.newLabel,
|
|
193
|
+
showHeader: options.showHeader,
|
|
194
|
+
classPrefix: "hlts-",
|
|
195
|
+
theme: resolveHtmlTheme(options.themeName)
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
const source = options.inputPath ? await readTextFile(options.inputPath) : await readStdin(stdin);
|
|
199
|
+
const language = resolveLanguage(options.language, options.inputPath);
|
|
200
|
+
if (options.mode === "ansi") {
|
|
201
|
+
return highlightAnsi(source, language, {
|
|
202
|
+
semanticHighlighting: options.semanticHighlighting,
|
|
203
|
+
lineNumbers: options.lineNumbers,
|
|
204
|
+
startLine: options.startLine
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
const htmlOptions = {
|
|
208
|
+
semanticHighlighting: options.semanticHighlighting,
|
|
209
|
+
lineNumbers: options.lineNumbers,
|
|
210
|
+
startLine: options.startLine,
|
|
211
|
+
theme: resolveHtmlTheme(options.themeName)
|
|
212
|
+
};
|
|
213
|
+
if (options.wrapInPre) {
|
|
214
|
+
return highlightBlock(source, language, {
|
|
215
|
+
...htmlOptions,
|
|
216
|
+
language
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return highlight(source, language, htmlOptions);
|
|
220
|
+
}
|
|
221
|
+
async function readTextFile(filePath) {
|
|
222
|
+
const { readFile } = await import("fs/promises");
|
|
223
|
+
return readFile(filePath, "utf8");
|
|
224
|
+
}
|
|
225
|
+
function readStdin(stdin) {
|
|
226
|
+
return new Promise((resolve, reject) => {
|
|
227
|
+
const chunks = [];
|
|
228
|
+
stdin.on("data", (chunk) => {
|
|
229
|
+
if (typeof chunk === "string") {
|
|
230
|
+
chunks.push(Buffer.from(chunk));
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
chunks.push(chunk);
|
|
234
|
+
});
|
|
235
|
+
stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
236
|
+
stdin.on("error", reject);
|
|
237
|
+
stdin.resume();
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
function resolveLanguage(explicitLanguage, filePath) {
|
|
241
|
+
if (explicitLanguage && explicitLanguage !== "typescript") {
|
|
242
|
+
return explicitLanguage;
|
|
243
|
+
}
|
|
244
|
+
if (!filePath) {
|
|
245
|
+
return explicitLanguage || "typescript";
|
|
246
|
+
}
|
|
247
|
+
const extension = extname(filePath);
|
|
248
|
+
return extension || explicitLanguage || "typescript";
|
|
249
|
+
}
|
|
250
|
+
function resolveHtmlTheme(themeName) {
|
|
251
|
+
if (!themeName) {
|
|
252
|
+
return void 0;
|
|
253
|
+
}
|
|
254
|
+
const theme = getTheme(themeName);
|
|
255
|
+
if (!theme) {
|
|
256
|
+
throw new Error(`Unknown theme: ${themeName}`);
|
|
257
|
+
}
|
|
258
|
+
return theme;
|
|
259
|
+
}
|
|
260
|
+
function nextValue(args, index, flagName) {
|
|
261
|
+
const value = args[index];
|
|
262
|
+
if (!value || value.startsWith("-")) {
|
|
263
|
+
throw new Error(`Missing value for ${flagName}`);
|
|
264
|
+
}
|
|
265
|
+
return value;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// src/index.ts
|
|
269
|
+
export * from "tree-sitter-ts-highlight";
|
|
270
|
+
export {
|
|
271
|
+
createHelpText,
|
|
272
|
+
parseCliArgs,
|
|
273
|
+
runCli
|
|
274
|
+
};
|
|
275
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/run-cli.ts","../src/index.ts"],"sourcesContent":["import { extname } from \"node:path\";\r\nimport {\r\n getTheme,\r\n highlight,\r\n highlightAnsi,\r\n highlightBlock,\r\n highlightDiff,\r\n} from \"tree-sitter-ts-highlight\";\r\n\r\nexport type CliMode = \"html\" | \"ansi\" | \"diff\";\r\n\r\nexport interface CliOptions {\r\n mode: CliMode;\r\n inputPath?: string;\r\n outputPath?: string;\r\n language: string;\r\n lineNumbers: boolean;\r\n startLine?: number;\r\n semanticHighlighting: boolean;\r\n wrapInPre: boolean;\r\n diffView: \"side-by-side\" | \"inline\";\r\n oldPath?: string;\r\n newPath?: string;\r\n oldLabel?: string;\r\n newLabel?: string;\r\n showHeader: boolean;\r\n themeName?: string;\r\n help: boolean;\r\n version: boolean;\r\n}\r\n\r\ninterface IoLike {\r\n stdin: NodeJS.ReadStream;\r\n stdout: NodeJS.WriteStream;\r\n stderr: NodeJS.WriteStream;\r\n exit: (code: number) => never | void;\r\n}\r\n\r\nconst VERSION = \"0.1.2\";\r\n\r\nexport function createHelpText(): string {\r\n return [\r\n \"tree-sitter-ts-highlight-cli\",\r\n \"\",\r\n \"Usage:\",\r\n \" hlts [options]\",\r\n \"\",\r\n \"Modes:\",\r\n \" --ansi Output ANSI-highlighted text for terminals\",\r\n \" --diff Output HTML highlighted diff (requires --old and --new)\",\r\n \"\",\r\n \"Input:\",\r\n \" -i, --input <file> Input file path (default: stdin)\",\r\n \" -o, --output <file> Output file path (default: stdout)\",\r\n \" -l, --language <lang> Language or extension (default: detect from file, else typescript)\",\r\n \"\",\r\n \"HTML options:\",\r\n \" --block Wrap output in <pre><code>\",\r\n \" --line-numbers Include line numbers\",\r\n \" --start-line <n> Starting line number\",\r\n \" --semantic Enable semantic token enhancement\",\r\n \" --theme <name> Built-in HTML theme name\",\r\n \"\",\r\n \"Diff options:\",\r\n \" --old <file> Old/original file for diff mode\",\r\n \" --new <file> New/updated file for diff mode\",\r\n \" --view <mode> side-by-side | inline (default: side-by-side)\",\r\n \" --old-label <label> Header label for old side\",\r\n \" --new-label <label> Header label for new side\",\r\n \" --no-header Hide diff headers\",\r\n \"\",\r\n \"General:\",\r\n \" -h, --help Show help\",\r\n \" -v, --version Show version\",\r\n ].join(\"\\n\");\r\n}\r\n\r\nexport function parseCliArgs(args: string[]): CliOptions {\r\n const options: CliOptions = {\r\n mode: \"html\",\r\n language: \"typescript\",\r\n lineNumbers: false,\r\n semanticHighlighting: false,\r\n wrapInPre: false,\r\n diffView: \"side-by-side\",\r\n showHeader: true,\r\n help: false,\r\n version: false,\r\n };\r\n\r\n for (let index = 0; index < args.length; index += 1) {\r\n const arg = args[index];\r\n\r\n if (arg === \"-h\" || arg === \"--help\") {\r\n options.help = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"-v\" || arg === \"--version\") {\r\n options.version = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"--ansi\") {\r\n options.mode = \"ansi\";\r\n continue;\r\n }\r\n\r\n if (arg === \"--diff\") {\r\n options.mode = \"diff\";\r\n continue;\r\n }\r\n\r\n if (arg === \"--line-numbers\") {\r\n options.lineNumbers = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"--semantic\") {\r\n options.semanticHighlighting = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"--block\") {\r\n options.wrapInPre = true;\r\n continue;\r\n }\r\n\r\n if (arg === \"--no-header\") {\r\n options.showHeader = false;\r\n continue;\r\n }\r\n\r\n if (arg === \"-i\" || arg === \"--input\") {\r\n options.inputPath = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"-o\" || arg === \"--output\") {\r\n options.outputPath = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"-l\" || arg === \"--language\") {\r\n options.language = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--start-line\") {\r\n const value = nextValue(args, ++index, arg);\r\n const startLine = Number.parseInt(value, 10);\r\n if (!Number.isFinite(startLine) || startLine <= 0) {\r\n throw new Error(`Invalid --start-line value: ${value}`);\r\n }\r\n options.startLine = startLine;\r\n continue;\r\n }\r\n\r\n if (arg === \"--theme\") {\r\n options.themeName = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--old\") {\r\n options.oldPath = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--new\") {\r\n options.newPath = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--view\") {\r\n const view = nextValue(args, ++index, arg);\r\n if (view !== \"side-by-side\" && view !== \"inline\") {\r\n throw new Error(`Invalid --view value: ${view}`);\r\n }\r\n options.diffView = view;\r\n continue;\r\n }\r\n\r\n if (arg === \"--old-label\") {\r\n options.oldLabel = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n if (arg === \"--new-label\") {\r\n options.newLabel = nextValue(args, ++index, arg);\r\n continue;\r\n }\r\n\r\n throw new Error(`Unknown argument: ${arg}`);\r\n }\r\n\r\n return options;\r\n}\r\n\r\nexport async function runCli(args: string[], io: IoLike): Promise<void> {\r\n try {\r\n const options = parseCliArgs(args);\r\n\r\n if (options.help) {\r\n io.stdout.write(`${createHelpText()}\\n`);\r\n return;\r\n }\r\n\r\n if (options.version) {\r\n io.stdout.write(`${VERSION}\\n`);\r\n return;\r\n }\r\n\r\n const renderResult = await render(options, io.stdin);\r\n\r\n if (options.outputPath) {\r\n const { writeFile } = await import(\"node:fs/promises\");\r\n await writeFile(options.outputPath, renderResult, \"utf8\");\r\n } else {\r\n io.stdout.write(renderResult);\r\n if (!renderResult.endsWith(\"\\n\")) {\r\n io.stdout.write(\"\\n\");\r\n }\r\n }\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n io.stderr.write(`Error: ${message}\\n`);\r\n io.stderr.write(\"Use --help to see usage.\\n\");\r\n io.exit(1);\r\n }\r\n}\r\n\r\nasync function render(options: CliOptions, stdin: NodeJS.ReadStream): Promise<string> {\r\n if (options.mode === \"diff\") {\r\n if (!options.oldPath || !options.newPath) {\r\n throw new Error(\"--diff requires both --old and --new\");\r\n }\r\n\r\n const { readFile } = await import(\"node:fs/promises\");\r\n const [oldSource, newSource] = await Promise.all([\r\n readFile(options.oldPath, \"utf8\"),\r\n readFile(options.newPath, \"utf8\"),\r\n ]);\r\n\r\n const language = resolveLanguage(options.language, options.newPath);\r\n\r\n return highlightDiff(oldSource, newSource, language, {\r\n view: options.diffView,\r\n semanticHighlighting: options.semanticHighlighting,\r\n oldLabel: options.oldLabel,\r\n newLabel: options.newLabel,\r\n showHeader: options.showHeader,\r\n classPrefix: \"hlts-\",\r\n theme: resolveHtmlTheme(options.themeName),\r\n });\r\n }\r\n\r\n const source = options.inputPath\r\n ? await readTextFile(options.inputPath)\r\n : await readStdin(stdin);\r\n\r\n const language = resolveLanguage(options.language, options.inputPath);\r\n\r\n if (options.mode === \"ansi\") {\r\n return highlightAnsi(source, language, {\r\n semanticHighlighting: options.semanticHighlighting,\r\n lineNumbers: options.lineNumbers,\r\n startLine: options.startLine,\r\n });\r\n }\r\n\r\n const htmlOptions = {\r\n semanticHighlighting: options.semanticHighlighting,\r\n lineNumbers: options.lineNumbers,\r\n startLine: options.startLine,\r\n theme: resolveHtmlTheme(options.themeName),\r\n };\r\n\r\n if (options.wrapInPre) {\r\n return highlightBlock(source, language, {\r\n ...htmlOptions,\r\n language,\r\n });\r\n }\r\n\r\n return highlight(source, language, htmlOptions);\r\n}\r\n\r\nasync function readTextFile(filePath: string): Promise<string> {\r\n const { readFile } = await import(\"node:fs/promises\");\r\n return readFile(filePath, \"utf8\");\r\n}\r\n\r\nfunction readStdin(stdin: NodeJS.ReadStream): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n const chunks: Buffer[] = [];\r\n stdin.on(\"data\", (chunk: Buffer | string) => {\r\n if (typeof chunk === \"string\") {\r\n chunks.push(Buffer.from(chunk));\r\n return;\r\n }\r\n chunks.push(chunk);\r\n });\r\n stdin.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf8\")));\r\n stdin.on(\"error\", reject);\r\n stdin.resume();\r\n });\r\n}\r\n\r\nfunction resolveLanguage(explicitLanguage: string, filePath?: string): string {\r\n if (explicitLanguage && explicitLanguage !== \"typescript\") {\r\n return explicitLanguage;\r\n }\r\n\r\n if (!filePath) {\r\n return explicitLanguage || \"typescript\";\r\n }\r\n\r\n const extension = extname(filePath);\r\n return extension || explicitLanguage || \"typescript\";\r\n}\r\n\r\nfunction resolveHtmlTheme(themeName?: string) {\r\n if (!themeName) {\r\n return undefined;\r\n }\r\n\r\n const theme = getTheme(themeName);\r\n if (!theme) {\r\n throw new Error(`Unknown theme: ${themeName}`);\r\n }\r\n return theme;\r\n}\r\n\r\nfunction nextValue(args: string[], index: number, flagName: string): string {\r\n const value = args[index];\r\n if (!value || value.startsWith(\"-\")) {\r\n throw new Error(`Missing value for ${flagName}`);\r\n }\r\n return value;\r\n}\r\n","export {\r\n runCli,\r\n parseCliArgs,\r\n createHelpText,\r\n type CliOptions,\r\n type CliMode,\r\n} from \"./run-cli\";\r\n\r\nexport * from \"tree-sitter-ts-highlight\";\r\nexport type * from \"tree-sitter-ts-highlight\";\r\nexport type * from \"tree-sitter-ts\";\r\n"],"mappings":"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","names":["language"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tree-sitter-ts-highlight-cli",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Command-line wrapper for tree-sitter-ts-highlight.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"hlts": "./dist/cli.js",
|
|
11
|
+
"tree-sitter-ts-highlight": "./dist/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"require": {
|
|
20
|
+
"types": "./dist/index.d.cts",
|
|
21
|
+
"default": "./dist/index.cjs"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup",
|
|
31
|
+
"typecheck": "tsc --noEmit",
|
|
32
|
+
"test": "jest",
|
|
33
|
+
"test:watch": "jest --watch"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"tree-sitter-ts": "^0.1.2",
|
|
37
|
+
"tree-sitter-ts-highlight": "^0.1.2"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@swc/core": "^1.15.11",
|
|
41
|
+
"@swc/jest": "^0.2.39",
|
|
42
|
+
"@types/jest": "^30.0.0",
|
|
43
|
+
"@types/node": "^25.3.0",
|
|
44
|
+
"jest": "^30.2.0",
|
|
45
|
+
"tsup": "^8.0.0",
|
|
46
|
+
"tsx": "^4.20.5",
|
|
47
|
+
"typescript": "^5.4.0"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public",
|
|
51
|
+
"provenance": false
|
|
52
|
+
},
|
|
53
|
+
"keywords": [
|
|
54
|
+
"cli",
|
|
55
|
+
"tree-sitter",
|
|
56
|
+
"syntax-highlighting",
|
|
57
|
+
"typescript",
|
|
58
|
+
"ansi",
|
|
59
|
+
"html"
|
|
60
|
+
],
|
|
61
|
+
"repository": {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "https://github.com/hieutran512/tree-sitter-ts-highlight-cli"
|
|
64
|
+
},
|
|
65
|
+
"license": "MIT",
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=18.0.0"
|
|
68
|
+
}
|
|
69
|
+
}
|