@alcyone-labs/arg-parser 1.0.0 → 1.1.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/README.md +844 -45
- package/dist/examples/fuzzy-demo.d.ts +8 -0
- package/dist/examples/fuzzy-demo.d.ts.map +1 -0
- package/dist/examples/fuzzy-test-example.d.ts +8 -0
- package/dist/examples/fuzzy-test-example.d.ts.map +1 -0
- package/dist/examples/fzf-search-cli.d.ts +8 -0
- package/dist/examples/fzf-search-cli.d.ts.map +1 -0
- package/dist/examples/getting-started.d.ts +27 -0
- package/dist/examples/getting-started.d.ts.map +1 -0
- package/dist/examples/mcp-preset-transports.d.ts +19 -0
- package/dist/examples/mcp-preset-transports.d.ts.map +1 -0
- package/dist/examples/simple-cli.d.ts +26 -0
- package/dist/examples/simple-cli.d.ts.map +1 -0
- package/dist/examples/v1.1.0-showcase.d.ts +16 -0
- package/dist/examples/v1.1.0-showcase.d.ts.map +1 -0
- package/dist/examples/with-env-example.d.ts +3 -0
- package/dist/examples/with-env-example.d.ts.map +1 -0
- package/dist/index-6G9StDO_.js +6445 -0
- package/dist/index-6G9StDO_.js.map +1 -0
- package/dist/index-CqU7Fj3C.cjs +6444 -0
- package/dist/index-CqU7Fj3C.cjs.map +1 -0
- package/dist/index-Dx_q1msW.js +4682 -0
- package/dist/index-Dx_q1msW.js.map +1 -0
- package/dist/index.cjs +1704 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.min.mjs +1628 -484
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +1660 -59
- package/dist/index.mjs.map +1 -1
- package/dist/src/ArgParser.d.ts +156 -0
- package/dist/src/ArgParser.d.ts.map +1 -0
- package/dist/{ArgParser.d.ts → src/ArgParserBase.d.ts} +20 -13
- package/dist/src/ArgParserBase.d.ts.map +1 -0
- package/dist/{FlagManager.d.ts → src/FlagManager.d.ts} +1 -1
- package/dist/src/FlagManager.d.ts.map +1 -0
- package/dist/src/fuzzy-test-cli.d.ts +5 -0
- package/dist/src/fuzzy-test-cli.d.ts.map +1 -0
- package/dist/src/fuzzy-tester.d.ts +101 -0
- package/dist/src/fuzzy-tester.d.ts.map +1 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/mcp-integration.d.ts +31 -0
- package/dist/src/mcp-integration.d.ts.map +1 -0
- package/dist/src/types.d.ts +154 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/sse-B5Jf_YpG.cjs +121 -0
- package/dist/sse-B5Jf_YpG.cjs.map +1 -0
- package/dist/sse-BDL3h2Ll.js +121 -0
- package/dist/sse-BDL3h2Ll.js.map +1 -0
- package/dist/sse-DSjLfGFo.js +107 -0
- package/dist/sse-DSjLfGFo.js.map +1 -0
- package/dist/stdio-Cf19UQO7.js +70 -0
- package/dist/stdio-Cf19UQO7.js.map +1 -0
- package/dist/stdio-DESvSONI.cjs +94 -0
- package/dist/stdio-DESvSONI.cjs.map +1 -0
- package/dist/stdio-DLOResWr.js +94 -0
- package/dist/stdio-DLOResWr.js.map +1 -0
- package/dist/streamableHttp-DXIdDSbF.js +342 -0
- package/dist/streamableHttp-DXIdDSbF.js.map +1 -0
- package/dist/streamableHttp-DsXlAnqJ.cjs +456 -0
- package/dist/streamableHttp-DsXlAnqJ.cjs.map +1 -0
- package/dist/streamableHttp-Vd4Qsgko.js +456 -0
- package/dist/streamableHttp-Vd4Qsgko.js.map +1 -0
- package/dist/types-DSxPEImy.cjs +943 -0
- package/dist/types-DSxPEImy.cjs.map +1 -0
- package/dist/types-DdsPVLQ5.js +846 -0
- package/dist/types-DdsPVLQ5.js.map +1 -0
- package/dist/types-DpK81FWv.js +944 -0
- package/dist/types-DpK81FWv.js.map +1 -0
- package/package.json +18 -7
- package/dist/ArgParser.d.ts.map +0 -1
- package/dist/FlagManager.d.ts.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/types.d.ts +0 -91
- package/dist/types.d.ts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -6,11 +6,15 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
|
|
|
6
6
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
7
7
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
8
8
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
9
|
-
var __flags, _throwForDuplicateFlags, _appName, _appCommandName, _subCommandName, _parameters, _handler, _throwForDuplicateFlags2, _description, _handleErrors, _parentParser, _lastParseResult, _inheritParentFlags, _subCommands, _flagManager,
|
|
9
|
+
var __flags, _throwForDuplicateFlags, _appName, _appCommandName, _subCommandName, _parameters, _handler, _throwForDuplicateFlags2, _description, _handleErrors, _parentParser, _lastParseResult, _inheritParentFlags, _subCommands, _flagManager, _fuzzyMode, _ArgParserBase_instances, _identifyCommandChainAndParsers_fn, _handleGlobalChecks_fn, _validateMandatoryFlags_fn, _applyDefaultValues_fn, _prepareAndExecuteHandler_fn, parseFlags_fn, _enableFuzzyMode_fn, displayErrorAndExit_fn, _printRecursiveToConsole_fn, _buildRecursiveString_fn, _buildRecursiveJson_fn, _generateDefaultEnvFileName_fn, _handleSaveToEnvFlag_fn, _saveToEnvFile_fn, _loadEnvFile_fn, _parseEnvFile_fn, _parseYamlFile_fn, _parseJsonFile_fn, _parseTomlFile_fn, _convertConfigToFlagValues_fn, _convertValueToFlagType_fn, _mergeEnvConfigWithArgs_fn, _generateEnvFormat_fn, _generateYamlFormat_fn, _generateJsonFormat_fn, _generateTomlFormat_fn, _getTypeString_fn, _ArgParser_instances, _startSingleTransport_fn;
|
|
10
|
+
import * as fs from "node:fs";
|
|
11
|
+
import * as path from "node:path";
|
|
10
12
|
import chalk from "chalk";
|
|
11
13
|
import { createRegExp, anyOf, oneOrMore, char } from "magic-regexp";
|
|
14
|
+
import * as yaml from "js-yaml";
|
|
15
|
+
import * as toml from "@iarna/toml";
|
|
16
|
+
import * as dotenv from "dotenv";
|
|
12
17
|
import { z } from "zod";
|
|
13
|
-
const path = {};
|
|
14
18
|
const zodFlagSchema = z.object({
|
|
15
19
|
name: z.string().min(1, "Flag name cannot be empty").describe(
|
|
16
20
|
"The output property name, used as a return key `{name: value}`. Must be unique."
|
|
@@ -35,14 +39,17 @@ const zodFlagSchema = z.object({
|
|
|
35
39
|
message: "Must be Boolean constructor"
|
|
36
40
|
}),
|
|
37
41
|
z.any().refine((val) => val === Array, {
|
|
42
|
+
// Native Array constructor
|
|
38
43
|
message: "Must be Array constructor"
|
|
39
44
|
}),
|
|
40
45
|
z.any().refine((val) => val === Object, {
|
|
46
|
+
// Native Object constructor
|
|
41
47
|
message: "Must be Object constructor"
|
|
42
48
|
}),
|
|
43
49
|
z.function().args(z.string()).returns(z.any()),
|
|
44
|
-
// Custom parser function
|
|
50
|
+
// Custom parser function (value: string) => any
|
|
45
51
|
z.string().refine(
|
|
52
|
+
// String literal types
|
|
46
53
|
(value) => ["boolean", "string", "number", "array", "object"].includes(
|
|
47
54
|
value.toLowerCase()
|
|
48
55
|
),
|
|
@@ -51,7 +58,7 @@ const zodFlagSchema = z.object({
|
|
|
51
58
|
}
|
|
52
59
|
)
|
|
53
60
|
]).default("string").describe(
|
|
54
|
-
"Expected data type or a custom parser function. Defaults to 'string'."
|
|
61
|
+
"Expected data type (constructor or string literal) or a custom parser function. Defaults to 'string'."
|
|
55
62
|
),
|
|
56
63
|
mandatory: z.union([z.boolean(), z.function().args(z.any()).returns(z.boolean())]).optional().describe(
|
|
57
64
|
"Makes the flag mandatory, can be a boolean or a function conditional on other args."
|
|
@@ -177,9 +184,9 @@ class ArgParserError extends Error {
|
|
|
177
184
|
this.commandChain = cmdChain;
|
|
178
185
|
}
|
|
179
186
|
}
|
|
180
|
-
const
|
|
187
|
+
const _ArgParserBase = class _ArgParserBase {
|
|
181
188
|
constructor(options = {}, initialFlags) {
|
|
182
|
-
__privateAdd(this,
|
|
189
|
+
__privateAdd(this, _ArgParserBase_instances);
|
|
183
190
|
__privateAdd(this, _appName, "Argument Parser");
|
|
184
191
|
__privateAdd(this, _appCommandName);
|
|
185
192
|
__privateAdd(this, _subCommandName, "");
|
|
@@ -198,6 +205,7 @@ const _ArgParser = class _ArgParser {
|
|
|
198
205
|
__privateAdd(this, _inheritParentFlags, false);
|
|
199
206
|
__privateAdd(this, _subCommands, /* @__PURE__ */ new Map());
|
|
200
207
|
__privateAdd(this, _flagManager);
|
|
208
|
+
__privateAdd(this, _fuzzyMode, false);
|
|
201
209
|
__privateSet(this, _appName, options.appName || "app");
|
|
202
210
|
if (options.blankSpaceWidth && !isNaN(Number(options.blankSpaceWidth)) && Number(options.blankSpaceWidth) > 20)
|
|
203
211
|
__privateGet(this, _parameters).blankSpaceWidth = Number(options.blankSpaceWidth);
|
|
@@ -247,9 +255,27 @@ const _ArgParser = class _ArgParser {
|
|
|
247
255
|
get flagNames() {
|
|
248
256
|
return __privateGet(this, _flagManager).flagNames;
|
|
249
257
|
}
|
|
258
|
+
getAppName() {
|
|
259
|
+
return __privateGet(this, _appName);
|
|
260
|
+
}
|
|
261
|
+
getAppCommandName() {
|
|
262
|
+
return __privateGet(this, _appCommandName);
|
|
263
|
+
}
|
|
264
|
+
getSubCommandName() {
|
|
265
|
+
return __privateGet(this, _subCommandName);
|
|
266
|
+
}
|
|
267
|
+
getDescription() {
|
|
268
|
+
return __privateGet(this, _description);
|
|
269
|
+
}
|
|
270
|
+
getHandler() {
|
|
271
|
+
return __privateGet(this, _handler);
|
|
272
|
+
}
|
|
273
|
+
getSubCommands() {
|
|
274
|
+
return __privateGet(this, _subCommands);
|
|
275
|
+
}
|
|
250
276
|
_addToOutput(flag, arg, output, _parseOptions) {
|
|
251
277
|
let value = arg;
|
|
252
|
-
if (flag
|
|
278
|
+
if (flag["type"] === Boolean) {
|
|
253
279
|
if (typeof arg === "boolean") {
|
|
254
280
|
value = arg;
|
|
255
281
|
} else if (typeof arg === "string") {
|
|
@@ -300,9 +326,9 @@ const _ArgParser = class _ArgParser {
|
|
|
300
326
|
throw new Error(`Sub-command '${subCommandConfig.name}' already exists`);
|
|
301
327
|
}
|
|
302
328
|
const subParser = subCommandConfig.parser;
|
|
303
|
-
if (!(subParser instanceof
|
|
329
|
+
if (!(subParser instanceof _ArgParserBase)) {
|
|
304
330
|
throw new Error(
|
|
305
|
-
`Parser for subcommand '${subCommandConfig.name}' is not an instance of
|
|
331
|
+
`Parser for subcommand '${subCommandConfig.name}' is not an instance of ArgParserBase. Please provide 'new ArgParserBase(...)' for the 'parser' property of an ISubCommand.`
|
|
306
332
|
);
|
|
307
333
|
}
|
|
308
334
|
__privateSet(subParser, _parentParser, this);
|
|
@@ -340,21 +366,21 @@ const _ArgParser = class _ArgParser {
|
|
|
340
366
|
if (filePath) {
|
|
341
367
|
try {
|
|
342
368
|
const dir = path.dirname(filePath);
|
|
343
|
-
if (!
|
|
344
|
-
|
|
369
|
+
if (!fs.existsSync(dir)) {
|
|
370
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
345
371
|
}
|
|
346
372
|
if (filePath.toLowerCase().endsWith(".json")) {
|
|
347
|
-
const outputObject = __privateMethod(this,
|
|
373
|
+
const outputObject = __privateMethod(this, _ArgParserBase_instances, _buildRecursiveJson_fn).call(this, this);
|
|
348
374
|
const jsonString = JSON.stringify(outputObject, null, 2);
|
|
349
|
-
|
|
375
|
+
fs.writeFileSync(filePath, jsonString);
|
|
350
376
|
console.log(`ArgParser configuration JSON dumped to: ${filePath}`);
|
|
351
377
|
} else {
|
|
352
|
-
const outputString = __privateMethod(this,
|
|
378
|
+
const outputString = __privateMethod(this, _ArgParserBase_instances, _buildRecursiveString_fn).call(this, this, 0);
|
|
353
379
|
const plainText = outputString.replace(
|
|
354
380
|
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
|
|
355
381
|
""
|
|
356
382
|
);
|
|
357
|
-
|
|
383
|
+
fs.writeFileSync(filePath, plainText);
|
|
358
384
|
console.log(`ArgParser configuration text dumped to: ${filePath}`);
|
|
359
385
|
}
|
|
360
386
|
} catch (error) {
|
|
@@ -365,12 +391,21 @@ const _ArgParser = class _ArgParser {
|
|
|
365
391
|
}
|
|
366
392
|
} else {
|
|
367
393
|
console.log("\n--- ArgParser Configuration Dump ---");
|
|
368
|
-
__privateMethod(this,
|
|
394
|
+
__privateMethod(this, _ArgParserBase_instances, _printRecursiveToConsole_fn).call(this, this, 0);
|
|
369
395
|
console.log("--- End Configuration Dump ---\\n");
|
|
370
396
|
}
|
|
371
397
|
}
|
|
372
398
|
parse(processArgs, options) {
|
|
373
|
-
|
|
399
|
+
var _a;
|
|
400
|
+
const originalProcessArgs = [...processArgs];
|
|
401
|
+
const shouldPreventExecution = typeof process !== "undefined" && (process.env["ARGPARSER_FUZZY_MODE"] === "true" || process.argv && process.argv.includes("--s-enable-fuzzy") && !processArgs.includes("--s-enable-fuzzy")) && !(options == null ? void 0 : options.skipHelpHandling);
|
|
402
|
+
if (shouldPreventExecution) {
|
|
403
|
+
return {
|
|
404
|
+
_fuzzyModePreventedExecution: true,
|
|
405
|
+
_originalInputArgs: originalProcessArgs
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
if (__privateMethod(this, _ArgParserBase_instances, _handleGlobalChecks_fn).call(this, processArgs, options)) {
|
|
374
409
|
return {};
|
|
375
410
|
}
|
|
376
411
|
try {
|
|
@@ -378,25 +413,34 @@ const _ArgParser = class _ArgParser {
|
|
|
378
413
|
finalParser: identifiedFinalParser,
|
|
379
414
|
commandChain: identifiedCommandChain,
|
|
380
415
|
parserChain: identifiedParserChain
|
|
381
|
-
} = __privateMethod(this,
|
|
416
|
+
} = __privateMethod(this, _ArgParserBase_instances, _identifyCommandChainAndParsers_fn).call(this, processArgs, this, [], [this]);
|
|
417
|
+
if (__privateMethod(_a = identifiedFinalParser, _ArgParserBase_instances, _handleSaveToEnvFlag_fn).call(_a, processArgs, identifiedParserChain)) {
|
|
418
|
+
return {};
|
|
419
|
+
}
|
|
382
420
|
const { finalArgs, handlerToExecute } = this._parseRecursive(
|
|
383
421
|
processArgs,
|
|
384
422
|
this,
|
|
385
423
|
{},
|
|
386
424
|
[],
|
|
387
|
-
options
|
|
425
|
+
options,
|
|
426
|
+
void 0
|
|
388
427
|
);
|
|
389
428
|
if (identifiedCommandChain.length > 0) {
|
|
390
429
|
finalArgs.$commandChain = identifiedCommandChain;
|
|
391
430
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
431
|
+
if (__privateGet(this, _fuzzyMode)) {
|
|
432
|
+
finalArgs._originalInputArgs = originalProcessArgs;
|
|
433
|
+
}
|
|
434
|
+
if (!__privateGet(this, _fuzzyMode)) {
|
|
435
|
+
__privateMethod(this, _ArgParserBase_instances, _validateMandatoryFlags_fn).call(this, finalArgs, identifiedParserChain, identifiedCommandChain);
|
|
436
|
+
}
|
|
437
|
+
__privateMethod(this, _ArgParserBase_instances, _applyDefaultValues_fn).call(this, finalArgs, identifiedFinalParser);
|
|
438
|
+
__privateMethod(this, _ArgParserBase_instances, _prepareAndExecuteHandler_fn).call(this, handlerToExecute, finalArgs, (options == null ? void 0 : options.skipHandlers) ?? false);
|
|
395
439
|
return finalArgs;
|
|
396
440
|
} catch (error) {
|
|
397
441
|
if (error instanceof ArgParserError) {
|
|
398
442
|
if (__privateGet(this, _handleErrors)) {
|
|
399
|
-
__privateMethod(this,
|
|
443
|
+
__privateMethod(this, _ArgParserBase_instances, displayErrorAndExit_fn).call(this, error);
|
|
400
444
|
return {};
|
|
401
445
|
} else {
|
|
402
446
|
throw error;
|
|
@@ -410,7 +454,7 @@ const _ArgParser = class _ArgParser {
|
|
|
410
454
|
* Recursive helper for parsing arguments and handling sub-commands.
|
|
411
455
|
* This method assumes the global help check has already been performed in `parse`.
|
|
412
456
|
*/
|
|
413
|
-
_parseRecursive(argsToParse, currentParser, accumulatedParentArgs, commandChainSoFar, options) {
|
|
457
|
+
_parseRecursive(argsToParse, currentParser, accumulatedParentArgs, commandChainSoFar, options, parentParser) {
|
|
414
458
|
var _a, _b;
|
|
415
459
|
let subCommandIndex = -1;
|
|
416
460
|
let subCommandName = null;
|
|
@@ -423,8 +467,8 @@ const _ArgParser = class _ArgParser {
|
|
|
423
467
|
}
|
|
424
468
|
}
|
|
425
469
|
const argsForCurrentLevel = subCommandIndex === -1 ? argsToParse : argsToParse.slice(0, subCommandIndex);
|
|
426
|
-
const { parsedArgs: currentLevelArgs, firstUnconsumedIndex } = __privateMethod(_a = currentParser,
|
|
427
|
-
__privateMethod(_b = currentParser,
|
|
470
|
+
const { parsedArgs: currentLevelArgs, firstUnconsumedIndex } = __privateMethod(_a = currentParser, _ArgParserBase_instances, parseFlags_fn).call(_a, argsForCurrentLevel, options);
|
|
471
|
+
__privateMethod(_b = currentParser, _ArgParserBase_instances, _applyDefaultValues_fn).call(_b, currentLevelArgs, currentParser);
|
|
428
472
|
const combinedArgsFromThisAndParents = {
|
|
429
473
|
...accumulatedParentArgs,
|
|
430
474
|
...currentLevelArgs
|
|
@@ -449,7 +493,8 @@ const _ArgParser = class _ArgParser {
|
|
|
449
493
|
args: currentLevelArgs,
|
|
450
494
|
parentArgs: accumulatedParentArgs,
|
|
451
495
|
commandChain: commandChainSoFar,
|
|
452
|
-
parser: currentParser
|
|
496
|
+
parser: currentParser,
|
|
497
|
+
parentParser
|
|
453
498
|
}
|
|
454
499
|
};
|
|
455
500
|
}
|
|
@@ -463,7 +508,7 @@ const _ArgParser = class _ArgParser {
|
|
|
463
508
|
);
|
|
464
509
|
}
|
|
465
510
|
const subCommandConfig = __privateGet(currentParser, _subCommands).get(subCommandName);
|
|
466
|
-
if (!subCommandConfig || !(subCommandConfig.parser instanceof
|
|
511
|
+
if (!subCommandConfig || !(subCommandConfig.parser instanceof _ArgParserBase)) {
|
|
467
512
|
throw new ArgParserError(
|
|
468
513
|
`Internal error: Subcommand '${subCommandName}' is misconfigured or its parser is not a valid ArgParser instance.`,
|
|
469
514
|
commandChainSoFar
|
|
@@ -481,7 +526,8 @@ const _ArgParser = class _ArgParser {
|
|
|
481
526
|
nextParser,
|
|
482
527
|
combinedArgsForNextLevel,
|
|
483
528
|
nextCommandChain,
|
|
484
|
-
options
|
|
529
|
+
options,
|
|
530
|
+
currentParser
|
|
485
531
|
);
|
|
486
532
|
}
|
|
487
533
|
helpText() {
|
|
@@ -513,7 +559,7 @@ const _ArgParser = class _ArgParser {
|
|
|
513
559
|
`;
|
|
514
560
|
help += Array.from(__privateGet(this, _subCommands).entries()).sort(([nameA], [nameB]) => nameA.localeCompare(nameB)).map(([name, subCommandConfig]) => {
|
|
515
561
|
const actualSubParserInstance = subCommandConfig.parser;
|
|
516
|
-
if (!(actualSubParserInstance instanceof
|
|
562
|
+
if (!(actualSubParserInstance instanceof _ArgParserBase)) {
|
|
517
563
|
return `${indent()}${green(name.padEnd(20))} [Error: Subcommand '${name}' has an invalid parser configuration]`;
|
|
518
564
|
}
|
|
519
565
|
let subHelp = `${indent()}${green(name.padEnd(20))} ${white(__privateGet(actualSubParserInstance, _description) || "")}`;
|
|
@@ -556,7 +602,7 @@ ${cyan("Flags:")}
|
|
|
556
602
|
const localFlags = __privateGet(this, _flagManager).flags;
|
|
557
603
|
if (localFlags.length > 0) {
|
|
558
604
|
help += localFlags.sort((flagA, flagB) => flagA["name"].localeCompare(flagB["name"])).map((flag) => {
|
|
559
|
-
const optionsText = flag["options"].
|
|
605
|
+
const optionsText = flag["options"].slice().sort((a, b) => a.length - b.length).map((opt) => green(opt)).join(", ");
|
|
560
606
|
const isMandatory = typeof flag.mandatory === "function" ? "dynamic" : flag.mandatory;
|
|
561
607
|
const mandatoryIndicator = isMandatory === true ? ` ${red(__privateGet(this, _parameters).mandatoryCharacter)}` : isMandatory === "dynamic" ? ` ${dim("(conditionally mandatory)")}` : "";
|
|
562
608
|
const descriptionLines = Array.isArray(flag["description"]) ? flag["description"] : [flag["description"]];
|
|
@@ -636,7 +682,8 @@ _lastParseResult = new WeakMap();
|
|
|
636
682
|
_inheritParentFlags = new WeakMap();
|
|
637
683
|
_subCommands = new WeakMap();
|
|
638
684
|
_flagManager = new WeakMap();
|
|
639
|
-
|
|
685
|
+
_fuzzyMode = new WeakMap();
|
|
686
|
+
_ArgParserBase_instances = new WeakSet();
|
|
640
687
|
_identifyCommandChainAndParsers_fn = function(argsToParse, currentParser, commandChainSoFar, parserChainSoFar) {
|
|
641
688
|
let subCommandIndex = -1;
|
|
642
689
|
let subCommandName = null;
|
|
@@ -657,7 +704,7 @@ _identifyCommandChainAndParsers_fn = function(argsToParse, currentParser, comman
|
|
|
657
704
|
};
|
|
658
705
|
}
|
|
659
706
|
const subCommandConfig = __privateGet(currentParser, _subCommands).get(subCommandName);
|
|
660
|
-
if (!subCommandConfig || !(subCommandConfig.parser instanceof
|
|
707
|
+
if (!subCommandConfig || !(subCommandConfig.parser instanceof _ArgParserBase)) {
|
|
661
708
|
throw new Error(
|
|
662
709
|
`Internal error: Subcommand '${subCommandName}' configuration is invalid or parser is missing.`
|
|
663
710
|
);
|
|
@@ -666,33 +713,72 @@ _identifyCommandChainAndParsers_fn = function(argsToParse, currentParser, comman
|
|
|
666
713
|
const nextArgs = argsToParse.slice(subCommandIndex + 1);
|
|
667
714
|
const nextCommandChain = [...commandChainSoFar, subCommandName];
|
|
668
715
|
const nextParserChain = [...parserChainSoFar, nextParser];
|
|
669
|
-
return __privateMethod(this,
|
|
716
|
+
return __privateMethod(this, _ArgParserBase_instances, _identifyCommandChainAndParsers_fn).call(this, nextArgs, nextParser, nextCommandChain, nextParserChain);
|
|
670
717
|
};
|
|
671
718
|
_handleGlobalChecks_fn = function(processArgs, options) {
|
|
672
|
-
var _a, _b, _c, _d;
|
|
673
|
-
|
|
719
|
+
var _a, _b, _c, _d, _e, _f;
|
|
720
|
+
const isRootCliParser = !__privateGet(this, _parentParser) && !!__privateGet(this, _appCommandName);
|
|
721
|
+
if (processArgs.length === 0 && isRootCliParser && !__privateGet(this, _handler)) {
|
|
674
722
|
console.log(this.helpText());
|
|
675
723
|
if (typeof process === "object" && typeof process.exit === "function") {
|
|
676
724
|
process.exit(0);
|
|
677
725
|
}
|
|
678
726
|
return true;
|
|
679
727
|
}
|
|
680
|
-
if (processArgs.includes("--
|
|
728
|
+
if (processArgs.includes("--s-debug-print")) {
|
|
681
729
|
this.printAll("ArgParser.full.json");
|
|
682
730
|
if (typeof process === "object" && typeof process.exit === "function") {
|
|
683
731
|
process.exit(0);
|
|
684
732
|
}
|
|
685
733
|
return true;
|
|
686
734
|
}
|
|
687
|
-
|
|
688
|
-
|
|
735
|
+
if (processArgs.includes("--s-enable-fuzzy")) {
|
|
736
|
+
__privateMethod(this, _ArgParserBase_instances, _enableFuzzyMode_fn).call(this);
|
|
737
|
+
const fuzzyIndex = processArgs.indexOf("--s-enable-fuzzy");
|
|
738
|
+
processArgs.splice(fuzzyIndex, 1);
|
|
739
|
+
}
|
|
740
|
+
const withEnvIndex = processArgs.findIndex((arg) => arg === "--s-with-env");
|
|
741
|
+
if (withEnvIndex !== -1) {
|
|
742
|
+
if (withEnvIndex + 1 >= processArgs.length) {
|
|
743
|
+
console.error(chalk.red("Error: --s-with-env requires a file path argument"));
|
|
744
|
+
if (typeof process === "object" && typeof process.exit === "function") {
|
|
745
|
+
process.exit(1);
|
|
746
|
+
}
|
|
747
|
+
return true;
|
|
748
|
+
}
|
|
749
|
+
const filePath = processArgs[withEnvIndex + 1];
|
|
750
|
+
if (!filePath || filePath.startsWith("-")) {
|
|
751
|
+
console.error(chalk.red("Error: --s-with-env requires a file path argument"));
|
|
752
|
+
if (typeof process === "object" && typeof process.exit === "function") {
|
|
753
|
+
process.exit(1);
|
|
754
|
+
}
|
|
755
|
+
return true;
|
|
756
|
+
}
|
|
757
|
+
try {
|
|
758
|
+
const { finalParser: identifiedFinalParser2, parserChain: identifiedParserChain } = __privateMethod(this, _ArgParserBase_instances, _identifyCommandChainAndParsers_fn).call(this, processArgs, this, [], [this]);
|
|
759
|
+
const envConfigArgs = __privateMethod(_a = identifiedFinalParser2, _ArgParserBase_instances, _loadEnvFile_fn).call(_a, filePath, identifiedParserChain);
|
|
760
|
+
if (envConfigArgs) {
|
|
761
|
+
const mergedArgs = __privateMethod(_b = identifiedFinalParser2, _ArgParserBase_instances, _mergeEnvConfigWithArgs_fn).call(_b, envConfigArgs, processArgs);
|
|
762
|
+
processArgs.length = 0;
|
|
763
|
+
processArgs.push(...mergedArgs);
|
|
764
|
+
}
|
|
765
|
+
} catch (error) {
|
|
766
|
+
console.error(chalk.red(`Error loading environment file: ${error instanceof Error ? error.message : String(error)}`));
|
|
767
|
+
if (typeof process === "object" && typeof process.exit === "function") {
|
|
768
|
+
process.exit(1);
|
|
769
|
+
}
|
|
770
|
+
return true;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
const { finalParser: identifiedFinalParser } = __privateMethod(this, _ArgParserBase_instances, _identifyCommandChainAndParsers_fn).call(this, processArgs, this, [], [this]);
|
|
774
|
+
if (processArgs.includes("--s-debug")) {
|
|
689
775
|
console.log(
|
|
690
|
-
chalk.yellow.bold("\n--- ArgParser --
|
|
776
|
+
chalk.yellow.bold("\n--- ArgParser --s-debug Runtime Context ---")
|
|
691
777
|
);
|
|
692
778
|
const {
|
|
693
779
|
commandChain: identifiedCommandChain,
|
|
694
780
|
parserChain: _identifiedParserChain
|
|
695
|
-
} = __privateMethod(this,
|
|
781
|
+
} = __privateMethod(this, _ArgParserBase_instances, _identifyCommandChainAndParsers_fn).call(this, processArgs, this, [], [this]);
|
|
696
782
|
console.log(
|
|
697
783
|
`Identified Command Chain: ${chalk.cyan(identifiedCommandChain.join(" -> ") || "(root)")}`
|
|
698
784
|
);
|
|
@@ -709,7 +795,7 @@ _handleGlobalChecks_fn = function(processArgs, options) {
|
|
|
709
795
|
const rootArgsSlice = rootSubCommandIndex === -1 ? remainingArgs : remainingArgs.slice(0, rootSubCommandIndex);
|
|
710
796
|
parsingSteps.push({ level: "(root)", argsSlice: rootArgsSlice });
|
|
711
797
|
try {
|
|
712
|
-
const { parsedArgs: rootParsedArgs } = __privateMethod(
|
|
798
|
+
const { parsedArgs: rootParsedArgs } = __privateMethod(_c = currentParser, _ArgParserBase_instances, parseFlags_fn).call(_c, rootArgsSlice, { skipHelpHandling: true });
|
|
713
799
|
parsingSteps[0].parsed = rootParsedArgs;
|
|
714
800
|
accumulatedArgs = { ...accumulatedArgs, ...rootParsedArgs };
|
|
715
801
|
} catch (e) {
|
|
@@ -726,7 +812,7 @@ _handleGlobalChecks_fn = function(processArgs, options) {
|
|
|
726
812
|
});
|
|
727
813
|
break;
|
|
728
814
|
}
|
|
729
|
-
currentParser = (
|
|
815
|
+
currentParser = (_d = __privateGet(currentParser, _subCommands).get(subCommandName)) == null ? void 0 : _d.parser;
|
|
730
816
|
remainingArgs = remainingArgs.slice(1);
|
|
731
817
|
const nextSubCommandIndex = remainingArgs.findIndex(
|
|
732
818
|
(arg) => __privateGet(currentParser, _subCommands).has(arg)
|
|
@@ -738,7 +824,7 @@ _handleGlobalChecks_fn = function(processArgs, options) {
|
|
|
738
824
|
};
|
|
739
825
|
parsingSteps.push(stepInfo);
|
|
740
826
|
try {
|
|
741
|
-
const { parsedArgs: currentLevelParsedArgs } = __privateMethod(
|
|
827
|
+
const { parsedArgs: currentLevelParsedArgs } = __privateMethod(_e = currentParser, _ArgParserBase_instances, parseFlags_fn).call(_e, currentLevelArgsSlice, {
|
|
742
828
|
skipHelpHandling: true
|
|
743
829
|
});
|
|
744
830
|
stepInfo.parsed = currentLevelParsedArgs;
|
|
@@ -779,21 +865,21 @@ _handleGlobalChecks_fn = function(processArgs, options) {
|
|
|
779
865
|
)
|
|
780
866
|
);
|
|
781
867
|
identifiedFinalParser.printAll();
|
|
782
|
-
console.log(chalk.yellow.bold("--- End ArgParser --
|
|
868
|
+
console.log(chalk.yellow.bold("--- End ArgParser --s-debug ---"));
|
|
783
869
|
if (typeof process === "object" && typeof process.exit === "function") {
|
|
784
870
|
process.exit(0);
|
|
785
871
|
}
|
|
786
872
|
return true;
|
|
787
873
|
}
|
|
788
874
|
let parserNameForLog = "undefined_parser";
|
|
789
|
-
if (identifiedFinalParser instanceof
|
|
875
|
+
if (identifiedFinalParser instanceof _ArgParserBase) {
|
|
790
876
|
parserNameForLog = identifiedFinalParser["#subCommandName"] || identifiedFinalParser["#appName"];
|
|
791
877
|
} else if (identifiedFinalParser) {
|
|
792
878
|
parserNameForLog = identifiedFinalParser.name || identifiedFinalParser.appName || "unknown_type";
|
|
793
879
|
}
|
|
794
|
-
if (!(identifiedFinalParser instanceof
|
|
880
|
+
if (!(identifiedFinalParser instanceof _ArgParserBase)) {
|
|
795
881
|
console.error(
|
|
796
|
-
`[ArgParser #_handleGlobalChecks Critical Error] identifiedFinalParser is not an instance of ArgParser. Cannot process help. Name: ${parserNameForLog}, Constructor: ${identifiedFinalParser ? (
|
|
882
|
+
`[ArgParser #_handleGlobalChecks Critical Error] identifiedFinalParser is not an instance of ArgParser. Cannot process help. Name: ${parserNameForLog}, Constructor: ${identifiedFinalParser ? (_f = identifiedFinalParser.constructor) == null ? void 0 : _f.name : "undefined"}`
|
|
797
883
|
);
|
|
798
884
|
return false;
|
|
799
885
|
}
|
|
@@ -816,11 +902,27 @@ _handleGlobalChecks_fn = function(processArgs, options) {
|
|
|
816
902
|
_validateMandatoryFlags_fn = function(finalArgs, parserChain, commandChain) {
|
|
817
903
|
const finalMandatoryFlagsMissing = [];
|
|
818
904
|
const checkedFlagNames = /* @__PURE__ */ new Set();
|
|
819
|
-
|
|
905
|
+
let parsersToValidate = [...parserChain];
|
|
906
|
+
if (parserChain.length > 1) {
|
|
907
|
+
const immediateChild = parserChain[1];
|
|
908
|
+
if (!__privateGet(immediateChild, _inheritParentFlags)) {
|
|
909
|
+
parsersToValidate = parsersToValidate.slice(1);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
for (let i = 0; i < parsersToValidate.length; i++) {
|
|
913
|
+
const parser = parsersToValidate[i];
|
|
820
914
|
const currentCommandChain = parser.getCommandChain();
|
|
821
915
|
for (const flag of __privateGet(parser, _flagManager).flags) {
|
|
822
916
|
if (flag["name"] === "help" || checkedFlagNames.has(flag["name"]))
|
|
823
917
|
continue;
|
|
918
|
+
let flagIsInheritedByChild = false;
|
|
919
|
+
if (i < parsersToValidate.length - 1) {
|
|
920
|
+
const immediateChild = parsersToValidate[i + 1];
|
|
921
|
+
if (__privateGet(immediateChild, _inheritParentFlags) && __privateGet(immediateChild, _flagManager).hasFlag(flag["name"])) {
|
|
922
|
+
flagIsInheritedByChild = true;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
if (flagIsInheritedByChild) continue;
|
|
824
926
|
const isMandatory = typeof flag["mandatory"] === "function" ? flag["mandatory"](finalArgs) : flag["mandatory"];
|
|
825
927
|
if (!isMandatory) continue;
|
|
826
928
|
const value = finalArgs[flag["name"]];
|
|
@@ -869,6 +971,16 @@ _prepareAndExecuteHandler_fn = function(handlerToExecute, finalArgs, skipHandler
|
|
|
869
971
|
if (skipHandlers || !handlerToExecute) {
|
|
870
972
|
return;
|
|
871
973
|
}
|
|
974
|
+
if (__privateGet(this, _fuzzyMode)) {
|
|
975
|
+
const commandChain = handlerToExecute.context.commandChain || [];
|
|
976
|
+
const args = handlerToExecute.context.args || {};
|
|
977
|
+
const inputArgs = finalArgs._originalInputArgs || "unknown";
|
|
978
|
+
const inputArgsStr = Array.isArray(inputArgs) ? inputArgs.join(" ") : inputArgs;
|
|
979
|
+
console.log(`[--s-enable-fuzzy] handler() skipped for command chain: ${commandChain.join(" ") || "(root)"}`);
|
|
980
|
+
console.log(` Input args: [${inputArgsStr}]`);
|
|
981
|
+
console.log(` Parsed args: ${JSON.stringify(args)}`);
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
872
984
|
const finalParserWhoseHandlerWillRun = handlerToExecute.context.parser;
|
|
873
985
|
const finalParserFlags = __privateGet(finalParserWhoseHandlerWillRun, _flagManager).flags;
|
|
874
986
|
const handlerArgs = handlerToExecute.context.args;
|
|
@@ -881,7 +993,23 @@ _prepareAndExecuteHandler_fn = function(handlerToExecute, finalArgs, skipHandler
|
|
|
881
993
|
}
|
|
882
994
|
}
|
|
883
995
|
handlerToExecute.context.args = handlerArgs;
|
|
884
|
-
|
|
996
|
+
try {
|
|
997
|
+
const handlerResult = handlerToExecute.handler(handlerToExecute.context);
|
|
998
|
+
if (handlerResult && typeof handlerResult.then === "function") {
|
|
999
|
+
finalArgs._asyncHandlerPromise = handlerResult;
|
|
1000
|
+
finalArgs._asyncHandlerInfo = handlerToExecute;
|
|
1001
|
+
handlerResult.catch(() => {
|
|
1002
|
+
});
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
finalArgs.handlerResponse = handlerResult;
|
|
1006
|
+
} catch (error) {
|
|
1007
|
+
if (__privateGet(this, _handleErrors)) {
|
|
1008
|
+
__privateMethod(this, _ArgParserBase_instances, displayErrorAndExit_fn).call(this, new ArgParserError(`Handler error: ${error}`, []));
|
|
1009
|
+
} else {
|
|
1010
|
+
throw error;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
885
1013
|
};
|
|
886
1014
|
parseFlags_fn = function(args, options) {
|
|
887
1015
|
var _a, _b;
|
|
@@ -949,6 +1077,19 @@ parseFlags_fn = function(args, options) {
|
|
|
949
1077
|
}
|
|
950
1078
|
return { parsedArgs: output, firstUnconsumedIndex };
|
|
951
1079
|
};
|
|
1080
|
+
/**
|
|
1081
|
+
* Enables fuzzy testing mode by disabling error handling and making flags optional
|
|
1082
|
+
*/
|
|
1083
|
+
_enableFuzzyMode_fn = function() {
|
|
1084
|
+
var _a;
|
|
1085
|
+
__privateSet(this, _fuzzyMode, true);
|
|
1086
|
+
__privateSet(this, _handleErrors, false);
|
|
1087
|
+
for (const [, subCommand] of __privateGet(this, _subCommands)) {
|
|
1088
|
+
if (subCommand.parser instanceof _ArgParserBase) {
|
|
1089
|
+
__privateMethod(_a = subCommand.parser, _ArgParserBase_instances, _enableFuzzyMode_fn).call(_a);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
952
1093
|
displayErrorAndExit_fn = function(error) {
|
|
953
1094
|
let commandNameToSuggest = "your-script";
|
|
954
1095
|
if (__privateGet(this, _appCommandName)) {
|
|
@@ -961,15 +1102,11 @@ displayErrorAndExit_fn = function(error) {
|
|
|
961
1102
|
} catch {
|
|
962
1103
|
}
|
|
963
1104
|
}
|
|
964
|
-
const commandPath = [
|
|
965
|
-
commandNameToSuggest,
|
|
966
|
-
...error.commandChain || []
|
|
967
|
-
].join(" ");
|
|
968
1105
|
console.error(`
|
|
969
1106
|
${chalk.red.bold("Error:")} ${error.message}`);
|
|
970
1107
|
console.error(
|
|
971
1108
|
`
|
|
972
|
-
${chalk.dim(`Try '${
|
|
1109
|
+
${chalk.dim(`Try '${commandNameToSuggest} --help' for usage details.`)}`
|
|
973
1110
|
);
|
|
974
1111
|
if (typeof process === "object" && typeof process.exit === "function") {
|
|
975
1112
|
process.exit(1);
|
|
@@ -1036,7 +1173,7 @@ _printRecursiveToConsole_fn = function(parser, level, visited = /* @__PURE__ */
|
|
|
1036
1173
|
if (subCommandParsers.length > 0) {
|
|
1037
1174
|
console.log(`${subIndent}Sub-Commands (${subCommandParsers.length}):`);
|
|
1038
1175
|
subCommandParsers.forEach((subCommand) => {
|
|
1039
|
-
__privateMethod(this,
|
|
1176
|
+
__privateMethod(this, _ArgParserBase_instances, _printRecursiveToConsole_fn).call(this, subCommand.parser, level + 1, visited);
|
|
1040
1177
|
});
|
|
1041
1178
|
} else {
|
|
1042
1179
|
console.log(`${subIndent}Sub-Commands: ${chalk.dim("none")}`);
|
|
@@ -1117,7 +1254,7 @@ _buildRecursiveString_fn = function(parser, level, visited = /* @__PURE__ */ new
|
|
|
1117
1254
|
if (subCommandParsers.length > 0) {
|
|
1118
1255
|
addLine(`${subIndent}Sub-Commands (${subCommandParsers.length}):`);
|
|
1119
1256
|
subCommandParsers.forEach((subCommand) => {
|
|
1120
|
-
output += __privateMethod(this,
|
|
1257
|
+
output += __privateMethod(this, _ArgParserBase_instances, _buildRecursiveString_fn).call(this, subCommand.parser, level + 1, visited);
|
|
1121
1258
|
});
|
|
1122
1259
|
} else {
|
|
1123
1260
|
addLine(`${subIndent}Sub-Commands: none`);
|
|
@@ -1179,14 +1316,1478 @@ _buildRecursiveJson_fn = function(parser, visited = /* @__PURE__ */ new Set()) {
|
|
|
1179
1316
|
const subCommands = Array.from(__privateGet(parser, _subCommands).values());
|
|
1180
1317
|
if (subCommands.length > 0) {
|
|
1181
1318
|
subCommands.forEach((sub) => {
|
|
1182
|
-
config.subCommands[sub.name] = __privateMethod(this,
|
|
1319
|
+
config.subCommands[sub.name] = __privateMethod(this, _ArgParserBase_instances, _buildRecursiveJson_fn).call(this, sub.parser, visited);
|
|
1183
1320
|
});
|
|
1184
1321
|
}
|
|
1185
1322
|
return config;
|
|
1186
1323
|
};
|
|
1324
|
+
/**
|
|
1325
|
+
* Generates a default environment file name based on the app name
|
|
1326
|
+
*/
|
|
1327
|
+
_generateDefaultEnvFileName_fn = function() {
|
|
1328
|
+
let baseName = "config";
|
|
1329
|
+
if (__privateGet(this, _appCommandName)) {
|
|
1330
|
+
baseName = __privateGet(this, _appCommandName);
|
|
1331
|
+
} else if (__privateGet(this, _appName) && __privateGet(this, _appName) !== "Argument Parser") {
|
|
1332
|
+
baseName = __privateGet(this, _appName);
|
|
1333
|
+
}
|
|
1334
|
+
baseName = baseName.split(/[\s-_]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
|
|
1335
|
+
return `${baseName}.env`;
|
|
1336
|
+
};
|
|
1337
|
+
/**
|
|
1338
|
+
* Handles the --s-save-to-env system flag at the final parser level
|
|
1339
|
+
*/
|
|
1340
|
+
_handleSaveToEnvFlag_fn = function(processArgs, parserChain) {
|
|
1341
|
+
const saveToEnvIndex = processArgs.findIndex((arg) => arg === "--s-save-to-env");
|
|
1342
|
+
if (saveToEnvIndex !== -1) {
|
|
1343
|
+
let filePath;
|
|
1344
|
+
if (saveToEnvIndex + 1 < processArgs.length) {
|
|
1345
|
+
const nextArg = processArgs[saveToEnvIndex + 1];
|
|
1346
|
+
if (nextArg && !nextArg.startsWith("-")) {
|
|
1347
|
+
filePath = nextArg;
|
|
1348
|
+
} else {
|
|
1349
|
+
filePath = __privateMethod(this, _ArgParserBase_instances, _generateDefaultEnvFileName_fn).call(this);
|
|
1350
|
+
}
|
|
1351
|
+
} else {
|
|
1352
|
+
filePath = __privateMethod(this, _ArgParserBase_instances, _generateDefaultEnvFileName_fn).call(this);
|
|
1353
|
+
}
|
|
1354
|
+
try {
|
|
1355
|
+
__privateMethod(this, _ArgParserBase_instances, _saveToEnvFile_fn).call(this, filePath, processArgs, parserChain);
|
|
1356
|
+
console.log(chalk.green(`Environment configuration saved to: ${filePath}`));
|
|
1357
|
+
if (typeof process === "object" && typeof process.exit === "function") {
|
|
1358
|
+
process.exit(0);
|
|
1359
|
+
}
|
|
1360
|
+
return true;
|
|
1361
|
+
} catch (error) {
|
|
1362
|
+
console.error(chalk.red(`Error saving environment file: ${error instanceof Error ? error.message : String(error)}`));
|
|
1363
|
+
if (typeof process === "object" && typeof process.exit === "function") {
|
|
1364
|
+
process.exit(1);
|
|
1365
|
+
}
|
|
1366
|
+
return true;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
return false;
|
|
1370
|
+
};
|
|
1371
|
+
/**
|
|
1372
|
+
* Saves the current parser's flags and their values to an environment file
|
|
1373
|
+
* in the specified format based on file extension.
|
|
1374
|
+
*/
|
|
1375
|
+
_saveToEnvFile_fn = function(filePath, processArgs, parserChain) {
|
|
1376
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
1377
|
+
let format;
|
|
1378
|
+
if (ext === ".yaml" || ext === ".yml") {
|
|
1379
|
+
format = "yaml";
|
|
1380
|
+
} else if (ext === ".json" || ext === ".jsonc") {
|
|
1381
|
+
format = "json";
|
|
1382
|
+
} else if (ext === ".toml" || ext === ".tml") {
|
|
1383
|
+
format = "toml";
|
|
1384
|
+
} else {
|
|
1385
|
+
format = "env";
|
|
1386
|
+
}
|
|
1387
|
+
const allFlags = [];
|
|
1388
|
+
const seenFlagNames = /* @__PURE__ */ new Set();
|
|
1389
|
+
for (let i = parserChain.length - 1; i >= 0; i--) {
|
|
1390
|
+
const parser = parserChain[i];
|
|
1391
|
+
for (const flag of __privateGet(parser, _flagManager).flags) {
|
|
1392
|
+
if (!seenFlagNames.has(flag["name"])) {
|
|
1393
|
+
allFlags.push(flag);
|
|
1394
|
+
seenFlagNames.add(flag["name"]);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
const flags = allFlags;
|
|
1399
|
+
const { parsedArgs } = __privateMethod(this, _ArgParserBase_instances, parseFlags_fn).call(this, processArgs.filter(
|
|
1400
|
+
(arg) => arg !== "--s-save-to-env" && arg !== filePath
|
|
1401
|
+
));
|
|
1402
|
+
let content;
|
|
1403
|
+
switch (format) {
|
|
1404
|
+
case "env":
|
|
1405
|
+
content = __privateMethod(this, _ArgParserBase_instances, _generateEnvFormat_fn).call(this, flags, parsedArgs);
|
|
1406
|
+
break;
|
|
1407
|
+
case "yaml":
|
|
1408
|
+
content = __privateMethod(this, _ArgParserBase_instances, _generateYamlFormat_fn).call(this, flags, parsedArgs);
|
|
1409
|
+
break;
|
|
1410
|
+
case "json":
|
|
1411
|
+
content = __privateMethod(this, _ArgParserBase_instances, _generateJsonFormat_fn).call(this, flags, parsedArgs);
|
|
1412
|
+
break;
|
|
1413
|
+
case "toml":
|
|
1414
|
+
content = __privateMethod(this, _ArgParserBase_instances, _generateTomlFormat_fn).call(this, flags, parsedArgs);
|
|
1415
|
+
break;
|
|
1416
|
+
}
|
|
1417
|
+
const dir = path.dirname(filePath);
|
|
1418
|
+
if (!fs.existsSync(dir)) {
|
|
1419
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1420
|
+
}
|
|
1421
|
+
fs.writeFileSync(filePath, content, "utf8");
|
|
1422
|
+
};
|
|
1423
|
+
/**
|
|
1424
|
+
* Loads configuration from an environment file in various formats
|
|
1425
|
+
*/
|
|
1426
|
+
_loadEnvFile_fn = function(filePath, parserChain) {
|
|
1427
|
+
if (!fs.existsSync(filePath)) {
|
|
1428
|
+
throw new Error(`Configuration file not found: ${filePath}`);
|
|
1429
|
+
}
|
|
1430
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
1431
|
+
let format;
|
|
1432
|
+
if (ext === ".yaml" || ext === ".yml") {
|
|
1433
|
+
format = "yaml";
|
|
1434
|
+
} else if (ext === ".json" || ext === ".jsonc") {
|
|
1435
|
+
format = "json";
|
|
1436
|
+
} else if (ext === ".toml" || ext === ".tml") {
|
|
1437
|
+
format = "toml";
|
|
1438
|
+
} else {
|
|
1439
|
+
format = "env";
|
|
1440
|
+
}
|
|
1441
|
+
const fileContent = fs.readFileSync(filePath, "utf8");
|
|
1442
|
+
let rawConfig;
|
|
1443
|
+
switch (format) {
|
|
1444
|
+
case "env":
|
|
1445
|
+
rawConfig = __privateMethod(this, _ArgParserBase_instances, _parseEnvFile_fn).call(this, fileContent);
|
|
1446
|
+
break;
|
|
1447
|
+
case "yaml":
|
|
1448
|
+
rawConfig = __privateMethod(this, _ArgParserBase_instances, _parseYamlFile_fn).call(this, fileContent);
|
|
1449
|
+
break;
|
|
1450
|
+
case "json":
|
|
1451
|
+
rawConfig = __privateMethod(this, _ArgParserBase_instances, _parseJsonFile_fn).call(this, fileContent);
|
|
1452
|
+
break;
|
|
1453
|
+
case "toml":
|
|
1454
|
+
rawConfig = __privateMethod(this, _ArgParserBase_instances, _parseTomlFile_fn).call(this, fileContent);
|
|
1455
|
+
break;
|
|
1456
|
+
}
|
|
1457
|
+
return __privateMethod(this, _ArgParserBase_instances, _convertConfigToFlagValues_fn).call(this, rawConfig, parserChain);
|
|
1458
|
+
};
|
|
1459
|
+
/**
|
|
1460
|
+
* Parses .env file content using dotenv
|
|
1461
|
+
*/
|
|
1462
|
+
_parseEnvFile_fn = function(content) {
|
|
1463
|
+
const parsed = dotenv.parse(content);
|
|
1464
|
+
const result = {};
|
|
1465
|
+
for (const [envKey, envValue] of Object.entries(parsed)) {
|
|
1466
|
+
const flagName = envKey.toLowerCase().replace(/_/g, "-");
|
|
1467
|
+
if (envValue === "true") {
|
|
1468
|
+
result[flagName] = true;
|
|
1469
|
+
} else if (envValue === "false") {
|
|
1470
|
+
result[flagName] = false;
|
|
1471
|
+
} else if (/^-?\d+$/.test(envValue)) {
|
|
1472
|
+
result[flagName] = parseInt(envValue, 10);
|
|
1473
|
+
} else if (/^-?\d*\.\d+$/.test(envValue)) {
|
|
1474
|
+
result[flagName] = parseFloat(envValue);
|
|
1475
|
+
} else if (envValue.includes(",")) {
|
|
1476
|
+
result[flagName] = envValue.split(",").map((v) => v.trim());
|
|
1477
|
+
} else {
|
|
1478
|
+
result[flagName] = envValue;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
return result;
|
|
1482
|
+
};
|
|
1483
|
+
/**
|
|
1484
|
+
* Parses YAML file content
|
|
1485
|
+
*/
|
|
1486
|
+
_parseYamlFile_fn = function(content) {
|
|
1487
|
+
const parsed = yaml.load(content);
|
|
1488
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
1489
|
+
throw new Error("YAML file must contain an object at the root level");
|
|
1490
|
+
}
|
|
1491
|
+
const { _meta, ...config } = parsed;
|
|
1492
|
+
return config;
|
|
1493
|
+
};
|
|
1494
|
+
/**
|
|
1495
|
+
* Parses JSON file content
|
|
1496
|
+
*/
|
|
1497
|
+
_parseJsonFile_fn = function(content) {
|
|
1498
|
+
const parsed = JSON.parse(content);
|
|
1499
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
1500
|
+
throw new Error("JSON file must contain an object at the root level");
|
|
1501
|
+
}
|
|
1502
|
+
const { _meta, ...config } = parsed;
|
|
1503
|
+
return config;
|
|
1504
|
+
};
|
|
1505
|
+
/**
|
|
1506
|
+
* Parses TOML file content
|
|
1507
|
+
*/
|
|
1508
|
+
_parseTomlFile_fn = function(content) {
|
|
1509
|
+
const parsed = toml.parse(content);
|
|
1510
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
1511
|
+
throw new Error("TOML file must contain an object at the root level");
|
|
1512
|
+
}
|
|
1513
|
+
return parsed;
|
|
1514
|
+
};
|
|
1515
|
+
/**
|
|
1516
|
+
* Converts raw configuration values to match flag types and validates them
|
|
1517
|
+
*/
|
|
1518
|
+
_convertConfigToFlagValues_fn = function(rawConfig, parserChain) {
|
|
1519
|
+
const result = {};
|
|
1520
|
+
const allFlags = [];
|
|
1521
|
+
const seenFlagNames = /* @__PURE__ */ new Set();
|
|
1522
|
+
for (let i = parserChain.length - 1; i >= 0; i--) {
|
|
1523
|
+
const parser = parserChain[i];
|
|
1524
|
+
for (const flag of __privateGet(parser, _flagManager).flags) {
|
|
1525
|
+
if (!seenFlagNames.has(flag["name"])) {
|
|
1526
|
+
allFlags.push(flag);
|
|
1527
|
+
seenFlagNames.add(flag["name"]);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
for (const [configKey, configValue] of Object.entries(rawConfig)) {
|
|
1532
|
+
const flag = allFlags.find((f) => f["name"] === configKey);
|
|
1533
|
+
if (!flag) {
|
|
1534
|
+
console.warn(chalk.yellow(`Warning: Configuration key '${configKey}' does not match any known flag. Ignoring.`));
|
|
1535
|
+
continue;
|
|
1536
|
+
}
|
|
1537
|
+
try {
|
|
1538
|
+
const convertedValue = __privateMethod(this, _ArgParserBase_instances, _convertValueToFlagType_fn).call(this, configValue, flag);
|
|
1539
|
+
result[configKey] = convertedValue;
|
|
1540
|
+
} catch (error) {
|
|
1541
|
+
console.error(chalk.red(`Error converting configuration value for '${configKey}': ${error instanceof Error ? error.message : String(error)}`));
|
|
1542
|
+
if (typeof process === "object" && typeof process.exit === "function") {
|
|
1543
|
+
process.exit(1);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
return result;
|
|
1548
|
+
};
|
|
1549
|
+
/**
|
|
1550
|
+
* Converts a configuration value to match the expected flag type
|
|
1551
|
+
*/
|
|
1552
|
+
_convertValueToFlagType_fn = function(value, flag) {
|
|
1553
|
+
const flagType = flag["type"];
|
|
1554
|
+
if (value === null || value === void 0) {
|
|
1555
|
+
return value;
|
|
1556
|
+
}
|
|
1557
|
+
if (flagType === Array || flag["allowMultiple"]) {
|
|
1558
|
+
if (Array.isArray(value)) return value;
|
|
1559
|
+
if (typeof value === "string") {
|
|
1560
|
+
return value.split(",").map((v) => v.trim());
|
|
1561
|
+
}
|
|
1562
|
+
return [value];
|
|
1563
|
+
}
|
|
1564
|
+
if (flagType === Boolean) {
|
|
1565
|
+
if (typeof value === "boolean") return value;
|
|
1566
|
+
if (typeof value === "string") {
|
|
1567
|
+
const lowerValue = value.toLowerCase();
|
|
1568
|
+
if (lowerValue === "true" || lowerValue === "1" || lowerValue === "yes") return true;
|
|
1569
|
+
if (lowerValue === "false" || lowerValue === "0" || lowerValue === "no") return false;
|
|
1570
|
+
}
|
|
1571
|
+
throw new Error(`Cannot convert '${value}' to boolean for flag '${flag["name"]}'`);
|
|
1572
|
+
}
|
|
1573
|
+
if (flagType === String) {
|
|
1574
|
+
return String(value);
|
|
1575
|
+
}
|
|
1576
|
+
if (flagType === Number) {
|
|
1577
|
+
const numValue = Number(value);
|
|
1578
|
+
if (isNaN(numValue)) {
|
|
1579
|
+
throw new Error(`Cannot convert '${value}' to number for flag '${flag["name"]}'`);
|
|
1580
|
+
}
|
|
1581
|
+
return numValue;
|
|
1582
|
+
}
|
|
1583
|
+
if (flag["enum"] && flag["enum"].length > 0) {
|
|
1584
|
+
if (!flag["enum"].includes(value)) {
|
|
1585
|
+
throw new Error(`Value '${value}' is not allowed for flag '${flag["name"]}'. Allowed values: ${flag["enum"].join(", ")}`);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
return value;
|
|
1589
|
+
};
|
|
1590
|
+
/**
|
|
1591
|
+
* Merges environment configuration with command line arguments
|
|
1592
|
+
* CLI arguments take precedence over file configuration
|
|
1593
|
+
*/
|
|
1594
|
+
_mergeEnvConfigWithArgs_fn = function(envConfig, processArgs) {
|
|
1595
|
+
const result = [...processArgs];
|
|
1596
|
+
const withEnvIndex = result.findIndex((arg) => arg === "--s-with-env");
|
|
1597
|
+
if (withEnvIndex !== -1) {
|
|
1598
|
+
result.splice(withEnvIndex, 2);
|
|
1599
|
+
}
|
|
1600
|
+
const existingFlags = /* @__PURE__ */ new Set();
|
|
1601
|
+
for (let i = 0; i < result.length; i++) {
|
|
1602
|
+
const arg = result[i];
|
|
1603
|
+
if (arg.startsWith("-")) {
|
|
1604
|
+
existingFlags.add(arg);
|
|
1605
|
+
if (arg.includes("=")) {
|
|
1606
|
+
const flagPart = arg.split("=")[0];
|
|
1607
|
+
existingFlags.add(flagPart);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
for (const [flagName, flagValue] of Object.entries(envConfig)) {
|
|
1612
|
+
const longFlag = `--${flagName}`;
|
|
1613
|
+
if (existingFlags.has(longFlag)) {
|
|
1614
|
+
continue;
|
|
1615
|
+
}
|
|
1616
|
+
if (typeof flagValue === "boolean") {
|
|
1617
|
+
if (flagValue) {
|
|
1618
|
+
result.push(longFlag);
|
|
1619
|
+
}
|
|
1620
|
+
} else if (Array.isArray(flagValue)) {
|
|
1621
|
+
for (const item of flagValue) {
|
|
1622
|
+
result.push(longFlag, String(item));
|
|
1623
|
+
}
|
|
1624
|
+
} else {
|
|
1625
|
+
result.push(longFlag, String(flagValue));
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
return result;
|
|
1629
|
+
};
|
|
1630
|
+
/**
|
|
1631
|
+
* Generates environment file content in Bash .env format
|
|
1632
|
+
*/
|
|
1633
|
+
_generateEnvFormat_fn = function(flags, parsedArgs) {
|
|
1634
|
+
const lines = [];
|
|
1635
|
+
lines.push("# Environment configuration generated by ArgParser");
|
|
1636
|
+
lines.push("# Format: Bash .env style");
|
|
1637
|
+
lines.push("");
|
|
1638
|
+
for (const flag of flags) {
|
|
1639
|
+
if (flag["name"] === "help") continue;
|
|
1640
|
+
const flagValue = parsedArgs[flag["name"]];
|
|
1641
|
+
const isSet = flagValue !== void 0 && flagValue !== null;
|
|
1642
|
+
const isMandatory = typeof flag["mandatory"] === "function" ? false : flag["mandatory"] ?? false;
|
|
1643
|
+
lines.push(`# ${flag["name"]}: ${Array.isArray(flag["description"]) ? flag["description"].join(" | ") : flag["description"]}`);
|
|
1644
|
+
lines.push(`# Options: ${flag["options"].join(", ")}`);
|
|
1645
|
+
lines.push(`# Type: ${__privateMethod(this, _ArgParserBase_instances, _getTypeString_fn).call(this, flag["type"])}`);
|
|
1646
|
+
if (flag["defaultValue"] !== void 0) {
|
|
1647
|
+
lines.push(`# Default: ${JSON.stringify(flag["defaultValue"])}`);
|
|
1648
|
+
}
|
|
1649
|
+
if (flag["enum"] && flag["enum"].length > 0) {
|
|
1650
|
+
lines.push(`# Allowed values: ${flag["enum"].join(", ")}`);
|
|
1651
|
+
}
|
|
1652
|
+
const envVarName = flag["name"].toUpperCase().replace(/[^A-Z0-9_]/g, "_");
|
|
1653
|
+
let envValue = "";
|
|
1654
|
+
if (isSet) {
|
|
1655
|
+
if (Array.isArray(flagValue)) {
|
|
1656
|
+
envValue = flagValue.join(",");
|
|
1657
|
+
} else if (typeof flagValue === "boolean") {
|
|
1658
|
+
envValue = flagValue ? "true" : "false";
|
|
1659
|
+
} else {
|
|
1660
|
+
envValue = String(flagValue);
|
|
1661
|
+
}
|
|
1662
|
+
lines.push(`${envVarName}="${envValue}"`);
|
|
1663
|
+
} else {
|
|
1664
|
+
const defaultVal = flag["defaultValue"] !== void 0 ? String(flag["defaultValue"]) : "";
|
|
1665
|
+
const prefix = isMandatory ? "" : "# ";
|
|
1666
|
+
lines.push(`${prefix}${envVarName}="${defaultVal}"`);
|
|
1667
|
+
}
|
|
1668
|
+
lines.push("");
|
|
1669
|
+
}
|
|
1670
|
+
return lines.join("\n");
|
|
1671
|
+
};
|
|
1672
|
+
/**
|
|
1673
|
+
* Generates environment file content in YAML format
|
|
1674
|
+
*/
|
|
1675
|
+
_generateYamlFormat_fn = function(flags, parsedArgs) {
|
|
1676
|
+
const config = {};
|
|
1677
|
+
const comments = [];
|
|
1678
|
+
comments.push("# Environment configuration generated by ArgParser");
|
|
1679
|
+
comments.push("# Format: YAML");
|
|
1680
|
+
comments.push("");
|
|
1681
|
+
for (const flag of flags) {
|
|
1682
|
+
if (flag["name"] === "help") continue;
|
|
1683
|
+
const flagValue = parsedArgs[flag["name"]];
|
|
1684
|
+
const isSet = flagValue !== void 0 && flagValue !== null;
|
|
1685
|
+
const isMandatory = typeof flag["mandatory"] === "function" ? false : flag["mandatory"] ?? false;
|
|
1686
|
+
comments.push(`# ${flag["name"]}: ${Array.isArray(flag["description"]) ? flag["description"].join(" | ") : flag["description"]}`);
|
|
1687
|
+
comments.push(`# Options: ${flag["options"].join(", ")}`);
|
|
1688
|
+
comments.push(`# Type: ${__privateMethod(this, _ArgParserBase_instances, _getTypeString_fn).call(this, flag["type"])}`);
|
|
1689
|
+
if (flag["defaultValue"] !== void 0) {
|
|
1690
|
+
comments.push(`# Default: ${JSON.stringify(flag["defaultValue"])}`);
|
|
1691
|
+
}
|
|
1692
|
+
if (flag["enum"] && flag["enum"].length > 0) {
|
|
1693
|
+
comments.push(`# Allowed values: ${flag["enum"].join(", ")}`);
|
|
1694
|
+
}
|
|
1695
|
+
if (isSet) {
|
|
1696
|
+
config[flag["name"]] = flagValue;
|
|
1697
|
+
} else if (isMandatory) {
|
|
1698
|
+
config[flag["name"]] = flag["defaultValue"] !== void 0 ? flag["defaultValue"] : null;
|
|
1699
|
+
}
|
|
1700
|
+
comments.push("");
|
|
1701
|
+
}
|
|
1702
|
+
const yamlContent = yaml.dump(config, {
|
|
1703
|
+
indent: 2,
|
|
1704
|
+
lineWidth: -1,
|
|
1705
|
+
noRefs: true,
|
|
1706
|
+
sortKeys: true
|
|
1707
|
+
});
|
|
1708
|
+
return comments.join("\n") + "\n" + yamlContent;
|
|
1709
|
+
};
|
|
1710
|
+
/**
|
|
1711
|
+
* Generates environment file content in JSON format
|
|
1712
|
+
*/
|
|
1713
|
+
_generateJsonFormat_fn = function(flags, parsedArgs) {
|
|
1714
|
+
const config = {};
|
|
1715
|
+
const metadata = {
|
|
1716
|
+
_meta: {
|
|
1717
|
+
generated_by: "ArgParser",
|
|
1718
|
+
format: "JSON",
|
|
1719
|
+
flags_info: {}
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1722
|
+
for (const flag of flags) {
|
|
1723
|
+
if (flag["name"] === "help") continue;
|
|
1724
|
+
const flagValue = parsedArgs[flag["name"]];
|
|
1725
|
+
const isSet = flagValue !== void 0 && flagValue !== null;
|
|
1726
|
+
const isMandatory = typeof flag["mandatory"] === "function" ? false : flag["mandatory"] ?? false;
|
|
1727
|
+
metadata._meta.flags_info[flag["name"]] = {
|
|
1728
|
+
description: Array.isArray(flag["description"]) ? flag["description"].join(" | ") : flag["description"],
|
|
1729
|
+
options: flag["options"],
|
|
1730
|
+
type: __privateMethod(this, _ArgParserBase_instances, _getTypeString_fn).call(this, flag["type"]),
|
|
1731
|
+
mandatory: isMandatory,
|
|
1732
|
+
defaultValue: flag["defaultValue"],
|
|
1733
|
+
enum: flag["enum"] && flag["enum"].length > 0 ? flag["enum"] : void 0
|
|
1734
|
+
};
|
|
1735
|
+
if (isSet) {
|
|
1736
|
+
config[flag["name"]] = flagValue;
|
|
1737
|
+
} else if (isMandatory) {
|
|
1738
|
+
config[flag["name"]] = flag["defaultValue"] !== void 0 ? flag["defaultValue"] : null;
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
const result = { ...metadata, ...config };
|
|
1742
|
+
return JSON.stringify(result, null, 2);
|
|
1743
|
+
};
|
|
1744
|
+
/**
|
|
1745
|
+
* Generates environment file content in TOML format
|
|
1746
|
+
*/
|
|
1747
|
+
_generateTomlFormat_fn = function(flags, parsedArgs) {
|
|
1748
|
+
const config = {};
|
|
1749
|
+
const lines = [];
|
|
1750
|
+
lines.push("# Environment configuration generated by ArgParser");
|
|
1751
|
+
lines.push("# Format: TOML");
|
|
1752
|
+
lines.push("");
|
|
1753
|
+
for (const flag of flags) {
|
|
1754
|
+
if (flag["name"] === "help") continue;
|
|
1755
|
+
const flagValue = parsedArgs[flag["name"]];
|
|
1756
|
+
const isSet = flagValue !== void 0 && flagValue !== null;
|
|
1757
|
+
const isMandatory = typeof flag["mandatory"] === "function" ? false : flag["mandatory"] ?? false;
|
|
1758
|
+
lines.push(`# ${flag["name"]}: ${Array.isArray(flag["description"]) ? flag["description"].join(" | ") : flag["description"]}`);
|
|
1759
|
+
lines.push(`# Options: ${flag["options"].join(", ")}`);
|
|
1760
|
+
lines.push(`# Type: ${__privateMethod(this, _ArgParserBase_instances, _getTypeString_fn).call(this, flag["type"])}`);
|
|
1761
|
+
if (flag["defaultValue"] !== void 0) {
|
|
1762
|
+
lines.push(`# Default: ${JSON.stringify(flag["defaultValue"])}`);
|
|
1763
|
+
}
|
|
1764
|
+
if (flag["enum"] && flag["enum"].length > 0) {
|
|
1765
|
+
lines.push(`# Allowed values: ${flag["enum"].join(", ")}`);
|
|
1766
|
+
}
|
|
1767
|
+
if (isSet) {
|
|
1768
|
+
config[flag["name"]] = flagValue;
|
|
1769
|
+
} else if (isMandatory) {
|
|
1770
|
+
config[flag["name"]] = flag["defaultValue"] !== void 0 ? flag["defaultValue"] : null;
|
|
1771
|
+
}
|
|
1772
|
+
lines.push("");
|
|
1773
|
+
}
|
|
1774
|
+
const tomlContent = toml.stringify(config);
|
|
1775
|
+
return lines.join("\n") + "\n" + tomlContent;
|
|
1776
|
+
};
|
|
1777
|
+
/**
|
|
1778
|
+
* Helper method to get a string representation of a flag's type
|
|
1779
|
+
*/
|
|
1780
|
+
_getTypeString_fn = function(type) {
|
|
1781
|
+
var _a;
|
|
1782
|
+
if (typeof type === "function") {
|
|
1783
|
+
return type.name || "custom function";
|
|
1784
|
+
} else if (typeof type === "string") {
|
|
1785
|
+
return type;
|
|
1786
|
+
} else if (typeof type === "object" && type) {
|
|
1787
|
+
try {
|
|
1788
|
+
return ((_a = type.constructor) == null ? void 0 : _a.name) || "object";
|
|
1789
|
+
} catch {
|
|
1790
|
+
return "object";
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
return "unknown";
|
|
1794
|
+
};
|
|
1795
|
+
let ArgParserBase = _ArgParserBase;
|
|
1796
|
+
function mapArgParserFlagToZodSchema(flag) {
|
|
1797
|
+
let zodSchema;
|
|
1798
|
+
const flagTypeOpt = flag["type"];
|
|
1799
|
+
let typeName;
|
|
1800
|
+
if (typeof flagTypeOpt === "function") {
|
|
1801
|
+
typeName = flagTypeOpt.name.toLowerCase().replace("constructor", "");
|
|
1802
|
+
} else {
|
|
1803
|
+
typeName = String(flagTypeOpt).toLowerCase();
|
|
1804
|
+
}
|
|
1805
|
+
const flagEnum = flag["enum"];
|
|
1806
|
+
const allowMultiple = flag["allowMultiple"];
|
|
1807
|
+
if (allowMultiple) {
|
|
1808
|
+
let itemSchema;
|
|
1809
|
+
if (flagEnum && Array.isArray(flagEnum) && flagEnum.length > 0) {
|
|
1810
|
+
if (flagEnum.every((e) => typeof e === "string")) {
|
|
1811
|
+
itemSchema = z.enum(flagEnum);
|
|
1812
|
+
} else if (flagEnum.every((e) => typeof e === "number")) {
|
|
1813
|
+
const literalSchemas = flagEnum.map((val) => z.literal(val));
|
|
1814
|
+
if (literalSchemas.length === 1) {
|
|
1815
|
+
itemSchema = literalSchemas[0];
|
|
1816
|
+
} else {
|
|
1817
|
+
itemSchema = z.union(
|
|
1818
|
+
literalSchemas
|
|
1819
|
+
);
|
|
1820
|
+
}
|
|
1821
|
+
} else {
|
|
1822
|
+
itemSchema = z.string();
|
|
1823
|
+
}
|
|
1824
|
+
} else {
|
|
1825
|
+
switch (typeName) {
|
|
1826
|
+
case "number":
|
|
1827
|
+
itemSchema = z.number();
|
|
1828
|
+
break;
|
|
1829
|
+
case "boolean":
|
|
1830
|
+
itemSchema = z.boolean();
|
|
1831
|
+
break;
|
|
1832
|
+
default:
|
|
1833
|
+
itemSchema = z.string();
|
|
1834
|
+
break;
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
zodSchema = z.array(itemSchema);
|
|
1838
|
+
} else {
|
|
1839
|
+
switch (typeName) {
|
|
1840
|
+
case "string":
|
|
1841
|
+
zodSchema = flagEnum && Array.isArray(flagEnum) && flagEnum.length > 0 && flagEnum.every((e) => typeof e === "string") ? z.enum(flagEnum) : z.string();
|
|
1842
|
+
break;
|
|
1843
|
+
case "number":
|
|
1844
|
+
if (flagEnum && Array.isArray(flagEnum) && flagEnum.length > 0 && flagEnum.every((e) => typeof e === "number")) {
|
|
1845
|
+
const literalSchemas = flagEnum.map((val) => z.literal(val));
|
|
1846
|
+
if (literalSchemas.length === 1) {
|
|
1847
|
+
zodSchema = literalSchemas[0];
|
|
1848
|
+
} else if (literalSchemas.length >= 2) {
|
|
1849
|
+
zodSchema = z.union(
|
|
1850
|
+
literalSchemas
|
|
1851
|
+
);
|
|
1852
|
+
} else {
|
|
1853
|
+
zodSchema = z.number();
|
|
1854
|
+
}
|
|
1855
|
+
} else {
|
|
1856
|
+
zodSchema = z.number();
|
|
1857
|
+
}
|
|
1858
|
+
break;
|
|
1859
|
+
case "boolean":
|
|
1860
|
+
zodSchema = z.boolean();
|
|
1861
|
+
break;
|
|
1862
|
+
case "array":
|
|
1863
|
+
const itemSchema = flagEnum && Array.isArray(flagEnum) && flagEnum.length > 0 && flagEnum.every((e) => typeof e === "string") ? z.enum(flagEnum) : z.string();
|
|
1864
|
+
zodSchema = z.array(itemSchema);
|
|
1865
|
+
break;
|
|
1866
|
+
case "object":
|
|
1867
|
+
zodSchema = z.record(z.string(), z.any());
|
|
1868
|
+
break;
|
|
1869
|
+
default:
|
|
1870
|
+
console.warn(
|
|
1871
|
+
`[MCP Integration] Flag '${flag["name"]}' has an unknown type '${typeName}'. Defaulting to z.string().`
|
|
1872
|
+
);
|
|
1873
|
+
zodSchema = z.string();
|
|
1874
|
+
break;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
const description = flag["description"];
|
|
1878
|
+
if (description) {
|
|
1879
|
+
zodSchema = zodSchema.describe(
|
|
1880
|
+
Array.isArray(description) ? description.join("\n") : description
|
|
1881
|
+
);
|
|
1882
|
+
}
|
|
1883
|
+
const defaultValue = flag["defaultValue"];
|
|
1884
|
+
if (defaultValue !== void 0) {
|
|
1885
|
+
zodSchema = zodSchema.default(defaultValue);
|
|
1886
|
+
} else if (!flag["mandatory"]) {
|
|
1887
|
+
zodSchema = zodSchema.optional();
|
|
1888
|
+
}
|
|
1889
|
+
return zodSchema;
|
|
1890
|
+
}
|
|
1891
|
+
function generateMcpToolsFromArgParser(rootParser, options) {
|
|
1892
|
+
const tools = [];
|
|
1893
|
+
const visitedParsers = /* @__PURE__ */ new Set();
|
|
1894
|
+
function buildToolsRecursively(currentParser, commandPathParts) {
|
|
1895
|
+
if (visitedParsers.has(currentParser)) return;
|
|
1896
|
+
visitedParsers.add(currentParser);
|
|
1897
|
+
const typedRootParser = rootParser;
|
|
1898
|
+
const typedCurrentParser = currentParser;
|
|
1899
|
+
const appName = typedRootParser.getAppName ? typedRootParser.getAppName() : typedRootParser["#appName"];
|
|
1900
|
+
const currentParserDescription = typedCurrentParser.getDescription ? typedCurrentParser.getDescription() : typedCurrentParser["#description"];
|
|
1901
|
+
const currentParserHandler = typedCurrentParser.getHandler ? typedCurrentParser.getHandler() : typedCurrentParser["#handler"];
|
|
1902
|
+
const currentParserFlags = typedCurrentParser.flags;
|
|
1903
|
+
const subCommandsMap = typedCurrentParser.getSubCommands ? typedCurrentParser.getSubCommands() : typedCurrentParser["#subCommands"];
|
|
1904
|
+
const currentParserSubCommands = subCommandsMap ? Array.from(subCommandsMap.values()) : [];
|
|
1905
|
+
let currentParserCommandName = typedCurrentParser.getAppCommandName ? typedCurrentParser.getAppCommandName() : typedCurrentParser["#appCommandName"];
|
|
1906
|
+
if (!currentParserCommandName && currentParser !== rootParser) {
|
|
1907
|
+
currentParserCommandName = typedCurrentParser.getSubCommandName ? typedCurrentParser.getSubCommandName() : typedCurrentParser["#subCommandName"];
|
|
1908
|
+
}
|
|
1909
|
+
if (currentParser !== rootParser && commandPathParts.length > 0) {
|
|
1910
|
+
currentParserCommandName = commandPathParts[commandPathParts.length - 1];
|
|
1911
|
+
}
|
|
1912
|
+
const currentParserCommandNameOrAppName = currentParserCommandName || appName;
|
|
1913
|
+
const effectiveCommandName = currentParserCommandName || (commandPathParts.length > 0 ? commandPathParts[commandPathParts.length - 1] : appName);
|
|
1914
|
+
let toolName;
|
|
1915
|
+
if (options == null ? void 0 : options.generateToolName) {
|
|
1916
|
+
toolName = options.generateToolName(commandPathParts, appName);
|
|
1917
|
+
} else {
|
|
1918
|
+
if (currentParser === rootParser) {
|
|
1919
|
+
toolName = currentParserCommandNameOrAppName || appName || "root_cmd";
|
|
1920
|
+
} else {
|
|
1921
|
+
toolName = effectiveCommandName || "cmd";
|
|
1922
|
+
}
|
|
1923
|
+
toolName = toolName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1924
|
+
}
|
|
1925
|
+
if (!toolName)
|
|
1926
|
+
toolName = currentParser === rootParser && appName ? appName : "cmd";
|
|
1927
|
+
if (options == null ? void 0 : options.toolNamePrefix) {
|
|
1928
|
+
toolName = options.toolNamePrefix + toolName;
|
|
1929
|
+
}
|
|
1930
|
+
if (options == null ? void 0 : options.toolNameSuffix) {
|
|
1931
|
+
toolName = toolName + options.toolNameSuffix;
|
|
1932
|
+
}
|
|
1933
|
+
if (currentParserHandler) {
|
|
1934
|
+
const flags = currentParserFlags;
|
|
1935
|
+
const zodProperties = {};
|
|
1936
|
+
const hasHelpFlag = flags.some((flag) => flag["name"] === "help");
|
|
1937
|
+
for (const flag of flags) {
|
|
1938
|
+
let flagSchema = mapArgParserFlagToZodSchema(flag);
|
|
1939
|
+
if (hasHelpFlag && flag["name"] !== "help" && flag["mandatory"]) {
|
|
1940
|
+
flagSchema = flagSchema.optional();
|
|
1941
|
+
}
|
|
1942
|
+
zodProperties[flag["name"]] = flagSchema;
|
|
1943
|
+
}
|
|
1944
|
+
const inputSchema = z.object(zodProperties);
|
|
1945
|
+
let outputSchema;
|
|
1946
|
+
if ((options == null ? void 0 : options.outputSchemaMap) && options.outputSchemaMap[toolName]) {
|
|
1947
|
+
const customSchema = options.outputSchemaMap[toolName];
|
|
1948
|
+
outputSchema = typeof customSchema === "object" && !customSchema._def ? z.object(customSchema) : customSchema;
|
|
1949
|
+
} else if (options == null ? void 0 : options.defaultOutputSchema) {
|
|
1950
|
+
outputSchema = options.defaultOutputSchema;
|
|
1951
|
+
}
|
|
1952
|
+
const tool = {
|
|
1953
|
+
name: toolName,
|
|
1954
|
+
description: currentParserDescription || `Executes the ${toolName} command.`,
|
|
1955
|
+
inputSchema,
|
|
1956
|
+
outputSchema,
|
|
1957
|
+
async execute(mcpInputArgs) {
|
|
1958
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1959
|
+
if (mcpInputArgs["help"] === true) {
|
|
1960
|
+
let helpParser = rootParser;
|
|
1961
|
+
const pathParts = [...commandPathParts];
|
|
1962
|
+
for (const part of pathParts) {
|
|
1963
|
+
const subCmd = helpParser.getSubCommand ? helpParser.getSubCommand(part) : void 0;
|
|
1964
|
+
if (subCmd && subCmd.parser) {
|
|
1965
|
+
helpParser = subCmd.parser;
|
|
1966
|
+
} else {
|
|
1967
|
+
break;
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
const helpText = helpParser.helpText ? helpParser.helpText() : "Help not available";
|
|
1971
|
+
if ((_a = options == null ? void 0 : options.outputSchemaMap) == null ? void 0 : _a[toolName]) {
|
|
1972
|
+
return {
|
|
1973
|
+
success: true,
|
|
1974
|
+
help: helpText,
|
|
1975
|
+
files: [],
|
|
1976
|
+
commandExecuted: null,
|
|
1977
|
+
stderrOutput: null
|
|
1978
|
+
};
|
|
1979
|
+
}
|
|
1980
|
+
return { success: true, message: helpText };
|
|
1981
|
+
}
|
|
1982
|
+
const argv = [...commandPathParts];
|
|
1983
|
+
const parserFlags = currentParserFlags;
|
|
1984
|
+
for (const flagDef of parserFlags) {
|
|
1985
|
+
const flagName = flagDef["name"];
|
|
1986
|
+
if (mcpInputArgs.hasOwnProperty(flagName)) {
|
|
1987
|
+
const value = mcpInputArgs[flagName];
|
|
1988
|
+
const flagType = flagDef["type"];
|
|
1989
|
+
const flagOptions = flagDef["options"];
|
|
1990
|
+
const isFlagOnly = flagDef["flagOnly"];
|
|
1991
|
+
const allowMultiple = flagDef["allowMultiple"];
|
|
1992
|
+
let flagTypeName = typeof flagType === "function" ? flagType.name.toLowerCase().replace("constructor", "") : String(flagType).toLowerCase();
|
|
1993
|
+
argv.push(flagOptions[0]);
|
|
1994
|
+
if (flagTypeName === "boolean") {
|
|
1995
|
+
if (value === true && isFlagOnly === false)
|
|
1996
|
+
argv.push(String(value));
|
|
1997
|
+
else if (value === false && isFlagOnly === false)
|
|
1998
|
+
argv.push(String(value));
|
|
1999
|
+
} else if (flagTypeName === "array") {
|
|
2000
|
+
if (Array.isArray(value)) {
|
|
2001
|
+
if (allowMultiple) {
|
|
2002
|
+
const originalArgvLength = argv.length;
|
|
2003
|
+
value.forEach((item) => {
|
|
2004
|
+
argv.push(flagOptions[0]);
|
|
2005
|
+
argv.push(String(item));
|
|
2006
|
+
});
|
|
2007
|
+
if (value.length > 0 && argv[originalArgvLength - 1] === flagOptions[0]) {
|
|
2008
|
+
argv.splice(originalArgvLength - 1, 1);
|
|
2009
|
+
}
|
|
2010
|
+
} else {
|
|
2011
|
+
argv.push(value.join(","));
|
|
2012
|
+
}
|
|
2013
|
+
} else if (value != null) argv.push(String(value));
|
|
2014
|
+
} else if (value !== null && value !== void 0)
|
|
2015
|
+
argv.push(String(value));
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
try {
|
|
2019
|
+
const parseResult = await rootParser.parse(
|
|
2020
|
+
argv
|
|
2021
|
+
);
|
|
2022
|
+
if (parseResult["$error"]) {
|
|
2023
|
+
const errorDetails = parseResult["$error"];
|
|
2024
|
+
const errPayload = {
|
|
2025
|
+
message: `Cmd error: ${errorDetails.type} - ${errorDetails.message}`,
|
|
2026
|
+
details: errorDetails.details
|
|
2027
|
+
};
|
|
2028
|
+
if ((_b = options == null ? void 0 : options.outputSchemaMap) == null ? void 0 : _b[toolName]) {
|
|
2029
|
+
return {
|
|
2030
|
+
error: errPayload.message,
|
|
2031
|
+
files: [],
|
|
2032
|
+
commandExecuted: null,
|
|
2033
|
+
stderrOutput: ((_c = errPayload.details) == null ? void 0 : _c.stderr) || null
|
|
2034
|
+
};
|
|
2035
|
+
}
|
|
2036
|
+
return {
|
|
2037
|
+
success: false,
|
|
2038
|
+
message: errPayload.message,
|
|
2039
|
+
data: errPayload.details
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
2042
|
+
let handlerResponse = parseResult["handlerResponse"];
|
|
2043
|
+
if (handlerResponse === void 0 && parseResult["$commandChain"]) {
|
|
2044
|
+
let finalParser = rootParser;
|
|
2045
|
+
let currentArgs = { ...parseResult };
|
|
2046
|
+
let resolvedParentArgs = void 0;
|
|
2047
|
+
const chain = parseResult["$commandChain"];
|
|
2048
|
+
for (let i = 0; i < chain.length; i++) {
|
|
2049
|
+
const cmdName = chain[i];
|
|
2050
|
+
const subCmdInfo = (finalParser == null ? void 0 : finalParser.getSubCommand) ? finalParser.getSubCommand(cmdName) : void 0;
|
|
2051
|
+
if (subCmdInfo && subCmdInfo.parser) {
|
|
2052
|
+
resolvedParentArgs = { ...currentArgs };
|
|
2053
|
+
currentArgs = currentArgs[cmdName] || {};
|
|
2054
|
+
finalParser = subCmdInfo.parser;
|
|
2055
|
+
} else if (i === 0 && finalParser && cmdName === (finalParser.getAppCommandName ? finalParser.getAppCommandName() : finalParser["#appCommandName"] || (finalParser.getAppName ? finalParser.getAppName() : finalParser["#appName"]))) {
|
|
2056
|
+
currentArgs = { ...parseResult };
|
|
2057
|
+
break;
|
|
2058
|
+
} else {
|
|
2059
|
+
finalParser = void 0;
|
|
2060
|
+
break;
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
const finalParserTyped = finalParser;
|
|
2064
|
+
const finalHandler = finalParserTyped.getHandler ? finalParserTyped.getHandler() : finalParserTyped["#handler"];
|
|
2065
|
+
if (finalParser && finalHandler) {
|
|
2066
|
+
const handlerToCall = finalHandler;
|
|
2067
|
+
const handlerContext = {
|
|
2068
|
+
args: currentArgs,
|
|
2069
|
+
commandChain: chain,
|
|
2070
|
+
parser: finalParser,
|
|
2071
|
+
parentArgs: resolvedParentArgs
|
|
2072
|
+
};
|
|
2073
|
+
try {
|
|
2074
|
+
handlerResponse = await handlerToCall(handlerContext);
|
|
2075
|
+
} catch (handlerError) {
|
|
2076
|
+
const errorMsg = `Handler error: ${handlerError.message || String(handlerError)}`;
|
|
2077
|
+
if ((_d = options == null ? void 0 : options.outputSchemaMap) == null ? void 0 : _d[toolName]) {
|
|
2078
|
+
return {
|
|
2079
|
+
error: errorMsg,
|
|
2080
|
+
files: [],
|
|
2081
|
+
commandExecuted: null,
|
|
2082
|
+
stderrOutput: null
|
|
2083
|
+
};
|
|
2084
|
+
}
|
|
2085
|
+
return { success: false, message: errorMsg };
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
if ((_e = options == null ? void 0 : options.outputSchemaMap) == null ? void 0 : _e[toolName]) {
|
|
2090
|
+
return handlerResponse;
|
|
2091
|
+
}
|
|
2092
|
+
return { success: true, data: handlerResponse };
|
|
2093
|
+
} catch (e) {
|
|
2094
|
+
let errorMsg;
|
|
2095
|
+
let errorDetails = e;
|
|
2096
|
+
if (e instanceof Error && e.message) {
|
|
2097
|
+
errorMsg = `Cmd error: handler_error - ${e.message}`;
|
|
2098
|
+
errorDetails = { details: e };
|
|
2099
|
+
} else {
|
|
2100
|
+
errorMsg = `MCP tool exec failed: ${e.message || String(e)}`;
|
|
2101
|
+
}
|
|
2102
|
+
if ((_f = options == null ? void 0 : options.outputSchemaMap) == null ? void 0 : _f[toolName]) {
|
|
2103
|
+
return {
|
|
2104
|
+
error: errorMsg,
|
|
2105
|
+
files: [],
|
|
2106
|
+
commandExecuted: null,
|
|
2107
|
+
stderrOutput: (errorDetails == null ? void 0 : errorDetails.stderr) || null
|
|
2108
|
+
};
|
|
2109
|
+
}
|
|
2110
|
+
return {
|
|
2111
|
+
success: false,
|
|
2112
|
+
message: errorMsg,
|
|
2113
|
+
data: errorDetails
|
|
2114
|
+
};
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
};
|
|
2118
|
+
tools.push(tool);
|
|
2119
|
+
}
|
|
2120
|
+
const subCommands = currentParserSubCommands;
|
|
2121
|
+
if (subCommands && (options == null ? void 0 : options.includeSubCommands) !== false) {
|
|
2122
|
+
for (const subCmdObj of subCommands) {
|
|
2123
|
+
if (subCmdObj.isMcp === true) {
|
|
2124
|
+
continue;
|
|
2125
|
+
}
|
|
2126
|
+
const nextPathParts = [...commandPathParts, subCmdObj.name];
|
|
2127
|
+
buildToolsRecursively(
|
|
2128
|
+
subCmdObj.parser,
|
|
2129
|
+
nextPathParts.filter((p) => p)
|
|
2130
|
+
);
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
}
|
|
2134
|
+
buildToolsRecursively(rootParser, []);
|
|
2135
|
+
return tools;
|
|
2136
|
+
}
|
|
2137
|
+
const _ArgParser = class _ArgParser extends ArgParserBase {
|
|
2138
|
+
constructor() {
|
|
2139
|
+
super(...arguments);
|
|
2140
|
+
__privateAdd(this, _ArgParser_instances);
|
|
2141
|
+
}
|
|
2142
|
+
/**
|
|
2143
|
+
* Generate MCP tools from this ArgParser instance
|
|
2144
|
+
* @param options Optional configuration for MCP tool generation
|
|
2145
|
+
* @returns Array of MCP tool structures ready for server registration
|
|
2146
|
+
*/
|
|
2147
|
+
toMcpTools(options) {
|
|
2148
|
+
return generateMcpToolsFromArgParser(this, options);
|
|
2149
|
+
}
|
|
2150
|
+
/**
|
|
2151
|
+
* Create an MCP server with tools generated from this ArgParser
|
|
2152
|
+
* @param serverInfo Server configuration
|
|
2153
|
+
* @param toolOptions Optional MCP tool generation options
|
|
2154
|
+
* @returns Configured MCP server instance
|
|
2155
|
+
*/
|
|
2156
|
+
createMcpServer(serverInfo, toolOptions) {
|
|
2157
|
+
const { McpServer } = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
2158
|
+
const server = new McpServer({
|
|
2159
|
+
id: serverInfo.name,
|
|
2160
|
+
version: serverInfo.version,
|
|
2161
|
+
name: serverInfo.name,
|
|
2162
|
+
description: serverInfo.description
|
|
2163
|
+
});
|
|
2164
|
+
const tools = this.toMcpTools(toolOptions);
|
|
2165
|
+
const uniqueTools = tools.reduce((acc, tool) => {
|
|
2166
|
+
if (!acc.find((t) => t.name === tool.name)) {
|
|
2167
|
+
acc.push(tool);
|
|
2168
|
+
}
|
|
2169
|
+
return acc;
|
|
2170
|
+
}, []);
|
|
2171
|
+
uniqueTools.forEach((tool) => {
|
|
2172
|
+
const toolConfig = {
|
|
2173
|
+
description: tool.description || "No description provided.",
|
|
2174
|
+
inputSchema: tool.inputSchema.shape || tool.inputSchema
|
|
2175
|
+
};
|
|
2176
|
+
if (tool.outputSchema) {
|
|
2177
|
+
toolConfig.outputSchema = tool.outputSchema.shape || tool.outputSchema;
|
|
2178
|
+
}
|
|
2179
|
+
server.registerTool(tool.name, toolConfig, tool.execute);
|
|
2180
|
+
});
|
|
2181
|
+
return server;
|
|
2182
|
+
}
|
|
2183
|
+
/**
|
|
2184
|
+
* Start an MCP server using stdio transport
|
|
2185
|
+
* @param serverInfo Server configuration
|
|
2186
|
+
* @param toolOptions Optional MCP tool generation options
|
|
2187
|
+
* @returns Promise that resolves when server is connected
|
|
2188
|
+
*/
|
|
2189
|
+
async startMcpServer(serverInfo, toolOptions) {
|
|
2190
|
+
return this.startMcpServerWithTransport(serverInfo, "stdio", {}, toolOptions);
|
|
2191
|
+
}
|
|
2192
|
+
/**
|
|
2193
|
+
* Start an MCP server with multiple transport types simultaneously
|
|
2194
|
+
* @param serverInfo Server configuration
|
|
2195
|
+
* @param transports Array of transport configurations
|
|
2196
|
+
* @param toolOptions Optional MCP tool generation options
|
|
2197
|
+
* @returns Promise that resolves when all servers are started
|
|
2198
|
+
*/
|
|
2199
|
+
async startMcpServerWithMultipleTransports(serverInfo, transports, toolOptions) {
|
|
2200
|
+
const server = this.createMcpServer(serverInfo, toolOptions);
|
|
2201
|
+
const startPromises = [];
|
|
2202
|
+
for (const transportConfig of transports) {
|
|
2203
|
+
const promise = __privateMethod(this, _ArgParser_instances, _startSingleTransport_fn).call(this, server, serverInfo, transportConfig);
|
|
2204
|
+
startPromises.push(promise);
|
|
2205
|
+
}
|
|
2206
|
+
await Promise.all(startPromises);
|
|
2207
|
+
console.error(`[${serverInfo.name}] All MCP transports started successfully`);
|
|
2208
|
+
}
|
|
2209
|
+
/**
|
|
2210
|
+
* Start an MCP server with a specific transport type
|
|
2211
|
+
* @param serverInfo Server configuration
|
|
2212
|
+
* @param transportType Type of transport to use
|
|
2213
|
+
* @param transportOptions Transport-specific options
|
|
2214
|
+
* @param toolOptions Optional MCP tool generation options
|
|
2215
|
+
* @returns Promise that resolves when server is connected
|
|
2216
|
+
*/
|
|
2217
|
+
async startMcpServerWithTransport(serverInfo, transportType, transportOptions = {}, toolOptions) {
|
|
2218
|
+
const server = this.createMcpServer(serverInfo, toolOptions);
|
|
2219
|
+
await __privateMethod(this, _ArgParser_instances, _startSingleTransport_fn).call(this, server, serverInfo, {
|
|
2220
|
+
type: transportType,
|
|
2221
|
+
...transportOptions
|
|
2222
|
+
});
|
|
2223
|
+
}
|
|
2224
|
+
/**
|
|
2225
|
+
* Override parse() to handle async handlers properly
|
|
2226
|
+
* This allows ArgParser to work with async handlers while keeping
|
|
2227
|
+
* backwards compatibility for synchronous usage
|
|
2228
|
+
*/
|
|
2229
|
+
parse(processArgs, options) {
|
|
2230
|
+
const result = super.parse(processArgs, options);
|
|
2231
|
+
const anyResult = result;
|
|
2232
|
+
if (anyResult._fuzzyModePreventedExecution) {
|
|
2233
|
+
return result;
|
|
2234
|
+
}
|
|
2235
|
+
if (anyResult._asyncHandlerPromise) {
|
|
2236
|
+
return this.parseAsync(processArgs, options);
|
|
2237
|
+
}
|
|
2238
|
+
return result;
|
|
2239
|
+
}
|
|
2240
|
+
/**
|
|
2241
|
+
* Async version of parse for when async handlers are detected
|
|
2242
|
+
*/
|
|
2243
|
+
async parseAsync(processArgs, options) {
|
|
2244
|
+
const result = super.parse(processArgs, options);
|
|
2245
|
+
const anyResult = result;
|
|
2246
|
+
if (anyResult._fuzzyModePreventedExecution) {
|
|
2247
|
+
return result;
|
|
2248
|
+
}
|
|
2249
|
+
if (anyResult._asyncHandlerPromise) {
|
|
2250
|
+
try {
|
|
2251
|
+
const handlerResult = await anyResult._asyncHandlerPromise;
|
|
2252
|
+
anyResult.handlerResponse = handlerResult;
|
|
2253
|
+
} catch (error) {
|
|
2254
|
+
if (this["#handleErrors"]) {
|
|
2255
|
+
anyResult.$error = {
|
|
2256
|
+
type: "handler_error",
|
|
2257
|
+
message: error instanceof Error ? error.message : String(error),
|
|
2258
|
+
details: error
|
|
2259
|
+
};
|
|
2260
|
+
} else {
|
|
2261
|
+
throw error;
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
delete anyResult._asyncHandlerPromise;
|
|
2265
|
+
delete anyResult._asyncHandlerInfo;
|
|
2266
|
+
}
|
|
2267
|
+
return result;
|
|
2268
|
+
}
|
|
2269
|
+
addMcpSubCommand(subCommandName = "mcp-server", serverInfo, optionsOrToolOptions) {
|
|
2270
|
+
let options;
|
|
2271
|
+
if (optionsOrToolOptions && typeof optionsOrToolOptions === "object" && ("includeSubCommands" in optionsOrToolOptions || "toolNamePrefix" in optionsOrToolOptions || "toolNameSuffix" in optionsOrToolOptions)) {
|
|
2272
|
+
options = { toolOptions: optionsOrToolOptions };
|
|
2273
|
+
} else {
|
|
2274
|
+
options = optionsOrToolOptions || {};
|
|
2275
|
+
}
|
|
2276
|
+
const { defaultTransports, defaultTransport, toolOptions } = options;
|
|
2277
|
+
const mcpHandler = async (ctx) => {
|
|
2278
|
+
if (!ctx.parentParser) {
|
|
2279
|
+
console.error(
|
|
2280
|
+
"[MCP Server] Critical: MCP server handler called without a parent parser context."
|
|
2281
|
+
);
|
|
2282
|
+
process.exit(1);
|
|
2283
|
+
}
|
|
2284
|
+
console.error(`[${serverInfo.name}] Starting MCP Server...`);
|
|
2285
|
+
const mcpParser = ctx.parentParser;
|
|
2286
|
+
const transports = ctx.args["transports"];
|
|
2287
|
+
if (transports) {
|
|
2288
|
+
try {
|
|
2289
|
+
const transportConfigs = JSON.parse(transports);
|
|
2290
|
+
await mcpParser.startMcpServerWithMultipleTransports(serverInfo, transportConfigs, toolOptions);
|
|
2291
|
+
} catch (error) {
|
|
2292
|
+
console.error("❌ Error parsing transports configuration:", error.message);
|
|
2293
|
+
console.error(`Expected JSON format: '[{"type":"stdio"},{"type":"sse","port":3001}]'`);
|
|
2294
|
+
process.exit(1);
|
|
2295
|
+
}
|
|
2296
|
+
} else if (defaultTransports && defaultTransports.length > 0) {
|
|
2297
|
+
await mcpParser.startMcpServerWithMultipleTransports(serverInfo, defaultTransports, toolOptions);
|
|
2298
|
+
} else if (defaultTransport) {
|
|
2299
|
+
await mcpParser.startMcpServerWithTransport(
|
|
2300
|
+
serverInfo,
|
|
2301
|
+
defaultTransport.type,
|
|
2302
|
+
{
|
|
2303
|
+
port: defaultTransport.port,
|
|
2304
|
+
host: defaultTransport.host,
|
|
2305
|
+
path: defaultTransport.path,
|
|
2306
|
+
sessionIdGenerator: defaultTransport.sessionIdGenerator
|
|
2307
|
+
},
|
|
2308
|
+
toolOptions
|
|
2309
|
+
);
|
|
2310
|
+
} else {
|
|
2311
|
+
const transportType = ctx.args["transport"] || "stdio";
|
|
2312
|
+
const transportOptions = {
|
|
2313
|
+
port: ctx.args["port"],
|
|
2314
|
+
host: ctx.args["host"],
|
|
2315
|
+
path: ctx.args["path"]
|
|
2316
|
+
};
|
|
2317
|
+
await mcpParser.startMcpServerWithTransport(serverInfo, transportType, transportOptions, toolOptions);
|
|
2318
|
+
}
|
|
2319
|
+
return new Promise(() => {
|
|
2320
|
+
});
|
|
2321
|
+
};
|
|
2322
|
+
const mcpSubParser = new ArgParserBase({}, [
|
|
2323
|
+
{
|
|
2324
|
+
name: "transport",
|
|
2325
|
+
description: "Transport type for MCP server (single transport mode)",
|
|
2326
|
+
options: ["--transport", "-t"],
|
|
2327
|
+
type: "string",
|
|
2328
|
+
enum: ["stdio", "sse", "streamable-http"],
|
|
2329
|
+
defaultValue: "stdio"
|
|
2330
|
+
},
|
|
2331
|
+
{
|
|
2332
|
+
name: "transports",
|
|
2333
|
+
description: "Multiple transports configuration as JSON array (overrides single transport)",
|
|
2334
|
+
options: ["--transports"],
|
|
2335
|
+
type: "string"
|
|
2336
|
+
},
|
|
2337
|
+
{
|
|
2338
|
+
name: "port",
|
|
2339
|
+
description: "Port number for HTTP-based transports (single transport mode)",
|
|
2340
|
+
options: ["--port", "-p"],
|
|
2341
|
+
type: "number",
|
|
2342
|
+
defaultValue: 3e3
|
|
2343
|
+
},
|
|
2344
|
+
{
|
|
2345
|
+
name: "host",
|
|
2346
|
+
description: "Host address for HTTP-based transports (single transport mode)",
|
|
2347
|
+
options: ["--host"],
|
|
2348
|
+
type: "string",
|
|
2349
|
+
defaultValue: "localhost"
|
|
2350
|
+
},
|
|
2351
|
+
{
|
|
2352
|
+
name: "path",
|
|
2353
|
+
description: "Path for HTTP-based transports (single transport mode)",
|
|
2354
|
+
options: ["--path"],
|
|
2355
|
+
type: "string",
|
|
2356
|
+
defaultValue: "/mcp"
|
|
2357
|
+
}
|
|
2358
|
+
]);
|
|
2359
|
+
this.addSubCommand({
|
|
2360
|
+
name: subCommandName,
|
|
2361
|
+
description: `Start ${serverInfo.name} as an MCP server`,
|
|
2362
|
+
handler: mcpHandler,
|
|
2363
|
+
parser: mcpSubParser,
|
|
2364
|
+
isMcp: true
|
|
2365
|
+
});
|
|
2366
|
+
return this;
|
|
2367
|
+
}
|
|
2368
|
+
/**
|
|
2369
|
+
* Factory method to create an ArgParser instance with MCP capabilities
|
|
2370
|
+
* This provides a clean API for users who want MCP functionality from the start
|
|
2371
|
+
*/
|
|
2372
|
+
static withMcp(options, initialFlags) {
|
|
2373
|
+
return new _ArgParser(options, initialFlags);
|
|
2374
|
+
}
|
|
2375
|
+
/**
|
|
2376
|
+
* Convert an existing ArgParserBase instance to ArgParser with MCP
|
|
2377
|
+
* This allows upgrading existing parsers to support MCP
|
|
2378
|
+
*/
|
|
2379
|
+
static fromArgParser(parser) {
|
|
2380
|
+
const originalParser = parser;
|
|
2381
|
+
const mcpParser = new _ArgParser({
|
|
2382
|
+
appName: originalParser.getAppName(),
|
|
2383
|
+
appCommandName: originalParser.getAppCommandName(),
|
|
2384
|
+
description: originalParser.getDescription(),
|
|
2385
|
+
handler: originalParser.getHandler(),
|
|
2386
|
+
handleErrors: originalParser["#handleErrors"],
|
|
2387
|
+
throwForDuplicateFlags: originalParser["#throwForDuplicateFlags"]
|
|
2388
|
+
});
|
|
2389
|
+
const originalFlags = originalParser.flags.filter(
|
|
2390
|
+
(flag) => flag.name !== "help"
|
|
2391
|
+
);
|
|
2392
|
+
if (originalFlags.length > 0) {
|
|
2393
|
+
mcpParser.addFlags(originalFlags);
|
|
2394
|
+
}
|
|
2395
|
+
const newParser = mcpParser;
|
|
2396
|
+
newParser["#subCommandName"] = originalParser["#subCommandName"];
|
|
2397
|
+
newParser["#parameters"] = originalParser["#parameters"];
|
|
2398
|
+
newParser["#parentParser"] = originalParser["#parentParser"];
|
|
2399
|
+
newParser["#lastParseResult"] = originalParser["#lastParseResult"];
|
|
2400
|
+
newParser["#inheritParentFlags"] = originalParser["#inheritParentFlags"];
|
|
2401
|
+
newParser["#subCommands"] = originalParser["#subCommands"];
|
|
2402
|
+
return mcpParser;
|
|
2403
|
+
}
|
|
2404
|
+
};
|
|
2405
|
+
_ArgParser_instances = new WeakSet();
|
|
2406
|
+
_startSingleTransport_fn = async function(server, serverInfo, transportConfig) {
|
|
2407
|
+
switch (transportConfig.type) {
|
|
2408
|
+
case "stdio": {
|
|
2409
|
+
const { StdioServerTransport } = await import("./stdio-DLOResWr.js");
|
|
2410
|
+
const transport = new StdioServerTransport();
|
|
2411
|
+
await server.connect(transport);
|
|
2412
|
+
console.error(`[${serverInfo.name}] MCP Server started with stdio transport`);
|
|
2413
|
+
break;
|
|
2414
|
+
}
|
|
2415
|
+
case "sse": {
|
|
2416
|
+
const { SSEServerTransport } = await import("./sse-BDL3h2Ll.js");
|
|
2417
|
+
const express = (await import("express")).default;
|
|
2418
|
+
const app = express();
|
|
2419
|
+
app.use(express.json());
|
|
2420
|
+
const port = transportConfig.port || 3e3;
|
|
2421
|
+
const path2 = transportConfig.path || "/sse";
|
|
2422
|
+
app.get(path2, (_req, res) => {
|
|
2423
|
+
const transport = new SSEServerTransport(path2, res);
|
|
2424
|
+
server.connect(transport);
|
|
2425
|
+
});
|
|
2426
|
+
await new Promise((resolve) => {
|
|
2427
|
+
app.listen(port, transportConfig.host || "localhost", () => {
|
|
2428
|
+
console.error(`[${serverInfo.name}] MCP Server listening on http://${transportConfig.host || "localhost"}:${port}${path2} (SSE)`);
|
|
2429
|
+
resolve();
|
|
2430
|
+
});
|
|
2431
|
+
});
|
|
2432
|
+
break;
|
|
2433
|
+
}
|
|
2434
|
+
case "streamable-http": {
|
|
2435
|
+
const { StreamableHTTPServerTransport } = await import("./streamableHttp-Vd4Qsgko.js");
|
|
2436
|
+
const express = (await import("express")).default;
|
|
2437
|
+
const app = express();
|
|
2438
|
+
app.use(express.json());
|
|
2439
|
+
const port = transportConfig.port || 3e3;
|
|
2440
|
+
const path2 = transportConfig.path || "/mcp";
|
|
2441
|
+
const transports = {};
|
|
2442
|
+
app.all(path2, async (req, res) => {
|
|
2443
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
2444
|
+
let transport;
|
|
2445
|
+
if (sessionId && transports[sessionId]) {
|
|
2446
|
+
transport = transports[sessionId];
|
|
2447
|
+
} else {
|
|
2448
|
+
transport = new StreamableHTTPServerTransport({
|
|
2449
|
+
sessionIdGenerator: transportConfig.sessionIdGenerator || (() => Math.random().toString(36).substring(7)),
|
|
2450
|
+
onsessioninitialized: (sessionId2) => {
|
|
2451
|
+
transports[sessionId2] = transport;
|
|
2452
|
+
}
|
|
2453
|
+
});
|
|
2454
|
+
transport.onclose = () => {
|
|
2455
|
+
if (transport.sessionId) {
|
|
2456
|
+
delete transports[transport.sessionId];
|
|
2457
|
+
}
|
|
2458
|
+
};
|
|
2459
|
+
await server.connect(transport);
|
|
2460
|
+
}
|
|
2461
|
+
await transport.handleRequest(req, res, req.body);
|
|
2462
|
+
});
|
|
2463
|
+
await new Promise((resolve) => {
|
|
2464
|
+
app.listen(port, transportConfig.host || "localhost", () => {
|
|
2465
|
+
console.error(`[${serverInfo.name}] MCP Server listening on http://${transportConfig.host || "localhost"}:${port}${path2} (HTTP)`);
|
|
2466
|
+
resolve();
|
|
2467
|
+
});
|
|
2468
|
+
});
|
|
2469
|
+
break;
|
|
2470
|
+
}
|
|
2471
|
+
default:
|
|
2472
|
+
throw new Error(`Unsupported transport type: ${transportConfig.type}`);
|
|
2473
|
+
}
|
|
2474
|
+
};
|
|
1187
2475
|
let ArgParser = _ArgParser;
|
|
2476
|
+
class ArgParserFuzzyTester {
|
|
2477
|
+
constructor(parser, options = {}) {
|
|
2478
|
+
this.parser = parser;
|
|
2479
|
+
this.options = {
|
|
2480
|
+
maxDepth: options.maxDepth ?? 5,
|
|
2481
|
+
randomTestCases: options.randomTestCases ?? 10,
|
|
2482
|
+
includePerformance: options.includePerformance ?? true,
|
|
2483
|
+
testErrorCases: options.testErrorCases ?? true,
|
|
2484
|
+
verbose: options.verbose ?? false
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2487
|
+
/**
|
|
2488
|
+
* Run comprehensive fuzzy testing on the ArgParser instance
|
|
2489
|
+
*/
|
|
2490
|
+
async runFuzzyTest() {
|
|
2491
|
+
const commandPaths = this.discoverCommandPaths();
|
|
2492
|
+
const results = [];
|
|
2493
|
+
if (this.options.verbose) {
|
|
2494
|
+
console.log(`Discovered ${commandPaths.length} command paths:`);
|
|
2495
|
+
commandPaths.forEach((path2) => console.log(` ${path2.join(" ") || "(root)"}`));
|
|
2496
|
+
}
|
|
2497
|
+
for (const commandPath of commandPaths) {
|
|
2498
|
+
const pathResults = await this.testCommandPath(commandPath);
|
|
2499
|
+
results.push(...pathResults);
|
|
2500
|
+
}
|
|
2501
|
+
return this.generateReport(commandPaths, results);
|
|
2502
|
+
}
|
|
2503
|
+
/**
|
|
2504
|
+
* Discover all possible command paths in the parser
|
|
2505
|
+
*/
|
|
2506
|
+
discoverCommandPaths() {
|
|
2507
|
+
const paths = [];
|
|
2508
|
+
paths.push([]);
|
|
2509
|
+
this.discoverSubCommandPaths(this.parser, [], paths, 0);
|
|
2510
|
+
return paths;
|
|
2511
|
+
}
|
|
2512
|
+
/**
|
|
2513
|
+
* Recursively discover subcommand paths
|
|
2514
|
+
*/
|
|
2515
|
+
discoverSubCommandPaths(parser, currentPath, allPaths, depth) {
|
|
2516
|
+
if (depth >= this.options.maxDepth) return;
|
|
2517
|
+
const subCommands = this.getSubCommands(parser);
|
|
2518
|
+
for (const [subCommandName, subCommand] of subCommands) {
|
|
2519
|
+
const newPath = [...currentPath, subCommandName];
|
|
2520
|
+
allPaths.push(newPath);
|
|
2521
|
+
this.discoverSubCommandPaths(subCommand.parser, newPath, allPaths, depth + 1);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
/**
|
|
2525
|
+
* Get subcommands from a parser instance
|
|
2526
|
+
*/
|
|
2527
|
+
getSubCommands(parser) {
|
|
2528
|
+
return parser.getSubCommands();
|
|
2529
|
+
}
|
|
2530
|
+
/**
|
|
2531
|
+
* Get flags from a parser instance
|
|
2532
|
+
*/
|
|
2533
|
+
getFlags(parser) {
|
|
2534
|
+
return parser.flags;
|
|
2535
|
+
}
|
|
2536
|
+
/**
|
|
2537
|
+
* Test a specific command path with various flag combinations
|
|
2538
|
+
*/
|
|
2539
|
+
async testCommandPath(commandPath) {
|
|
2540
|
+
const results = [];
|
|
2541
|
+
const targetParser = this.getParserForPath(commandPath);
|
|
2542
|
+
const flags = this.getFlags(targetParser);
|
|
2543
|
+
if (this.options.verbose) {
|
|
2544
|
+
console.log(`Testing command path: ${commandPath.join(" ") || "(root)"}`);
|
|
2545
|
+
}
|
|
2546
|
+
const validCombinations = this.generateValidFlagCombinations(flags);
|
|
2547
|
+
for (const flagArgs of validCombinations) {
|
|
2548
|
+
const fullArgs = [...commandPath, ...flagArgs];
|
|
2549
|
+
const result = await this.executeTest(fullArgs, commandPath);
|
|
2550
|
+
results.push(result);
|
|
2551
|
+
}
|
|
2552
|
+
for (let i = 0; i < this.options.randomTestCases; i++) {
|
|
2553
|
+
const randomArgs = this.generateRandomFlagCombination(flags);
|
|
2554
|
+
const fullArgs = [...commandPath, ...randomArgs];
|
|
2555
|
+
const result = await this.executeTest(fullArgs, commandPath);
|
|
2556
|
+
results.push(result);
|
|
2557
|
+
}
|
|
2558
|
+
if (this.options.testErrorCases) {
|
|
2559
|
+
const errorCases = this.generateErrorCases(flags);
|
|
2560
|
+
for (const errorArgs of errorCases) {
|
|
2561
|
+
const fullArgs = [...commandPath, ...errorArgs];
|
|
2562
|
+
const result = await this.executeTest(fullArgs, commandPath, true);
|
|
2563
|
+
results.push(result);
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
return results;
|
|
2567
|
+
}
|
|
2568
|
+
/**
|
|
2569
|
+
* Get the parser instance for a specific command path
|
|
2570
|
+
*/
|
|
2571
|
+
getParserForPath(commandPath) {
|
|
2572
|
+
let currentParser = this.parser;
|
|
2573
|
+
for (const command of commandPath) {
|
|
2574
|
+
const subCommands = this.getSubCommands(currentParser);
|
|
2575
|
+
const subCommand = subCommands.get(command);
|
|
2576
|
+
if (!subCommand) {
|
|
2577
|
+
throw new Error(`Command path not found: ${commandPath.join(" ")}`);
|
|
2578
|
+
}
|
|
2579
|
+
currentParser = subCommand.parser;
|
|
2580
|
+
}
|
|
2581
|
+
return currentParser;
|
|
2582
|
+
}
|
|
2583
|
+
/**
|
|
2584
|
+
* Generate valid flag combinations for testing
|
|
2585
|
+
*/
|
|
2586
|
+
generateValidFlagCombinations(flags) {
|
|
2587
|
+
const combinations = [];
|
|
2588
|
+
const mandatoryFlags = flags.filter(
|
|
2589
|
+
(f) => f["name"] !== "help" && (typeof f["mandatory"] === "boolean" ? f["mandatory"] : false)
|
|
2590
|
+
);
|
|
2591
|
+
const optionalFlags = flags.filter(
|
|
2592
|
+
(f) => f["name"] !== "help" && (typeof f["mandatory"] === "boolean" ? !f["mandatory"] : true)
|
|
2593
|
+
);
|
|
2594
|
+
const mandatoryArgs = [];
|
|
2595
|
+
for (const flag of mandatoryFlags) {
|
|
2596
|
+
const flagArgs = this.generateFlagArgs(flag, "valid");
|
|
2597
|
+
mandatoryArgs.push(...flagArgs);
|
|
2598
|
+
}
|
|
2599
|
+
if (mandatoryArgs.length > 0) {
|
|
2600
|
+
combinations.push([...mandatoryArgs]);
|
|
2601
|
+
} else {
|
|
2602
|
+
combinations.push([]);
|
|
2603
|
+
}
|
|
2604
|
+
for (const flag of optionalFlags) {
|
|
2605
|
+
const flagArgs = this.generateFlagArgs(flag, "valid");
|
|
2606
|
+
if (flagArgs.length > 0) {
|
|
2607
|
+
combinations.push([...mandatoryArgs, ...flagArgs]);
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
if (optionalFlags.length > 1) {
|
|
2611
|
+
for (let i = 0; i < optionalFlags.length - 1; i++) {
|
|
2612
|
+
for (let j = i + 1; j < optionalFlags.length; j++) {
|
|
2613
|
+
const flag1Args = this.generateFlagArgs(optionalFlags[i], "valid");
|
|
2614
|
+
const flag2Args = this.generateFlagArgs(optionalFlags[j], "valid");
|
|
2615
|
+
if (flag1Args.length > 0 && flag2Args.length > 0) {
|
|
2616
|
+
combinations.push([...mandatoryArgs, ...flag1Args, ...flag2Args]);
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
return combinations;
|
|
2622
|
+
}
|
|
2623
|
+
/**
|
|
2624
|
+
* Generate random flag combination
|
|
2625
|
+
*/
|
|
2626
|
+
generateRandomFlagCombination(flags) {
|
|
2627
|
+
const args = [];
|
|
2628
|
+
const availableFlags = flags.filter((f) => f["name"] !== "help");
|
|
2629
|
+
for (const flag of availableFlags) {
|
|
2630
|
+
if (Math.random() < 0.3) {
|
|
2631
|
+
const flagArgs = this.generateFlagArgs(flag, "random");
|
|
2632
|
+
args.push(...flagArgs);
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
return args;
|
|
2636
|
+
}
|
|
2637
|
+
/**
|
|
2638
|
+
* Generate error test cases
|
|
2639
|
+
*/
|
|
2640
|
+
generateErrorCases(flags) {
|
|
2641
|
+
const errorCases = [];
|
|
2642
|
+
errorCases.push(["--invalid-flag"]);
|
|
2643
|
+
errorCases.push(["--nonexistent", "value"]);
|
|
2644
|
+
for (const flag of flags) {
|
|
2645
|
+
if (flag["name"] === "help") continue;
|
|
2646
|
+
const invalidArgs = this.generateFlagArgs(flag, "invalid");
|
|
2647
|
+
if (invalidArgs.length > 0) {
|
|
2648
|
+
errorCases.push(invalidArgs);
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
return errorCases;
|
|
2652
|
+
}
|
|
2653
|
+
/**
|
|
2654
|
+
* Generate arguments for a specific flag
|
|
2655
|
+
*/
|
|
2656
|
+
generateFlagArgs(flag, mode) {
|
|
2657
|
+
const option = flag["options"][0];
|
|
2658
|
+
if (!option) return [];
|
|
2659
|
+
if (flag["flagOnly"]) {
|
|
2660
|
+
return [option];
|
|
2661
|
+
}
|
|
2662
|
+
const values = this.generateFlagValues(flag, mode);
|
|
2663
|
+
const args = [];
|
|
2664
|
+
for (const value of values) {
|
|
2665
|
+
if (flag["allowLigature"] && Math.random() < 0.5) {
|
|
2666
|
+
args.push(`${option}=${value}`);
|
|
2667
|
+
} else {
|
|
2668
|
+
args.push(option, value);
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
return args;
|
|
2672
|
+
}
|
|
2673
|
+
/**
|
|
2674
|
+
* Generate values for a flag based on its type and constraints
|
|
2675
|
+
*/
|
|
2676
|
+
generateFlagValues(flag, mode) {
|
|
2677
|
+
const count = flag["allowMultiple"] && mode !== "invalid" ? Math.floor(Math.random() * 3) + 1 : 1;
|
|
2678
|
+
const values = [];
|
|
2679
|
+
for (let i = 0; i < count; i++) {
|
|
2680
|
+
values.push(this.generateSingleFlagValue(flag, mode));
|
|
2681
|
+
}
|
|
2682
|
+
return values;
|
|
2683
|
+
}
|
|
2684
|
+
/**
|
|
2685
|
+
* Generate a single value for a flag
|
|
2686
|
+
*/
|
|
2687
|
+
generateSingleFlagValue(flag, mode) {
|
|
2688
|
+
if (mode === "invalid") {
|
|
2689
|
+
if (flag["type"] === Number) return "not-a-number";
|
|
2690
|
+
if (flag["enum"] && flag["enum"].length > 0) return "invalid-enum-value";
|
|
2691
|
+
if (flag["type"] === Boolean) return "not-boolean";
|
|
2692
|
+
return "invalid-value";
|
|
2693
|
+
}
|
|
2694
|
+
if (flag["enum"] && flag["enum"].length > 0) {
|
|
2695
|
+
const randomIndex = Math.floor(Math.random() * flag["enum"].length);
|
|
2696
|
+
return String(flag["enum"][randomIndex]);
|
|
2697
|
+
}
|
|
2698
|
+
if (flag["type"] === Number) {
|
|
2699
|
+
return String(Math.floor(Math.random() * 1e3));
|
|
2700
|
+
}
|
|
2701
|
+
if (flag["type"] === Boolean) {
|
|
2702
|
+
return Math.random() < 0.5 ? "true" : "false";
|
|
2703
|
+
}
|
|
2704
|
+
const testStrings = [
|
|
2705
|
+
"test-value",
|
|
2706
|
+
"hello-world",
|
|
2707
|
+
"file.txt",
|
|
2708
|
+
"/path/to/file",
|
|
2709
|
+
"user@example.com",
|
|
2710
|
+
"123",
|
|
2711
|
+
"special-chars-!@#"
|
|
2712
|
+
];
|
|
2713
|
+
return testStrings[Math.floor(Math.random() * testStrings.length)];
|
|
2714
|
+
}
|
|
2715
|
+
/**
|
|
2716
|
+
* Execute a single test case
|
|
2717
|
+
*/
|
|
2718
|
+
async executeTest(args, commandPath, expectError = false) {
|
|
2719
|
+
const startTime = this.options.includePerformance ? Date.now() : 0;
|
|
2720
|
+
try {
|
|
2721
|
+
const originalArgs = [...args];
|
|
2722
|
+
const testResult = this.parser.parse(args, {
|
|
2723
|
+
skipHelpHandling: true
|
|
2724
|
+
});
|
|
2725
|
+
if (testResult && typeof testResult === "object") {
|
|
2726
|
+
testResult._originalInputArgs = originalArgs;
|
|
2727
|
+
}
|
|
2728
|
+
const executionTime = this.options.includePerformance ? Date.now() - startTime : void 0;
|
|
2729
|
+
return {
|
|
2730
|
+
commandPath,
|
|
2731
|
+
args,
|
|
2732
|
+
success: !expectError,
|
|
2733
|
+
parsedResult: testResult,
|
|
2734
|
+
executionTime
|
|
2735
|
+
};
|
|
2736
|
+
} catch (error) {
|
|
2737
|
+
const executionTime = this.options.includePerformance ? Date.now() - startTime : void 0;
|
|
2738
|
+
return {
|
|
2739
|
+
commandPath,
|
|
2740
|
+
args,
|
|
2741
|
+
success: expectError,
|
|
2742
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2743
|
+
executionTime
|
|
2744
|
+
};
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
/**
|
|
2748
|
+
* Generate comprehensive test report
|
|
2749
|
+
*/
|
|
2750
|
+
generateReport(commandPaths, results) {
|
|
2751
|
+
const totalTests = results.length;
|
|
2752
|
+
const successfulTests = results.filter((r) => r.success).length;
|
|
2753
|
+
const failedTests = totalTests - successfulTests;
|
|
2754
|
+
const coverageByPath = {};
|
|
2755
|
+
for (const path2 of commandPaths) {
|
|
2756
|
+
const pathKey = path2.join(" ") || "(root)";
|
|
2757
|
+
const pathResults = results.filter(
|
|
2758
|
+
(r) => JSON.stringify(r.commandPath) === JSON.stringify(path2)
|
|
2759
|
+
);
|
|
2760
|
+
coverageByPath[pathKey] = {
|
|
2761
|
+
total: pathResults.length,
|
|
2762
|
+
passed: pathResults.filter((r) => r.success).length
|
|
2763
|
+
};
|
|
2764
|
+
}
|
|
2765
|
+
const errorTypes = {};
|
|
2766
|
+
for (const result of results) {
|
|
2767
|
+
if (result.error) {
|
|
2768
|
+
const errorType = result.error.split(":")[0] || "Unknown";
|
|
2769
|
+
errorTypes[errorType] = (errorTypes[errorType] || 0) + 1;
|
|
2770
|
+
}
|
|
2771
|
+
}
|
|
2772
|
+
return {
|
|
2773
|
+
totalTests,
|
|
2774
|
+
successfulTests,
|
|
2775
|
+
failedTests,
|
|
2776
|
+
commandPaths,
|
|
2777
|
+
results,
|
|
2778
|
+
summary: {
|
|
2779
|
+
coverageByPath,
|
|
2780
|
+
errorTypes
|
|
2781
|
+
}
|
|
2782
|
+
};
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
1188
2785
|
export {
|
|
1189
2786
|
ArgParser,
|
|
1190
|
-
|
|
2787
|
+
ArgParserBase,
|
|
2788
|
+
ArgParserError,
|
|
2789
|
+
ArgParserFuzzyTester,
|
|
2790
|
+
generateMcpToolsFromArgParser,
|
|
2791
|
+
zodFlagSchema
|
|
1191
2792
|
};
|
|
1192
2793
|
//# sourceMappingURL=index.mjs.map
|