politty 0.7.0 → 0.9.0
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/cli.js +1 -1
- package/dist/docs/index.d.ts +44 -2
- package/dist/docs/index.js +827 -43
- package/dist/index.js +1 -1
- package/dist/{runner-D43SkHt5.js → runner-APRZYXUS.js} +74 -3
- package/package.json +22 -67
- package/dist/arg-registry-DDJpsUea.d.cts +0 -942
- package/dist/arg-registry-DDJpsUea.d.cts.map +0 -1
- package/dist/arg-registry-DDJpsUea.d.ts.map +0 -1
- package/dist/augment.cjs +0 -0
- package/dist/augment.d.cts +0 -17
- package/dist/augment.d.cts.map +0 -1
- package/dist/augment.d.ts.map +0 -1
- package/dist/cli.cjs +0 -54
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.d.cts +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/completion/index.cjs +0 -23
- package/dist/completion/index.d.cts +0 -3
- package/dist/completion-CLHO3Xaz.cjs +0 -5769
- package/dist/completion-CLHO3Xaz.cjs.map +0 -1
- package/dist/completion-DHnVx9Zk.js.map +0 -1
- package/dist/docs/index.cjs +0 -2343
- package/dist/docs/index.cjs.map +0 -1
- package/dist/docs/index.d.cts +0 -710
- package/dist/docs/index.d.cts.map +0 -1
- package/dist/docs/index.d.ts.map +0 -1
- package/dist/docs/index.js.map +0 -1
- package/dist/index-DKGn3lIl.d.ts.map +0 -1
- package/dist/index-WyViqW59.d.cts +0 -663
- package/dist/index-WyViqW59.d.cts.map +0 -1
- package/dist/index.cjs +0 -45
- package/dist/index.d.cts +0 -685
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/log-collector-DK32-73m.js.map +0 -1
- package/dist/log-collector-DUqC427m.cjs +0 -185
- package/dist/log-collector-DUqC427m.cjs.map +0 -1
- package/dist/prompt/clack/index.cjs +0 -33
- package/dist/prompt/clack/index.cjs.map +0 -1
- package/dist/prompt/clack/index.d.cts +0 -18
- package/dist/prompt/clack/index.d.cts.map +0 -1
- package/dist/prompt/clack/index.d.ts.map +0 -1
- package/dist/prompt/clack/index.js.map +0 -1
- package/dist/prompt/index.cjs +0 -7
- package/dist/prompt/index.d.cts +0 -108
- package/dist/prompt/index.d.cts.map +0 -1
- package/dist/prompt/index.d.ts.map +0 -1
- package/dist/prompt/inquirer/index.cjs +0 -48
- package/dist/prompt/inquirer/index.cjs.map +0 -1
- package/dist/prompt/inquirer/index.d.cts +0 -18
- package/dist/prompt/inquirer/index.d.cts.map +0 -1
- package/dist/prompt/inquirer/index.d.ts.map +0 -1
- package/dist/prompt/inquirer/index.js.map +0 -1
- package/dist/prompt-Bs9e-Em3.cjs +0 -196
- package/dist/prompt-Bs9e-Em3.cjs.map +0 -1
- package/dist/prompt-Cc8Tfmdv.js.map +0 -1
- package/dist/runner-D43SkHt5.js.map +0 -1
- package/dist/runner-DvFvokV6.cjs +0 -2865
- package/dist/runner-DvFvokV6.cjs.map +0 -1
- package/dist/schema-extractor-BxSRwLrx.cjs +0 -710
- package/dist/schema-extractor-BxSRwLrx.cjs.map +0 -1
- package/dist/schema-extractor-Dqe7_kyQ.js.map +0 -1
package/dist/runner-DvFvokV6.cjs
DELETED
|
@@ -1,2865 +0,0 @@
|
|
|
1
|
-
const require_log_collector = require('./log-collector-DUqC427m.cjs');
|
|
2
|
-
const require_schema_extractor = require('./schema-extractor-BxSRwLrx.cjs');
|
|
3
|
-
let node_util = require("node:util");
|
|
4
|
-
let string_width = require("string-width");
|
|
5
|
-
string_width = require_log_collector.__toESM(string_width, 1);
|
|
6
|
-
|
|
7
|
-
//#region src/core/case-proxy.ts
|
|
8
|
-
/**
|
|
9
|
-
* Wrap an args object with a Proxy that allows dual-case access.
|
|
10
|
-
*
|
|
11
|
-
* Given `{ "my-option": "value" }`, both `obj["my-option"]` and `obj.myOption`
|
|
12
|
-
* will return `"value"`.
|
|
13
|
-
*
|
|
14
|
-
* - `Object.keys()`, `JSON.stringify()`, and spread return only the original keys.
|
|
15
|
-
* - The `in` operator detects both case variants.
|
|
16
|
-
*/
|
|
17
|
-
function createDualCaseProxy(obj) {
|
|
18
|
-
return new Proxy(obj, {
|
|
19
|
-
get(target, prop, receiver) {
|
|
20
|
-
if (typeof prop === "string") {
|
|
21
|
-
if (prop in target) return Reflect.get(target, prop, receiver);
|
|
22
|
-
const camel = require_schema_extractor.toCamelCase(prop);
|
|
23
|
-
if (camel !== prop && camel in target) return Reflect.get(target, camel, receiver);
|
|
24
|
-
const kebab = require_schema_extractor.toKebabCase(prop);
|
|
25
|
-
if (kebab !== prop && kebab in target) return Reflect.get(target, kebab, receiver);
|
|
26
|
-
}
|
|
27
|
-
return Reflect.get(target, prop, receiver);
|
|
28
|
-
},
|
|
29
|
-
has(target, prop) {
|
|
30
|
-
if (typeof prop === "string") {
|
|
31
|
-
if (prop in target) return true;
|
|
32
|
-
const camel = require_schema_extractor.toCamelCase(prop);
|
|
33
|
-
if (camel !== prop && camel in target) return true;
|
|
34
|
-
const kebab = require_schema_extractor.toKebabCase(prop);
|
|
35
|
-
if (kebab !== prop && kebab in target) return true;
|
|
36
|
-
}
|
|
37
|
-
return Reflect.has(target, prop);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
//#endregion
|
|
43
|
-
//#region src/executor/command-runner.ts
|
|
44
|
-
/**
|
|
45
|
-
* Execute a command lifecycle: setup → run → cleanup
|
|
46
|
-
*
|
|
47
|
-
* This is an internal function that executes the command's lifecycle hooks.
|
|
48
|
-
* For running commands with argument parsing, use `runCommand` instead.
|
|
49
|
-
*
|
|
50
|
-
* @param command - The command to execute
|
|
51
|
-
* @param args - Already validated arguments
|
|
52
|
-
* @param options - Lifecycle options
|
|
53
|
-
* @returns The result of command execution
|
|
54
|
-
* @internal
|
|
55
|
-
*/
|
|
56
|
-
async function executeLifecycle(command, args, _options = {}) {
|
|
57
|
-
let error;
|
|
58
|
-
let result;
|
|
59
|
-
const collector = _options.captureLogs ?? false ? require_log_collector.createLogCollector() : null;
|
|
60
|
-
collector?.start();
|
|
61
|
-
const setupContext = { args };
|
|
62
|
-
const cleanupContext = {
|
|
63
|
-
args,
|
|
64
|
-
error
|
|
65
|
-
};
|
|
66
|
-
let signalHandler;
|
|
67
|
-
if (_options.handleSignals) {
|
|
68
|
-
signalHandler = async (_signal) => {
|
|
69
|
-
if (signalHandler) {
|
|
70
|
-
process.off("SIGINT", signalHandler);
|
|
71
|
-
process.off("SIGTERM", signalHandler);
|
|
72
|
-
}
|
|
73
|
-
const signalError = /* @__PURE__ */ new Error("Process interrupted");
|
|
74
|
-
cleanupContext.error = signalError;
|
|
75
|
-
if (command.cleanup) try {
|
|
76
|
-
await command.cleanup(cleanupContext);
|
|
77
|
-
} catch (e) {
|
|
78
|
-
console.error("Error during signal cleanup:", e);
|
|
79
|
-
}
|
|
80
|
-
if (_options.globalCleanup) try {
|
|
81
|
-
await _options.globalCleanup({ error: signalError });
|
|
82
|
-
} catch (e) {
|
|
83
|
-
console.error("Error during global signal cleanup:", e);
|
|
84
|
-
}
|
|
85
|
-
collector?.stop();
|
|
86
|
-
if (process.stdout.writableNeedDrain) await new Promise((resolve) => {
|
|
87
|
-
const timeout = setTimeout(() => {
|
|
88
|
-
process.stdout.off("drain", onDrain);
|
|
89
|
-
resolve();
|
|
90
|
-
}, 200);
|
|
91
|
-
const onDrain = () => {
|
|
92
|
-
clearTimeout(timeout);
|
|
93
|
-
resolve();
|
|
94
|
-
};
|
|
95
|
-
process.stdout.once("drain", onDrain);
|
|
96
|
-
});
|
|
97
|
-
process.exit(1);
|
|
98
|
-
};
|
|
99
|
-
process.on("SIGINT", signalHandler);
|
|
100
|
-
process.on("SIGTERM", signalHandler);
|
|
101
|
-
}
|
|
102
|
-
try {
|
|
103
|
-
if (command.setup) await command.setup(setupContext);
|
|
104
|
-
if (command.run) result = await command.run(args);
|
|
105
|
-
} catch (e) {
|
|
106
|
-
error = e instanceof Error ? e : new Error(String(e));
|
|
107
|
-
} finally {
|
|
108
|
-
if (signalHandler) {
|
|
109
|
-
process.off("SIGINT", signalHandler);
|
|
110
|
-
process.off("SIGTERM", signalHandler);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
if (command.cleanup) {
|
|
114
|
-
cleanupContext.error = error;
|
|
115
|
-
try {
|
|
116
|
-
await command.cleanup(cleanupContext);
|
|
117
|
-
} catch (cleanupError) {
|
|
118
|
-
if (!error) error = cleanupError instanceof Error ? cleanupError : new Error(String(cleanupError));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
collector?.stop();
|
|
122
|
-
const logs = require_log_collector.mergeLogs(_options.existingLogs ?? require_log_collector.emptyLogs(), collector?.getLogs() ?? require_log_collector.emptyLogs());
|
|
123
|
-
if (error) return {
|
|
124
|
-
success: false,
|
|
125
|
-
error,
|
|
126
|
-
exitCode: 1,
|
|
127
|
-
logs
|
|
128
|
-
};
|
|
129
|
-
return {
|
|
130
|
-
success: true,
|
|
131
|
-
result,
|
|
132
|
-
exitCode: 0,
|
|
133
|
-
logs
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
//#endregion
|
|
138
|
-
//#region src/output/logger.ts
|
|
139
|
-
/**
|
|
140
|
-
* Check if color output should be disabled
|
|
141
|
-
*/
|
|
142
|
-
function shouldDisableColor() {
|
|
143
|
-
if (process.env.NO_COLOR !== void 0) return true;
|
|
144
|
-
if (process.env.FORCE_COLOR === "0") return true;
|
|
145
|
-
if (process.env.FORCE_COLOR) return false;
|
|
146
|
-
if (process.env.CI) return true;
|
|
147
|
-
if (!process.stdout.isTTY) return true;
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Global flag to control color output
|
|
152
|
-
*/
|
|
153
|
-
let colorDisabled = shouldDisableColor();
|
|
154
|
-
/**
|
|
155
|
-
* Enable or disable color output programmatically
|
|
156
|
-
*/
|
|
157
|
-
function setColorEnabled(enabled) {
|
|
158
|
-
colorDisabled = !enabled;
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Check if color output is currently enabled
|
|
162
|
-
*/
|
|
163
|
-
function isColorEnabled() {
|
|
164
|
-
return !colorDisabled;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Create a style function that applies the given styles
|
|
168
|
-
*/
|
|
169
|
-
function createStyleFn(...styleArgs) {
|
|
170
|
-
return (text) => {
|
|
171
|
-
if (colorDisabled) return text;
|
|
172
|
-
let result = text;
|
|
173
|
-
for (const style of styleArgs) result = (0, node_util.styleText)(style, result);
|
|
174
|
-
return result;
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Semantic style functions for inline text styling
|
|
179
|
-
*/
|
|
180
|
-
const styles = {
|
|
181
|
-
success: createStyleFn("green"),
|
|
182
|
-
error: createStyleFn("red"),
|
|
183
|
-
warning: createStyleFn("yellow"),
|
|
184
|
-
info: createStyleFn("cyan"),
|
|
185
|
-
bold: createStyleFn("bold"),
|
|
186
|
-
dim: createStyleFn("dim"),
|
|
187
|
-
italic: createStyleFn("italic"),
|
|
188
|
-
underline: createStyleFn("underline"),
|
|
189
|
-
red: createStyleFn("red"),
|
|
190
|
-
green: createStyleFn("green"),
|
|
191
|
-
yellow: createStyleFn("yellow"),
|
|
192
|
-
blue: createStyleFn("blue"),
|
|
193
|
-
magenta: createStyleFn("magenta"),
|
|
194
|
-
cyan: createStyleFn("cyan"),
|
|
195
|
-
white: createStyleFn("white"),
|
|
196
|
-
gray: createStyleFn("gray"),
|
|
197
|
-
command: createStyleFn("bold"),
|
|
198
|
-
commandName: createStyleFn("bold", "underline", "cyan"),
|
|
199
|
-
option: createStyleFn("cyan"),
|
|
200
|
-
optionName: createStyleFn("bold"),
|
|
201
|
-
placeholder: createStyleFn("dim"),
|
|
202
|
-
defaultValue: createStyleFn("dim"),
|
|
203
|
-
required: createStyleFn("yellow"),
|
|
204
|
-
description: (text) => text,
|
|
205
|
-
sectionHeader: createStyleFn("bold", "underline"),
|
|
206
|
-
version: createStyleFn("dim")
|
|
207
|
-
};
|
|
208
|
-
/**
|
|
209
|
-
* Standardized symbols for CLI output
|
|
210
|
-
*/
|
|
211
|
-
const symbols = {
|
|
212
|
-
success: styles.green("✓"),
|
|
213
|
-
error: styles.red("✖"),
|
|
214
|
-
warning: styles.yellow("⚠"),
|
|
215
|
-
info: styles.cyan("ℹ"),
|
|
216
|
-
bullet: styles.gray("•"),
|
|
217
|
-
arrow: styles.gray("→")
|
|
218
|
-
};
|
|
219
|
-
/**
|
|
220
|
-
* Logger for CLI output
|
|
221
|
-
*/
|
|
222
|
-
const logger = {
|
|
223
|
-
/**
|
|
224
|
-
* Log informational message
|
|
225
|
-
*/
|
|
226
|
-
info(message) {
|
|
227
|
-
console.log(message);
|
|
228
|
-
},
|
|
229
|
-
/**
|
|
230
|
-
* Log success message
|
|
231
|
-
*/
|
|
232
|
-
success(message) {
|
|
233
|
-
console.log(`${symbols.success} ${styles.success(message)}`);
|
|
234
|
-
},
|
|
235
|
-
/**
|
|
236
|
-
* Log warning message
|
|
237
|
-
*/
|
|
238
|
-
warn(message) {
|
|
239
|
-
console.warn(`${symbols.warning} ${styles.warning(message)}`);
|
|
240
|
-
},
|
|
241
|
-
/**
|
|
242
|
-
* Log error message
|
|
243
|
-
*/
|
|
244
|
-
error(message) {
|
|
245
|
-
console.error(`${symbols.error} ${styles.error(message)}`);
|
|
246
|
-
},
|
|
247
|
-
/**
|
|
248
|
-
* Log raw message without prefix
|
|
249
|
-
*/
|
|
250
|
-
log(message) {
|
|
251
|
-
console.log(message);
|
|
252
|
-
},
|
|
253
|
-
/**
|
|
254
|
-
* Log empty line
|
|
255
|
-
*/
|
|
256
|
-
newline() {
|
|
257
|
-
console.log("");
|
|
258
|
-
},
|
|
259
|
-
/**
|
|
260
|
-
* Log debug message with dim color
|
|
261
|
-
*/
|
|
262
|
-
debug(message) {
|
|
263
|
-
console.log(styles.dim(message));
|
|
264
|
-
}
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
//#endregion
|
|
268
|
-
//#region src/output/markdown-renderer.ts
|
|
269
|
-
/**
|
|
270
|
-
* Lightweight Markdown-to-terminal renderer.
|
|
271
|
-
*
|
|
272
|
-
* Supports a subset of Markdown tailored for CLI help notes:
|
|
273
|
-
* - Inline: bold, italic, inline code, links
|
|
274
|
-
* - Block: paragraphs, unordered/ordered lists, blockquotes, headings,
|
|
275
|
-
* horizontal rules, fenced code blocks
|
|
276
|
-
*/
|
|
277
|
-
/**
|
|
278
|
-
* Apply inline Markdown formatting to a string.
|
|
279
|
-
*
|
|
280
|
-
* Processing order matters to avoid conflicts:
|
|
281
|
-
* 1. Inline code (backticks) — content inside is literal, no further processing
|
|
282
|
-
* 2. Bold (**text**)
|
|
283
|
-
* 3. Italic (*text* or _text_)
|
|
284
|
-
* 4. Links [text](url)
|
|
285
|
-
*/
|
|
286
|
-
function renderInline(text) {
|
|
287
|
-
const codeSpans = [];
|
|
288
|
-
let result = text.replace(/`([^`]+)`/g, (_match, code) => {
|
|
289
|
-
const index = codeSpans.length;
|
|
290
|
-
codeSpans.push(styles.cyan(code));
|
|
291
|
-
return `\x00CODE${index}\x00`;
|
|
292
|
-
});
|
|
293
|
-
result = result.replace(/\*\*(.+?)\*\*/g, (_match, content) => styles.bold(content));
|
|
294
|
-
result = result.replace(/__(.+?)__/g, (_match, content) => styles.bold(content));
|
|
295
|
-
result = result.replace(/\*(.+?)\*/g, (_match, content) => styles.italic(content));
|
|
296
|
-
result = result.replace(/(?<!\w)_(.+?)_(?!\w)/g, (_match, content) => styles.italic(content));
|
|
297
|
-
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, linkText, url) => `${styles.underline(linkText)} ${styles.dim(`(${url})`)}`);
|
|
298
|
-
result = result.replace(/\x00CODE(\d+)\x00/g, (_match, index) => codeSpans[Number(index)]);
|
|
299
|
-
return result;
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Render a Markdown string to styled terminal output.
|
|
303
|
-
*
|
|
304
|
-
* Block-level processing:
|
|
305
|
-
* - Splits input into blocks separated by blank lines
|
|
306
|
-
* - Detects headings, horizontal rules, blockquotes, lists, code blocks, and paragraphs
|
|
307
|
-
* - Applies inline formatting within each block
|
|
308
|
-
*/
|
|
309
|
-
function renderMarkdown(markdown) {
|
|
310
|
-
return splitIntoBlocks(markdown.split("\n")).map(renderBlock).join("\n\n");
|
|
311
|
-
}
|
|
312
|
-
const HEADING_RE = /^(#{1,6})\s+(.+)$/;
|
|
313
|
-
const HR_RE = /^(?:---+|\*\*\*+|___+)\s*$/;
|
|
314
|
-
const BLOCKQUOTE_RE = /^>\s?(.*)$/;
|
|
315
|
-
const UL_RE = /^-\s+(.+)$/;
|
|
316
|
-
const OL_RE = /^(\d+)[.)]\s+(.+)$/;
|
|
317
|
-
const FENCE_OPEN_RE = /^(`{3,}|~{3,})(\S*)\s*$/;
|
|
318
|
-
const ALERT_RE = /^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\s*$/;
|
|
319
|
-
const TABLE_ROW_RE = /^\|(.+)\|$/;
|
|
320
|
-
const TABLE_SEP_RE = /^\|(\s*:?-+:?\s*\|)+$/;
|
|
321
|
-
/**
|
|
322
|
-
* Split lines into logical blocks separated by blank lines.
|
|
323
|
-
* Consecutive lines of the same block type are grouped together.
|
|
324
|
-
*/
|
|
325
|
-
function splitIntoBlocks(lines) {
|
|
326
|
-
const blocks = [];
|
|
327
|
-
let i = 0;
|
|
328
|
-
while (i < lines.length) {
|
|
329
|
-
const line = lines[i];
|
|
330
|
-
if (line.trim() === "") {
|
|
331
|
-
i++;
|
|
332
|
-
continue;
|
|
333
|
-
}
|
|
334
|
-
const fenceMatch = line.match(FENCE_OPEN_RE);
|
|
335
|
-
if (fenceMatch) {
|
|
336
|
-
const fence = fenceMatch[1];
|
|
337
|
-
const lang = fenceMatch[2] ?? "";
|
|
338
|
-
const codeLines = [];
|
|
339
|
-
i++;
|
|
340
|
-
while (i < lines.length) {
|
|
341
|
-
if (lines[i].startsWith(fence.charAt(0).repeat(fence.length)) && lines[i].trim() === fence.charAt(0).repeat(Math.max(fence.length, lines[i].trim().length))) {
|
|
342
|
-
i++;
|
|
343
|
-
break;
|
|
344
|
-
}
|
|
345
|
-
codeLines.push(lines[i]);
|
|
346
|
-
i++;
|
|
347
|
-
}
|
|
348
|
-
blocks.push({
|
|
349
|
-
type: "code",
|
|
350
|
-
lang,
|
|
351
|
-
lines: codeLines
|
|
352
|
-
});
|
|
353
|
-
continue;
|
|
354
|
-
}
|
|
355
|
-
const headingMatch = line.match(HEADING_RE);
|
|
356
|
-
if (headingMatch) {
|
|
357
|
-
blocks.push({
|
|
358
|
-
type: "heading",
|
|
359
|
-
level: headingMatch[1].length,
|
|
360
|
-
content: headingMatch[2]
|
|
361
|
-
});
|
|
362
|
-
i++;
|
|
363
|
-
continue;
|
|
364
|
-
}
|
|
365
|
-
if (HR_RE.test(line)) {
|
|
366
|
-
blocks.push({ type: "hr" });
|
|
367
|
-
i++;
|
|
368
|
-
continue;
|
|
369
|
-
}
|
|
370
|
-
if (BLOCKQUOTE_RE.test(line)) {
|
|
371
|
-
const bqLines = [];
|
|
372
|
-
while (i < lines.length) {
|
|
373
|
-
const bqMatch = lines[i].match(BLOCKQUOTE_RE);
|
|
374
|
-
if (bqMatch) {
|
|
375
|
-
bqLines.push(bqMatch[1]);
|
|
376
|
-
i++;
|
|
377
|
-
} else break;
|
|
378
|
-
}
|
|
379
|
-
if (bqLines.length > 0) {
|
|
380
|
-
const alertMatch = bqLines[0].match(ALERT_RE);
|
|
381
|
-
if (alertMatch) {
|
|
382
|
-
const contentLines = bqLines.slice(1).filter((l) => l !== "");
|
|
383
|
-
blocks.push({
|
|
384
|
-
type: "alert",
|
|
385
|
-
alertType: alertMatch[1],
|
|
386
|
-
lines: contentLines
|
|
387
|
-
});
|
|
388
|
-
continue;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
blocks.push({
|
|
392
|
-
type: "blockquote",
|
|
393
|
-
lines: bqLines
|
|
394
|
-
});
|
|
395
|
-
continue;
|
|
396
|
-
}
|
|
397
|
-
if (UL_RE.test(line)) {
|
|
398
|
-
const items = [];
|
|
399
|
-
while (i < lines.length) {
|
|
400
|
-
const ulMatch = lines[i].match(UL_RE);
|
|
401
|
-
if (ulMatch) {
|
|
402
|
-
items.push(ulMatch[1]);
|
|
403
|
-
i++;
|
|
404
|
-
} else break;
|
|
405
|
-
}
|
|
406
|
-
blocks.push({
|
|
407
|
-
type: "ul",
|
|
408
|
-
items
|
|
409
|
-
});
|
|
410
|
-
continue;
|
|
411
|
-
}
|
|
412
|
-
const olMatch = line.match(OL_RE);
|
|
413
|
-
if (olMatch) {
|
|
414
|
-
const start = Number(olMatch[1]);
|
|
415
|
-
const items = [];
|
|
416
|
-
while (i < lines.length) {
|
|
417
|
-
const match = lines[i].match(OL_RE);
|
|
418
|
-
if (match) {
|
|
419
|
-
items.push(match[2]);
|
|
420
|
-
i++;
|
|
421
|
-
} else break;
|
|
422
|
-
}
|
|
423
|
-
blocks.push({
|
|
424
|
-
type: "ol",
|
|
425
|
-
items,
|
|
426
|
-
start
|
|
427
|
-
});
|
|
428
|
-
continue;
|
|
429
|
-
}
|
|
430
|
-
if (TABLE_ROW_RE.test(line) && i + 1 < lines.length && TABLE_SEP_RE.test(lines[i + 1])) {
|
|
431
|
-
const headers = parseCells(line);
|
|
432
|
-
const alignments = parseAlignments(lines[i + 1]);
|
|
433
|
-
i += 2;
|
|
434
|
-
const rows = [];
|
|
435
|
-
while (i < lines.length && TABLE_ROW_RE.test(lines[i])) {
|
|
436
|
-
rows.push(parseCells(lines[i]));
|
|
437
|
-
i++;
|
|
438
|
-
}
|
|
439
|
-
blocks.push({
|
|
440
|
-
type: "table",
|
|
441
|
-
headers,
|
|
442
|
-
alignments,
|
|
443
|
-
rows
|
|
444
|
-
});
|
|
445
|
-
continue;
|
|
446
|
-
}
|
|
447
|
-
const paraLines = [];
|
|
448
|
-
while (i < lines.length) {
|
|
449
|
-
const l = lines[i];
|
|
450
|
-
if (l.trim() === "" || HEADING_RE.test(l) || HR_RE.test(l) || BLOCKQUOTE_RE.test(l) || UL_RE.test(l) || OL_RE.test(l) || FENCE_OPEN_RE.test(l) || TABLE_ROW_RE.test(l) && i + 1 < lines.length && TABLE_SEP_RE.test(lines[i + 1])) break;
|
|
451
|
-
paraLines.push(l);
|
|
452
|
-
i++;
|
|
453
|
-
}
|
|
454
|
-
if (paraLines.length > 0) blocks.push({
|
|
455
|
-
type: "paragraph",
|
|
456
|
-
lines: paraLines
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
|
-
return blocks;
|
|
460
|
-
}
|
|
461
|
-
/**
|
|
462
|
-
* Parse cells from a table row: `| a | b | c |` → `["a", "b", "c"]`
|
|
463
|
-
*/
|
|
464
|
-
function parseCells(row) {
|
|
465
|
-
return row.slice(1, -1).split("|").map((cell) => cell.trim());
|
|
466
|
-
}
|
|
467
|
-
/**
|
|
468
|
-
* Parse alignment from separator row: `|:---|:---:|---:|` → `["left", "center", "right"]`
|
|
469
|
-
*/
|
|
470
|
-
function parseAlignments(sepRow) {
|
|
471
|
-
return sepRow.slice(1, -1).split("|").map((cell) => {
|
|
472
|
-
const trimmed = cell.trim();
|
|
473
|
-
if (trimmed.startsWith(":") && trimmed.endsWith(":")) return "center";
|
|
474
|
-
if (trimmed.endsWith(":")) return "right";
|
|
475
|
-
return "left";
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
/**
|
|
479
|
-
* Pad a string to a given width with the specified alignment.
|
|
480
|
-
*/
|
|
481
|
-
function alignText(text, width, alignment) {
|
|
482
|
-
const visualWidth = (0, string_width.default)(text);
|
|
483
|
-
const total = Math.max(0, width - visualWidth);
|
|
484
|
-
if (alignment === "right") return " ".repeat(total) + text;
|
|
485
|
-
if (alignment === "center") {
|
|
486
|
-
const left = Math.floor(total / 2);
|
|
487
|
-
return " ".repeat(left) + text + " ".repeat(total - left);
|
|
488
|
-
}
|
|
489
|
-
return text + " ".repeat(total);
|
|
490
|
-
}
|
|
491
|
-
/**
|
|
492
|
-
* Style configuration for GitHub-style alert blocks.
|
|
493
|
-
*/
|
|
494
|
-
const alertStyles = {
|
|
495
|
-
NOTE: {
|
|
496
|
-
icon: "ℹ",
|
|
497
|
-
label: "Note",
|
|
498
|
-
styleFn: styles.cyan
|
|
499
|
-
},
|
|
500
|
-
TIP: {
|
|
501
|
-
icon: "💡",
|
|
502
|
-
label: "Tip",
|
|
503
|
-
styleFn: styles.green
|
|
504
|
-
},
|
|
505
|
-
IMPORTANT: {
|
|
506
|
-
icon: "❗",
|
|
507
|
-
label: "Important",
|
|
508
|
-
styleFn: styles.magenta
|
|
509
|
-
},
|
|
510
|
-
WARNING: {
|
|
511
|
-
icon: "⚠",
|
|
512
|
-
label: "Warning",
|
|
513
|
-
styleFn: styles.yellow
|
|
514
|
-
},
|
|
515
|
-
CAUTION: {
|
|
516
|
-
icon: "🔴",
|
|
517
|
-
label: "Caution",
|
|
518
|
-
styleFn: styles.red
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
/**
|
|
522
|
-
* Render a single block to styled terminal output.
|
|
523
|
-
*/
|
|
524
|
-
function renderBlock(block) {
|
|
525
|
-
switch (block.type) {
|
|
526
|
-
case "heading": return styles.green(styles.bold(renderInline(block.content)));
|
|
527
|
-
case "hr": return styles.dim("─".repeat(40));
|
|
528
|
-
case "blockquote": {
|
|
529
|
-
const prefix = styles.dim("│ ");
|
|
530
|
-
return block.lines.map((line) => `${prefix}${renderInline(line)}`).join("\n");
|
|
531
|
-
}
|
|
532
|
-
case "alert": {
|
|
533
|
-
const { icon, label, styleFn } = alertStyles[block.alertType];
|
|
534
|
-
const prefix = styleFn(styles.bold("│")) + " ";
|
|
535
|
-
const header = `${prefix}${styleFn(icon)} ${styleFn(label)}`;
|
|
536
|
-
if (block.lines.length === 0) return header;
|
|
537
|
-
return `${header}\n${block.lines.map((line) => `${prefix}${renderInline(line)}`).join("\n")}`;
|
|
538
|
-
}
|
|
539
|
-
case "ul": return block.items.map((item) => `${styles.dim("•")} ${renderInline(item)}`).join("\n");
|
|
540
|
-
case "ol": {
|
|
541
|
-
const maxNum = block.start + block.items.length - 1;
|
|
542
|
-
const width = String(maxNum).length;
|
|
543
|
-
return block.items.map((item, i) => {
|
|
544
|
-
const num = String(block.start + i).padStart(width, " ");
|
|
545
|
-
return `${styles.dim(`${num}.`)} ${renderInline(item)}`;
|
|
546
|
-
}).join("\n");
|
|
547
|
-
}
|
|
548
|
-
case "table": {
|
|
549
|
-
const colCount = block.headers.length;
|
|
550
|
-
const renderedHeaders = block.headers.map((h) => renderInline(h));
|
|
551
|
-
const renderedRows = block.rows.map((row) => Array.from({ length: colCount }, (_, i) => renderInline(row[i] ?? "")));
|
|
552
|
-
const colWidths = renderedHeaders.map((h, i) => {
|
|
553
|
-
const headerWidth = (0, string_width.default)(h);
|
|
554
|
-
const cellWidths = renderedRows.map((row) => (0, string_width.default)(row[i]));
|
|
555
|
-
return Math.max(headerWidth, ...cellWidths);
|
|
556
|
-
});
|
|
557
|
-
const pipe = styles.dim("│");
|
|
558
|
-
const topBorder = styles.dim(`┌─${colWidths.map((w) => "─".repeat(w)).join("─┬─")}─┐`);
|
|
559
|
-
const midBorder = styles.dim(`├─${colWidths.map((w) => "─".repeat(w)).join("─┼─")}─┤`);
|
|
560
|
-
const botBorder = styles.dim(`└─${colWidths.map((w) => "─".repeat(w)).join("─┴─")}─┘`);
|
|
561
|
-
return [
|
|
562
|
-
topBorder,
|
|
563
|
-
`${pipe} ${renderedHeaders.map((h, i) => styles.bold(alignText(h, colWidths[i], block.alignments[i] ?? "left"))).join(` ${pipe} `)} ${pipe}`,
|
|
564
|
-
midBorder,
|
|
565
|
-
...renderedRows.map((row) => {
|
|
566
|
-
return `${pipe} ${row.map((cell, i) => alignText(cell, colWidths[i], block.alignments[i] ?? "left")).join(` ${pipe} `)} ${pipe}`;
|
|
567
|
-
}),
|
|
568
|
-
botBorder
|
|
569
|
-
].join("\n");
|
|
570
|
-
}
|
|
571
|
-
case "code": return block.lines.map((line) => ` ${styles.yellow(line)}`).join("\n");
|
|
572
|
-
case "paragraph": return renderInline(block.lines.join(" "));
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
//#endregion
|
|
577
|
-
//#region src/output/help-generator.ts
|
|
578
|
-
/**
|
|
579
|
-
* Default descriptions for built-in options
|
|
580
|
-
*/
|
|
581
|
-
const defaultBuiltinDescriptions = {
|
|
582
|
-
help: "Show help",
|
|
583
|
-
helpAll: "Show help with all subcommand options",
|
|
584
|
-
version: "Show version"
|
|
585
|
-
};
|
|
586
|
-
/**
|
|
587
|
-
* Internal subcommands are reserved for framework internals and hidden from help output.
|
|
588
|
-
*/
|
|
589
|
-
function isVisibleSubcommand(name) {
|
|
590
|
-
return !name.startsWith("__");
|
|
591
|
-
}
|
|
592
|
-
function getVisibleSubcommandEntries(subCommands) {
|
|
593
|
-
return Object.entries(subCommands).filter(([name]) => isVisibleSubcommand(name));
|
|
594
|
-
}
|
|
595
|
-
/**
|
|
596
|
-
* Build full command name from context
|
|
597
|
-
*/
|
|
598
|
-
function buildFullCommandName(command, context) {
|
|
599
|
-
if (context?.rootName && context.commandPath && context.commandPath.length > 0) return context.commandPath.join(" ");
|
|
600
|
-
return command.name ?? "command";
|
|
601
|
-
}
|
|
602
|
-
/**
|
|
603
|
-
* Build usage command name (includes root name for subcommands)
|
|
604
|
-
*/
|
|
605
|
-
function buildUsageCommandName(command, context) {
|
|
606
|
-
if (context?.rootName && context.commandPath && context.commandPath.length > 0) return `${context.rootName} ${context.commandPath.join(" ")}`;
|
|
607
|
-
return command.name ?? "command";
|
|
608
|
-
}
|
|
609
|
-
/**
|
|
610
|
-
* Render the usage line for a command
|
|
611
|
-
*/
|
|
612
|
-
function renderUsageLine(command, context) {
|
|
613
|
-
const parts = [];
|
|
614
|
-
const name = buildUsageCommandName(command, context);
|
|
615
|
-
parts.push(styles.commandName(name));
|
|
616
|
-
if (context?.globalExtracted?.fields.length) parts.push(styles.placeholder("[global options]"));
|
|
617
|
-
const extracted = require_schema_extractor.getExtractedFields(command);
|
|
618
|
-
if (extracted) {
|
|
619
|
-
const positionals = extracted.fields.filter((a) => a.positional);
|
|
620
|
-
if (extracted.fields.filter((a) => !a.positional).length > 0) parts.push(styles.placeholder("[options]"));
|
|
621
|
-
if (command.subCommands && getVisibleSubcommandEntries(command.subCommands).length > 0) parts.push(styles.placeholder("[command]"));
|
|
622
|
-
for (const arg of positionals) if (arg.required) parts.push(styles.option(`<${arg.name}>`));
|
|
623
|
-
else parts.push(styles.placeholder(`[${arg.name}]`));
|
|
624
|
-
} else if (command.subCommands && getVisibleSubcommandEntries(command.subCommands).length > 0) parts.push(styles.placeholder("[command]"));
|
|
625
|
-
return parts.join(" ");
|
|
626
|
-
}
|
|
627
|
-
/**
|
|
628
|
-
* Render the options section
|
|
629
|
-
*/
|
|
630
|
-
function renderOptions(command, descriptions = {}, context) {
|
|
631
|
-
const lines = [];
|
|
632
|
-
const desc = {
|
|
633
|
-
help: descriptions.help ?? defaultBuiltinDescriptions.help,
|
|
634
|
-
helpAll: descriptions.helpAll ?? defaultBuiltinDescriptions.helpAll,
|
|
635
|
-
version: descriptions.version ?? defaultBuiltinDescriptions.version
|
|
636
|
-
};
|
|
637
|
-
const extracted = require_schema_extractor.getExtractedFields(command);
|
|
638
|
-
const hasUserDefinedh = extracted?.fields.some((f) => f.overrideBuiltinAlias === true && require_schema_extractor.getAllAliases(f).includes("h")) ?? false;
|
|
639
|
-
const hasUserDefinedH = extracted?.fields.some((f) => f.overrideBuiltinAlias === true && require_schema_extractor.getAllAliases(f).includes("H")) ?? false;
|
|
640
|
-
if (hasUserDefinedh) lines.push(formatOption(styles.option("--help"), desc.help));
|
|
641
|
-
else lines.push(formatOption(`${styles.option("-h")}, ${styles.option("--help")}`, desc.help));
|
|
642
|
-
if (hasUserDefinedH) lines.push(formatOption(styles.option("--help-all"), desc.helpAll));
|
|
643
|
-
else lines.push(formatOption(`${styles.option("-H")}, ${styles.option("--help-all")}`, desc.helpAll));
|
|
644
|
-
if (context?.rootVersion) lines.push(formatOption(styles.option("--version"), desc.version));
|
|
645
|
-
if (!extracted) return lines.join("\n");
|
|
646
|
-
if (extracted.schemaType === "discriminatedUnion" && extracted.discriminator) return renderDiscriminatedUnionOptions(extracted, command, lines);
|
|
647
|
-
if (extracted.schemaType === "union" && extracted.unionOptions) return renderUnionOptions(extracted, command, lines);
|
|
648
|
-
if (extracted.schemaType === "xor" && extracted.unionOptions) return renderUnionOptions(extracted, command, lines);
|
|
649
|
-
const options = extracted.fields.filter((a) => !a.positional);
|
|
650
|
-
for (const opt of options) {
|
|
651
|
-
const flags = formatFlags(opt);
|
|
652
|
-
let desc = opt.description ?? "";
|
|
653
|
-
if (opt.defaultValue !== void 0) desc += ` ${styles.defaultValue(`(default: ${JSON.stringify(opt.defaultValue)})`)}`;
|
|
654
|
-
if (opt.required) desc += ` ${styles.required("(required)")}`;
|
|
655
|
-
const envInfo = formatEnvInfo(opt.env);
|
|
656
|
-
if (envInfo) desc += ` ${envInfo}`;
|
|
657
|
-
lines.push(formatOption(flags, desc));
|
|
658
|
-
const negationLine = formatNegationLine(opt);
|
|
659
|
-
if (negationLine) lines.push(negationLine);
|
|
660
|
-
}
|
|
661
|
-
return lines.join("\n");
|
|
662
|
-
}
|
|
663
|
-
/**
|
|
664
|
-
* Render a separate line for the custom negation option when a
|
|
665
|
-
* `negationDescription` is provided. When no description is given, the
|
|
666
|
-
* negation is shown inline by `formatFlags`.
|
|
667
|
-
*/
|
|
668
|
-
function formatNegationLine(opt, indent = 0, extraDescPadding = 0) {
|
|
669
|
-
if (!opt.negationDisplay || !opt.negationDescription) return null;
|
|
670
|
-
return formatOption(styles.option(`--${opt.negationDisplay}`), `${opt.negationDescription} ${styles.dim(`(↔ --${opt.cliName})`)}`, indent, extraDescPadding);
|
|
671
|
-
}
|
|
672
|
-
/**
|
|
673
|
-
* Render options for discriminated union with variants
|
|
674
|
-
*/
|
|
675
|
-
function renderDiscriminatedUnionOptions(extracted, _command, lines) {
|
|
676
|
-
const discriminator = extracted.discriminator;
|
|
677
|
-
const variants = extracted.variants ?? [];
|
|
678
|
-
const discriminatorField = extracted.fields.find((f) => f.name === discriminator);
|
|
679
|
-
if (discriminatorField) {
|
|
680
|
-
const variantValues = variants.map((v) => v.discriminatorValue).join("|");
|
|
681
|
-
const flags = `${styles.option(`--${discriminator}`)} ${styles.placeholder(`<${variantValues}>`)}`;
|
|
682
|
-
const description = extracted.description ?? discriminatorField.description ?? "Action to perform";
|
|
683
|
-
lines.push(formatOption(flags, description));
|
|
684
|
-
}
|
|
685
|
-
const commonFields = /* @__PURE__ */ new Set();
|
|
686
|
-
const allFieldNames = /* @__PURE__ */ new Set();
|
|
687
|
-
for (const variant of variants) for (const field of variant.fields) allFieldNames.add(field.name);
|
|
688
|
-
for (const fieldName of allFieldNames) {
|
|
689
|
-
if (fieldName === discriminator) continue;
|
|
690
|
-
if (variants.every((v) => v.fields.some((f) => f.name === fieldName))) commonFields.add(fieldName);
|
|
691
|
-
}
|
|
692
|
-
for (const fieldName of commonFields) {
|
|
693
|
-
const field = extracted.fields.find((f) => f.name === fieldName);
|
|
694
|
-
if (field && !field.positional) {
|
|
695
|
-
const flags = formatFlags(field);
|
|
696
|
-
let desc = field.description ?? "";
|
|
697
|
-
if (field.defaultValue !== void 0) desc += ` ${styles.defaultValue(`(default: ${JSON.stringify(field.defaultValue)})`)}`;
|
|
698
|
-
const envInfo = formatEnvInfo(field.env);
|
|
699
|
-
if (envInfo) desc += ` ${envInfo}`;
|
|
700
|
-
lines.push(formatOption(flags, desc));
|
|
701
|
-
const negationLine = formatNegationLine(field);
|
|
702
|
-
if (negationLine) lines.push(negationLine);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
for (const variant of variants) {
|
|
706
|
-
const variantFields = variant.fields.filter((f) => f.name !== discriminator && !commonFields.has(f.name) && !f.positional);
|
|
707
|
-
if (variantFields.length > 0) {
|
|
708
|
-
lines.push("");
|
|
709
|
-
const variantLabel = variant.description ? `${styles.dim("When")} ${styles.option(discriminator)}=${styles.bold(variant.discriminatorValue)}: ${variant.description}` : `${styles.dim("When")} ${styles.option(discriminator)}=${styles.bold(variant.discriminatorValue)}:`;
|
|
710
|
-
lines.push(variantLabel);
|
|
711
|
-
for (const field of variantFields) {
|
|
712
|
-
const flags = formatFlags(field);
|
|
713
|
-
let desc = field.description ?? "";
|
|
714
|
-
if (field.defaultValue !== void 0) desc += ` ${styles.defaultValue(`(default: ${JSON.stringify(field.defaultValue)})`)}`;
|
|
715
|
-
if (field.required) desc += ` ${styles.required("(required)")}`;
|
|
716
|
-
const envInfo = formatEnvInfo(field.env);
|
|
717
|
-
if (envInfo) desc += ` ${envInfo}`;
|
|
718
|
-
lines.push(formatOption(flags, desc, 1));
|
|
719
|
-
const negationLine = formatNegationLine(field, 1);
|
|
720
|
-
if (negationLine) lines.push(negationLine);
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
return lines.join("\n");
|
|
725
|
-
}
|
|
726
|
-
/**
|
|
727
|
-
* Render options for union with multiple options
|
|
728
|
-
*/
|
|
729
|
-
function renderUnionOptions(extracted, _command, lines) {
|
|
730
|
-
const unionOptions = extracted.unionOptions ?? [];
|
|
731
|
-
const commonFields = /* @__PURE__ */ new Set();
|
|
732
|
-
const allFieldNames = /* @__PURE__ */ new Set();
|
|
733
|
-
for (const option of unionOptions) for (const field of option.fields) allFieldNames.add(field.name);
|
|
734
|
-
for (const fieldName of allFieldNames) if (unionOptions.every((o) => o.fields.some((f) => f.name === fieldName))) commonFields.add(fieldName);
|
|
735
|
-
for (const fieldName of commonFields) {
|
|
736
|
-
const field = extracted.fields.find((f) => f.name === fieldName);
|
|
737
|
-
if (field && !field.positional) {
|
|
738
|
-
const flags = formatFlags(field);
|
|
739
|
-
let desc = field.description ?? "";
|
|
740
|
-
if (field.defaultValue !== void 0) desc += ` ${styles.defaultValue(`(default: ${JSON.stringify(field.defaultValue)})`)}`;
|
|
741
|
-
const envInfo = formatEnvInfo(field.env);
|
|
742
|
-
if (envInfo) desc += ` ${envInfo}`;
|
|
743
|
-
lines.push(formatOption(flags, desc));
|
|
744
|
-
const negationLine = formatNegationLine(field);
|
|
745
|
-
if (negationLine) lines.push(negationLine);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
for (let i = 0; i < unionOptions.length; i++) {
|
|
749
|
-
const option = unionOptions[i];
|
|
750
|
-
if (!option) continue;
|
|
751
|
-
const uniqueFields = option.fields.filter((f) => !commonFields.has(f.name) && !f.positional);
|
|
752
|
-
const label = option.description ?? `Variant ${i + 1}`;
|
|
753
|
-
if (uniqueFields.length > 0) {
|
|
754
|
-
lines.push("");
|
|
755
|
-
lines.push(` ${styles.bold(`${label}:`)}`);
|
|
756
|
-
for (const field of uniqueFields) {
|
|
757
|
-
const flags = formatFlags(field);
|
|
758
|
-
let desc = field.description ?? "";
|
|
759
|
-
if (field.defaultValue !== void 0) desc += ` ${styles.defaultValue(`(default: ${JSON.stringify(field.defaultValue)})`)}`;
|
|
760
|
-
if (field.required) desc += ` ${styles.required("(required)")}`;
|
|
761
|
-
const envInfo = formatEnvInfo(field.env);
|
|
762
|
-
if (envInfo) desc += ` ${envInfo}`;
|
|
763
|
-
lines.push(formatOption(flags, desc, 1));
|
|
764
|
-
const negationLine = formatNegationLine(field, 1);
|
|
765
|
-
if (negationLine) lines.push(negationLine);
|
|
766
|
-
}
|
|
767
|
-
} else {
|
|
768
|
-
lines.push("");
|
|
769
|
-
lines.push(` ${styles.bold(`${label}:`)}`);
|
|
770
|
-
lines.push(` ${styles.dim(styles.italic("no options"))}`);
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
return lines.join("\n");
|
|
774
|
-
}
|
|
775
|
-
/**
|
|
776
|
-
* Format option flags (-v, --verbose <VALUE>)
|
|
777
|
-
* Uses cliName (kebab-case) for display
|
|
778
|
-
*/
|
|
779
|
-
function formatFlags(opt) {
|
|
780
|
-
const aliasParts = [];
|
|
781
|
-
if (opt.alias) {
|
|
782
|
-
for (const alias of opt.alias) if (alias.length === 1) aliasParts.push(styles.option(`-${alias}`));
|
|
783
|
-
}
|
|
784
|
-
let longFlag = styles.option(`--${opt.cliName}`);
|
|
785
|
-
if (opt.type !== "boolean") {
|
|
786
|
-
const placeholder = opt.placeholder ?? opt.cliName.toUpperCase();
|
|
787
|
-
longFlag += ` ${styles.placeholder(`<${placeholder}>`)}`;
|
|
788
|
-
}
|
|
789
|
-
aliasParts.push(longFlag);
|
|
790
|
-
if (opt.alias) {
|
|
791
|
-
for (const alias of opt.alias) if (alias.length > 1) {
|
|
792
|
-
let longAlias = styles.option(`--${alias}`);
|
|
793
|
-
if (opt.type !== "boolean") {
|
|
794
|
-
const placeholder = opt.placeholder ?? opt.cliName.toUpperCase();
|
|
795
|
-
longAlias += ` ${styles.placeholder(`<${placeholder}>`)}`;
|
|
796
|
-
}
|
|
797
|
-
aliasParts.push(longAlias);
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
const aliasStr = aliasParts.join(", ");
|
|
801
|
-
if (opt.type === "boolean" && opt.negationDisplay && !opt.negationDescription) return `${aliasStr} / ${styles.option(`--${opt.negationDisplay}`)}`;
|
|
802
|
-
return aliasStr;
|
|
803
|
-
}
|
|
804
|
-
/**
|
|
805
|
-
* Format environment variable info for help display
|
|
806
|
-
*/
|
|
807
|
-
function formatEnvInfo(env) {
|
|
808
|
-
if (!env) return "";
|
|
809
|
-
const envNames = Array.isArray(env) ? env : [env];
|
|
810
|
-
return styles.dim(`[env: ${envNames.join(", ")}]`);
|
|
811
|
-
}
|
|
812
|
-
/**
|
|
813
|
-
* Strip ANSI escape codes from a string to get visual length
|
|
814
|
-
*/
|
|
815
|
-
function stripAnsi(str) {
|
|
816
|
-
return str.replace(/\x1B\[[0-9;]*m/g, "");
|
|
817
|
-
}
|
|
818
|
-
/**
|
|
819
|
-
* Pad a string that may contain ANSI codes to a visual width
|
|
820
|
-
*/
|
|
821
|
-
function padEndVisual(str, width) {
|
|
822
|
-
const visualLength = stripAnsi(str).length;
|
|
823
|
-
const padding = Math.max(0, width - visualLength);
|
|
824
|
-
return str + " ".repeat(padding);
|
|
825
|
-
}
|
|
826
|
-
/**
|
|
827
|
-
* Format a single option line
|
|
828
|
-
* If flags exceed the column width, description is moved to the next line
|
|
829
|
-
*/
|
|
830
|
-
function formatOption(flags, description, indent = 0, extraDescPadding = 0) {
|
|
831
|
-
const flagWidth = 32;
|
|
832
|
-
const indentStr = " ".repeat(indent);
|
|
833
|
-
const visualFlagLength = stripAnsi(flags).length;
|
|
834
|
-
const effectiveFlagWidth = flagWidth - indent * 2 + extraDescPadding;
|
|
835
|
-
if (visualFlagLength >= effectiveFlagWidth) return `${indentStr} ${flags}\n${" ".repeat(effectiveFlagWidth + 2 + indent * 2)}${description}`;
|
|
836
|
-
return `${indentStr} ${padEndVisual(flags, effectiveFlagWidth)}${description}`;
|
|
837
|
-
}
|
|
838
|
-
/**
|
|
839
|
-
* Format a single option field as a help line
|
|
840
|
-
*/
|
|
841
|
-
function formatFieldLine(opt, indent = 0, extraDescPadding = 0) {
|
|
842
|
-
const flags = formatFlags(opt);
|
|
843
|
-
let desc = opt.description ?? "";
|
|
844
|
-
if (opt.defaultValue !== void 0) desc += ` ${styles.defaultValue(`(default: ${JSON.stringify(opt.defaultValue)})`)}`;
|
|
845
|
-
if (opt.required) desc += ` ${styles.required("(required)")}`;
|
|
846
|
-
const envInfo = formatEnvInfo(opt.env);
|
|
847
|
-
if (envInfo) desc += ` ${envInfo}`;
|
|
848
|
-
return formatOption(flags, desc, indent, extraDescPadding);
|
|
849
|
-
}
|
|
850
|
-
/**
|
|
851
|
-
* Render global options section
|
|
852
|
-
*/
|
|
853
|
-
function renderGlobalOptions(globalExtracted) {
|
|
854
|
-
const lines = [];
|
|
855
|
-
for (const opt of globalExtracted.fields) {
|
|
856
|
-
if (opt.positional) continue;
|
|
857
|
-
lines.push(formatFieldLine(opt));
|
|
858
|
-
const negationLine = formatNegationLine(opt);
|
|
859
|
-
if (negationLine) lines.push(negationLine);
|
|
860
|
-
}
|
|
861
|
-
return lines.join("\n");
|
|
862
|
-
}
|
|
863
|
-
/**
|
|
864
|
-
* Render options for a subcommand (used by showSubcommandOptions)
|
|
865
|
-
*/
|
|
866
|
-
function renderSubcommandOptionsCompact(command, indent) {
|
|
867
|
-
const lines = [];
|
|
868
|
-
const extracted = require_schema_extractor.getExtractedFields(command);
|
|
869
|
-
if (extracted) {
|
|
870
|
-
const options = extracted.fields.filter((a) => !a.positional);
|
|
871
|
-
for (const opt of options) {
|
|
872
|
-
const flags = formatFlags(opt);
|
|
873
|
-
let desc = opt.description ?? "";
|
|
874
|
-
if (opt.defaultValue !== void 0) desc += ` ${styles.defaultValue(`(default: ${JSON.stringify(opt.defaultValue)})`)}`;
|
|
875
|
-
const envInfo = formatEnvInfo(opt.env);
|
|
876
|
-
if (envInfo) desc += ` ${envInfo}`;
|
|
877
|
-
lines.push(formatOption(flags, desc, indent, 2));
|
|
878
|
-
const negationLine = formatNegationLine(opt, indent, 2);
|
|
879
|
-
if (negationLine) lines.push(negationLine);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
return lines;
|
|
883
|
-
}
|
|
884
|
-
/**
|
|
885
|
-
* Render subcommands recursively with their options (flat style)
|
|
886
|
-
*/
|
|
887
|
-
function renderSubcommandsWithOptions(subCommands, parentPath, baseIndent) {
|
|
888
|
-
const lines = [];
|
|
889
|
-
for (const [name, subCmd] of getVisibleSubcommandEntries(subCommands)) {
|
|
890
|
-
const cmd = require_schema_extractor.resolveSubCommandMeta(subCmd);
|
|
891
|
-
const fullPath = parentPath ? `${parentPath} ${name}` : name;
|
|
892
|
-
const desc = cmd?.description ?? "";
|
|
893
|
-
const aliases = cmd?.aliases;
|
|
894
|
-
const displayName = aliases && aliases.length > 0 ? `${fullPath}, ${aliases.join(", ")}` : fullPath;
|
|
895
|
-
lines.push(formatOption(styles.command(displayName), desc, baseIndent));
|
|
896
|
-
if (cmd) {
|
|
897
|
-
const optionLines = renderSubcommandOptionsCompact(cmd, baseIndent + 1);
|
|
898
|
-
lines.push(...optionLines);
|
|
899
|
-
const visibleNestedSubCommands = cmd.subCommands ? Object.fromEntries(getVisibleSubcommandEntries(cmd.subCommands)) : void 0;
|
|
900
|
-
if (visibleNestedSubCommands && Object.keys(visibleNestedSubCommands).length > 0) {
|
|
901
|
-
const nestedLines = renderSubcommandsWithOptions(visibleNestedSubCommands, fullPath, baseIndent);
|
|
902
|
-
lines.push(...nestedLines);
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
return lines;
|
|
907
|
-
}
|
|
908
|
-
/**
|
|
909
|
-
* Generate help text for a command
|
|
910
|
-
*
|
|
911
|
-
* @param command - The command to generate help for
|
|
912
|
-
* @param options - Help generation options
|
|
913
|
-
* @returns Formatted help text
|
|
914
|
-
*/
|
|
915
|
-
function generateHelp(command, options) {
|
|
916
|
-
const sections = [];
|
|
917
|
-
const context = options.context;
|
|
918
|
-
const displayName = buildFullCommandName(command, context);
|
|
919
|
-
if (displayName) {
|
|
920
|
-
let header = styles.commandName(displayName);
|
|
921
|
-
if (context?.rootName && context.commandPath && context.commandPath.length > 0) if (context.rootVersion) header += ` ${styles.version(`(${context.rootName} v${context.rootVersion})`)}`;
|
|
922
|
-
else header += ` ${styles.version(`(${context.rootName})`)}`;
|
|
923
|
-
else if (context?.rootVersion) header += ` ${styles.version(`v${context.rootVersion}`)}`;
|
|
924
|
-
sections.push(header);
|
|
925
|
-
}
|
|
926
|
-
if (context?.aliasFor) sections.push(styles.dim(`Alias for ${styles.commandName(context.aliasFor)}`));
|
|
927
|
-
if (command.description) sections.push(command.description);
|
|
928
|
-
if (!context?.aliasFor && command.aliases && command.aliases.length > 0) sections.push(`${styles.sectionHeader("Aliases:")} ${command.aliases.map((a) => styles.command(a)).join(", ")}`);
|
|
929
|
-
sections.push(`${styles.sectionHeader("Usage:")} ${renderUsageLine(command, context)}`);
|
|
930
|
-
const optionsText = renderOptions(command, options.descriptions, context);
|
|
931
|
-
if (optionsText) sections.push(`${styles.sectionHeader("Options:")}\n${optionsText}`);
|
|
932
|
-
if (context?.globalExtracted?.fields.length) sections.push(`${styles.sectionHeader("Global Options:")}\n${renderGlobalOptions(context.globalExtracted)}`);
|
|
933
|
-
if (options.showSubcommands !== false && command.subCommands && getVisibleSubcommandEntries(command.subCommands).length > 0) {
|
|
934
|
-
const currentPath = context?.commandPath?.join(" ") ?? "";
|
|
935
|
-
const visibleSubCommands = Object.fromEntries(getVisibleSubcommandEntries(command.subCommands));
|
|
936
|
-
if (options.showSubcommandOptions) {
|
|
937
|
-
const subLines = renderSubcommandsWithOptions(visibleSubCommands, currentPath, 0);
|
|
938
|
-
sections.push(`${styles.sectionHeader("Commands:")}\n${subLines.join("\n")}`);
|
|
939
|
-
} else {
|
|
940
|
-
const subLines = [];
|
|
941
|
-
for (const [name, subCmd] of Object.entries(visibleSubCommands)) {
|
|
942
|
-
const cmd = require_schema_extractor.resolveSubCommandMeta(subCmd);
|
|
943
|
-
const desc = cmd?.description ?? "";
|
|
944
|
-
const fullName = currentPath ? `${currentPath} ${name}` : name;
|
|
945
|
-
const aliases = cmd?.aliases;
|
|
946
|
-
const displayName = aliases && aliases.length > 0 ? `${fullName}, ${aliases.join(", ")}` : fullName;
|
|
947
|
-
subLines.push(formatOption(styles.command(displayName), desc));
|
|
948
|
-
}
|
|
949
|
-
sections.push(`${styles.sectionHeader("Commands:")}\n${subLines.join("\n")}`);
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
if (command.examples && command.examples.length > 0) {
|
|
953
|
-
const exampleLines = renderExamplesForHelp(command.examples, context);
|
|
954
|
-
sections.push(`${styles.sectionHeader("Examples:")}\n${exampleLines}`);
|
|
955
|
-
}
|
|
956
|
-
if (command.notes) {
|
|
957
|
-
const indented = renderMarkdown(command.notes).split("\n").map((line) => line === "" ? "" : ` ${line}`).join("\n");
|
|
958
|
-
sections.push(`${styles.sectionHeader("Notes:")}\n${indented}`);
|
|
959
|
-
}
|
|
960
|
-
return `\n${sections.join("\n\n")}\n`;
|
|
961
|
-
}
|
|
962
|
-
/**
|
|
963
|
-
* Render examples for CLI help output
|
|
964
|
-
*/
|
|
965
|
-
function renderExamplesForHelp(examples, context) {
|
|
966
|
-
const lines = [];
|
|
967
|
-
const cmdPrefix = context?.rootName ? `${context.rootName} ` : "";
|
|
968
|
-
const cmdPath = context?.commandPath?.join(" ") ?? "";
|
|
969
|
-
const fullPrefix = cmdPath ? `${cmdPrefix}${cmdPath} ` : cmdPrefix;
|
|
970
|
-
for (const example of examples) {
|
|
971
|
-
lines.push(` ${styles.dim(example.desc)}`);
|
|
972
|
-
lines.push(` ${styles.dim("$")} ${fullPrefix}${example.cmd}`);
|
|
973
|
-
if (example.output) for (const line of example.output.split("\n")) lines.push(` ${line}`);
|
|
974
|
-
lines.push("");
|
|
975
|
-
}
|
|
976
|
-
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
977
|
-
return lines.join("\n");
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
//#endregion
|
|
981
|
-
//#region src/validator/validation-errors.ts
|
|
982
|
-
/**
|
|
983
|
-
* Error thrown when positional argument configuration is invalid
|
|
984
|
-
*/
|
|
985
|
-
var PositionalConfigError = class extends Error {
|
|
986
|
-
constructor(message) {
|
|
987
|
-
super(message);
|
|
988
|
-
this.name = "PositionalConfigError";
|
|
989
|
-
}
|
|
990
|
-
};
|
|
991
|
-
/**
|
|
992
|
-
* Error thrown when a reserved alias is used
|
|
993
|
-
*/
|
|
994
|
-
var ReservedAliasError = class extends Error {
|
|
995
|
-
constructor(message) {
|
|
996
|
-
super(message);
|
|
997
|
-
this.name = "ReservedAliasError";
|
|
998
|
-
}
|
|
999
|
-
};
|
|
1000
|
-
/**
|
|
1001
|
-
* Error thrown when duplicate field names are detected
|
|
1002
|
-
*/
|
|
1003
|
-
var DuplicateFieldError = class extends Error {
|
|
1004
|
-
constructor(message) {
|
|
1005
|
-
super(message);
|
|
1006
|
-
this.name = "DuplicateFieldError";
|
|
1007
|
-
}
|
|
1008
|
-
};
|
|
1009
|
-
/**
|
|
1010
|
-
* Error thrown when duplicate aliases are detected
|
|
1011
|
-
*/
|
|
1012
|
-
var DuplicateAliasError = class extends Error {
|
|
1013
|
-
constructor(message) {
|
|
1014
|
-
super(message);
|
|
1015
|
-
this.name = "DuplicateAliasError";
|
|
1016
|
-
}
|
|
1017
|
-
};
|
|
1018
|
-
/**
|
|
1019
|
-
* Error thrown when fields are case variants of each other (e.g. "my-option" and "myOption")
|
|
1020
|
-
*/
|
|
1021
|
-
var CaseVariantCollisionError = class extends Error {
|
|
1022
|
-
constructor(message) {
|
|
1023
|
-
super(message);
|
|
1024
|
-
this.name = "CaseVariantCollisionError";
|
|
1025
|
-
}
|
|
1026
|
-
};
|
|
1027
|
-
/**
|
|
1028
|
-
* Error thrown when a custom boolean negation name collides with another
|
|
1029
|
-
* field's name, cliName, alias, or another field's negation (including
|
|
1030
|
-
* derived camelCase variants).
|
|
1031
|
-
*/
|
|
1032
|
-
var DuplicateNegationError = class extends Error {
|
|
1033
|
-
constructor(message) {
|
|
1034
|
-
super(message);
|
|
1035
|
-
this.name = "DuplicateNegationError";
|
|
1036
|
-
}
|
|
1037
|
-
};
|
|
1038
|
-
|
|
1039
|
-
//#endregion
|
|
1040
|
-
//#region src/validator/command-validator.ts
|
|
1041
|
-
/**
|
|
1042
|
-
* Check for duplicate field names
|
|
1043
|
-
*/
|
|
1044
|
-
function checkDuplicateFields(extracted, commandPath) {
|
|
1045
|
-
const errors = [];
|
|
1046
|
-
const seenNames = /* @__PURE__ */ new Map();
|
|
1047
|
-
for (const field of extracted.fields) {
|
|
1048
|
-
if (seenNames.has(field.name)) errors.push({
|
|
1049
|
-
commandPath,
|
|
1050
|
-
type: "duplicate_field",
|
|
1051
|
-
message: `Duplicate field name "${field.name}" detected.`,
|
|
1052
|
-
field: field.name
|
|
1053
|
-
});
|
|
1054
|
-
seenNames.set(field.name, field.name);
|
|
1055
|
-
}
|
|
1056
|
-
return errors;
|
|
1057
|
-
}
|
|
1058
|
-
/**
|
|
1059
|
-
* Check for case-variant collisions (e.g. "my-option" and "myOption" defined simultaneously)
|
|
1060
|
-
*/
|
|
1061
|
-
function checkCaseVariantCollisions(extracted, commandPath) {
|
|
1062
|
-
const errors = [];
|
|
1063
|
-
const canonicalMap = /* @__PURE__ */ new Map();
|
|
1064
|
-
for (const field of extracted.fields) {
|
|
1065
|
-
const camel = require_schema_extractor.toCamelCase(field.name);
|
|
1066
|
-
const existing = canonicalMap.get(camel);
|
|
1067
|
-
if (existing && existing !== field.name) errors.push({
|
|
1068
|
-
commandPath,
|
|
1069
|
-
type: "case_variant_collision",
|
|
1070
|
-
message: `Fields "${existing}" and "${field.name}" are case variants of each other and would collide.`,
|
|
1071
|
-
field: field.name
|
|
1072
|
-
});
|
|
1073
|
-
canonicalMap.set(camel, field.name);
|
|
1074
|
-
}
|
|
1075
|
-
return errors;
|
|
1076
|
-
}
|
|
1077
|
-
/**
|
|
1078
|
-
* Check for duplicate aliases and alias-field name conflicts
|
|
1079
|
-
*/
|
|
1080
|
-
function checkDuplicateAliases(extracted, commandPath) {
|
|
1081
|
-
const errors = [];
|
|
1082
|
-
const seenAliases = /* @__PURE__ */ new Map();
|
|
1083
|
-
const fieldNames = new Set(extracted.fields.map((f) => f.name));
|
|
1084
|
-
const cliNames = new Set(extracted.fields.map((f) => f.cliName));
|
|
1085
|
-
const registerAlias = (alias, fieldName, isDerived) => {
|
|
1086
|
-
if (fieldNames.has(alias) || cliNames.has(alias)) errors.push({
|
|
1087
|
-
commandPath,
|
|
1088
|
-
type: "duplicate_alias",
|
|
1089
|
-
message: `Alias "${alias}" for field "${fieldName}" conflicts with existing field name or CLI name "${alias}".`,
|
|
1090
|
-
field: fieldName
|
|
1091
|
-
});
|
|
1092
|
-
const existingField = seenAliases.get(alias);
|
|
1093
|
-
if (existingField && existingField !== fieldName) {
|
|
1094
|
-
const qualifier = isDerived ? " (derived camelCase variant)" : "";
|
|
1095
|
-
errors.push({
|
|
1096
|
-
commandPath,
|
|
1097
|
-
type: "duplicate_alias",
|
|
1098
|
-
message: `Duplicate alias "${alias}"${qualifier} detected. Both "${existingField}" and "${fieldName}" use the same alias.`,
|
|
1099
|
-
field: fieldName
|
|
1100
|
-
});
|
|
1101
|
-
}
|
|
1102
|
-
seenAliases.set(alias, fieldName);
|
|
1103
|
-
};
|
|
1104
|
-
for (const field of extracted.fields) {
|
|
1105
|
-
const allAliases = require_schema_extractor.getAllAliases(field);
|
|
1106
|
-
if (allAliases.length === 0) continue;
|
|
1107
|
-
for (const alias of allAliases) {
|
|
1108
|
-
registerAlias(alias, field.name, false);
|
|
1109
|
-
if (alias.length > 1 && alias.includes("-")) {
|
|
1110
|
-
const camelVariant = require_schema_extractor.toCamelCase(alias);
|
|
1111
|
-
if (camelVariant !== alias && !fieldNames.has(camelVariant)) registerAlias(camelVariant, field.name, true);
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
return errors;
|
|
1116
|
-
}
|
|
1117
|
-
/**
|
|
1118
|
-
* Check for collisions involving custom boolean `negation` names
|
|
1119
|
-
*/
|
|
1120
|
-
function checkDuplicateNegations(extracted, commandPath) {
|
|
1121
|
-
const errors = [];
|
|
1122
|
-
const claimed = /* @__PURE__ */ new Map();
|
|
1123
|
-
const claim = (name, fieldName, kind) => {
|
|
1124
|
-
if (!claimed.has(name)) claimed.set(name, {
|
|
1125
|
-
field: fieldName,
|
|
1126
|
-
kind
|
|
1127
|
-
});
|
|
1128
|
-
};
|
|
1129
|
-
for (const field of extracted.fields) {
|
|
1130
|
-
claim(field.name, field.name, "field name");
|
|
1131
|
-
if (field.name.includes("-")) {
|
|
1132
|
-
const camelName = require_schema_extractor.toCamelCase(field.name);
|
|
1133
|
-
if (camelName !== field.name) claim(camelName, field.name, "field name");
|
|
1134
|
-
}
|
|
1135
|
-
if (field.cliName !== field.name) claim(field.cliName, field.name, "CLI name");
|
|
1136
|
-
if (field.cliName.includes("-")) {
|
|
1137
|
-
const camelCli = require_schema_extractor.toCamelCase(field.cliName);
|
|
1138
|
-
if (camelCli !== field.cliName) claim(camelCli, field.name, "CLI name");
|
|
1139
|
-
}
|
|
1140
|
-
for (const alias of require_schema_extractor.getAllAliases(field)) {
|
|
1141
|
-
claim(alias, field.name, "alias");
|
|
1142
|
-
if (alias.length > 1 && alias.includes("-")) {
|
|
1143
|
-
const camelVariant = require_schema_extractor.toCamelCase(alias);
|
|
1144
|
-
if (camelVariant !== alias) claim(camelVariant, field.name, "alias");
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
if (field.type === "boolean" && field.negation !== false && typeof field.negation !== "string") {
|
|
1148
|
-
const defaultKebab = `no-${field.cliName}`;
|
|
1149
|
-
claim(defaultKebab, field.name, "default negation");
|
|
1150
|
-
const camelBase = require_schema_extractor.toCamelCase(field.cliName);
|
|
1151
|
-
const defaultCamel = `no${camelBase[0]?.toUpperCase() ?? ""}${camelBase.slice(1)}`;
|
|
1152
|
-
if (defaultCamel !== defaultKebab) claim(defaultCamel, field.name, "default negation");
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
const seenNegations = /* @__PURE__ */ new Map();
|
|
1156
|
-
const register = (name, fieldName, isDerived) => {
|
|
1157
|
-
const claim = claimed.get(name);
|
|
1158
|
-
if (claim) {
|
|
1159
|
-
const qualifier = isDerived ? " (derived camelCase variant)" : "";
|
|
1160
|
-
const conflict = claim.field === fieldName ? `the same field's own ${claim.kind} "${name}"` : `${claim.kind} "${name}" of field "${claim.field}"`;
|
|
1161
|
-
errors.push({
|
|
1162
|
-
commandPath,
|
|
1163
|
-
type: "duplicate_negation",
|
|
1164
|
-
message: `Negation "${name}"${qualifier} for field "${fieldName}" conflicts with ${conflict}.`,
|
|
1165
|
-
field: fieldName
|
|
1166
|
-
});
|
|
1167
|
-
}
|
|
1168
|
-
const existing = seenNegations.get(name);
|
|
1169
|
-
if (existing && existing !== fieldName) {
|
|
1170
|
-
const qualifier = isDerived ? " (derived camelCase variant)" : "";
|
|
1171
|
-
errors.push({
|
|
1172
|
-
commandPath,
|
|
1173
|
-
type: "duplicate_negation",
|
|
1174
|
-
message: `Duplicate negation "${name}"${qualifier} detected. Both "${existing}" and "${fieldName}" use the same negation name.`,
|
|
1175
|
-
field: fieldName
|
|
1176
|
-
});
|
|
1177
|
-
}
|
|
1178
|
-
seenNegations.set(name, fieldName);
|
|
1179
|
-
};
|
|
1180
|
-
for (const field of extracted.fields) {
|
|
1181
|
-
if (typeof field.negation !== "string") continue;
|
|
1182
|
-
register(field.negation, field.name, false);
|
|
1183
|
-
if (field.negation.includes("-")) {
|
|
1184
|
-
const camelVariant = require_schema_extractor.toCamelCase(field.negation);
|
|
1185
|
-
if (camelVariant !== field.negation) register(camelVariant, field.name, true);
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
return errors;
|
|
1189
|
-
}
|
|
1190
|
-
/**
|
|
1191
|
-
* Check positional argument configuration
|
|
1192
|
-
*/
|
|
1193
|
-
function checkPositionalConfig(extracted, commandPath) {
|
|
1194
|
-
const errors = [];
|
|
1195
|
-
const positionalFields = extracted.fields.filter((f) => f.positional);
|
|
1196
|
-
let foundArrayPositional = null;
|
|
1197
|
-
let foundOptionalPositional = null;
|
|
1198
|
-
for (const field of positionalFields) {
|
|
1199
|
-
if (foundArrayPositional !== null) errors.push({
|
|
1200
|
-
commandPath,
|
|
1201
|
-
type: "positional_config",
|
|
1202
|
-
message: `Positional argument "${field.name}" cannot follow array positional argument "${foundArrayPositional}".`,
|
|
1203
|
-
field: field.name
|
|
1204
|
-
});
|
|
1205
|
-
if (field.type === "array" && foundOptionalPositional !== null) errors.push({
|
|
1206
|
-
commandPath,
|
|
1207
|
-
type: "positional_config",
|
|
1208
|
-
message: `Array positional "${field.name}" cannot be used with optional positional "${foundOptionalPositional}" (ambiguous parsing).`,
|
|
1209
|
-
field: field.name
|
|
1210
|
-
});
|
|
1211
|
-
if (foundOptionalPositional !== null && field.required) errors.push({
|
|
1212
|
-
commandPath,
|
|
1213
|
-
type: "positional_config",
|
|
1214
|
-
message: `Required positional "${field.name}" cannot follow optional positional "${foundOptionalPositional}".`,
|
|
1215
|
-
field: field.name
|
|
1216
|
-
});
|
|
1217
|
-
if (field.type === "array") foundArrayPositional = field.name;
|
|
1218
|
-
if (!field.required) foundOptionalPositional = field.name;
|
|
1219
|
-
}
|
|
1220
|
-
return errors;
|
|
1221
|
-
}
|
|
1222
|
-
/**
|
|
1223
|
-
* Check for reserved aliases used without override flag
|
|
1224
|
-
*/
|
|
1225
|
-
function checkReservedAliases(extracted, commandPath) {
|
|
1226
|
-
const errors = [];
|
|
1227
|
-
for (const field of extracted.fields) {
|
|
1228
|
-
if (field.overrideBuiltinAlias === true) continue;
|
|
1229
|
-
for (const alias of require_schema_extractor.getAllAliases(field)) if (alias === "h" || alias === "H") errors.push({
|
|
1230
|
-
commandPath,
|
|
1231
|
-
type: "reserved_alias",
|
|
1232
|
-
message: `Alias "${alias}" is reserved for --${alias === "h" ? "help" : "help-all"}.`,
|
|
1233
|
-
field: field.name
|
|
1234
|
-
});
|
|
1235
|
-
}
|
|
1236
|
-
return errors;
|
|
1237
|
-
}
|
|
1238
|
-
/**
|
|
1239
|
-
* Validate that no duplicate field names exist
|
|
1240
|
-
*
|
|
1241
|
-
* @param extracted - Extracted fields from schema
|
|
1242
|
-
* @throws {DuplicateFieldError} If duplicate field names are found
|
|
1243
|
-
*/
|
|
1244
|
-
function validateDuplicateFields(extracted) {
|
|
1245
|
-
const errors = checkDuplicateFields(extracted, []);
|
|
1246
|
-
if (errors.length > 0) throw new DuplicateFieldError(`Duplicate field name "${errors[0]?.field ?? "unknown"}" detected. Each field must have a unique name.`);
|
|
1247
|
-
}
|
|
1248
|
-
/**
|
|
1249
|
-
* Validate that no duplicate aliases exist
|
|
1250
|
-
*
|
|
1251
|
-
* Also checks for conflicts between aliases and field names
|
|
1252
|
-
*
|
|
1253
|
-
* @param extracted - Extracted fields from schema
|
|
1254
|
-
* @throws {DuplicateAliasError} If duplicate aliases are found or alias conflicts with field name
|
|
1255
|
-
*/
|
|
1256
|
-
function validateDuplicateAliases(extracted) {
|
|
1257
|
-
const errors = checkDuplicateAliases(extracted, []);
|
|
1258
|
-
if (errors.length > 0) {
|
|
1259
|
-
const err = errors[0];
|
|
1260
|
-
throw new DuplicateAliasError(err.message);
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
/**
|
|
1264
|
-
* Validate positional argument configuration
|
|
1265
|
-
*
|
|
1266
|
-
* Rules:
|
|
1267
|
-
* - Array positional arguments must be the last positional
|
|
1268
|
-
* - No positional arguments can follow an array positional
|
|
1269
|
-
* - Required positional arguments cannot follow optional positional arguments
|
|
1270
|
-
* - Array positional and optional positional cannot be used together (ambiguous parsing)
|
|
1271
|
-
*
|
|
1272
|
-
* @param extracted - Extracted fields from schema
|
|
1273
|
-
* @throws {PositionalConfigError} If configuration is invalid
|
|
1274
|
-
*/
|
|
1275
|
-
function validatePositionalConfig(extracted) {
|
|
1276
|
-
const errors = checkPositionalConfig(extracted, []);
|
|
1277
|
-
if (errors.length > 0) {
|
|
1278
|
-
const err = errors[0];
|
|
1279
|
-
throw new PositionalConfigError(err.message);
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
/**
|
|
1283
|
-
* Validate that no reserved aliases are used without explicit override
|
|
1284
|
-
*
|
|
1285
|
-
* Reserved aliases:
|
|
1286
|
-
* - 'h' is reserved for --help
|
|
1287
|
-
* - 'H' is reserved for --help-all
|
|
1288
|
-
*
|
|
1289
|
-
* Users can override these by setting overrideBuiltinAlias: true
|
|
1290
|
-
*
|
|
1291
|
-
* @param extracted - Extracted fields from schema
|
|
1292
|
-
* @param _hasSubCommands - Whether the command has subcommands (reserved for future use)
|
|
1293
|
-
* @throws {ReservedAliasError} If a reserved alias is used without override flag
|
|
1294
|
-
*/
|
|
1295
|
-
function validateReservedAliases(extracted, _hasSubCommands) {
|
|
1296
|
-
const errors = checkReservedAliases(extracted, []);
|
|
1297
|
-
if (errors.length > 0) {
|
|
1298
|
-
const field = errors[0].field ?? "unknown";
|
|
1299
|
-
const found = extracted.fields.find((f) => f.name === field);
|
|
1300
|
-
const alias = (found ? require_schema_extractor.getAllAliases(found) : []).find((a) => a === "h" || a === "H") ?? "h";
|
|
1301
|
-
throw new ReservedAliasError(`Alias "${alias}" is reserved for --${alias === "h" ? "help" : "help-all"}. To override this, set { overrideBuiltinAlias: true } for "${field}" and keep the alias where it is currently defined (in alias or hiddenAlias).`);
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
/**
|
|
1305
|
-
* Validate that custom boolean negation names do not collide with anything
|
|
1306
|
-
*
|
|
1307
|
-
* @param extracted - Extracted fields from schema
|
|
1308
|
-
* @throws {DuplicateNegationError} If a colliding negation is found
|
|
1309
|
-
*/
|
|
1310
|
-
function validateDuplicateNegations(extracted) {
|
|
1311
|
-
const errors = checkDuplicateNegations(extracted, []);
|
|
1312
|
-
if (errors.length > 0) {
|
|
1313
|
-
const err = errors[0];
|
|
1314
|
-
throw new DuplicateNegationError(err.message);
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
/**
|
|
1318
|
-
* Validate that no case-variant collisions exist
|
|
1319
|
-
*
|
|
1320
|
-
* @param extracted - Extracted fields from schema
|
|
1321
|
-
* @throws {CaseVariantCollisionError} If case-variant collisions are found
|
|
1322
|
-
*/
|
|
1323
|
-
function validateCaseVariantCollisions(extracted) {
|
|
1324
|
-
const errors = checkCaseVariantCollisions(extracted, []);
|
|
1325
|
-
if (errors.length > 0) {
|
|
1326
|
-
const err = errors[0];
|
|
1327
|
-
throw new CaseVariantCollisionError(err.message);
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
/**
|
|
1331
|
-
* Validate that no case-variant collisions exist between two schemas
|
|
1332
|
-
* (e.g., global args and command args).
|
|
1333
|
-
*
|
|
1334
|
-
* @param extractedA - Extracted fields from first schema (e.g., global args)
|
|
1335
|
-
* @param extractedB - Extracted fields from second schema (e.g., command args)
|
|
1336
|
-
* @throws {CaseVariantCollisionError} If cross-schema case-variant collisions are found
|
|
1337
|
-
*/
|
|
1338
|
-
function validateCrossSchemaCollisions(extractedA, extractedB) {
|
|
1339
|
-
const canonicalMap = /* @__PURE__ */ new Map();
|
|
1340
|
-
for (const field of extractedA.fields) canonicalMap.set(require_schema_extractor.toCamelCase(field.name), field.name);
|
|
1341
|
-
for (const field of extractedB.fields) {
|
|
1342
|
-
const camel = require_schema_extractor.toCamelCase(field.name);
|
|
1343
|
-
const existing = canonicalMap.get(camel);
|
|
1344
|
-
if (existing && existing !== field.name) throw new CaseVariantCollisionError(`Global field "${existing}" and command field "${field.name}" are case variants of each other and would collide.`);
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
/**
|
|
1348
|
-
* Collect validation errors for a single command's schema (non-throwing)
|
|
1349
|
-
*/
|
|
1350
|
-
function collectSchemaErrors(extracted, _hasSubCommands, commandPath) {
|
|
1351
|
-
return [
|
|
1352
|
-
...checkDuplicateFields(extracted, commandPath),
|
|
1353
|
-
...checkCaseVariantCollisions(extracted, commandPath),
|
|
1354
|
-
...checkDuplicateAliases(extracted, commandPath),
|
|
1355
|
-
...checkDuplicateNegations(extracted, commandPath),
|
|
1356
|
-
...checkPositionalConfig(extracted, commandPath),
|
|
1357
|
-
...checkReservedAliases(extracted, commandPath)
|
|
1358
|
-
];
|
|
1359
|
-
}
|
|
1360
|
-
/**
|
|
1361
|
-
* Check for alias conflicts within subcommands
|
|
1362
|
-
* - Aliases must not conflict with subcommand names
|
|
1363
|
-
* - Aliases must not conflict with other aliases
|
|
1364
|
-
*/
|
|
1365
|
-
function checkSubCommandAliasConflicts(command, commandPath) {
|
|
1366
|
-
const errors = [];
|
|
1367
|
-
if (!command.subCommands) return errors;
|
|
1368
|
-
const nameToOwner = /* @__PURE__ */ new Map();
|
|
1369
|
-
for (const [name] of Object.entries(command.subCommands)) nameToOwner.set(name, name);
|
|
1370
|
-
for (const [name, subCmdValue] of Object.entries(command.subCommands)) {
|
|
1371
|
-
const resolved = require_schema_extractor.isLazyCommand(subCmdValue) ? subCmdValue.meta : typeof subCmdValue !== "function" ? subCmdValue : null;
|
|
1372
|
-
if (!resolved?.aliases) continue;
|
|
1373
|
-
const subCommandPath = [...commandPath, name];
|
|
1374
|
-
for (const alias of resolved.aliases) {
|
|
1375
|
-
if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(alias)) {
|
|
1376
|
-
errors.push({
|
|
1377
|
-
commandPath: subCommandPath,
|
|
1378
|
-
type: "invalid_alias",
|
|
1379
|
-
message: `Alias "${alias}" is invalid. Aliases must start with an alphanumeric character and contain only alphanumeric characters, hyphens, or underscores.`,
|
|
1380
|
-
field: name
|
|
1381
|
-
});
|
|
1382
|
-
continue;
|
|
1383
|
-
}
|
|
1384
|
-
if (alias === name) {
|
|
1385
|
-
errors.push({
|
|
1386
|
-
commandPath: subCommandPath,
|
|
1387
|
-
type: "duplicate_alias",
|
|
1388
|
-
message: `Alias "${alias}" conflicts with its own name.`,
|
|
1389
|
-
field: name
|
|
1390
|
-
});
|
|
1391
|
-
continue;
|
|
1392
|
-
}
|
|
1393
|
-
const existing = nameToOwner.get(alias);
|
|
1394
|
-
if (existing) if (existing === name) errors.push({
|
|
1395
|
-
commandPath: subCommandPath,
|
|
1396
|
-
type: "duplicate_alias",
|
|
1397
|
-
message: `Alias "${alias}" is duplicated within the alias list.`,
|
|
1398
|
-
field: name
|
|
1399
|
-
});
|
|
1400
|
-
else errors.push({
|
|
1401
|
-
commandPath: subCommandPath,
|
|
1402
|
-
type: "duplicate_alias",
|
|
1403
|
-
message: `Alias "${alias}" conflicts with existing subcommand or alias "${existing}".`,
|
|
1404
|
-
field: name
|
|
1405
|
-
});
|
|
1406
|
-
else nameToOwner.set(alias, name);
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
|
-
return errors;
|
|
1410
|
-
}
|
|
1411
|
-
/**
|
|
1412
|
-
* Validate a command and all its subcommands recursively
|
|
1413
|
-
*
|
|
1414
|
-
* This function collects all validation errors without throwing,
|
|
1415
|
-
* making it suitable for test assertions.
|
|
1416
|
-
*
|
|
1417
|
-
* @param command - The command to validate
|
|
1418
|
-
* @param options - Validation options
|
|
1419
|
-
* @returns Validation result with all errors collected
|
|
1420
|
-
*
|
|
1421
|
-
* @example
|
|
1422
|
-
* ```ts
|
|
1423
|
-
* const result = await validateCommand(myCommand);
|
|
1424
|
-
* if (!result.valid) {
|
|
1425
|
-
* console.error(result.errors);
|
|
1426
|
-
* }
|
|
1427
|
-
* ```
|
|
1428
|
-
*/
|
|
1429
|
-
async function validateCommand(command, options = {}) {
|
|
1430
|
-
const commandPath = options.commandPath ?? [command.name];
|
|
1431
|
-
const errors = [];
|
|
1432
|
-
const hasSubCommands = command.subCommands ? Object.keys(command.subCommands).length > 0 : false;
|
|
1433
|
-
if (command.args) {
|
|
1434
|
-
const extracted = require_schema_extractor.extractFields(command.args);
|
|
1435
|
-
errors.push(...collectSchemaErrors(extracted, hasSubCommands, commandPath));
|
|
1436
|
-
}
|
|
1437
|
-
errors.push(...checkSubCommandAliasConflicts(command, commandPath));
|
|
1438
|
-
if (command.subCommands) for (const [name, subCmd] of Object.entries(command.subCommands)) {
|
|
1439
|
-
const subResult = await validateCommand(await require_schema_extractor.resolveLazyCommand(subCmd), { commandPath: [...commandPath, name] });
|
|
1440
|
-
if (!subResult.valid) errors.push(...subResult.errors);
|
|
1441
|
-
}
|
|
1442
|
-
if (errors.length === 0) return { valid: true };
|
|
1443
|
-
return {
|
|
1444
|
-
valid: false,
|
|
1445
|
-
errors
|
|
1446
|
-
};
|
|
1447
|
-
}
|
|
1448
|
-
/**
|
|
1449
|
-
* Format command validation errors for display
|
|
1450
|
-
*
|
|
1451
|
-
* @param errors - Array of validation errors
|
|
1452
|
-
* @returns Formatted error message
|
|
1453
|
-
*/
|
|
1454
|
-
function formatCommandValidationErrors(errors) {
|
|
1455
|
-
if (errors.length === 0) return "";
|
|
1456
|
-
const lines = ["Command definition errors:"];
|
|
1457
|
-
for (const error of errors) {
|
|
1458
|
-
const path = error.commandPath.join(" > ");
|
|
1459
|
-
lines.push(` - [${path}] ${error.message}`);
|
|
1460
|
-
}
|
|
1461
|
-
return lines.join("\n");
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
//#endregion
|
|
1465
|
-
//#region src/parser/argv-parser.ts
|
|
1466
|
-
/**
|
|
1467
|
-
* Parse argv into a flat record
|
|
1468
|
-
*
|
|
1469
|
-
* Supports:
|
|
1470
|
-
* - Long options: --flag, --flag=value, --flag value
|
|
1471
|
-
* - Short options: -f, -f=value, -f value
|
|
1472
|
-
* - Combined short options: -abc (treated as -a -b -c if all are boolean)
|
|
1473
|
-
* - Positional arguments
|
|
1474
|
-
* - -- to stop parsing options
|
|
1475
|
-
* - Boolean negation: --no-flag, --noFlag (requires `booleanFlags`)
|
|
1476
|
-
*
|
|
1477
|
-
* **Note:** When using negation detection (`--noFlag` / `--no-flag`),
|
|
1478
|
-
* supply `definedNames` so that options whose names happen to start with
|
|
1479
|
-
* "no" (e.g. `noDryRun`) are not mistaken for negation of another flag.
|
|
1480
|
-
* Without `definedNames`, all `--noX` forms matching a boolean flag will
|
|
1481
|
-
* be treated as negation.
|
|
1482
|
-
*
|
|
1483
|
-
* @param argv - Command line arguments
|
|
1484
|
-
* @param options - Parser options
|
|
1485
|
-
* @returns Parsed arguments
|
|
1486
|
-
*/
|
|
1487
|
-
function parseArgv(argv, options = {}) {
|
|
1488
|
-
const { aliasMap = /* @__PURE__ */ new Map(), booleanFlags = /* @__PURE__ */ new Set(), arrayFlags = /* @__PURE__ */ new Set(), definedNames = /* @__PURE__ */ new Set(), negationMap = /* @__PURE__ */ new Map(), customNegatedFields = /* @__PURE__ */ new Set() } = options;
|
|
1489
|
-
const result = {
|
|
1490
|
-
options: {},
|
|
1491
|
-
positionals: [],
|
|
1492
|
-
rest: []
|
|
1493
|
-
};
|
|
1494
|
-
let i = 0;
|
|
1495
|
-
let stopParsing = false;
|
|
1496
|
-
const setOption = (name, value) => {
|
|
1497
|
-
const resolvedName = aliasMap.get(name) ?? name;
|
|
1498
|
-
if (arrayFlags.has(resolvedName)) {
|
|
1499
|
-
const existing = result.options[resolvedName];
|
|
1500
|
-
if (Array.isArray(existing)) existing.push(value);
|
|
1501
|
-
else if (existing !== void 0) result.options[resolvedName] = [existing, value];
|
|
1502
|
-
else result.options[resolvedName] = [value];
|
|
1503
|
-
} else result.options[resolvedName] = value;
|
|
1504
|
-
};
|
|
1505
|
-
while (i < argv.length) {
|
|
1506
|
-
const arg = argv[i];
|
|
1507
|
-
if (stopParsing) {
|
|
1508
|
-
result.rest.push(arg);
|
|
1509
|
-
i++;
|
|
1510
|
-
continue;
|
|
1511
|
-
}
|
|
1512
|
-
if (arg === "--") {
|
|
1513
|
-
stopParsing = true;
|
|
1514
|
-
i++;
|
|
1515
|
-
continue;
|
|
1516
|
-
}
|
|
1517
|
-
if (arg.startsWith("--")) {
|
|
1518
|
-
const withoutDashes = arg.slice(2);
|
|
1519
|
-
if (!withoutDashes.includes("=")) {
|
|
1520
|
-
const negatedField = negationMap.get(withoutDashes);
|
|
1521
|
-
if (negatedField && booleanFlags.has(negatedField)) {
|
|
1522
|
-
setOption(negatedField, false);
|
|
1523
|
-
i++;
|
|
1524
|
-
continue;
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1527
|
-
if (withoutDashes.startsWith("no-")) {
|
|
1528
|
-
const flagName = withoutDashes.slice(3);
|
|
1529
|
-
if (flagName === flagName.toLowerCase()) {
|
|
1530
|
-
const resolvedName = aliasMap.get(flagName) ?? flagName;
|
|
1531
|
-
if (booleanFlags.has(resolvedName) && !customNegatedFields.has(resolvedName)) {
|
|
1532
|
-
const asIsResolved = aliasMap.get(withoutDashes) ?? withoutDashes;
|
|
1533
|
-
if (!definedNames.has(asIsResolved)) {
|
|
1534
|
-
setOption(flagName, false);
|
|
1535
|
-
i++;
|
|
1536
|
-
continue;
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
if (withoutDashes.length > 2 && withoutDashes.startsWith("no") && /[A-Z]/.test(withoutDashes[2])) {
|
|
1542
|
-
const camelFlagName = withoutDashes[2].toLowerCase() + withoutDashes.slice(3);
|
|
1543
|
-
const resolvedName = aliasMap.get(camelFlagName) ?? camelFlagName;
|
|
1544
|
-
if (booleanFlags.has(resolvedName) && !customNegatedFields.has(resolvedName)) {
|
|
1545
|
-
const asIsResolved = aliasMap.get(withoutDashes) ?? withoutDashes;
|
|
1546
|
-
if (!definedNames.has(asIsResolved)) {
|
|
1547
|
-
setOption(camelFlagName, false);
|
|
1548
|
-
i++;
|
|
1549
|
-
continue;
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
}
|
|
1553
|
-
const eqIndex = withoutDashes.indexOf("=");
|
|
1554
|
-
if (eqIndex !== -1) {
|
|
1555
|
-
setOption(withoutDashes.slice(0, eqIndex), withoutDashes.slice(eqIndex + 1));
|
|
1556
|
-
i++;
|
|
1557
|
-
} else {
|
|
1558
|
-
const name = withoutDashes;
|
|
1559
|
-
const resolvedName = aliasMap.get(name) ?? name;
|
|
1560
|
-
if (booleanFlags.has(resolvedName)) {
|
|
1561
|
-
setOption(name, true);
|
|
1562
|
-
i++;
|
|
1563
|
-
} else {
|
|
1564
|
-
const nextArg = argv[i + 1];
|
|
1565
|
-
if (nextArg !== void 0 && !nextArg.startsWith("-")) {
|
|
1566
|
-
setOption(name, nextArg);
|
|
1567
|
-
i += 2;
|
|
1568
|
-
} else {
|
|
1569
|
-
setOption(name, true);
|
|
1570
|
-
i++;
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
}
|
|
1574
|
-
continue;
|
|
1575
|
-
}
|
|
1576
|
-
if (arg.startsWith("-") && arg.length > 1 && !arg.startsWith("--")) {
|
|
1577
|
-
const withoutDash = arg.slice(1);
|
|
1578
|
-
const eqIndex = withoutDash.indexOf("=");
|
|
1579
|
-
if (eqIndex !== -1) {
|
|
1580
|
-
setOption(withoutDash.slice(0, eqIndex), withoutDash.slice(eqIndex + 1));
|
|
1581
|
-
i++;
|
|
1582
|
-
} else if (withoutDash.length === 1) {
|
|
1583
|
-
const name = withoutDash;
|
|
1584
|
-
const resolvedName = aliasMap.get(name) ?? name;
|
|
1585
|
-
if (booleanFlags.has(resolvedName)) {
|
|
1586
|
-
setOption(name, true);
|
|
1587
|
-
i++;
|
|
1588
|
-
} else {
|
|
1589
|
-
const nextArg = argv[i + 1];
|
|
1590
|
-
if (nextArg !== void 0 && !nextArg.startsWith("-")) {
|
|
1591
|
-
setOption(name, nextArg);
|
|
1592
|
-
i += 2;
|
|
1593
|
-
} else {
|
|
1594
|
-
setOption(name, true);
|
|
1595
|
-
i++;
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
} else {
|
|
1599
|
-
for (const char of withoutDash) setOption(char, true);
|
|
1600
|
-
i++;
|
|
1601
|
-
}
|
|
1602
|
-
continue;
|
|
1603
|
-
}
|
|
1604
|
-
result.positionals.push(arg);
|
|
1605
|
-
i++;
|
|
1606
|
-
}
|
|
1607
|
-
return result;
|
|
1608
|
-
}
|
|
1609
|
-
/**
|
|
1610
|
-
* Build parser options from extracted fields
|
|
1611
|
-
*/
|
|
1612
|
-
function buildParserOptions(extracted) {
|
|
1613
|
-
const aliasMap = /* @__PURE__ */ new Map();
|
|
1614
|
-
const booleanFlags = /* @__PURE__ */ new Set();
|
|
1615
|
-
const arrayFlags = /* @__PURE__ */ new Set();
|
|
1616
|
-
const definedNames = /* @__PURE__ */ new Set();
|
|
1617
|
-
const negationMap = /* @__PURE__ */ new Map();
|
|
1618
|
-
const customNegatedFields = /* @__PURE__ */ new Set();
|
|
1619
|
-
for (const field of extracted.fields) definedNames.add(field.name);
|
|
1620
|
-
for (const field of extracted.fields) {
|
|
1621
|
-
if (field.cliName !== field.name) aliasMap.set(field.cliName, field.name);
|
|
1622
|
-
for (const alias of require_schema_extractor.getAllAliases(field)) {
|
|
1623
|
-
aliasMap.set(alias, field.name);
|
|
1624
|
-
if (alias.length > 1 && alias.includes("-")) {
|
|
1625
|
-
const camelAlias = require_schema_extractor.toCamelCase(alias);
|
|
1626
|
-
if (camelAlias !== alias && !definedNames.has(camelAlias) && !aliasMap.has(camelAlias)) aliasMap.set(camelAlias, field.name);
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
const camelVariant = require_schema_extractor.toCamelCase(field.name);
|
|
1630
|
-
if (camelVariant !== field.name && !definedNames.has(camelVariant) && !aliasMap.has(camelVariant)) aliasMap.set(camelVariant, field.name);
|
|
1631
|
-
if (field.type === "boolean") booleanFlags.add(field.name);
|
|
1632
|
-
if (field.type === "array") arrayFlags.add(field.name);
|
|
1633
|
-
if (field.type === "boolean" && (typeof field.negation === "string" || field.negation === false)) {
|
|
1634
|
-
customNegatedFields.add(field.name);
|
|
1635
|
-
if (typeof field.negation === "string") {
|
|
1636
|
-
negationMap.set(field.negation, field.name);
|
|
1637
|
-
if (field.negation.includes("-")) {
|
|
1638
|
-
const camelNegation = require_schema_extractor.toCamelCase(field.negation);
|
|
1639
|
-
if (camelNegation !== field.negation) negationMap.set(camelNegation, field.name);
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
return {
|
|
1645
|
-
aliasMap,
|
|
1646
|
-
booleanFlags,
|
|
1647
|
-
arrayFlags,
|
|
1648
|
-
definedNames,
|
|
1649
|
-
negationMap,
|
|
1650
|
-
customNegatedFields
|
|
1651
|
-
};
|
|
1652
|
-
}
|
|
1653
|
-
/**
|
|
1654
|
-
* Merge parsed argv with positional fields to create a flat record
|
|
1655
|
-
*/
|
|
1656
|
-
function mergeWithPositionals(parsed, extracted) {
|
|
1657
|
-
const result = { ...parsed.options };
|
|
1658
|
-
const positionalFields = extracted.fields.filter((f) => f.positional);
|
|
1659
|
-
const allPositionals = parsed.rest.length > 0 ? [...parsed.positionals, ...parsed.rest] : parsed.positionals;
|
|
1660
|
-
let positionalIndex = 0;
|
|
1661
|
-
for (const field of positionalFields) {
|
|
1662
|
-
if (positionalIndex >= allPositionals.length) break;
|
|
1663
|
-
if (field.type === "array") {
|
|
1664
|
-
result[field.name] = allPositionals.slice(positionalIndex);
|
|
1665
|
-
break;
|
|
1666
|
-
} else {
|
|
1667
|
-
result[field.name] = allPositionals[positionalIndex];
|
|
1668
|
-
positionalIndex++;
|
|
1669
|
-
}
|
|
1670
|
-
}
|
|
1671
|
-
return result;
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
//#endregion
|
|
1675
|
-
//#region src/parser/subcommand-scanner.ts
|
|
1676
|
-
/**
|
|
1677
|
-
* Build lookup tables from extracted global schema fields.
|
|
1678
|
-
* Shared by scanForSubcommand, separateGlobalArgs, and findFirstPositional.
|
|
1679
|
-
*/
|
|
1680
|
-
function buildGlobalFlagLookup(globalExtracted) {
|
|
1681
|
-
const { aliasMap = /* @__PURE__ */ new Map(), booleanFlags = /* @__PURE__ */ new Set(), negationMap = /* @__PURE__ */ new Map(), customNegatedFields = /* @__PURE__ */ new Set() } = buildParserOptions(globalExtracted);
|
|
1682
|
-
const shortAliases = /* @__PURE__ */ new Set();
|
|
1683
|
-
for (const field of globalExtracted.fields) for (const alias of require_schema_extractor.getAllAliases(field)) if (alias.length === 1) shortAliases.add(alias);
|
|
1684
|
-
return {
|
|
1685
|
-
aliasMap,
|
|
1686
|
-
booleanFlags,
|
|
1687
|
-
flagNames: new Set(globalExtracted.fields.map((f) => f.name)),
|
|
1688
|
-
cliNames: new Set(globalExtracted.fields.map((f) => f.cliName)),
|
|
1689
|
-
aliases: shortAliases,
|
|
1690
|
-
negationMap,
|
|
1691
|
-
customNegatedFields
|
|
1692
|
-
};
|
|
1693
|
-
}
|
|
1694
|
-
/**
|
|
1695
|
-
* Resolve a long option (--flag, --flag=value, --no-flag, --custom-negation)
|
|
1696
|
-
* against global flag lookup. Returns the resolved camelCase name and whether
|
|
1697
|
-
* it is a known global flag.
|
|
1698
|
-
*
|
|
1699
|
-
* `isSuppressedNegation` is true when the token matches a default `--no-X`
|
|
1700
|
-
* form that has been suppressed by a custom `negation` on the target field.
|
|
1701
|
-
* The caller may use this to keep argv scanning past such tokens (so a
|
|
1702
|
-
* trailing subcommand is still detected) even though they no longer negate.
|
|
1703
|
-
*/
|
|
1704
|
-
function resolveGlobalLongOption(arg, lookup) {
|
|
1705
|
-
const withoutDashes = arg.includes("=") ? arg.slice(2, arg.indexOf("=")) : arg.slice(2);
|
|
1706
|
-
const customNegated = !arg.includes("=") ? lookup.negationMap.get(withoutDashes) : void 0;
|
|
1707
|
-
if (customNegated) return {
|
|
1708
|
-
resolvedName: customNegated,
|
|
1709
|
-
withoutDashes,
|
|
1710
|
-
isNegated: true,
|
|
1711
|
-
isGlobal: lookup.flagNames.has(customNegated),
|
|
1712
|
-
isSuppressedNegation: false
|
|
1713
|
-
};
|
|
1714
|
-
const kebabNegated = withoutDashes.startsWith("no-");
|
|
1715
|
-
const camelNegated = !kebabNegated && withoutDashes.length > 2 && withoutDashes.startsWith("no") && /[A-Z]/.test(withoutDashes[2]);
|
|
1716
|
-
if (kebabNegated || camelNegated) {
|
|
1717
|
-
const literalResolved = lookup.aliasMap.get(withoutDashes) ?? withoutDashes;
|
|
1718
|
-
if (lookup.flagNames.has(literalResolved) || lookup.cliNames.has(withoutDashes)) return {
|
|
1719
|
-
resolvedName: literalResolved,
|
|
1720
|
-
withoutDashes,
|
|
1721
|
-
isNegated: false,
|
|
1722
|
-
isGlobal: true,
|
|
1723
|
-
isSuppressedNegation: false
|
|
1724
|
-
};
|
|
1725
|
-
}
|
|
1726
|
-
const defaultIsNegated = kebabNegated || camelNegated;
|
|
1727
|
-
const flagName = kebabNegated ? withoutDashes.slice(3) : camelNegated ? withoutDashes[2].toLowerCase() + withoutDashes.slice(3) : withoutDashes;
|
|
1728
|
-
const resolvedName = lookup.aliasMap.get(flagName) ?? flagName;
|
|
1729
|
-
const suppressDefaultNegation = defaultIsNegated && lookup.customNegatedFields.has(resolvedName);
|
|
1730
|
-
return {
|
|
1731
|
-
resolvedName,
|
|
1732
|
-
withoutDashes,
|
|
1733
|
-
isNegated: defaultIsNegated && !suppressDefaultNegation,
|
|
1734
|
-
isGlobal: !suppressDefaultNegation && (lookup.flagNames.has(resolvedName) || lookup.cliNames.has(withoutDashes) || lookup.cliNames.has(flagName)),
|
|
1735
|
-
isSuppressedNegation: suppressDefaultNegation
|
|
1736
|
-
};
|
|
1737
|
-
}
|
|
1738
|
-
/**
|
|
1739
|
-
* Check whether a non-boolean flag should consume the next argv token as its value.
|
|
1740
|
-
* Returns true when the next token exists, is not a flag, and the current flag
|
|
1741
|
-
* is not boolean / negated / using = syntax.
|
|
1742
|
-
*/
|
|
1743
|
-
function shouldConsumeValue(arg, resolvedName, isNegated, nextArg, booleanFlags) {
|
|
1744
|
-
return !arg.includes("=") && !booleanFlags.has(resolvedName) && !isNegated && nextArg !== void 0 && !nextArg.startsWith("-");
|
|
1745
|
-
}
|
|
1746
|
-
/**
|
|
1747
|
-
* Collect a recognized global flag (and its value if applicable) into `dest`,
|
|
1748
|
-
* returning how many argv positions were consumed (1 or 2).
|
|
1749
|
-
*/
|
|
1750
|
-
function collectGlobalFlag(argv, i, resolvedName, isNegated, booleanFlags, dest) {
|
|
1751
|
-
const arg = argv[i];
|
|
1752
|
-
dest.push(arg);
|
|
1753
|
-
if (shouldConsumeValue(arg, resolvedName, isNegated, argv[i + 1], booleanFlags)) {
|
|
1754
|
-
dest.push(argv[i + 1]);
|
|
1755
|
-
return 2;
|
|
1756
|
-
}
|
|
1757
|
-
return 1;
|
|
1758
|
-
}
|
|
1759
|
-
/**
|
|
1760
|
-
* Scan argv to find the subcommand position, skipping over global flags.
|
|
1761
|
-
*
|
|
1762
|
-
* Walks argv and recognizes global flags (long, short, --no-*) so that
|
|
1763
|
-
* `my-cli --verbose build --output dist` correctly identifies `build` as
|
|
1764
|
-
* the subcommand (index 1) rather than treating `--verbose` as the subcommand.
|
|
1765
|
-
*
|
|
1766
|
-
* Limitation: flags appearing before the subcommand name are matched only
|
|
1767
|
-
* against the global schema. If a flag is defined in both global and a
|
|
1768
|
-
* subcommand's local schema, the pre-subcommand occurrence is always treated
|
|
1769
|
-
* as global because the local schema is not available until the subcommand is
|
|
1770
|
-
* identified (lazy-loaded commands make eager checking infeasible). Place
|
|
1771
|
-
* colliding flags after the subcommand name so that `separateGlobalArgs` can
|
|
1772
|
-
* apply local-precedence logic.
|
|
1773
|
-
*
|
|
1774
|
-
* @param argv - Command line arguments
|
|
1775
|
-
* @param subCommandNames - Valid subcommand names
|
|
1776
|
-
* @param globalExtracted - Extracted fields from global args schema
|
|
1777
|
-
* @returns Scan result with subcommand position and token separation
|
|
1778
|
-
*/
|
|
1779
|
-
function scanForSubcommand(argv, subCommandNames, globalExtracted) {
|
|
1780
|
-
const lookup = buildGlobalFlagLookup(globalExtracted);
|
|
1781
|
-
const subCommandNameSet = new Set(subCommandNames);
|
|
1782
|
-
const globalTokensBefore = [];
|
|
1783
|
-
const suppressedTokens = [];
|
|
1784
|
-
let i = 0;
|
|
1785
|
-
while (i < argv.length) {
|
|
1786
|
-
const arg = argv[i];
|
|
1787
|
-
if (arg === "--" || BUILTIN_FLAGS.has(arg)) break;
|
|
1788
|
-
if (!arg.startsWith("-") && subCommandNameSet.has(arg)) return {
|
|
1789
|
-
subCommandIndex: i,
|
|
1790
|
-
globalTokensBefore,
|
|
1791
|
-
tokensAfterSubcommand: argv.slice(i + 1),
|
|
1792
|
-
suppressedTokens
|
|
1793
|
-
};
|
|
1794
|
-
if (arg.startsWith("--")) {
|
|
1795
|
-
const { resolvedName, isNegated, isGlobal, isSuppressedNegation } = resolveGlobalLongOption(arg, lookup);
|
|
1796
|
-
if (isGlobal) {
|
|
1797
|
-
i += collectGlobalFlag(argv, i, resolvedName, isNegated, lookup.booleanFlags, globalTokensBefore);
|
|
1798
|
-
continue;
|
|
1799
|
-
}
|
|
1800
|
-
if (isSuppressedNegation) {
|
|
1801
|
-
suppressedTokens.push(arg.includes("=") ? arg.slice(2, arg.indexOf("=")) : arg.slice(2));
|
|
1802
|
-
i++;
|
|
1803
|
-
continue;
|
|
1804
|
-
}
|
|
1805
|
-
break;
|
|
1806
|
-
}
|
|
1807
|
-
if (arg.startsWith("-") && arg.length > 1) {
|
|
1808
|
-
const withoutDash = arg.includes("=") ? arg.slice(1, arg.indexOf("=")) : arg.slice(1);
|
|
1809
|
-
if (withoutDash.length === 1) {
|
|
1810
|
-
const resolvedName = lookup.aliasMap.get(withoutDash) ?? withoutDash;
|
|
1811
|
-
if (lookup.aliases.has(withoutDash) || lookup.flagNames.has(resolvedName)) {
|
|
1812
|
-
i += collectGlobalFlag(argv, i, resolvedName, false, lookup.booleanFlags, globalTokensBefore);
|
|
1813
|
-
continue;
|
|
1814
|
-
}
|
|
1815
|
-
}
|
|
1816
|
-
break;
|
|
1817
|
-
}
|
|
1818
|
-
break;
|
|
1819
|
-
}
|
|
1820
|
-
return {
|
|
1821
|
-
subCommandIndex: -1,
|
|
1822
|
-
globalTokensBefore,
|
|
1823
|
-
tokensAfterSubcommand: [],
|
|
1824
|
-
suppressedTokens
|
|
1825
|
-
};
|
|
1826
|
-
}
|
|
1827
|
-
const BUILTIN_FLAGS = new Set([
|
|
1828
|
-
"--help",
|
|
1829
|
-
"-h",
|
|
1830
|
-
"--help-all",
|
|
1831
|
-
"-H",
|
|
1832
|
-
"--version"
|
|
1833
|
-
]);
|
|
1834
|
-
/**
|
|
1835
|
-
* Find the index of the first positional argument in argv, properly skipping
|
|
1836
|
-
* global flag values. Returns -1 when no positional is present.
|
|
1837
|
-
*
|
|
1838
|
-
* Mirrors `scanForSubcommand`'s conservative stop conditions: the scan stops
|
|
1839
|
-
* (returning -1) on a `--` terminator, a builtin flag (`--help`/`--version`),
|
|
1840
|
-
* an unknown long flag, or an unknown/combined short flag. Past such tokens we
|
|
1841
|
-
* can't tell a flag *value* from a positional, so continuing would misclassify
|
|
1842
|
-
* e.g. `--help plugin` or `--unknown value` and wrongly trip plugin dispatch.
|
|
1843
|
-
*
|
|
1844
|
-
* Without globalExtracted, no flag is global, so any leading flag halts the
|
|
1845
|
-
* scan and a positional is only found when it precedes every flag.
|
|
1846
|
-
*/
|
|
1847
|
-
function findFirstPositionalIndex(argv, globalExtracted) {
|
|
1848
|
-
const lookup = globalExtracted ? buildGlobalFlagLookup(globalExtracted) : {
|
|
1849
|
-
aliasMap: /* @__PURE__ */ new Map(),
|
|
1850
|
-
booleanFlags: /* @__PURE__ */ new Set(),
|
|
1851
|
-
flagNames: /* @__PURE__ */ new Set(),
|
|
1852
|
-
cliNames: /* @__PURE__ */ new Set(),
|
|
1853
|
-
aliases: /* @__PURE__ */ new Set(),
|
|
1854
|
-
negationMap: /* @__PURE__ */ new Map(),
|
|
1855
|
-
customNegatedFields: /* @__PURE__ */ new Set()
|
|
1856
|
-
};
|
|
1857
|
-
for (let i = 0; i < argv.length; i++) {
|
|
1858
|
-
const arg = argv[i];
|
|
1859
|
-
if (!arg.startsWith("-")) return i;
|
|
1860
|
-
if (arg === "--" || BUILTIN_FLAGS.has(arg)) return -1;
|
|
1861
|
-
if (arg.startsWith("--")) {
|
|
1862
|
-
const { resolvedName, isNegated, isGlobal, isSuppressedNegation } = resolveGlobalLongOption(arg, lookup);
|
|
1863
|
-
if (isGlobal) {
|
|
1864
|
-
if (shouldConsumeValue(arg, resolvedName, isNegated, argv[i + 1], lookup.booleanFlags)) i++;
|
|
1865
|
-
continue;
|
|
1866
|
-
}
|
|
1867
|
-
if (isSuppressedNegation) continue;
|
|
1868
|
-
return -1;
|
|
1869
|
-
}
|
|
1870
|
-
const withoutDash = arg.includes("=") ? arg.slice(1, arg.indexOf("=")) : arg.slice(1);
|
|
1871
|
-
if (withoutDash.length === 1) {
|
|
1872
|
-
const resolvedName = lookup.aliasMap.get(withoutDash) ?? withoutDash;
|
|
1873
|
-
if (lookup.aliases.has(withoutDash) || lookup.flagNames.has(resolvedName)) {
|
|
1874
|
-
if (shouldConsumeValue(arg, resolvedName, false, argv[i + 1], lookup.booleanFlags)) i++;
|
|
1875
|
-
continue;
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
return -1;
|
|
1879
|
-
}
|
|
1880
|
-
return -1;
|
|
1881
|
-
}
|
|
1882
|
-
/**
|
|
1883
|
-
* Find the first positional argument in argv, properly skipping global flag
|
|
1884
|
-
* values. Thin wrapper over {@link findFirstPositionalIndex} — see that
|
|
1885
|
-
* function for the scan and stop conditions. Returns `undefined` when none.
|
|
1886
|
-
*/
|
|
1887
|
-
function findFirstPositional(argv, globalExtracted) {
|
|
1888
|
-
const index = findFirstPositionalIndex(argv, globalExtracted);
|
|
1889
|
-
return index >= 0 ? argv[index] : void 0;
|
|
1890
|
-
}
|
|
1891
|
-
|
|
1892
|
-
//#endregion
|
|
1893
|
-
//#region src/parser/arg-parser.ts
|
|
1894
|
-
/**
|
|
1895
|
-
* Parse CLI arguments for a command
|
|
1896
|
-
*
|
|
1897
|
-
* @param argv - Command line arguments
|
|
1898
|
-
* @param command - The command to parse for
|
|
1899
|
-
* @param options - Parse options
|
|
1900
|
-
* @returns Parse result
|
|
1901
|
-
*/
|
|
1902
|
-
function parseArgs(argv, command, options = {}) {
|
|
1903
|
-
const subCommandNameSet = require_schema_extractor.listSubCommandNamesWithAliases(command);
|
|
1904
|
-
const subCommandNames = [...subCommandNameSet];
|
|
1905
|
-
const hasSubCommands = subCommandNames.length > 0;
|
|
1906
|
-
if (hasSubCommands && argv.length > 0) if (options.globalExtracted) {
|
|
1907
|
-
const scanResult = scanForSubcommand(argv, subCommandNames, options.globalExtracted);
|
|
1908
|
-
if (scanResult.subCommandIndex >= 0) {
|
|
1909
|
-
const rawGlobalArgs = parseGlobalArgs(scanResult.globalTokensBefore, options.globalExtracted);
|
|
1910
|
-
return {
|
|
1911
|
-
helpRequested: false,
|
|
1912
|
-
helpAllRequested: false,
|
|
1913
|
-
versionRequested: false,
|
|
1914
|
-
subCommand: argv[scanResult.subCommandIndex],
|
|
1915
|
-
remainingArgs: scanResult.tokensAfterSubcommand,
|
|
1916
|
-
rawArgs: {},
|
|
1917
|
-
positionals: [],
|
|
1918
|
-
unknownFlags: scanResult.suppressedTokens,
|
|
1919
|
-
rawGlobalArgs
|
|
1920
|
-
};
|
|
1921
|
-
}
|
|
1922
|
-
} else {
|
|
1923
|
-
const firstArg = argv[0];
|
|
1924
|
-
if (firstArg && !firstArg.startsWith("-") && subCommandNameSet.has(firstArg)) return {
|
|
1925
|
-
helpRequested: false,
|
|
1926
|
-
helpAllRequested: false,
|
|
1927
|
-
versionRequested: false,
|
|
1928
|
-
subCommand: firstArg,
|
|
1929
|
-
remainingArgs: argv.slice(1),
|
|
1930
|
-
rawArgs: {},
|
|
1931
|
-
positionals: [],
|
|
1932
|
-
unknownFlags: []
|
|
1933
|
-
};
|
|
1934
|
-
}
|
|
1935
|
-
let extracted;
|
|
1936
|
-
if (command.args) {
|
|
1937
|
-
extracted = require_schema_extractor.extractFields(command.args);
|
|
1938
|
-
if (!options.skipValidation) {
|
|
1939
|
-
validateDuplicateFields(extracted);
|
|
1940
|
-
validateCaseVariantCollisions(extracted);
|
|
1941
|
-
validateDuplicateAliases(extracted);
|
|
1942
|
-
validateDuplicateNegations(extracted);
|
|
1943
|
-
validatePositionalConfig(extracted);
|
|
1944
|
-
validateReservedAliases(extracted, hasSubCommands);
|
|
1945
|
-
if (options.globalExtracted) validateCrossSchemaCollisions(options.globalExtracted, extracted);
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
const ddIdx = argv.indexOf("--");
|
|
1949
|
-
const flagScanArgv = ddIdx >= 0 ? argv.slice(0, ddIdx) : argv;
|
|
1950
|
-
const hasUserDefinedH = extracted?.fields.some((f) => f.overrideBuiltinAlias === true && require_schema_extractor.getAllAliases(f).includes("H")) ?? false;
|
|
1951
|
-
const hasUserDefinedh = extracted?.fields.some((f) => f.overrideBuiltinAlias === true && require_schema_extractor.getAllAliases(f).includes("h")) ?? false;
|
|
1952
|
-
const helpAllRequested = flagScanArgv.includes("--help-all") || !hasUserDefinedH && flagScanArgv.includes("-H");
|
|
1953
|
-
const helpRequested = !helpAllRequested && (flagScanArgv.includes("--help") || !hasUserDefinedh && flagScanArgv.includes("-h"));
|
|
1954
|
-
const versionRequested = flagScanArgv.includes("--version");
|
|
1955
|
-
if (helpRequested || helpAllRequested || versionRequested) return {
|
|
1956
|
-
helpRequested,
|
|
1957
|
-
helpAllRequested,
|
|
1958
|
-
versionRequested,
|
|
1959
|
-
subCommand: void 0,
|
|
1960
|
-
remainingArgs: [],
|
|
1961
|
-
rawArgs: {},
|
|
1962
|
-
positionals: [],
|
|
1963
|
-
unknownFlags: []
|
|
1964
|
-
};
|
|
1965
|
-
let commandArgv = argv;
|
|
1966
|
-
let rawGlobalArgs;
|
|
1967
|
-
if (options.globalExtracted) {
|
|
1968
|
-
const { separated, globalParsed } = separateGlobalArgs(argv, options.globalExtracted, extracted);
|
|
1969
|
-
commandArgv = separated;
|
|
1970
|
-
rawGlobalArgs = globalParsed;
|
|
1971
|
-
}
|
|
1972
|
-
if (!extracted) return {
|
|
1973
|
-
helpRequested: false,
|
|
1974
|
-
helpAllRequested: false,
|
|
1975
|
-
versionRequested: false,
|
|
1976
|
-
subCommand: void 0,
|
|
1977
|
-
remainingArgs: [],
|
|
1978
|
-
rawArgs: {},
|
|
1979
|
-
positionals: [],
|
|
1980
|
-
unknownFlags: [],
|
|
1981
|
-
rawGlobalArgs
|
|
1982
|
-
};
|
|
1983
|
-
const parserOptions = buildParserOptions(extracted);
|
|
1984
|
-
const parsed = parseArgv(commandArgv, parserOptions);
|
|
1985
|
-
const rawArgs = mergeWithPositionals(parsed, extracted);
|
|
1986
|
-
for (const field of extracted.fields) if (field.env && rawArgs[field.name] === void 0) {
|
|
1987
|
-
const envNames = Array.isArray(field.env) ? field.env : [field.env];
|
|
1988
|
-
for (const envName of envNames) {
|
|
1989
|
-
const envValue = process.env[envName];
|
|
1990
|
-
if (envValue !== void 0) {
|
|
1991
|
-
rawArgs[field.name] = envValue;
|
|
1992
|
-
break;
|
|
1993
|
-
}
|
|
1994
|
-
}
|
|
1995
|
-
}
|
|
1996
|
-
const knownFlags = new Set(extracted.fields.map((f) => f.name));
|
|
1997
|
-
const knownCliNames = new Set(extracted.fields.map((f) => f.cliName));
|
|
1998
|
-
const knownAliases = /* @__PURE__ */ new Set();
|
|
1999
|
-
for (const f of extracted.fields) for (const alias of require_schema_extractor.getAllAliases(f)) knownAliases.add(alias);
|
|
2000
|
-
if (options.globalExtracted) for (const f of options.globalExtracted.fields) {
|
|
2001
|
-
knownFlags.add(f.name);
|
|
2002
|
-
knownCliNames.add(f.cliName);
|
|
2003
|
-
for (const alias of require_schema_extractor.getAllAliases(f)) knownAliases.add(alias);
|
|
2004
|
-
}
|
|
2005
|
-
const unknownFlags = [];
|
|
2006
|
-
for (const key of Object.keys(parsed.options)) if (!knownFlags.has(key) && !knownCliNames.has(key) && !knownAliases.has(key)) unknownFlags.push(key);
|
|
2007
|
-
return {
|
|
2008
|
-
helpRequested: false,
|
|
2009
|
-
helpAllRequested: false,
|
|
2010
|
-
versionRequested: false,
|
|
2011
|
-
subCommand: void 0,
|
|
2012
|
-
remainingArgs: [],
|
|
2013
|
-
rawArgs,
|
|
2014
|
-
positionals: parsed.positionals,
|
|
2015
|
-
unknownFlags,
|
|
2016
|
-
extractedFields: extracted,
|
|
2017
|
-
rawGlobalArgs
|
|
2018
|
-
};
|
|
2019
|
-
}
|
|
2020
|
-
/**
|
|
2021
|
-
* Parse global args from a list of tokens (e.g., tokens before the subcommand).
|
|
2022
|
-
* Env fallbacks are applied later in the runner on the accumulated global args.
|
|
2023
|
-
*/
|
|
2024
|
-
function parseGlobalArgs(tokens, globalExtracted) {
|
|
2025
|
-
if (tokens.length === 0) return {};
|
|
2026
|
-
return mergeWithPositionals(parseArgv(tokens, buildParserOptions(globalExtracted)), globalExtracted);
|
|
2027
|
-
}
|
|
2028
|
-
/**
|
|
2029
|
-
* Separate global flags from command-local args in argv.
|
|
2030
|
-
* Global flags mixed with command args (e.g., `build --verbose --output dist`)
|
|
2031
|
-
* are extracted and returned separately.
|
|
2032
|
-
* When a flag is defined in both global and local schemas, the local definition
|
|
2033
|
-
* takes precedence (the flag stays in the command tokens).
|
|
2034
|
-
*
|
|
2035
|
-
* Note: Combined short flags (e.g., `-vq`) are not decomposed here; only
|
|
2036
|
-
* single-character short options are recognized as global. The underlying
|
|
2037
|
-
* `parseArgv` handles combined shorts for command-local parsing.
|
|
2038
|
-
*/
|
|
2039
|
-
function separateGlobalArgs(argv, globalExtracted, localExtracted) {
|
|
2040
|
-
const lookup = buildGlobalFlagLookup(globalExtracted);
|
|
2041
|
-
const localFieldNames = new Set(localExtracted?.fields.map((f) => f.name) ?? []);
|
|
2042
|
-
const localCliNames = new Set(localExtracted?.fields.map((f) => f.cliName) ?? []);
|
|
2043
|
-
const localAliasMapKeys = localExtracted ? new Set(buildParserOptions(localExtracted).aliasMap?.keys() ?? []) : /* @__PURE__ */ new Set();
|
|
2044
|
-
const globalTokens = [];
|
|
2045
|
-
const commandTokens = [];
|
|
2046
|
-
for (let i = 0; i < argv.length; i++) {
|
|
2047
|
-
const arg = argv[i];
|
|
2048
|
-
if (arg === "--") {
|
|
2049
|
-
commandTokens.push(...argv.slice(i));
|
|
2050
|
-
break;
|
|
2051
|
-
}
|
|
2052
|
-
if (arg.startsWith("--")) {
|
|
2053
|
-
const { resolvedName, withoutDashes, isNegated, isGlobal } = resolveGlobalLongOption(arg, lookup);
|
|
2054
|
-
const flagName = resolvedName;
|
|
2055
|
-
const isLocalCollision = localFieldNames.has(withoutDashes) || localFieldNames.has(flagName) || localCliNames.has(withoutDashes) || localCliNames.has(flagName) || localAliasMapKeys.has(withoutDashes) || localAliasMapKeys.has(flagName);
|
|
2056
|
-
if (isGlobal && !isLocalCollision) {
|
|
2057
|
-
i += collectGlobalFlag(argv, i, resolvedName, isNegated, lookup.booleanFlags, globalTokens) - 1;
|
|
2058
|
-
continue;
|
|
2059
|
-
}
|
|
2060
|
-
} else if (arg.startsWith("-") && arg.length > 1) {
|
|
2061
|
-
const withoutDash = arg.includes("=") ? arg.slice(1, arg.indexOf("=")) : arg.slice(1);
|
|
2062
|
-
if (withoutDash.length === 1) {
|
|
2063
|
-
const resolvedName = lookup.aliasMap.get(withoutDash) ?? withoutDash;
|
|
2064
|
-
if ((lookup.aliases.has(withoutDash) || lookup.flagNames.has(resolvedName)) && !localAliasMapKeys.has(withoutDash)) {
|
|
2065
|
-
i += collectGlobalFlag(argv, i, resolvedName, false, lookup.booleanFlags, globalTokens) - 1;
|
|
2066
|
-
continue;
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
commandTokens.push(arg);
|
|
2071
|
-
}
|
|
2072
|
-
return {
|
|
2073
|
-
separated: commandTokens,
|
|
2074
|
-
globalParsed: parseGlobalArgs(globalTokens, globalExtracted)
|
|
2075
|
-
};
|
|
2076
|
-
}
|
|
2077
|
-
|
|
2078
|
-
//#endregion
|
|
2079
|
-
//#region src/validator/error-formatter.ts
|
|
2080
|
-
/**
|
|
2081
|
-
* Calculate Levenshtein distance between two strings
|
|
2082
|
-
*/
|
|
2083
|
-
function levenshteinDistance(a, b) {
|
|
2084
|
-
const matrix = [];
|
|
2085
|
-
for (let i = 0; i <= b.length; i++) matrix[i] = [i];
|
|
2086
|
-
for (let j = 0; j <= a.length; j++) matrix[0][j] = j;
|
|
2087
|
-
for (let i = 1; i <= b.length; i++) for (let j = 1; j <= a.length; j++) if (b.charAt(i - 1) === a.charAt(j - 1)) matrix[i][j] = matrix[i - 1][j - 1];
|
|
2088
|
-
else matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1);
|
|
2089
|
-
return matrix[b.length][a.length];
|
|
2090
|
-
}
|
|
2091
|
-
/**
|
|
2092
|
-
* Find similar strings from a list
|
|
2093
|
-
*/
|
|
2094
|
-
function findSimilar(target, candidates) {
|
|
2095
|
-
const threshold = Math.max(2, Math.floor(target.length / 2));
|
|
2096
|
-
return candidates.map((candidate) => ({
|
|
2097
|
-
candidate,
|
|
2098
|
-
distance: levenshteinDistance(target.toLowerCase(), candidate.toLowerCase())
|
|
2099
|
-
})).filter(({ distance }) => distance <= threshold).sort((a, b) => a.distance - b.distance).map(({ candidate }) => candidate).slice(0, 3);
|
|
2100
|
-
}
|
|
2101
|
-
/**
|
|
2102
|
-
* Format unknown flag warning with suggestions (for strip mode)
|
|
2103
|
-
*
|
|
2104
|
-
* @param flag - The unknown flag (e.g., "--verbos")
|
|
2105
|
-
* @param knownFlags - List of known flag names
|
|
2106
|
-
* @returns Formatted warning message with suggestions
|
|
2107
|
-
*/
|
|
2108
|
-
function formatUnknownFlagWarning(flag, knownFlags) {
|
|
2109
|
-
const similar = findSimilar(flag.replace(/^-{1,2}/, ""), knownFlags);
|
|
2110
|
-
let message = `${styles.warning("Warning: Unknown option:")} ${styles.bold(flag)}`;
|
|
2111
|
-
if (similar.length > 0) {
|
|
2112
|
-
message += `\n\n${styles.info("Did you mean?")}`;
|
|
2113
|
-
for (const suggestion of similar) message += `\n ${symbols.arrow} ${styles.option(`--${suggestion}`)}`;
|
|
2114
|
-
}
|
|
2115
|
-
return message;
|
|
2116
|
-
}
|
|
2117
|
-
/**
|
|
2118
|
-
* Format runtime error
|
|
2119
|
-
*
|
|
2120
|
-
* @param error - The error that occurred
|
|
2121
|
-
* @param debug - Whether to include stack trace
|
|
2122
|
-
* @returns Formatted error message
|
|
2123
|
-
*/
|
|
2124
|
-
function formatRuntimeError(error, debug) {
|
|
2125
|
-
if (debug && error.stack) return `${styles.error("Error:")} ${error.message}\n\n${styles.dim(error.stack)}`;
|
|
2126
|
-
return `${styles.error("Error:")} ${error.message}`;
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
|
-
//#endregion
|
|
2130
|
-
//#region src/validator/zod-validator.ts
|
|
2131
|
-
/**
|
|
2132
|
-
* Convert ZodError to ValidationError array (zod v4 compatible)
|
|
2133
|
-
*/
|
|
2134
|
-
function formatZodErrors(error) {
|
|
2135
|
-
return error.issues.map((issue) => ({
|
|
2136
|
-
path: issue.path.map(String),
|
|
2137
|
-
message: issue.message,
|
|
2138
|
-
code: issue.code,
|
|
2139
|
-
received: "received" in issue ? issue.received : void 0,
|
|
2140
|
-
expected: "expected" in issue ? String(issue.expected) : void 0
|
|
2141
|
-
}));
|
|
2142
|
-
}
|
|
2143
|
-
/**
|
|
2144
|
-
* Validate raw arguments against a schema
|
|
2145
|
-
*
|
|
2146
|
-
* @param rawArgs - Parsed but unvalidated arguments
|
|
2147
|
-
* @param schema - Zod schema (ZodObject, ZodDiscriminatedUnion, etc.)
|
|
2148
|
-
* @returns Validation result with typed data or errors
|
|
2149
|
-
*/
|
|
2150
|
-
function validateArgs(rawArgs, schema) {
|
|
2151
|
-
const result = schema.safeParse(rawArgs);
|
|
2152
|
-
if (result.success) return {
|
|
2153
|
-
success: true,
|
|
2154
|
-
data: result.data
|
|
2155
|
-
};
|
|
2156
|
-
return {
|
|
2157
|
-
success: false,
|
|
2158
|
-
errors: formatZodErrors(result.error)
|
|
2159
|
-
};
|
|
2160
|
-
}
|
|
2161
|
-
/**
|
|
2162
|
-
* Format validation errors for display
|
|
2163
|
-
*/
|
|
2164
|
-
function formatValidationErrors(errors) {
|
|
2165
|
-
return errors.map((e) => {
|
|
2166
|
-
return `${e.path.length > 0 ? `${e.path.join(".")}: ` : ""}${e.message}`;
|
|
2167
|
-
}).join("\n");
|
|
2168
|
-
}
|
|
2169
|
-
|
|
2170
|
-
//#endregion
|
|
2171
|
-
//#region src/core/effect-runner.ts
|
|
2172
|
-
/**
|
|
2173
|
-
* Execute all registered effect callbacks for validated args.
|
|
2174
|
-
*
|
|
2175
|
-
* Effects run sequentially in field-definition order.
|
|
2176
|
-
* Only fires for fields that have an `effect` callback defined.
|
|
2177
|
-
*
|
|
2178
|
-
* @param validatedArgs - The validated (post-Zod) argument values
|
|
2179
|
-
* @param extracted - The extracted fields from the schema
|
|
2180
|
-
* @param globalArgs - The validated global args (passed to command arg effects)
|
|
2181
|
-
*/
|
|
2182
|
-
async function runEffects(validatedArgs, extracted, globalArgs) {
|
|
2183
|
-
for (const field of extracted.fields) {
|
|
2184
|
-
if (!field.effect) continue;
|
|
2185
|
-
await field.effect(validatedArgs[field.name], {
|
|
2186
|
-
name: field.name,
|
|
2187
|
-
args: validatedArgs,
|
|
2188
|
-
...globalArgs != null && { globalArgs }
|
|
2189
|
-
});
|
|
2190
|
-
}
|
|
2191
|
-
}
|
|
2192
|
-
|
|
2193
|
-
//#endregion
|
|
2194
|
-
//#region src/core/runner.ts
|
|
2195
|
-
var runner_exports = /* @__PURE__ */ require_log_collector.__exportAll({
|
|
2196
|
-
runCommand: () => runCommand,
|
|
2197
|
-
runMain: () => runMain
|
|
2198
|
-
});
|
|
2199
|
-
/**
|
|
2200
|
-
* Default logger using console
|
|
2201
|
-
*/
|
|
2202
|
-
const defaultLogger = {
|
|
2203
|
-
log: (message) => console.log(message),
|
|
2204
|
-
error: (message) => console.error(message)
|
|
2205
|
-
};
|
|
2206
|
-
/**
|
|
2207
|
-
* Run a command with the given arguments (programmatic/test usage)
|
|
2208
|
-
*
|
|
2209
|
-
* This function parses arguments, validates them, routes to subcommands,
|
|
2210
|
-
* and executes the command. It does NOT call process.exit.
|
|
2211
|
-
*
|
|
2212
|
-
* @param command - The command to run
|
|
2213
|
-
* @param argv - Command line arguments to parse
|
|
2214
|
-
* @param options - Run options
|
|
2215
|
-
* @returns The result of command execution
|
|
2216
|
-
*
|
|
2217
|
-
* @example
|
|
2218
|
-
* ```ts
|
|
2219
|
-
* import { defineCommand, runCommand } from "politty";
|
|
2220
|
-
*
|
|
2221
|
-
* const command = defineCommand({
|
|
2222
|
-
* name: "my-cli",
|
|
2223
|
-
* args: z.object({ name: z.string() }),
|
|
2224
|
-
* run: ({ name }) => console.log(`Hello, ${name}!`),
|
|
2225
|
-
* });
|
|
2226
|
-
*
|
|
2227
|
-
* // In tests
|
|
2228
|
-
* const result = await runCommand(command, ["--name", "World"]);
|
|
2229
|
-
* expect(result.exitCode).toBe(0);
|
|
2230
|
-
* ```
|
|
2231
|
-
*/
|
|
2232
|
-
async function runCommand(command, argv, options = {}) {
|
|
2233
|
-
const globalExtracted = extractAndValidateGlobal(options);
|
|
2234
|
-
const shouldCaptureLogs = options.captureLogs ?? false;
|
|
2235
|
-
const globalCollector = shouldCaptureLogs ? require_log_collector.createLogCollector() : null;
|
|
2236
|
-
if (options.setup) {
|
|
2237
|
-
globalCollector?.start();
|
|
2238
|
-
try {
|
|
2239
|
-
await options.setup({});
|
|
2240
|
-
} catch (e) {
|
|
2241
|
-
const error = e instanceof Error ? e : new Error(String(e));
|
|
2242
|
-
if (options.cleanup) try {
|
|
2243
|
-
await options.cleanup({ error });
|
|
2244
|
-
} catch {}
|
|
2245
|
-
globalCollector?.stop();
|
|
2246
|
-
return {
|
|
2247
|
-
success: false,
|
|
2248
|
-
error,
|
|
2249
|
-
exitCode: 1,
|
|
2250
|
-
logs: globalCollector?.getLogs() ?? require_log_collector.emptyLogs()
|
|
2251
|
-
};
|
|
2252
|
-
}
|
|
2253
|
-
globalCollector?.stop();
|
|
2254
|
-
}
|
|
2255
|
-
const result = await runCommandInternal(command, argv, {
|
|
2256
|
-
...options,
|
|
2257
|
-
handleSignals: false,
|
|
2258
|
-
_globalExtracted: globalExtracted,
|
|
2259
|
-
_globalCleanup: options.cleanup,
|
|
2260
|
-
_existingLogs: globalCollector?.getLogs()
|
|
2261
|
-
});
|
|
2262
|
-
if (options.cleanup) {
|
|
2263
|
-
const cleanupCollector = shouldCaptureLogs ? require_log_collector.createLogCollector() : null;
|
|
2264
|
-
cleanupCollector?.start();
|
|
2265
|
-
const cleanupCtx = { error: !result.success ? result.error : void 0 };
|
|
2266
|
-
try {
|
|
2267
|
-
await options.cleanup(cleanupCtx);
|
|
2268
|
-
} catch (e) {
|
|
2269
|
-
if (result.success) {
|
|
2270
|
-
const error = e instanceof Error ? e : new Error(String(e));
|
|
2271
|
-
cleanupCollector?.stop();
|
|
2272
|
-
return {
|
|
2273
|
-
success: false,
|
|
2274
|
-
error,
|
|
2275
|
-
exitCode: 1,
|
|
2276
|
-
logs: require_log_collector.mergeLogs(result.logs, cleanupCollector?.getLogs() ?? require_log_collector.emptyLogs())
|
|
2277
|
-
};
|
|
2278
|
-
}
|
|
2279
|
-
}
|
|
2280
|
-
cleanupCollector?.stop();
|
|
2281
|
-
const cleanupLogs = cleanupCollector?.getLogs() ?? require_log_collector.emptyLogs();
|
|
2282
|
-
if (cleanupLogs.entries.length > 0) return {
|
|
2283
|
-
...result,
|
|
2284
|
-
logs: require_log_collector.mergeLogs(result.logs, cleanupLogs)
|
|
2285
|
-
};
|
|
2286
|
-
}
|
|
2287
|
-
return result;
|
|
2288
|
-
}
|
|
2289
|
-
/**
|
|
2290
|
-
* Hidden internal subcommands (e.g. `__refresh-completion`) are spawned
|
|
2291
|
-
* by background hooks and must not run user-provided
|
|
2292
|
-
* `setup`/`cleanup`/`prompt` or required `globalArgs`. Those exist for
|
|
2293
|
-
* the foreground CLI run; replaying them in a detached child causes
|
|
2294
|
-
* duplicate side effects, stuck prompts, and validation failures the
|
|
2295
|
-
* user never opted into.
|
|
2296
|
-
*
|
|
2297
|
-
* We treat any registered subcommand whose name starts with `__` as
|
|
2298
|
-
* internal. We use `findFirstPositional` (schema-aware) instead of the
|
|
2299
|
-
* naive "first non-flag token" so an option *value* like
|
|
2300
|
-
* `--name __refresh-completion` doesn't trip the bypass — that would
|
|
2301
|
-
* silently skip lifecycle hooks for ordinary invocations.
|
|
2302
|
-
*/
|
|
2303
|
-
function isInternalSubcommandInvocation(command, argv, globalExtracted) {
|
|
2304
|
-
const firstPositional = findFirstPositional(argv, globalExtracted);
|
|
2305
|
-
if (!firstPositional || !firstPositional.startsWith("__")) return false;
|
|
2306
|
-
return Boolean(command.subCommands?.[firstPositional]);
|
|
2307
|
-
}
|
|
2308
|
-
/**
|
|
2309
|
-
* Run a CLI command as the main entry point
|
|
2310
|
-
*
|
|
2311
|
-
* This function:
|
|
2312
|
-
* - Uses process.argv for arguments
|
|
2313
|
-
* - Handles SIGINT/SIGTERM signals
|
|
2314
|
-
* - Calls process.exit with the appropriate exit code
|
|
2315
|
-
* - Invokes `command.runMainHook` once before parsing if set, so plug-ins
|
|
2316
|
-
* like `withCompletionCommand` can fire detached background work
|
|
2317
|
-
* - Bypasses user `setup`/`cleanup`/`prompt` and required `globalArgs`
|
|
2318
|
-
* for registered hidden subcommands whose name starts with `__`
|
|
2319
|
-
* (e.g. `__refresh-completion`)
|
|
2320
|
-
*
|
|
2321
|
-
* @param command - The command to run
|
|
2322
|
-
* @param options - Main options (version, debug)
|
|
2323
|
-
*
|
|
2324
|
-
* @example
|
|
2325
|
-
* ```ts
|
|
2326
|
-
* import { defineCommand, runMain } from "politty";
|
|
2327
|
-
*
|
|
2328
|
-
* const command = defineCommand({
|
|
2329
|
-
* name: "my-cli",
|
|
2330
|
-
* run: () => console.log("Hello!"),
|
|
2331
|
-
* });
|
|
2332
|
-
*
|
|
2333
|
-
* runMain(command, { version: "1.0.0" });
|
|
2334
|
-
* ```
|
|
2335
|
-
*/
|
|
2336
|
-
async function runMain(command, options = {}) {
|
|
2337
|
-
if (command.runMainHook) try {
|
|
2338
|
-
command.runMainHook(process.argv.slice(2));
|
|
2339
|
-
} catch {}
|
|
2340
|
-
const argv = process.argv.slice(2);
|
|
2341
|
-
let globalExtractedForBypass;
|
|
2342
|
-
if (options.globalArgs) try {
|
|
2343
|
-
globalExtractedForBypass = require_schema_extractor.extractFields(options.globalArgs);
|
|
2344
|
-
} catch {}
|
|
2345
|
-
let effectiveOptions = options;
|
|
2346
|
-
if (isInternalSubcommandInvocation(command, argv, globalExtractedForBypass)) {
|
|
2347
|
-
const { setup: _s, cleanup: _c, prompt: _p, globalArgs: _g, ...rest } = options;
|
|
2348
|
-
effectiveOptions = rest;
|
|
2349
|
-
}
|
|
2350
|
-
const globalExtracted = extractAndValidateGlobal(effectiveOptions);
|
|
2351
|
-
if (effectiveOptions.onUnknownSubcommand && !isInternalSubcommandInvocation(command, argv, globalExtractedForBypass)) {
|
|
2352
|
-
const knownSubCommands = require_schema_extractor.listSubCommandNamesWithAliases(command);
|
|
2353
|
-
if (knownSubCommands.size > 0) {
|
|
2354
|
-
const positionalIndex = findFirstPositionalIndex(argv, globalExtracted);
|
|
2355
|
-
const name = positionalIndex >= 0 ? argv[positionalIndex] : void 0;
|
|
2356
|
-
if (name && !knownSubCommands.has(name)) {
|
|
2357
|
-
const forwardArgs = argv.slice(positionalIndex + 1);
|
|
2358
|
-
const exitCode = await effectiveOptions.onUnknownSubcommand({
|
|
2359
|
-
commandPath: [],
|
|
2360
|
-
name,
|
|
2361
|
-
args: forwardArgs
|
|
2362
|
-
});
|
|
2363
|
-
if (typeof exitCode === "number") {
|
|
2364
|
-
await flushStandardStreams();
|
|
2365
|
-
return process.exit(exitCode);
|
|
2366
|
-
}
|
|
2367
|
-
}
|
|
2368
|
-
}
|
|
2369
|
-
}
|
|
2370
|
-
if (effectiveOptions.setup) try {
|
|
2371
|
-
await effectiveOptions.setup({});
|
|
2372
|
-
} catch (e) {
|
|
2373
|
-
const error = e instanceof Error ? e : new Error(String(e));
|
|
2374
|
-
if (effectiveOptions.cleanup) try {
|
|
2375
|
-
await effectiveOptions.cleanup({ error });
|
|
2376
|
-
} catch {}
|
|
2377
|
-
process.exit(1);
|
|
2378
|
-
}
|
|
2379
|
-
const result = await runCommandInternal(command, argv, {
|
|
2380
|
-
debug: effectiveOptions.debug,
|
|
2381
|
-
captureLogs: effectiveOptions.captureLogs,
|
|
2382
|
-
skipValidation: effectiveOptions.skipValidation,
|
|
2383
|
-
handleSignals: true,
|
|
2384
|
-
logger: effectiveOptions.logger,
|
|
2385
|
-
globalArgs: effectiveOptions.globalArgs,
|
|
2386
|
-
prompt: effectiveOptions.prompt,
|
|
2387
|
-
onUnknownSubcommand: effectiveOptions.onUnknownSubcommand,
|
|
2388
|
-
_globalExtracted: globalExtracted,
|
|
2389
|
-
_globalCleanup: effectiveOptions.cleanup,
|
|
2390
|
-
_context: {
|
|
2391
|
-
commandPath: [],
|
|
2392
|
-
rootName: command.name,
|
|
2393
|
-
rootVersion: effectiveOptions.version,
|
|
2394
|
-
globalExtracted
|
|
2395
|
-
}
|
|
2396
|
-
});
|
|
2397
|
-
if ((effectiveOptions.displayErrors ?? true) && !result.success && result.error) (effectiveOptions.logger ?? defaultLogger).error(formatRuntimeError(result.error, effectiveOptions.debug ?? false));
|
|
2398
|
-
if (effectiveOptions.cleanup) {
|
|
2399
|
-
const cleanupCtx = { error: !result.success ? result.error : void 0 };
|
|
2400
|
-
try {
|
|
2401
|
-
await effectiveOptions.cleanup(cleanupCtx);
|
|
2402
|
-
} catch {}
|
|
2403
|
-
}
|
|
2404
|
-
await flushStandardStreams();
|
|
2405
|
-
process.exit(result.exitCode);
|
|
2406
|
-
}
|
|
2407
|
-
/**
|
|
2408
|
-
* Flush stdout/stderr before exit to prevent truncated output when piped
|
|
2409
|
-
* (pipe writes are buffered asynchronously, so exiting early loses data).
|
|
2410
|
-
*
|
|
2411
|
-
* We await a zero-byte write's callback rather than a `drain` event: `drain`
|
|
2412
|
-
* only fires after a `write()` returned `false` (backpressure), so buffered
|
|
2413
|
-
* writes that never tripped it would hang. The write callback is ordered after
|
|
2414
|
-
* all pending writes, so it resolves once the buffer is flushed.
|
|
2415
|
-
*/
|
|
2416
|
-
async function flushStandardStreams() {
|
|
2417
|
-
await Promise.all([process.stdout, process.stderr].map((stream) => stream.writableLength > 0 ? new Promise((resolve) => stream.write("", () => resolve())) : Promise.resolve()));
|
|
2418
|
-
}
|
|
2419
|
-
/**
|
|
2420
|
-
* Internal implementation of command running
|
|
2421
|
-
*/
|
|
2422
|
-
async function runCommandInternal(command, argv, options = {}) {
|
|
2423
|
-
const logger = options.logger ?? defaultLogger;
|
|
2424
|
-
const context = options._context ?? {
|
|
2425
|
-
commandPath: [],
|
|
2426
|
-
rootName: command.name,
|
|
2427
|
-
globalExtracted: options._globalExtracted
|
|
2428
|
-
};
|
|
2429
|
-
const collector = options.captureLogs ?? false ? require_log_collector.createLogCollector() : null;
|
|
2430
|
-
collector?.start();
|
|
2431
|
-
const getCurrentLogs = () => {
|
|
2432
|
-
return require_log_collector.mergeLogs(options._existingLogs ?? require_log_collector.emptyLogs(), collector?.getLogs() ?? require_log_collector.emptyLogs());
|
|
2433
|
-
};
|
|
2434
|
-
try {
|
|
2435
|
-
const parseResult = parseArgs(argv, command, {
|
|
2436
|
-
skipValidation: options.skipValidation,
|
|
2437
|
-
globalExtracted: options._globalExtracted
|
|
2438
|
-
});
|
|
2439
|
-
const accumulatedGlobalArgs = {
|
|
2440
|
-
...options._parsedGlobalArgs,
|
|
2441
|
-
...parseResult.rawGlobalArgs
|
|
2442
|
-
};
|
|
2443
|
-
const nestedCommandPath = context.commandPath ?? [];
|
|
2444
|
-
if (options.onUnknownSubcommand && nestedCommandPath.length > 0) {
|
|
2445
|
-
const knownSubCommands = require_schema_extractor.listSubCommandNamesWithAliases(command);
|
|
2446
|
-
if (knownSubCommands.size > 0) {
|
|
2447
|
-
const positionalIndex = findFirstPositionalIndex(argv, options._globalExtracted);
|
|
2448
|
-
const name = positionalIndex >= 0 ? argv[positionalIndex] : void 0;
|
|
2449
|
-
if (name && !knownSubCommands.has(name)) {
|
|
2450
|
-
const forwardArgs = argv.slice(positionalIndex + 1);
|
|
2451
|
-
const exitCode = await options.onUnknownSubcommand({
|
|
2452
|
-
commandPath: nestedCommandPath,
|
|
2453
|
-
name,
|
|
2454
|
-
args: forwardArgs
|
|
2455
|
-
});
|
|
2456
|
-
if (typeof exitCode === "number") {
|
|
2457
|
-
collector?.stop();
|
|
2458
|
-
if (options.handleSignals) {
|
|
2459
|
-
if (options._globalCleanup) try {
|
|
2460
|
-
await options._globalCleanup({ error: void 0 });
|
|
2461
|
-
} catch {}
|
|
2462
|
-
await flushStandardStreams();
|
|
2463
|
-
process.exit(exitCode);
|
|
2464
|
-
}
|
|
2465
|
-
return exitCode === 0 ? {
|
|
2466
|
-
success: true,
|
|
2467
|
-
result: void 0,
|
|
2468
|
-
exitCode: 0,
|
|
2469
|
-
logs: getCurrentLogs()
|
|
2470
|
-
} : {
|
|
2471
|
-
success: false,
|
|
2472
|
-
error: /* @__PURE__ */ new Error(`Plugin "${[...nestedCommandPath, name].join(" ")}" exited with code ${exitCode}`),
|
|
2473
|
-
exitCode,
|
|
2474
|
-
logs: getCurrentLogs()
|
|
2475
|
-
};
|
|
2476
|
-
}
|
|
2477
|
-
}
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
if (parseResult.helpRequested || parseResult.helpAllRequested) {
|
|
2481
|
-
let hasUnknownSubcommand = false;
|
|
2482
|
-
const subCmdNames = require_schema_extractor.listSubCommands(command);
|
|
2483
|
-
const allSubCmdNameSet = require_schema_extractor.listSubCommandNamesWithAliases(command);
|
|
2484
|
-
if (subCmdNames.length > 0) {
|
|
2485
|
-
const potentialSubCmd = findFirstPositional(argv, context.globalExtracted);
|
|
2486
|
-
if (potentialSubCmd && !allSubCmdNameSet.has(potentialSubCmd)) hasUnknownSubcommand = true;
|
|
2487
|
-
}
|
|
2488
|
-
const help = generateHelp(command, {
|
|
2489
|
-
showSubcommands: options.showSubcommands ?? true,
|
|
2490
|
-
showSubcommandOptions: parseResult.helpAllRequested || options.showSubcommandOptions,
|
|
2491
|
-
context
|
|
2492
|
-
});
|
|
2493
|
-
logger.log(help);
|
|
2494
|
-
collector?.stop();
|
|
2495
|
-
if (hasUnknownSubcommand) {
|
|
2496
|
-
const unknownCmd = findFirstPositional(argv, context.globalExtracted) ?? "";
|
|
2497
|
-
const similar = findSimilar(unknownCmd, [...allSubCmdNameSet]);
|
|
2498
|
-
const suggestion = similar.length > 0 ? ` Did you mean: ${similar.join(", ")}?` : "";
|
|
2499
|
-
return {
|
|
2500
|
-
success: false,
|
|
2501
|
-
error: /* @__PURE__ */ new Error(`Unknown subcommand: ${unknownCmd}${suggestion ? `.${suggestion}` : ""}`),
|
|
2502
|
-
exitCode: 1,
|
|
2503
|
-
logs: getCurrentLogs()
|
|
2504
|
-
};
|
|
2505
|
-
}
|
|
2506
|
-
return {
|
|
2507
|
-
success: true,
|
|
2508
|
-
result: void 0,
|
|
2509
|
-
exitCode: 0,
|
|
2510
|
-
logs: getCurrentLogs()
|
|
2511
|
-
};
|
|
2512
|
-
}
|
|
2513
|
-
if (parseResult.versionRequested) {
|
|
2514
|
-
const version = context.rootVersion;
|
|
2515
|
-
if (version) logger.log(version);
|
|
2516
|
-
collector?.stop();
|
|
2517
|
-
return {
|
|
2518
|
-
success: true,
|
|
2519
|
-
result: void 0,
|
|
2520
|
-
exitCode: 0,
|
|
2521
|
-
logs: getCurrentLogs()
|
|
2522
|
-
};
|
|
2523
|
-
}
|
|
2524
|
-
if (parseResult.subCommand) {
|
|
2525
|
-
if (parseResult.unknownFlags.length > 0) {
|
|
2526
|
-
const globalMode = context.globalExtracted?.unknownKeysMode ?? "strip";
|
|
2527
|
-
if (globalMode === "strict") {
|
|
2528
|
-
collector?.stop();
|
|
2529
|
-
return {
|
|
2530
|
-
success: false,
|
|
2531
|
-
error: /* @__PURE__ */ new Error(`Unknown flags: ${parseResult.unknownFlags.join(", ")}`),
|
|
2532
|
-
exitCode: 1,
|
|
2533
|
-
logs: getCurrentLogs()
|
|
2534
|
-
};
|
|
2535
|
-
}
|
|
2536
|
-
if (globalMode === "strip") {
|
|
2537
|
-
const knownGlobalFlags = context.globalExtracted?.fields.map((f) => f.name) ?? [];
|
|
2538
|
-
for (const flag of parseResult.unknownFlags) logger.error(formatUnknownFlagWarning(flag, knownGlobalFlags));
|
|
2539
|
-
}
|
|
2540
|
-
}
|
|
2541
|
-
const resolved = await require_schema_extractor.resolveSubcommandWithAlias(command, parseResult.subCommand);
|
|
2542
|
-
if (resolved) {
|
|
2543
|
-
const subContext = {
|
|
2544
|
-
commandPath: [...context.commandPath ?? [], parseResult.subCommand],
|
|
2545
|
-
rootName: context.rootName,
|
|
2546
|
-
rootVersion: context.rootVersion,
|
|
2547
|
-
globalExtracted: context.globalExtracted,
|
|
2548
|
-
aliasFor: resolved.aliasFor
|
|
2549
|
-
};
|
|
2550
|
-
collector?.stop();
|
|
2551
|
-
return runCommandInternal(resolved.command, parseResult.remainingArgs, {
|
|
2552
|
-
...options,
|
|
2553
|
-
_context: subContext,
|
|
2554
|
-
_existingLogs: getCurrentLogs(),
|
|
2555
|
-
_parsedGlobalArgs: accumulatedGlobalArgs
|
|
2556
|
-
});
|
|
2557
|
-
}
|
|
2558
|
-
}
|
|
2559
|
-
if (require_schema_extractor.listSubCommands(command).length > 0 && !parseResult.subCommand && !command.run) {
|
|
2560
|
-
const help = generateHelp(command, {
|
|
2561
|
-
showSubcommands: options.showSubcommands ?? true,
|
|
2562
|
-
context
|
|
2563
|
-
});
|
|
2564
|
-
logger.log(help);
|
|
2565
|
-
collector?.stop();
|
|
2566
|
-
return {
|
|
2567
|
-
success: true,
|
|
2568
|
-
result: void 0,
|
|
2569
|
-
exitCode: 0,
|
|
2570
|
-
logs: getCurrentLogs()
|
|
2571
|
-
};
|
|
2572
|
-
}
|
|
2573
|
-
if (parseResult.unknownFlags.length > 0) {
|
|
2574
|
-
const unknownKeysMode = parseResult.extractedFields?.unknownKeysMode ?? "strip";
|
|
2575
|
-
const knownFlags = parseResult.extractedFields?.fields.map((f) => f.name) ?? [];
|
|
2576
|
-
if (unknownKeysMode === "strict") {
|
|
2577
|
-
collector?.stop();
|
|
2578
|
-
return {
|
|
2579
|
-
success: false,
|
|
2580
|
-
error: /* @__PURE__ */ new Error(`Unknown flags: ${parseResult.unknownFlags.join(", ")}`),
|
|
2581
|
-
exitCode: 1,
|
|
2582
|
-
logs: getCurrentLogs()
|
|
2583
|
-
};
|
|
2584
|
-
} else if (unknownKeysMode === "strip") for (const flag of parseResult.unknownFlags) logger.error(formatUnknownFlagWarning(flag, knownFlags));
|
|
2585
|
-
}
|
|
2586
|
-
let validatedGlobalArgs = {};
|
|
2587
|
-
const isCompletionInvocation = command.name === "__complete";
|
|
2588
|
-
if (options.globalArgs && options._globalExtracted && !isCompletionInvocation) {
|
|
2589
|
-
for (const field of options._globalExtracted.fields) if (field.env && accumulatedGlobalArgs[field.name] === void 0) {
|
|
2590
|
-
const envNames = Array.isArray(field.env) ? field.env : [field.env];
|
|
2591
|
-
for (const envName of envNames) {
|
|
2592
|
-
const envValue = process.env[envName];
|
|
2593
|
-
if (envValue !== void 0) {
|
|
2594
|
-
accumulatedGlobalArgs[field.name] = envValue;
|
|
2595
|
-
break;
|
|
2596
|
-
}
|
|
2597
|
-
}
|
|
2598
|
-
}
|
|
2599
|
-
if (options.prompt) {
|
|
2600
|
-
const resolved = await options.prompt(accumulatedGlobalArgs, options._globalExtracted);
|
|
2601
|
-
Object.assign(accumulatedGlobalArgs, resolved);
|
|
2602
|
-
}
|
|
2603
|
-
const globalValidation = validateArgs(accumulatedGlobalArgs, options.globalArgs);
|
|
2604
|
-
if (!globalValidation.success) {
|
|
2605
|
-
collector?.stop();
|
|
2606
|
-
return {
|
|
2607
|
-
success: false,
|
|
2608
|
-
error: new Error(formatValidationErrors(globalValidation.errors)),
|
|
2609
|
-
exitCode: 1,
|
|
2610
|
-
logs: getCurrentLogs()
|
|
2611
|
-
};
|
|
2612
|
-
}
|
|
2613
|
-
validatedGlobalArgs = globalValidation.data;
|
|
2614
|
-
}
|
|
2615
|
-
if (!command.args) {
|
|
2616
|
-
const proxiedGlobalArgs = createDualCaseProxy(validatedGlobalArgs);
|
|
2617
|
-
if (options._globalExtracted && !isCompletionInvocation) await runEffects(proxiedGlobalArgs, options._globalExtracted, proxiedGlobalArgs);
|
|
2618
|
-
collector?.stop();
|
|
2619
|
-
return await executeLifecycle(command, proxiedGlobalArgs, {
|
|
2620
|
-
handleSignals: options.handleSignals,
|
|
2621
|
-
captureLogs: options.captureLogs,
|
|
2622
|
-
existingLogs: getCurrentLogs(),
|
|
2623
|
-
globalCleanup: options._globalCleanup
|
|
2624
|
-
});
|
|
2625
|
-
}
|
|
2626
|
-
let argsToValidate = parseResult.rawArgs;
|
|
2627
|
-
if (options.prompt && parseResult.extractedFields) {
|
|
2628
|
-
const resolved = await options.prompt(argsToValidate, parseResult.extractedFields);
|
|
2629
|
-
argsToValidate = {
|
|
2630
|
-
...argsToValidate,
|
|
2631
|
-
...resolved
|
|
2632
|
-
};
|
|
2633
|
-
}
|
|
2634
|
-
const validationResult = validateArgs(argsToValidate, command.args);
|
|
2635
|
-
if (!validationResult.success) {
|
|
2636
|
-
collector?.stop();
|
|
2637
|
-
return {
|
|
2638
|
-
success: false,
|
|
2639
|
-
error: new Error(formatValidationErrors(validationResult.errors)),
|
|
2640
|
-
exitCode: 1,
|
|
2641
|
-
logs: getCurrentLogs()
|
|
2642
|
-
};
|
|
2643
|
-
}
|
|
2644
|
-
const proxiedCommandArgs = createDualCaseProxy(validationResult.data);
|
|
2645
|
-
const proxiedGlobalArgs = createDualCaseProxy(validatedGlobalArgs);
|
|
2646
|
-
if (options._globalExtracted && !isCompletionInvocation) await runEffects(proxiedGlobalArgs, options._globalExtracted, proxiedGlobalArgs);
|
|
2647
|
-
if (parseResult.extractedFields && !isCompletionInvocation) await runEffects(proxiedCommandArgs, parseResult.extractedFields, proxiedGlobalArgs);
|
|
2648
|
-
const mergedArgs = createDualCaseProxy({
|
|
2649
|
-
...proxiedGlobalArgs,
|
|
2650
|
-
...proxiedCommandArgs
|
|
2651
|
-
});
|
|
2652
|
-
collector?.stop();
|
|
2653
|
-
return await executeLifecycle(command, mergedArgs, {
|
|
2654
|
-
handleSignals: options.handleSignals,
|
|
2655
|
-
captureLogs: options.captureLogs,
|
|
2656
|
-
existingLogs: getCurrentLogs(),
|
|
2657
|
-
globalCleanup: options._globalCleanup
|
|
2658
|
-
});
|
|
2659
|
-
} catch (error) {
|
|
2660
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
2661
|
-
collector?.stop();
|
|
2662
|
-
return {
|
|
2663
|
-
success: false,
|
|
2664
|
-
error: err,
|
|
2665
|
-
exitCode: 1,
|
|
2666
|
-
logs: getCurrentLogs()
|
|
2667
|
-
};
|
|
2668
|
-
}
|
|
2669
|
-
}
|
|
2670
|
-
/**
|
|
2671
|
-
* Extract global fields from options.globalArgs and validate the schema upfront.
|
|
2672
|
-
* Rejects positional fields since global options must be flags.
|
|
2673
|
-
* Returns undefined when no globalArgs is provided.
|
|
2674
|
-
*/
|
|
2675
|
-
function extractAndValidateGlobal(options) {
|
|
2676
|
-
if (!options.globalArgs) return void 0;
|
|
2677
|
-
const extracted = require_schema_extractor.extractFields(options.globalArgs);
|
|
2678
|
-
if (!options.skipValidation) {
|
|
2679
|
-
validateDuplicateFields(extracted);
|
|
2680
|
-
validateCaseVariantCollisions(extracted);
|
|
2681
|
-
validateDuplicateAliases(extracted);
|
|
2682
|
-
validateDuplicateNegations(extracted);
|
|
2683
|
-
validateReservedAliases(extracted, true);
|
|
2684
|
-
const positionalNames = extracted.fields.filter((f) => f.positional).map((f) => f.name);
|
|
2685
|
-
if (positionalNames.length > 0) throw new Error(`Global options schema must not contain positional arguments. Found: ${positionalNames.join(", ")}`);
|
|
2686
|
-
}
|
|
2687
|
-
return extracted;
|
|
2688
|
-
}
|
|
2689
|
-
|
|
2690
|
-
//#endregion
|
|
2691
|
-
Object.defineProperty(exports, 'CaseVariantCollisionError', {
|
|
2692
|
-
enumerable: true,
|
|
2693
|
-
get: function () {
|
|
2694
|
-
return CaseVariantCollisionError;
|
|
2695
|
-
}
|
|
2696
|
-
});
|
|
2697
|
-
Object.defineProperty(exports, 'DuplicateAliasError', {
|
|
2698
|
-
enumerable: true,
|
|
2699
|
-
get: function () {
|
|
2700
|
-
return DuplicateAliasError;
|
|
2701
|
-
}
|
|
2702
|
-
});
|
|
2703
|
-
Object.defineProperty(exports, 'DuplicateFieldError', {
|
|
2704
|
-
enumerable: true,
|
|
2705
|
-
get: function () {
|
|
2706
|
-
return DuplicateFieldError;
|
|
2707
|
-
}
|
|
2708
|
-
});
|
|
2709
|
-
Object.defineProperty(exports, 'DuplicateNegationError', {
|
|
2710
|
-
enumerable: true,
|
|
2711
|
-
get: function () {
|
|
2712
|
-
return DuplicateNegationError;
|
|
2713
|
-
}
|
|
2714
|
-
});
|
|
2715
|
-
Object.defineProperty(exports, 'PositionalConfigError', {
|
|
2716
|
-
enumerable: true,
|
|
2717
|
-
get: function () {
|
|
2718
|
-
return PositionalConfigError;
|
|
2719
|
-
}
|
|
2720
|
-
});
|
|
2721
|
-
Object.defineProperty(exports, 'ReservedAliasError', {
|
|
2722
|
-
enumerable: true,
|
|
2723
|
-
get: function () {
|
|
2724
|
-
return ReservedAliasError;
|
|
2725
|
-
}
|
|
2726
|
-
});
|
|
2727
|
-
Object.defineProperty(exports, 'createDualCaseProxy', {
|
|
2728
|
-
enumerable: true,
|
|
2729
|
-
get: function () {
|
|
2730
|
-
return createDualCaseProxy;
|
|
2731
|
-
}
|
|
2732
|
-
});
|
|
2733
|
-
Object.defineProperty(exports, 'formatCommandValidationErrors', {
|
|
2734
|
-
enumerable: true,
|
|
2735
|
-
get: function () {
|
|
2736
|
-
return formatCommandValidationErrors;
|
|
2737
|
-
}
|
|
2738
|
-
});
|
|
2739
|
-
Object.defineProperty(exports, 'formatValidationErrors', {
|
|
2740
|
-
enumerable: true,
|
|
2741
|
-
get: function () {
|
|
2742
|
-
return formatValidationErrors;
|
|
2743
|
-
}
|
|
2744
|
-
});
|
|
2745
|
-
Object.defineProperty(exports, 'generateHelp', {
|
|
2746
|
-
enumerable: true,
|
|
2747
|
-
get: function () {
|
|
2748
|
-
return generateHelp;
|
|
2749
|
-
}
|
|
2750
|
-
});
|
|
2751
|
-
Object.defineProperty(exports, 'isColorEnabled', {
|
|
2752
|
-
enumerable: true,
|
|
2753
|
-
get: function () {
|
|
2754
|
-
return isColorEnabled;
|
|
2755
|
-
}
|
|
2756
|
-
});
|
|
2757
|
-
Object.defineProperty(exports, 'logger', {
|
|
2758
|
-
enumerable: true,
|
|
2759
|
-
get: function () {
|
|
2760
|
-
return logger;
|
|
2761
|
-
}
|
|
2762
|
-
});
|
|
2763
|
-
Object.defineProperty(exports, 'parseArgv', {
|
|
2764
|
-
enumerable: true,
|
|
2765
|
-
get: function () {
|
|
2766
|
-
return parseArgv;
|
|
2767
|
-
}
|
|
2768
|
-
});
|
|
2769
|
-
Object.defineProperty(exports, 'renderInline', {
|
|
2770
|
-
enumerable: true,
|
|
2771
|
-
get: function () {
|
|
2772
|
-
return renderInline;
|
|
2773
|
-
}
|
|
2774
|
-
});
|
|
2775
|
-
Object.defineProperty(exports, 'renderMarkdown', {
|
|
2776
|
-
enumerable: true,
|
|
2777
|
-
get: function () {
|
|
2778
|
-
return renderMarkdown;
|
|
2779
|
-
}
|
|
2780
|
-
});
|
|
2781
|
-
Object.defineProperty(exports, 'runCommand', {
|
|
2782
|
-
enumerable: true,
|
|
2783
|
-
get: function () {
|
|
2784
|
-
return runCommand;
|
|
2785
|
-
}
|
|
2786
|
-
});
|
|
2787
|
-
Object.defineProperty(exports, 'runMain', {
|
|
2788
|
-
enumerable: true,
|
|
2789
|
-
get: function () {
|
|
2790
|
-
return runMain;
|
|
2791
|
-
}
|
|
2792
|
-
});
|
|
2793
|
-
Object.defineProperty(exports, 'runner_exports', {
|
|
2794
|
-
enumerable: true,
|
|
2795
|
-
get: function () {
|
|
2796
|
-
return runner_exports;
|
|
2797
|
-
}
|
|
2798
|
-
});
|
|
2799
|
-
Object.defineProperty(exports, 'setColorEnabled', {
|
|
2800
|
-
enumerable: true,
|
|
2801
|
-
get: function () {
|
|
2802
|
-
return setColorEnabled;
|
|
2803
|
-
}
|
|
2804
|
-
});
|
|
2805
|
-
Object.defineProperty(exports, 'styles', {
|
|
2806
|
-
enumerable: true,
|
|
2807
|
-
get: function () {
|
|
2808
|
-
return styles;
|
|
2809
|
-
}
|
|
2810
|
-
});
|
|
2811
|
-
Object.defineProperty(exports, 'symbols', {
|
|
2812
|
-
enumerable: true,
|
|
2813
|
-
get: function () {
|
|
2814
|
-
return symbols;
|
|
2815
|
-
}
|
|
2816
|
-
});
|
|
2817
|
-
Object.defineProperty(exports, 'validateCaseVariantCollisions', {
|
|
2818
|
-
enumerable: true,
|
|
2819
|
-
get: function () {
|
|
2820
|
-
return validateCaseVariantCollisions;
|
|
2821
|
-
}
|
|
2822
|
-
});
|
|
2823
|
-
Object.defineProperty(exports, 'validateCommand', {
|
|
2824
|
-
enumerable: true,
|
|
2825
|
-
get: function () {
|
|
2826
|
-
return validateCommand;
|
|
2827
|
-
}
|
|
2828
|
-
});
|
|
2829
|
-
Object.defineProperty(exports, 'validateCrossSchemaCollisions', {
|
|
2830
|
-
enumerable: true,
|
|
2831
|
-
get: function () {
|
|
2832
|
-
return validateCrossSchemaCollisions;
|
|
2833
|
-
}
|
|
2834
|
-
});
|
|
2835
|
-
Object.defineProperty(exports, 'validateDuplicateAliases', {
|
|
2836
|
-
enumerable: true,
|
|
2837
|
-
get: function () {
|
|
2838
|
-
return validateDuplicateAliases;
|
|
2839
|
-
}
|
|
2840
|
-
});
|
|
2841
|
-
Object.defineProperty(exports, 'validateDuplicateFields', {
|
|
2842
|
-
enumerable: true,
|
|
2843
|
-
get: function () {
|
|
2844
|
-
return validateDuplicateFields;
|
|
2845
|
-
}
|
|
2846
|
-
});
|
|
2847
|
-
Object.defineProperty(exports, 'validateDuplicateNegations', {
|
|
2848
|
-
enumerable: true,
|
|
2849
|
-
get: function () {
|
|
2850
|
-
return validateDuplicateNegations;
|
|
2851
|
-
}
|
|
2852
|
-
});
|
|
2853
|
-
Object.defineProperty(exports, 'validatePositionalConfig', {
|
|
2854
|
-
enumerable: true,
|
|
2855
|
-
get: function () {
|
|
2856
|
-
return validatePositionalConfig;
|
|
2857
|
-
}
|
|
2858
|
-
});
|
|
2859
|
-
Object.defineProperty(exports, 'validateReservedAliases', {
|
|
2860
|
-
enumerable: true,
|
|
2861
|
-
get: function () {
|
|
2862
|
-
return validateReservedAliases;
|
|
2863
|
-
}
|
|
2864
|
-
});
|
|
2865
|
-
//# sourceMappingURL=runner-DvFvokV6.cjs.map
|