jsdoczoom 0.1.0 → 0.2.1
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/dist/barrel.js +37 -36
- package/dist/cli.js +248 -163
- package/dist/drilldown.js +173 -163
- package/dist/errors.js +14 -14
- package/dist/eslint-engine.js +214 -96
- package/dist/eslint-plugin.js +316 -159
- package/dist/file-discovery.js +44 -42
- package/dist/index.js +1 -1
- package/dist/jsdoc-parser.js +157 -157
- package/dist/lint.js +44 -29
- package/dist/selector.js +24 -21
- package/dist/skill-text.js +488 -7
- package/dist/type-declarations.js +83 -69
- package/dist/types.js +6 -6
- package/dist/validate.js +84 -69
- package/package.json +7 -1
- package/types/barrel.d.ts +4 -1
- package/types/drilldown.d.ts +12 -2
- package/types/errors.d.ts +8 -8
- package/types/eslint-engine.d.ts +23 -11
- package/types/eslint-plugin.d.ts +6 -5
- package/types/file-discovery.d.ts +5 -1
- package/types/index.d.ts +18 -1
- package/types/lint.d.ts +11 -2
- package/types/skill-text.d.ts +4 -1
- package/types/types.d.ts +59 -43
- package/types/validate.d.ts +11 -2
package/dist/barrel.js
CHANGED
|
@@ -19,8 +19,8 @@ import { basename, dirname, resolve } from "node:path";
|
|
|
19
19
|
* @returns true if the file is a barrel (index.ts or index.tsx)
|
|
20
20
|
*/
|
|
21
21
|
export function isBarrel(filePath) {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const name = basename(filePath);
|
|
23
|
+
return name === "index.ts" || name === "index.tsx";
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Discover the children of a barrel file.
|
|
@@ -35,36 +35,37 @@ export function isBarrel(filePath) {
|
|
|
35
35
|
* @returns Sorted array of absolute paths to child files
|
|
36
36
|
*/
|
|
37
37
|
export function getBarrelChildren(barrelPath, _cwd) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return entries.sort();
|
|
38
|
+
const dir = dirname(barrelPath);
|
|
39
|
+
const barrelName = basename(barrelPath);
|
|
40
|
+
let entries;
|
|
41
|
+
try {
|
|
42
|
+
entries = readdirSync(dir, { withFileTypes: true })
|
|
43
|
+
.map((e) => ({ name: e.name, isDirectory: e.isDirectory() }))
|
|
44
|
+
.flatMap((entry) => {
|
|
45
|
+
if (entry.isDirectory) {
|
|
46
|
+
// Check for child barrel in this subdirectory
|
|
47
|
+
const childBarrel = findChildBarrel(resolve(dir, entry.name));
|
|
48
|
+
return childBarrel ? [childBarrel] : [];
|
|
49
|
+
}
|
|
50
|
+
// Sibling file: must be .ts/.tsx, not .d.ts, not the barrel itself
|
|
51
|
+
if (isTsFile(entry.name) && entry.name !== barrelName) {
|
|
52
|
+
return [resolve(dir, entry.name)];
|
|
53
|
+
}
|
|
54
|
+
return [];
|
|
55
|
+
});
|
|
56
|
+
} catch {
|
|
57
|
+
// Directory unreadable (permissions, deleted, etc.) — no children discoverable
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
return entries.sort();
|
|
62
61
|
}
|
|
63
62
|
/**
|
|
64
63
|
* Check if a filename is a .ts or .tsx file (excluding .d.ts).
|
|
65
64
|
*/
|
|
66
65
|
function isTsFile(name) {
|
|
67
|
-
|
|
66
|
+
return (
|
|
67
|
+
(name.endsWith(".ts") || name.endsWith(".tsx")) && !name.endsWith(".d.ts")
|
|
68
|
+
);
|
|
68
69
|
}
|
|
69
70
|
/**
|
|
70
71
|
* Find the barrel file in a subdirectory.
|
|
@@ -72,13 +73,13 @@ function isTsFile(name) {
|
|
|
72
73
|
* Returns the absolute path to the barrel, or null if none found.
|
|
73
74
|
*/
|
|
74
75
|
function findChildBarrel(subdirPath) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
const tsPath = resolve(subdirPath, "index.ts");
|
|
77
|
+
if (existsSync(tsPath)) {
|
|
78
|
+
return tsPath;
|
|
79
|
+
}
|
|
80
|
+
const tsxPath = resolve(subdirPath, "index.tsx");
|
|
81
|
+
if (existsSync(tsxPath)) {
|
|
82
|
+
return tsxPath;
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
84
85
|
}
|
package/dist/cli.js
CHANGED
|
@@ -4,9 +4,10 @@ import { drilldown, drilldownFiles } from "./drilldown.js";
|
|
|
4
4
|
import { JsdocError } from "./errors.js";
|
|
5
5
|
import { lint } from "./lint.js";
|
|
6
6
|
import { parseSelector } from "./selector.js";
|
|
7
|
-
import { SKILL_TEXT } from "./skill-text.js";
|
|
7
|
+
import { RULE_EXPLANATIONS, SKILL_TEXT } from "./skill-text.js";
|
|
8
8
|
import { VALIDATION_STATUS_PRIORITY } from "./types.js";
|
|
9
9
|
import { validate } from "./validate.js";
|
|
10
|
+
|
|
10
11
|
/**
|
|
11
12
|
* Parses argv flags (--help, --validate, --lint, --skill, --pretty, --limit,
|
|
12
13
|
* --no-gitignore), dispatches to drilldown, validation, or lint mode, and
|
|
@@ -27,8 +28,9 @@ Options:
|
|
|
27
28
|
-l, --lint Run lint mode (comprehensive JSDoc quality)
|
|
28
29
|
-s, --skill Print JSDoc writing guidelines
|
|
29
30
|
--pretty Format JSON output with 2-space indent
|
|
30
|
-
--limit N Max results shown (default
|
|
31
|
+
--limit N Max results shown (default 500)
|
|
31
32
|
--no-gitignore Include files ignored by .gitignore
|
|
33
|
+
--explain-rule R Explain a lint rule with examples (e.g. jsdoc/informative-docs)
|
|
32
34
|
|
|
33
35
|
Selector:
|
|
34
36
|
A glob pattern or file path, optionally with @depth suffix (1-4).
|
|
@@ -51,6 +53,15 @@ Barrel gating (glob mode):
|
|
|
51
53
|
index.ts files with a @summary gate sibling files at depths 1-2.
|
|
52
54
|
At depth 3 the barrel disappears and its children appear at depth 1.
|
|
53
55
|
|
|
56
|
+
Modes:
|
|
57
|
+
-v Validate file-level structure (has JSDoc block, @summary, description)
|
|
58
|
+
-l Lint comprehensive JSDoc quality (file-level + function-level tags)
|
|
59
|
+
|
|
60
|
+
Exit codes:
|
|
61
|
+
0 Success (all files pass)
|
|
62
|
+
1 Runtime error (invalid arguments, missing files)
|
|
63
|
+
2 Validation or lint failures found
|
|
64
|
+
|
|
54
65
|
Workflow:
|
|
55
66
|
$ jsdoczoom src/**/*.ts
|
|
56
67
|
{ "items": [{ "next_id": "src/utils@2", "text": "..." }, ...] }
|
|
@@ -66,222 +77,296 @@ Workflow:
|
|
|
66
77
|
* Parse CLI arguments into flags and positional args.
|
|
67
78
|
*/
|
|
68
79
|
function parseArgs(args) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
gitignore,
|
|
116
|
-
selectorArg,
|
|
117
|
-
};
|
|
80
|
+
let help = false;
|
|
81
|
+
let validateMode = false;
|
|
82
|
+
let lintMode = false;
|
|
83
|
+
let skillMode = false;
|
|
84
|
+
let pretty = false;
|
|
85
|
+
let limit = 500;
|
|
86
|
+
let gitignore = true;
|
|
87
|
+
let explainRule;
|
|
88
|
+
let selectorArg;
|
|
89
|
+
for (let i = 0; i < args.length; i++) {
|
|
90
|
+
const arg = args[i];
|
|
91
|
+
if (arg === "-h" || arg === "--help") {
|
|
92
|
+
help = true;
|
|
93
|
+
} else if (arg === "-v" || arg === "--validate") {
|
|
94
|
+
validateMode = true;
|
|
95
|
+
} else if (arg === "-l" || arg === "--lint") {
|
|
96
|
+
lintMode = true;
|
|
97
|
+
} else if (arg === "-s" || arg === "--skill") {
|
|
98
|
+
skillMode = true;
|
|
99
|
+
} else if (arg === "--pretty") {
|
|
100
|
+
pretty = true;
|
|
101
|
+
} else if (arg === "--limit") {
|
|
102
|
+
const next = args[++i];
|
|
103
|
+
limit = Number(next);
|
|
104
|
+
} else if (arg === "--no-gitignore") {
|
|
105
|
+
gitignore = false;
|
|
106
|
+
} else if (arg === "--explain-rule") {
|
|
107
|
+
const next = args[++i];
|
|
108
|
+
explainRule = next;
|
|
109
|
+
} else if (arg.startsWith("-")) {
|
|
110
|
+
throw new JsdocError("INVALID_SELECTOR", `Unrecognized option: ${arg}`);
|
|
111
|
+
} else if (selectorArg === undefined) {
|
|
112
|
+
selectorArg = arg;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
help,
|
|
117
|
+
validateMode,
|
|
118
|
+
lintMode,
|
|
119
|
+
skillMode,
|
|
120
|
+
pretty,
|
|
121
|
+
limit,
|
|
122
|
+
gitignore,
|
|
123
|
+
explainRule,
|
|
124
|
+
selectorArg,
|
|
125
|
+
};
|
|
118
126
|
}
|
|
119
127
|
/**
|
|
120
128
|
* Resolve stdin file paths to absolute paths.
|
|
121
129
|
*/
|
|
122
130
|
function parseStdinPaths(stdin, cwd) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
131
|
+
return stdin
|
|
132
|
+
.split("\n")
|
|
133
|
+
.map((line) => line.trim())
|
|
134
|
+
.filter((line) => line.length > 0)
|
|
135
|
+
.map((line) => resolve(cwd, line));
|
|
128
136
|
}
|
|
129
137
|
/**
|
|
130
138
|
* Extract depth from a selector argument string.
|
|
131
139
|
* Returns undefined if no @depth suffix is present.
|
|
132
140
|
*/
|
|
133
141
|
function extractDepthFromArg(selectorArg) {
|
|
134
|
-
|
|
135
|
-
|
|
142
|
+
const parsed = parseSelector(selectorArg);
|
|
143
|
+
return parsed.depth;
|
|
136
144
|
}
|
|
137
145
|
/**
|
|
138
146
|
* Process stdin mode: file paths piped in.
|
|
139
147
|
*/
|
|
140
|
-
async function processStdin(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
148
|
+
async function processStdin(
|
|
149
|
+
stdin,
|
|
150
|
+
selectorArg,
|
|
151
|
+
validateMode,
|
|
152
|
+
lintMode,
|
|
153
|
+
pretty,
|
|
154
|
+
limit,
|
|
155
|
+
cwd,
|
|
156
|
+
) {
|
|
157
|
+
const stdinPaths = parseStdinPaths(stdin, cwd);
|
|
158
|
+
const depth =
|
|
159
|
+
selectorArg !== undefined ? extractDepthFromArg(selectorArg) : undefined;
|
|
160
|
+
if (lintMode) {
|
|
161
|
+
const { lintFiles } = await import("./lint.js");
|
|
162
|
+
const result = await lintFiles(stdinPaths, cwd, limit);
|
|
163
|
+
writeLintResult(result, pretty);
|
|
164
|
+
} else if (validateMode) {
|
|
165
|
+
const { validateFiles } = await import("./validate.js");
|
|
166
|
+
const result = await validateFiles(stdinPaths, cwd, limit);
|
|
167
|
+
writeValidationResult(result, pretty);
|
|
168
|
+
} else {
|
|
169
|
+
const result = drilldownFiles(stdinPaths, depth, cwd, limit);
|
|
170
|
+
writeResult(result, pretty);
|
|
171
|
+
}
|
|
157
172
|
}
|
|
158
173
|
/**
|
|
159
174
|
* Process selector mode: glob or path argument.
|
|
160
175
|
*/
|
|
161
|
-
async function processSelector(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
176
|
+
async function processSelector(
|
|
177
|
+
selectorArg,
|
|
178
|
+
validateMode,
|
|
179
|
+
lintMode,
|
|
180
|
+
pretty,
|
|
181
|
+
limit,
|
|
182
|
+
gitignore,
|
|
183
|
+
cwd,
|
|
184
|
+
) {
|
|
185
|
+
const selector = selectorArg
|
|
186
|
+
? parseSelector(selectorArg)
|
|
187
|
+
: { type: "glob", pattern: "**/*.{ts,tsx}", depth: undefined };
|
|
188
|
+
if (lintMode) {
|
|
189
|
+
const result = await lint(selector, cwd, limit, gitignore);
|
|
190
|
+
writeLintResult(result, pretty);
|
|
191
|
+
} else if (validateMode) {
|
|
192
|
+
const result = await validate(selector, cwd, limit, gitignore);
|
|
193
|
+
writeValidationResult(result, pretty);
|
|
194
|
+
} else {
|
|
195
|
+
const result = drilldown(selector, cwd, gitignore, limit);
|
|
196
|
+
writeResult(result, pretty);
|
|
197
|
+
}
|
|
177
198
|
}
|
|
178
199
|
/**
|
|
179
200
|
* Write an error to stderr as JSON and set exit code.
|
|
180
201
|
*/
|
|
181
202
|
function writeError(error) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
203
|
+
if (error instanceof JsdocError) {
|
|
204
|
+
process.stderr.write(`${JSON.stringify(error.toJSON())}\n`);
|
|
205
|
+
process.exitCode = 1;
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
209
|
+
process.stderr.write(
|
|
210
|
+
`${JSON.stringify({ error: { code: "INTERNAL_ERROR", message } })}\n`,
|
|
211
|
+
);
|
|
212
|
+
process.exitCode = 1;
|
|
190
213
|
}
|
|
191
214
|
/**
|
|
192
215
|
* Main CLI entry point. Exported for testability.
|
|
193
216
|
*/
|
|
194
217
|
export async function main(args, stdin) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
218
|
+
try {
|
|
219
|
+
const {
|
|
220
|
+
help,
|
|
221
|
+
validateMode,
|
|
222
|
+
lintMode,
|
|
223
|
+
skillMode,
|
|
224
|
+
pretty,
|
|
225
|
+
limit,
|
|
226
|
+
gitignore,
|
|
227
|
+
explainRule,
|
|
228
|
+
selectorArg,
|
|
229
|
+
} = parseArgs(args);
|
|
230
|
+
if (help) {
|
|
231
|
+
process.stdout.write(HELP_TEXT);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (skillMode) {
|
|
235
|
+
process.stdout.write(SKILL_TEXT);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (explainRule !== undefined) {
|
|
239
|
+
const explanation = RULE_EXPLANATIONS[explainRule];
|
|
240
|
+
if (explanation) {
|
|
241
|
+
process.stdout.write(explanation);
|
|
242
|
+
} else {
|
|
243
|
+
const available = Object.keys(RULE_EXPLANATIONS).join(", ");
|
|
244
|
+
writeError(
|
|
245
|
+
new JsdocError(
|
|
246
|
+
"INVALID_SELECTOR",
|
|
247
|
+
`Unknown rule: ${explainRule}. Available rules: ${available}`,
|
|
248
|
+
),
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if (validateMode && lintMode) {
|
|
254
|
+
writeError(
|
|
255
|
+
new JsdocError("INVALID_SELECTOR", "Cannot use -v and -l together"),
|
|
256
|
+
);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const cwd = process.cwd();
|
|
260
|
+
if (stdin !== undefined) {
|
|
261
|
+
await processStdin(
|
|
262
|
+
stdin,
|
|
263
|
+
selectorArg,
|
|
264
|
+
validateMode,
|
|
265
|
+
lintMode,
|
|
266
|
+
pretty,
|
|
267
|
+
limit,
|
|
268
|
+
cwd,
|
|
269
|
+
);
|
|
270
|
+
} else {
|
|
271
|
+
await processSelector(
|
|
272
|
+
selectorArg,
|
|
273
|
+
validateMode,
|
|
274
|
+
lintMode,
|
|
275
|
+
pretty,
|
|
276
|
+
limit,
|
|
277
|
+
gitignore,
|
|
278
|
+
cwd,
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
} catch (error) {
|
|
282
|
+
writeError(error);
|
|
283
|
+
}
|
|
220
284
|
}
|
|
221
285
|
/**
|
|
222
286
|
* Write a result to stdout as JSON.
|
|
223
287
|
*/
|
|
224
288
|
function writeResult(result, pretty) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
289
|
+
const json = pretty
|
|
290
|
+
? JSON.stringify(result, null, 2)
|
|
291
|
+
: JSON.stringify(result);
|
|
292
|
+
process.stdout.write(`${json}\n`);
|
|
229
293
|
}
|
|
230
294
|
/**
|
|
231
295
|
* Count invalid files across all validation groups.
|
|
232
296
|
*/
|
|
233
297
|
function countInvalid(result) {
|
|
234
|
-
|
|
298
|
+
return VALIDATION_STATUS_PRIORITY.reduce(
|
|
299
|
+
(sum, status) => sum + (result[status]?.files.length ?? 0),
|
|
300
|
+
0,
|
|
301
|
+
);
|
|
235
302
|
}
|
|
236
303
|
/**
|
|
237
304
|
* Write validation result to stdout and set exit code.
|
|
238
305
|
* Adds success/message fields to the output.
|
|
239
306
|
*/
|
|
240
307
|
function writeValidationResult(result, pretty) {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
308
|
+
const invalidCount = countInvalid(result);
|
|
309
|
+
if (invalidCount === 0) {
|
|
310
|
+
writeResult(
|
|
311
|
+
{ success: true, message: "All files passed validation" },
|
|
312
|
+
pretty,
|
|
313
|
+
);
|
|
314
|
+
} else {
|
|
315
|
+
writeResult(
|
|
316
|
+
{
|
|
317
|
+
...result,
|
|
318
|
+
success: false,
|
|
319
|
+
error: {
|
|
320
|
+
code: "VALIDATION_FAILED",
|
|
321
|
+
message: `${invalidCount} file(s) failed validation`,
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
pretty,
|
|
325
|
+
);
|
|
326
|
+
process.exitCode = 2;
|
|
327
|
+
}
|
|
250
328
|
}
|
|
251
329
|
/**
|
|
252
330
|
* Write lint result to stdout and set exit code 2 if issues found.
|
|
253
331
|
*/
|
|
254
332
|
function writeLintResult(result, pretty) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
333
|
+
writeResult(result, pretty);
|
|
334
|
+
if (result.summary.filesWithIssues > 0) {
|
|
335
|
+
process.exitCode = 2;
|
|
336
|
+
// Warn if output was truncated
|
|
337
|
+
if (result.summary.filesWithIssues > result.files.length) {
|
|
338
|
+
process.stderr.write(
|
|
339
|
+
`Warning: output truncated to ${result.files.length} of ${result.summary.filesWithIssues} files with issues. Use --limit to see more.\n`,
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
259
343
|
}
|
|
260
344
|
async function readStdin() {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
345
|
+
const chunks = [];
|
|
346
|
+
for await (const chunk of process.stdin) {
|
|
347
|
+
chunks.push(chunk);
|
|
348
|
+
}
|
|
349
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
266
350
|
}
|
|
267
351
|
// Auto-invoke when run as CLI
|
|
268
352
|
function isDirectRun() {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
353
|
+
if (!process.argv[1]) return false;
|
|
354
|
+
try {
|
|
355
|
+
const scriptPath = process.argv[1].replace(/\\/g, "/");
|
|
356
|
+
return (
|
|
357
|
+
import.meta.url.endsWith(scriptPath) ||
|
|
358
|
+
import.meta.url.endsWith("/cli.js")
|
|
359
|
+
);
|
|
360
|
+
} catch {
|
|
361
|
+
// Cannot determine script path — safe to skip auto-invoke
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
280
364
|
}
|
|
281
365
|
if (isDirectRun()) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
366
|
+
// Only read stdin when it's explicitly piped (isTTY === false, not just undefined)
|
|
367
|
+
const stdinText =
|
|
368
|
+
process.stdin.isTTY === false ? await readStdin() : undefined;
|
|
369
|
+
main(process.argv.slice(2), stdinText).catch(() => {
|
|
370
|
+
// Error already handled in main
|
|
371
|
+
});
|
|
287
372
|
}
|