politty 0.4.14 → 0.4.16
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 +7 -1
- package/dist/{arg-registry-CkPDokIu.d.ts → arg-registry-Cd6xnjHa.d.ts} +118 -4
- package/dist/arg-registry-Cd6xnjHa.d.ts.map +1 -0
- package/dist/{arg-registry-r5wYN6qd.d.cts → arg-registry-MVWOAcvw.d.cts} +118 -4
- package/dist/arg-registry-MVWOAcvw.d.cts.map +1 -0
- package/dist/augment.d.cts +1 -1
- package/dist/augment.d.cts.map +1 -1
- package/dist/augment.d.ts +1 -1
- package/dist/augment.d.ts.map +1 -1
- package/dist/completion/index.cjs +2 -1
- package/dist/completion/index.d.cts +2 -2
- package/dist/completion/index.d.ts +2 -2
- package/dist/completion/index.js +2 -2
- package/dist/{completion-yHz8Pdr7.js → completion-B04iiki9.js} +580 -31
- package/dist/completion-B04iiki9.js.map +1 -0
- package/dist/{completion-CAekGYS4.cjs → completion-BlZxMSeU.cjs} +598 -43
- package/dist/completion-BlZxMSeU.cjs.map +1 -0
- package/dist/docs/index.cjs +121 -65
- package/dist/docs/index.cjs.map +1 -1
- package/dist/docs/index.d.cts +5 -1
- package/dist/docs/index.d.cts.map +1 -1
- package/dist/docs/index.d.ts +5 -1
- package/dist/docs/index.d.ts.map +1 -1
- package/dist/docs/index.js +124 -67
- package/dist/docs/index.js.map +1 -1
- package/dist/{index-DPswv0Vt.d.cts → index-CPebddth.d.cts} +58 -4
- package/dist/index-CPebddth.d.cts.map +1 -0
- package/dist/{index-BLySW_2k.d.ts → index-DR9HLxIP.d.ts} +58 -4
- package/dist/index-DR9HLxIP.d.ts.map +1 -0
- package/dist/index.cjs +12 -10
- package/dist/index.d.cts +39 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +39 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/{subcommand-router-C9ONv6Nq.cjs → log-collector-Cd2_mv87.cjs} +1 -59
- package/dist/log-collector-Cd2_mv87.cjs.map +1 -0
- package/dist/{subcommand-router--EUt6ftA.js → log-collector-Cu6MCtAx.js} +2 -43
- package/dist/log-collector-Cu6MCtAx.js.map +1 -0
- package/dist/prompt/clack/index.cjs +1 -1
- package/dist/prompt/clack/index.cjs.map +1 -1
- package/dist/prompt/clack/index.d.cts +1 -1
- package/dist/prompt/clack/index.d.cts.map +1 -1
- package/dist/prompt/clack/index.d.ts +1 -1
- package/dist/prompt/clack/index.d.ts.map +1 -1
- package/dist/prompt/clack/index.js.map +1 -1
- package/dist/prompt/index.d.cts +1 -1
- package/dist/prompt/index.d.cts.map +1 -1
- package/dist/prompt/index.d.ts +1 -1
- package/dist/prompt/index.d.ts.map +1 -1
- package/dist/prompt/inquirer/index.cjs +1 -1
- package/dist/prompt/inquirer/index.cjs.map +1 -1
- package/dist/prompt/inquirer/index.d.cts +1 -1
- package/dist/prompt/inquirer/index.d.cts.map +1 -1
- package/dist/prompt/inquirer/index.d.ts +1 -1
- package/dist/prompt/inquirer/index.d.ts.map +1 -1
- package/dist/prompt/inquirer/index.js.map +1 -1
- package/dist/prompt-BKHqGrFw.js.map +1 -1
- package/dist/prompt-aXfSf27y.cjs.map +1 -1
- package/dist/{runner-DSZw1AsW.js → runner-BHeCMEa5.js} +383 -57
- package/dist/runner-BHeCMEa5.js.map +1 -0
- package/dist/{runner-CY5fOsSh.cjs → runner-BcyR6Z8r.cjs} +434 -96
- package/dist/runner-BcyR6Z8r.cjs.map +1 -0
- package/dist/{lazy-AGV9Pkt5.cjs → subcommand-router-DQy0KZU-.cjs} +148 -4
- package/dist/subcommand-router-DQy0KZU-.cjs.map +1 -0
- package/dist/{lazy-DiMJSDMB.js → subcommand-router-XZBWe8HN.js} +118 -4
- package/dist/subcommand-router-XZBWe8HN.js.map +1 -0
- package/package.json +16 -16
- package/dist/arg-registry-CkPDokIu.d.ts.map +0 -1
- package/dist/arg-registry-r5wYN6qd.d.cts.map +0 -1
- package/dist/completion-CAekGYS4.cjs.map +0 -1
- package/dist/completion-yHz8Pdr7.js.map +0 -1
- package/dist/index-BLySW_2k.d.ts.map +0 -1
- package/dist/index-DPswv0Vt.d.cts.map +0 -1
- package/dist/lazy-AGV9Pkt5.cjs.map +0 -1
- package/dist/lazy-DiMJSDMB.js.map +0 -1
- package/dist/runner-CY5fOsSh.cjs.map +0 -1
- package/dist/runner-DSZw1AsW.js.map +0 -1
- package/dist/subcommand-router--EUt6ftA.js.map +0 -1
- package/dist/subcommand-router-C9ONv6Nq.cjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import {
|
|
1
|
+
import { a as resolveSubcommandWithAlias, c as resolveSubCommandMeta, d as getExtractedFields, l as extractFields, m as toKebabCase, n as listSubCommands, o as isLazyCommand, p as toCamelCase, r as resolveLazyCommand, t as listSubCommandNamesWithAliases, u as getAllAliases } from "./subcommand-router-XZBWe8HN.js";
|
|
2
|
+
import { n as emptyLogs, r as mergeLogs, t as createLogCollector } from "./log-collector-Cu6MCtAx.js";
|
|
3
3
|
import { styleText } from "node:util";
|
|
4
4
|
import stringWidth from "string-width";
|
|
5
5
|
|
|
@@ -236,24 +236,45 @@ const symbols = {
|
|
|
236
236
|
* Logger for CLI output
|
|
237
237
|
*/
|
|
238
238
|
const logger = {
|
|
239
|
+
/**
|
|
240
|
+
* Log informational message
|
|
241
|
+
*/
|
|
239
242
|
info(message) {
|
|
240
243
|
console.log(message);
|
|
241
244
|
},
|
|
245
|
+
/**
|
|
246
|
+
* Log success message
|
|
247
|
+
*/
|
|
242
248
|
success(message) {
|
|
243
249
|
console.log(`${symbols.success} ${styles.success(message)}`);
|
|
244
250
|
},
|
|
251
|
+
/**
|
|
252
|
+
* Log warning message
|
|
253
|
+
*/
|
|
245
254
|
warn(message) {
|
|
246
255
|
console.warn(`${symbols.warning} ${styles.warning(message)}`);
|
|
247
256
|
},
|
|
257
|
+
/**
|
|
258
|
+
* Log error message
|
|
259
|
+
*/
|
|
248
260
|
error(message) {
|
|
249
261
|
console.error(`${symbols.error} ${styles.error(message)}`);
|
|
250
262
|
},
|
|
263
|
+
/**
|
|
264
|
+
* Log raw message without prefix
|
|
265
|
+
*/
|
|
251
266
|
log(message) {
|
|
252
267
|
console.log(message);
|
|
253
268
|
},
|
|
269
|
+
/**
|
|
270
|
+
* Log empty line
|
|
271
|
+
*/
|
|
254
272
|
newline() {
|
|
255
273
|
console.log("");
|
|
256
274
|
},
|
|
275
|
+
/**
|
|
276
|
+
* Log debug message with dim color
|
|
277
|
+
*/
|
|
257
278
|
debug(message) {
|
|
258
279
|
console.log(styles.dim(message));
|
|
259
280
|
}
|
|
@@ -650,10 +671,21 @@ function renderOptions(command, descriptions = {}, context) {
|
|
|
650
671
|
const envInfo = formatEnvInfo(opt.env);
|
|
651
672
|
if (envInfo) desc += ` ${envInfo}`;
|
|
652
673
|
lines.push(formatOption(flags, desc));
|
|
674
|
+
const negationLine = formatNegationLine(opt);
|
|
675
|
+
if (negationLine) lines.push(negationLine);
|
|
653
676
|
}
|
|
654
677
|
return lines.join("\n");
|
|
655
678
|
}
|
|
656
679
|
/**
|
|
680
|
+
* Render a separate line for the custom negation option when a
|
|
681
|
+
* `negationDescription` is provided. When no description is given, the
|
|
682
|
+
* negation is shown inline by `formatFlags`.
|
|
683
|
+
*/
|
|
684
|
+
function formatNegationLine(opt, indent = 0, extraDescPadding = 0) {
|
|
685
|
+
if (!opt.negationDisplay || !opt.negationDescription) return null;
|
|
686
|
+
return formatOption(styles.option(`--${opt.negationDisplay}`), `${opt.negationDescription} ${styles.dim(`(↔ --${opt.cliName})`)}`, indent, extraDescPadding);
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
657
689
|
* Render options for discriminated union with variants
|
|
658
690
|
*/
|
|
659
691
|
function renderDiscriminatedUnionOptions(extracted, _command, lines) {
|
|
@@ -682,6 +714,8 @@ function renderDiscriminatedUnionOptions(extracted, _command, lines) {
|
|
|
682
714
|
const envInfo = formatEnvInfo(field.env);
|
|
683
715
|
if (envInfo) desc += ` ${envInfo}`;
|
|
684
716
|
lines.push(formatOption(flags, desc));
|
|
717
|
+
const negationLine = formatNegationLine(field);
|
|
718
|
+
if (negationLine) lines.push(negationLine);
|
|
685
719
|
}
|
|
686
720
|
}
|
|
687
721
|
for (const variant of variants) {
|
|
@@ -697,7 +731,9 @@ function renderDiscriminatedUnionOptions(extracted, _command, lines) {
|
|
|
697
731
|
if (field.required) desc += ` ${styles.required("(required)")}`;
|
|
698
732
|
const envInfo = formatEnvInfo(field.env);
|
|
699
733
|
if (envInfo) desc += ` ${envInfo}`;
|
|
700
|
-
lines.push(formatOption(
|
|
734
|
+
lines.push(formatOption(flags, desc, 1));
|
|
735
|
+
const negationLine = formatNegationLine(field, 1);
|
|
736
|
+
if (negationLine) lines.push(negationLine);
|
|
701
737
|
}
|
|
702
738
|
}
|
|
703
739
|
}
|
|
@@ -721,6 +757,8 @@ function renderUnionOptions(extracted, _command, lines) {
|
|
|
721
757
|
const envInfo = formatEnvInfo(field.env);
|
|
722
758
|
if (envInfo) desc += ` ${envInfo}`;
|
|
723
759
|
lines.push(formatOption(flags, desc));
|
|
760
|
+
const negationLine = formatNegationLine(field);
|
|
761
|
+
if (negationLine) lines.push(negationLine);
|
|
724
762
|
}
|
|
725
763
|
}
|
|
726
764
|
for (let i = 0; i < unionOptions.length; i++) {
|
|
@@ -738,7 +776,9 @@ function renderUnionOptions(extracted, _command, lines) {
|
|
|
738
776
|
if (field.required) desc += ` ${styles.required("(required)")}`;
|
|
739
777
|
const envInfo = formatEnvInfo(field.env);
|
|
740
778
|
if (envInfo) desc += ` ${envInfo}`;
|
|
741
|
-
lines.push(formatOption(
|
|
779
|
+
lines.push(formatOption(flags, desc, 1));
|
|
780
|
+
const negationLine = formatNegationLine(field, 1);
|
|
781
|
+
if (negationLine) lines.push(negationLine);
|
|
742
782
|
}
|
|
743
783
|
} else {
|
|
744
784
|
lines.push("");
|
|
@@ -753,16 +793,16 @@ function renderUnionOptions(extracted, _command, lines) {
|
|
|
753
793
|
* Uses cliName (kebab-case) for display
|
|
754
794
|
*/
|
|
755
795
|
function formatFlags(opt) {
|
|
756
|
-
const
|
|
796
|
+
const aliasParts = [];
|
|
757
797
|
if (opt.alias) {
|
|
758
|
-
for (const alias of opt.alias) if (alias.length === 1)
|
|
798
|
+
for (const alias of opt.alias) if (alias.length === 1) aliasParts.push(styles.option(`-${alias}`));
|
|
759
799
|
}
|
|
760
800
|
let longFlag = styles.option(`--${opt.cliName}`);
|
|
761
801
|
if (opt.type !== "boolean") {
|
|
762
802
|
const placeholder = opt.placeholder ?? opt.cliName.toUpperCase();
|
|
763
803
|
longFlag += ` ${styles.placeholder(`<${placeholder}>`)}`;
|
|
764
804
|
}
|
|
765
|
-
|
|
805
|
+
aliasParts.push(longFlag);
|
|
766
806
|
if (opt.alias) {
|
|
767
807
|
for (const alias of opt.alias) if (alias.length > 1) {
|
|
768
808
|
let longAlias = styles.option(`--${alias}`);
|
|
@@ -770,10 +810,12 @@ function formatFlags(opt) {
|
|
|
770
810
|
const placeholder = opt.placeholder ?? opt.cliName.toUpperCase();
|
|
771
811
|
longAlias += ` ${styles.placeholder(`<${placeholder}>`)}`;
|
|
772
812
|
}
|
|
773
|
-
|
|
813
|
+
aliasParts.push(longAlias);
|
|
774
814
|
}
|
|
775
815
|
}
|
|
776
|
-
|
|
816
|
+
const aliasStr = aliasParts.join(", ");
|
|
817
|
+
if (opt.type === "boolean" && opt.negationDisplay && !opt.negationDescription) return `${aliasStr} / ${styles.option(`--${opt.negationDisplay}`)}`;
|
|
818
|
+
return aliasStr;
|
|
777
819
|
}
|
|
778
820
|
/**
|
|
779
821
|
* Format environment variable info for help display
|
|
@@ -825,7 +867,14 @@ function formatFieldLine(opt, indent = 0, extraDescPadding = 0) {
|
|
|
825
867
|
* Render global options section
|
|
826
868
|
*/
|
|
827
869
|
function renderGlobalOptions(globalExtracted) {
|
|
828
|
-
|
|
870
|
+
const lines = [];
|
|
871
|
+
for (const opt of globalExtracted.fields) {
|
|
872
|
+
if (opt.positional) continue;
|
|
873
|
+
lines.push(formatFieldLine(opt));
|
|
874
|
+
const negationLine = formatNegationLine(opt);
|
|
875
|
+
if (negationLine) lines.push(negationLine);
|
|
876
|
+
}
|
|
877
|
+
return lines.join("\n");
|
|
829
878
|
}
|
|
830
879
|
/**
|
|
831
880
|
* Render options for a subcommand (used by showSubcommandOptions)
|
|
@@ -842,6 +891,8 @@ function renderSubcommandOptionsCompact(command, indent) {
|
|
|
842
891
|
const envInfo = formatEnvInfo(opt.env);
|
|
843
892
|
if (envInfo) desc += ` ${envInfo}`;
|
|
844
893
|
lines.push(formatOption(flags, desc, indent, 2));
|
|
894
|
+
const negationLine = formatNegationLine(opt, indent, 2);
|
|
895
|
+
if (negationLine) lines.push(negationLine);
|
|
845
896
|
}
|
|
846
897
|
}
|
|
847
898
|
return lines;
|
|
@@ -855,7 +906,9 @@ function renderSubcommandsWithOptions(subCommands, parentPath, baseIndent) {
|
|
|
855
906
|
const cmd = resolveSubCommandMeta(subCmd);
|
|
856
907
|
const fullPath = parentPath ? `${parentPath} ${name}` : name;
|
|
857
908
|
const desc = cmd?.description ?? "";
|
|
858
|
-
|
|
909
|
+
const aliases = cmd?.aliases;
|
|
910
|
+
const displayName = aliases && aliases.length > 0 ? `${fullPath}, ${aliases.join(", ")}` : fullPath;
|
|
911
|
+
lines.push(formatOption(styles.command(displayName), desc, baseIndent));
|
|
859
912
|
if (cmd) {
|
|
860
913
|
const optionLines = renderSubcommandOptionsCompact(cmd, baseIndent + 1);
|
|
861
914
|
lines.push(...optionLines);
|
|
@@ -886,7 +939,9 @@ function generateHelp(command, options) {
|
|
|
886
939
|
else if (context?.rootVersion) header += ` ${styles.version(`v${context.rootVersion}`)}`;
|
|
887
940
|
sections.push(header);
|
|
888
941
|
}
|
|
942
|
+
if (context?.aliasFor) sections.push(styles.dim(`Alias for ${styles.commandName(context.aliasFor)}`));
|
|
889
943
|
if (command.description) sections.push(command.description);
|
|
944
|
+
if (!context?.aliasFor && command.aliases && command.aliases.length > 0) sections.push(`${styles.sectionHeader("Aliases:")} ${command.aliases.map((a) => styles.command(a)).join(", ")}`);
|
|
890
945
|
sections.push(`${styles.sectionHeader("Usage:")} ${renderUsageLine(command, context)}`);
|
|
891
946
|
const optionsText = renderOptions(command, options.descriptions, context);
|
|
892
947
|
if (optionsText) sections.push(`${styles.sectionHeader("Options:")}\n${optionsText}`);
|
|
@@ -900,9 +955,12 @@ function generateHelp(command, options) {
|
|
|
900
955
|
} else {
|
|
901
956
|
const subLines = [];
|
|
902
957
|
for (const [name, subCmd] of Object.entries(visibleSubCommands)) {
|
|
903
|
-
const
|
|
958
|
+
const cmd = resolveSubCommandMeta(subCmd);
|
|
959
|
+
const desc = cmd?.description ?? "";
|
|
904
960
|
const fullName = currentPath ? `${currentPath} ${name}` : name;
|
|
905
|
-
|
|
961
|
+
const aliases = cmd?.aliases;
|
|
962
|
+
const displayName = aliases && aliases.length > 0 ? `${fullName}, ${aliases.join(", ")}` : fullName;
|
|
963
|
+
subLines.push(formatOption(styles.command(displayName), desc));
|
|
906
964
|
}
|
|
907
965
|
sections.push(`${styles.sectionHeader("Commands:")}\n${subLines.join("\n")}`);
|
|
908
966
|
}
|
|
@@ -982,6 +1040,17 @@ var CaseVariantCollisionError = class extends Error {
|
|
|
982
1040
|
this.name = "CaseVariantCollisionError";
|
|
983
1041
|
}
|
|
984
1042
|
};
|
|
1043
|
+
/**
|
|
1044
|
+
* Error thrown when a custom boolean negation name collides with another
|
|
1045
|
+
* field's name, cliName, alias, or another field's negation (including
|
|
1046
|
+
* derived camelCase variants).
|
|
1047
|
+
*/
|
|
1048
|
+
var DuplicateNegationError = class extends Error {
|
|
1049
|
+
constructor(message) {
|
|
1050
|
+
super(message);
|
|
1051
|
+
this.name = "DuplicateNegationError";
|
|
1052
|
+
}
|
|
1053
|
+
};
|
|
985
1054
|
|
|
986
1055
|
//#endregion
|
|
987
1056
|
//#region src/validator/command-validator.ts
|
|
@@ -1062,6 +1131,79 @@ function checkDuplicateAliases(extracted, commandPath) {
|
|
|
1062
1131
|
return errors;
|
|
1063
1132
|
}
|
|
1064
1133
|
/**
|
|
1134
|
+
* Check for collisions involving custom boolean `negation` names
|
|
1135
|
+
*/
|
|
1136
|
+
function checkDuplicateNegations(extracted, commandPath) {
|
|
1137
|
+
const errors = [];
|
|
1138
|
+
const claimed = /* @__PURE__ */ new Map();
|
|
1139
|
+
const claim = (name, fieldName, kind) => {
|
|
1140
|
+
if (!claimed.has(name)) claimed.set(name, {
|
|
1141
|
+
field: fieldName,
|
|
1142
|
+
kind
|
|
1143
|
+
});
|
|
1144
|
+
};
|
|
1145
|
+
for (const field of extracted.fields) {
|
|
1146
|
+
claim(field.name, field.name, "field name");
|
|
1147
|
+
if (field.name.includes("-")) {
|
|
1148
|
+
const camelName = toCamelCase(field.name);
|
|
1149
|
+
if (camelName !== field.name) claim(camelName, field.name, "field name");
|
|
1150
|
+
}
|
|
1151
|
+
if (field.cliName !== field.name) claim(field.cliName, field.name, "CLI name");
|
|
1152
|
+
if (field.cliName.includes("-")) {
|
|
1153
|
+
const camelCli = toCamelCase(field.cliName);
|
|
1154
|
+
if (camelCli !== field.cliName) claim(camelCli, field.name, "CLI name");
|
|
1155
|
+
}
|
|
1156
|
+
for (const alias of getAllAliases(field)) {
|
|
1157
|
+
claim(alias, field.name, "alias");
|
|
1158
|
+
if (alias.length > 1 && alias.includes("-")) {
|
|
1159
|
+
const camelVariant = toCamelCase(alias);
|
|
1160
|
+
if (camelVariant !== alias) claim(camelVariant, field.name, "alias");
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
if (field.type === "boolean" && field.negation !== false && typeof field.negation !== "string") {
|
|
1164
|
+
const defaultKebab = `no-${field.cliName}`;
|
|
1165
|
+
claim(defaultKebab, field.name, "default negation");
|
|
1166
|
+
const camelBase = toCamelCase(field.cliName);
|
|
1167
|
+
const defaultCamel = `no${camelBase[0]?.toUpperCase() ?? ""}${camelBase.slice(1)}`;
|
|
1168
|
+
if (defaultCamel !== defaultKebab) claim(defaultCamel, field.name, "default negation");
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
const seenNegations = /* @__PURE__ */ new Map();
|
|
1172
|
+
const register = (name, fieldName, isDerived) => {
|
|
1173
|
+
const claim = claimed.get(name);
|
|
1174
|
+
if (claim) {
|
|
1175
|
+
const qualifier = isDerived ? " (derived camelCase variant)" : "";
|
|
1176
|
+
const conflict = claim.field === fieldName ? `the same field's own ${claim.kind} "${name}"` : `${claim.kind} "${name}" of field "${claim.field}"`;
|
|
1177
|
+
errors.push({
|
|
1178
|
+
commandPath,
|
|
1179
|
+
type: "duplicate_negation",
|
|
1180
|
+
message: `Negation "${name}"${qualifier} for field "${fieldName}" conflicts with ${conflict}.`,
|
|
1181
|
+
field: fieldName
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
const existing = seenNegations.get(name);
|
|
1185
|
+
if (existing && existing !== fieldName) {
|
|
1186
|
+
const qualifier = isDerived ? " (derived camelCase variant)" : "";
|
|
1187
|
+
errors.push({
|
|
1188
|
+
commandPath,
|
|
1189
|
+
type: "duplicate_negation",
|
|
1190
|
+
message: `Duplicate negation "${name}"${qualifier} detected. Both "${existing}" and "${fieldName}" use the same negation name.`,
|
|
1191
|
+
field: fieldName
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
seenNegations.set(name, fieldName);
|
|
1195
|
+
};
|
|
1196
|
+
for (const field of extracted.fields) {
|
|
1197
|
+
if (typeof field.negation !== "string") continue;
|
|
1198
|
+
register(field.negation, field.name, false);
|
|
1199
|
+
if (field.negation.includes("-")) {
|
|
1200
|
+
const camelVariant = toCamelCase(field.negation);
|
|
1201
|
+
if (camelVariant !== field.negation) register(camelVariant, field.name, true);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
return errors;
|
|
1205
|
+
}
|
|
1206
|
+
/**
|
|
1065
1207
|
* Check positional argument configuration
|
|
1066
1208
|
*/
|
|
1067
1209
|
function checkPositionalConfig(extracted, commandPath) {
|
|
@@ -1176,6 +1318,19 @@ function validateReservedAliases(extracted, _hasSubCommands) {
|
|
|
1176
1318
|
}
|
|
1177
1319
|
}
|
|
1178
1320
|
/**
|
|
1321
|
+
* Validate that custom boolean negation names do not collide with anything
|
|
1322
|
+
*
|
|
1323
|
+
* @param extracted - Extracted fields from schema
|
|
1324
|
+
* @throws {DuplicateNegationError} If a colliding negation is found
|
|
1325
|
+
*/
|
|
1326
|
+
function validateDuplicateNegations(extracted) {
|
|
1327
|
+
const errors = checkDuplicateNegations(extracted, []);
|
|
1328
|
+
if (errors.length > 0) {
|
|
1329
|
+
const err = errors[0];
|
|
1330
|
+
throw new DuplicateNegationError(err.message);
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
/**
|
|
1179
1334
|
* Validate that no case-variant collisions exist
|
|
1180
1335
|
*
|
|
1181
1336
|
* @param extracted - Extracted fields from schema
|
|
@@ -1213,11 +1368,63 @@ function collectSchemaErrors(extracted, _hasSubCommands, commandPath) {
|
|
|
1213
1368
|
...checkDuplicateFields(extracted, commandPath),
|
|
1214
1369
|
...checkCaseVariantCollisions(extracted, commandPath),
|
|
1215
1370
|
...checkDuplicateAliases(extracted, commandPath),
|
|
1371
|
+
...checkDuplicateNegations(extracted, commandPath),
|
|
1216
1372
|
...checkPositionalConfig(extracted, commandPath),
|
|
1217
1373
|
...checkReservedAliases(extracted, commandPath)
|
|
1218
1374
|
];
|
|
1219
1375
|
}
|
|
1220
1376
|
/**
|
|
1377
|
+
* Check for alias conflicts within subcommands
|
|
1378
|
+
* - Aliases must not conflict with subcommand names
|
|
1379
|
+
* - Aliases must not conflict with other aliases
|
|
1380
|
+
*/
|
|
1381
|
+
function checkSubCommandAliasConflicts(command, commandPath) {
|
|
1382
|
+
const errors = [];
|
|
1383
|
+
if (!command.subCommands) return errors;
|
|
1384
|
+
const nameToOwner = /* @__PURE__ */ new Map();
|
|
1385
|
+
for (const [name] of Object.entries(command.subCommands)) nameToOwner.set(name, name);
|
|
1386
|
+
for (const [name, subCmdValue] of Object.entries(command.subCommands)) {
|
|
1387
|
+
const resolved = isLazyCommand(subCmdValue) ? subCmdValue.meta : typeof subCmdValue !== "function" ? subCmdValue : null;
|
|
1388
|
+
if (!resolved?.aliases) continue;
|
|
1389
|
+
const subCommandPath = [...commandPath, name];
|
|
1390
|
+
for (const alias of resolved.aliases) {
|
|
1391
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(alias)) {
|
|
1392
|
+
errors.push({
|
|
1393
|
+
commandPath: subCommandPath,
|
|
1394
|
+
type: "invalid_alias",
|
|
1395
|
+
message: `Alias "${alias}" is invalid. Aliases must start with an alphanumeric character and contain only alphanumeric characters, hyphens, or underscores.`,
|
|
1396
|
+
field: name
|
|
1397
|
+
});
|
|
1398
|
+
continue;
|
|
1399
|
+
}
|
|
1400
|
+
if (alias === name) {
|
|
1401
|
+
errors.push({
|
|
1402
|
+
commandPath: subCommandPath,
|
|
1403
|
+
type: "duplicate_alias",
|
|
1404
|
+
message: `Alias "${alias}" conflicts with its own name.`,
|
|
1405
|
+
field: name
|
|
1406
|
+
});
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
const existing = nameToOwner.get(alias);
|
|
1410
|
+
if (existing) if (existing === name) errors.push({
|
|
1411
|
+
commandPath: subCommandPath,
|
|
1412
|
+
type: "duplicate_alias",
|
|
1413
|
+
message: `Alias "${alias}" is duplicated within the alias list.`,
|
|
1414
|
+
field: name
|
|
1415
|
+
});
|
|
1416
|
+
else errors.push({
|
|
1417
|
+
commandPath: subCommandPath,
|
|
1418
|
+
type: "duplicate_alias",
|
|
1419
|
+
message: `Alias "${alias}" conflicts with existing subcommand or alias "${existing}".`,
|
|
1420
|
+
field: name
|
|
1421
|
+
});
|
|
1422
|
+
else nameToOwner.set(alias, name);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
return errors;
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1221
1428
|
* Validate a command and all its subcommands recursively
|
|
1222
1429
|
*
|
|
1223
1430
|
* This function collects all validation errors without throwing,
|
|
@@ -1243,6 +1450,7 @@ async function validateCommand(command, options = {}) {
|
|
|
1243
1450
|
const extracted = extractFields(command.args);
|
|
1244
1451
|
errors.push(...collectSchemaErrors(extracted, hasSubCommands, commandPath));
|
|
1245
1452
|
}
|
|
1453
|
+
errors.push(...checkSubCommandAliasConflicts(command, commandPath));
|
|
1246
1454
|
if (command.subCommands) for (const [name, subCmd] of Object.entries(command.subCommands)) {
|
|
1247
1455
|
const subResult = await validateCommand(await resolveLazyCommand(subCmd), { commandPath: [...commandPath, name] });
|
|
1248
1456
|
if (!subResult.valid) errors.push(...subResult.errors);
|
|
@@ -1293,7 +1501,7 @@ function formatCommandValidationErrors(errors) {
|
|
|
1293
1501
|
* @returns Parsed arguments
|
|
1294
1502
|
*/
|
|
1295
1503
|
function parseArgv(argv, options = {}) {
|
|
1296
|
-
const { aliasMap = /* @__PURE__ */ new Map(), booleanFlags = /* @__PURE__ */ new Set(), arrayFlags = /* @__PURE__ */ new Set(), definedNames = /* @__PURE__ */ new Set() } = options;
|
|
1504
|
+
const { aliasMap = /* @__PURE__ */ new Map(), booleanFlags = /* @__PURE__ */ new Set(), arrayFlags = /* @__PURE__ */ new Set(), definedNames = /* @__PURE__ */ new Set(), negationMap = /* @__PURE__ */ new Map(), customNegatedFields = /* @__PURE__ */ new Set() } = options;
|
|
1297
1505
|
const result = {
|
|
1298
1506
|
options: {},
|
|
1299
1507
|
positionals: [],
|
|
@@ -1324,11 +1532,19 @@ function parseArgv(argv, options = {}) {
|
|
|
1324
1532
|
}
|
|
1325
1533
|
if (arg.startsWith("--")) {
|
|
1326
1534
|
const withoutDashes = arg.slice(2);
|
|
1535
|
+
if (!withoutDashes.includes("=")) {
|
|
1536
|
+
const negatedField = negationMap.get(withoutDashes);
|
|
1537
|
+
if (negatedField && booleanFlags.has(negatedField)) {
|
|
1538
|
+
setOption(negatedField, false);
|
|
1539
|
+
i++;
|
|
1540
|
+
continue;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1327
1543
|
if (withoutDashes.startsWith("no-")) {
|
|
1328
1544
|
const flagName = withoutDashes.slice(3);
|
|
1329
1545
|
if (flagName === flagName.toLowerCase()) {
|
|
1330
1546
|
const resolvedName = aliasMap.get(flagName) ?? flagName;
|
|
1331
|
-
if (booleanFlags.has(resolvedName)) {
|
|
1547
|
+
if (booleanFlags.has(resolvedName) && !customNegatedFields.has(resolvedName)) {
|
|
1332
1548
|
const asIsResolved = aliasMap.get(withoutDashes) ?? withoutDashes;
|
|
1333
1549
|
if (!definedNames.has(asIsResolved)) {
|
|
1334
1550
|
setOption(flagName, false);
|
|
@@ -1341,7 +1557,7 @@ function parseArgv(argv, options = {}) {
|
|
|
1341
1557
|
if (withoutDashes.length > 2 && withoutDashes.startsWith("no") && /[A-Z]/.test(withoutDashes[2])) {
|
|
1342
1558
|
const camelFlagName = withoutDashes[2].toLowerCase() + withoutDashes.slice(3);
|
|
1343
1559
|
const resolvedName = aliasMap.get(camelFlagName) ?? camelFlagName;
|
|
1344
|
-
if (booleanFlags.has(resolvedName)) {
|
|
1560
|
+
if (booleanFlags.has(resolvedName) && !customNegatedFields.has(resolvedName)) {
|
|
1345
1561
|
const asIsResolved = aliasMap.get(withoutDashes) ?? withoutDashes;
|
|
1346
1562
|
if (!definedNames.has(asIsResolved)) {
|
|
1347
1563
|
setOption(camelFlagName, false);
|
|
@@ -1414,6 +1630,8 @@ function buildParserOptions(extracted) {
|
|
|
1414
1630
|
const booleanFlags = /* @__PURE__ */ new Set();
|
|
1415
1631
|
const arrayFlags = /* @__PURE__ */ new Set();
|
|
1416
1632
|
const definedNames = /* @__PURE__ */ new Set();
|
|
1633
|
+
const negationMap = /* @__PURE__ */ new Map();
|
|
1634
|
+
const customNegatedFields = /* @__PURE__ */ new Set();
|
|
1417
1635
|
for (const field of extracted.fields) definedNames.add(field.name);
|
|
1418
1636
|
for (const field of extracted.fields) {
|
|
1419
1637
|
if (field.cliName !== field.name) aliasMap.set(field.cliName, field.name);
|
|
@@ -1428,12 +1646,24 @@ function buildParserOptions(extracted) {
|
|
|
1428
1646
|
if (camelVariant !== field.name && !definedNames.has(camelVariant) && !aliasMap.has(camelVariant)) aliasMap.set(camelVariant, field.name);
|
|
1429
1647
|
if (field.type === "boolean") booleanFlags.add(field.name);
|
|
1430
1648
|
if (field.type === "array") arrayFlags.add(field.name);
|
|
1649
|
+
if (field.type === "boolean" && (typeof field.negation === "string" || field.negation === false)) {
|
|
1650
|
+
customNegatedFields.add(field.name);
|
|
1651
|
+
if (typeof field.negation === "string") {
|
|
1652
|
+
negationMap.set(field.negation, field.name);
|
|
1653
|
+
if (field.negation.includes("-")) {
|
|
1654
|
+
const camelNegation = toCamelCase(field.negation);
|
|
1655
|
+
if (camelNegation !== field.negation) negationMap.set(camelNegation, field.name);
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1431
1659
|
}
|
|
1432
1660
|
return {
|
|
1433
1661
|
aliasMap,
|
|
1434
1662
|
booleanFlags,
|
|
1435
1663
|
arrayFlags,
|
|
1436
|
-
definedNames
|
|
1664
|
+
definedNames,
|
|
1665
|
+
negationMap,
|
|
1666
|
+
customNegatedFields
|
|
1437
1667
|
};
|
|
1438
1668
|
}
|
|
1439
1669
|
/**
|
|
@@ -1464,7 +1694,7 @@ function mergeWithPositionals(parsed, extracted) {
|
|
|
1464
1694
|
* Shared by scanForSubcommand, separateGlobalArgs, and findFirstPositional.
|
|
1465
1695
|
*/
|
|
1466
1696
|
function buildGlobalFlagLookup(globalExtracted) {
|
|
1467
|
-
const { aliasMap = /* @__PURE__ */ new Map(), booleanFlags = /* @__PURE__ */ new Set() } = buildParserOptions(globalExtracted);
|
|
1697
|
+
const { aliasMap = /* @__PURE__ */ new Map(), booleanFlags = /* @__PURE__ */ new Set(), negationMap = /* @__PURE__ */ new Map(), customNegatedFields = /* @__PURE__ */ new Set() } = buildParserOptions(globalExtracted);
|
|
1468
1698
|
const shortAliases = /* @__PURE__ */ new Set();
|
|
1469
1699
|
for (const field of globalExtracted.fields) for (const alias of getAllAliases(field)) if (alias.length === 1) shortAliases.add(alias);
|
|
1470
1700
|
return {
|
|
@@ -1472,23 +1702,53 @@ function buildGlobalFlagLookup(globalExtracted) {
|
|
|
1472
1702
|
booleanFlags,
|
|
1473
1703
|
flagNames: new Set(globalExtracted.fields.map((f) => f.name)),
|
|
1474
1704
|
cliNames: new Set(globalExtracted.fields.map((f) => f.cliName)),
|
|
1475
|
-
aliases: shortAliases
|
|
1705
|
+
aliases: shortAliases,
|
|
1706
|
+
negationMap,
|
|
1707
|
+
customNegatedFields
|
|
1476
1708
|
};
|
|
1477
1709
|
}
|
|
1478
1710
|
/**
|
|
1479
|
-
* Resolve a long option (--flag, --flag=value, --no-flag)
|
|
1480
|
-
* Returns the resolved camelCase name and whether
|
|
1711
|
+
* Resolve a long option (--flag, --flag=value, --no-flag, --custom-negation)
|
|
1712
|
+
* against global flag lookup. Returns the resolved camelCase name and whether
|
|
1713
|
+
* it is a known global flag.
|
|
1714
|
+
*
|
|
1715
|
+
* `isSuppressedNegation` is true when the token matches a default `--no-X`
|
|
1716
|
+
* form that has been suppressed by a custom `negation` on the target field.
|
|
1717
|
+
* The caller may use this to keep argv scanning past such tokens (so a
|
|
1718
|
+
* trailing subcommand is still detected) even though they no longer negate.
|
|
1481
1719
|
*/
|
|
1482
1720
|
function resolveGlobalLongOption(arg, lookup) {
|
|
1483
1721
|
const withoutDashes = arg.includes("=") ? arg.slice(2, arg.indexOf("=")) : arg.slice(2);
|
|
1484
|
-
const
|
|
1485
|
-
|
|
1722
|
+
const customNegated = !arg.includes("=") ? lookup.negationMap.get(withoutDashes) : void 0;
|
|
1723
|
+
if (customNegated) return {
|
|
1724
|
+
resolvedName: customNegated,
|
|
1725
|
+
withoutDashes,
|
|
1726
|
+
isNegated: true,
|
|
1727
|
+
isGlobal: lookup.flagNames.has(customNegated),
|
|
1728
|
+
isSuppressedNegation: false
|
|
1729
|
+
};
|
|
1730
|
+
const kebabNegated = withoutDashes.startsWith("no-");
|
|
1731
|
+
const camelNegated = !kebabNegated && withoutDashes.length > 2 && withoutDashes.startsWith("no") && /[A-Z]/.test(withoutDashes[2]);
|
|
1732
|
+
if (kebabNegated || camelNegated) {
|
|
1733
|
+
const literalResolved = lookup.aliasMap.get(withoutDashes) ?? withoutDashes;
|
|
1734
|
+
if (lookup.flagNames.has(literalResolved) || lookup.cliNames.has(withoutDashes)) return {
|
|
1735
|
+
resolvedName: literalResolved,
|
|
1736
|
+
withoutDashes,
|
|
1737
|
+
isNegated: false,
|
|
1738
|
+
isGlobal: true,
|
|
1739
|
+
isSuppressedNegation: false
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
const defaultIsNegated = kebabNegated || camelNegated;
|
|
1743
|
+
const flagName = kebabNegated ? withoutDashes.slice(3) : camelNegated ? withoutDashes[2].toLowerCase() + withoutDashes.slice(3) : withoutDashes;
|
|
1486
1744
|
const resolvedName = lookup.aliasMap.get(flagName) ?? flagName;
|
|
1745
|
+
const suppressDefaultNegation = defaultIsNegated && lookup.customNegatedFields.has(resolvedName);
|
|
1487
1746
|
return {
|
|
1488
1747
|
resolvedName,
|
|
1489
1748
|
withoutDashes,
|
|
1490
|
-
isNegated,
|
|
1491
|
-
isGlobal: lookup.flagNames.has(resolvedName) || lookup.cliNames.has(withoutDashes) || lookup.cliNames.has(flagName)
|
|
1749
|
+
isNegated: defaultIsNegated && !suppressDefaultNegation,
|
|
1750
|
+
isGlobal: !suppressDefaultNegation && (lookup.flagNames.has(resolvedName) || lookup.cliNames.has(withoutDashes) || lookup.cliNames.has(flagName)),
|
|
1751
|
+
isSuppressedNegation: suppressDefaultNegation
|
|
1492
1752
|
};
|
|
1493
1753
|
}
|
|
1494
1754
|
/**
|
|
@@ -1536,6 +1796,7 @@ function scanForSubcommand(argv, subCommandNames, globalExtracted) {
|
|
|
1536
1796
|
const lookup = buildGlobalFlagLookup(globalExtracted);
|
|
1537
1797
|
const subCommandNameSet = new Set(subCommandNames);
|
|
1538
1798
|
const globalTokensBefore = [];
|
|
1799
|
+
const suppressedTokens = [];
|
|
1539
1800
|
let i = 0;
|
|
1540
1801
|
while (i < argv.length) {
|
|
1541
1802
|
const arg = argv[i];
|
|
@@ -1543,14 +1804,20 @@ function scanForSubcommand(argv, subCommandNames, globalExtracted) {
|
|
|
1543
1804
|
if (!arg.startsWith("-") && subCommandNameSet.has(arg)) return {
|
|
1544
1805
|
subCommandIndex: i,
|
|
1545
1806
|
globalTokensBefore,
|
|
1546
|
-
tokensAfterSubcommand: argv.slice(i + 1)
|
|
1807
|
+
tokensAfterSubcommand: argv.slice(i + 1),
|
|
1808
|
+
suppressedTokens
|
|
1547
1809
|
};
|
|
1548
1810
|
if (arg.startsWith("--")) {
|
|
1549
|
-
const { resolvedName, isNegated, isGlobal } = resolveGlobalLongOption(arg, lookup);
|
|
1811
|
+
const { resolvedName, isNegated, isGlobal, isSuppressedNegation } = resolveGlobalLongOption(arg, lookup);
|
|
1550
1812
|
if (isGlobal) {
|
|
1551
1813
|
i += collectGlobalFlag(argv, i, resolvedName, isNegated, lookup.booleanFlags, globalTokensBefore);
|
|
1552
1814
|
continue;
|
|
1553
1815
|
}
|
|
1816
|
+
if (isSuppressedNegation) {
|
|
1817
|
+
suppressedTokens.push(arg.includes("=") ? arg.slice(2, arg.indexOf("=")) : arg.slice(2));
|
|
1818
|
+
i++;
|
|
1819
|
+
continue;
|
|
1820
|
+
}
|
|
1554
1821
|
break;
|
|
1555
1822
|
}
|
|
1556
1823
|
if (arg.startsWith("-") && arg.length > 1) {
|
|
@@ -1569,7 +1836,8 @@ function scanForSubcommand(argv, subCommandNames, globalExtracted) {
|
|
|
1569
1836
|
return {
|
|
1570
1837
|
subCommandIndex: -1,
|
|
1571
1838
|
globalTokensBefore,
|
|
1572
|
-
tokensAfterSubcommand: []
|
|
1839
|
+
tokensAfterSubcommand: [],
|
|
1840
|
+
suppressedTokens
|
|
1573
1841
|
};
|
|
1574
1842
|
}
|
|
1575
1843
|
const BUILTIN_FLAGS = new Set([
|
|
@@ -1615,7 +1883,8 @@ function findFirstPositional(argv, globalExtracted) {
|
|
|
1615
1883
|
* @returns Parse result
|
|
1616
1884
|
*/
|
|
1617
1885
|
function parseArgs(argv, command, options = {}) {
|
|
1618
|
-
const
|
|
1886
|
+
const subCommandNameSet = listSubCommandNamesWithAliases(command);
|
|
1887
|
+
const subCommandNames = [...subCommandNameSet];
|
|
1619
1888
|
const hasSubCommands = subCommandNames.length > 0;
|
|
1620
1889
|
if (hasSubCommands && argv.length > 0) if (options.globalExtracted) {
|
|
1621
1890
|
const scanResult = scanForSubcommand(argv, subCommandNames, options.globalExtracted);
|
|
@@ -1629,13 +1898,13 @@ function parseArgs(argv, command, options = {}) {
|
|
|
1629
1898
|
remainingArgs: scanResult.tokensAfterSubcommand,
|
|
1630
1899
|
rawArgs: {},
|
|
1631
1900
|
positionals: [],
|
|
1632
|
-
unknownFlags:
|
|
1901
|
+
unknownFlags: scanResult.suppressedTokens,
|
|
1633
1902
|
rawGlobalArgs
|
|
1634
1903
|
};
|
|
1635
1904
|
}
|
|
1636
1905
|
} else {
|
|
1637
1906
|
const firstArg = argv[0];
|
|
1638
|
-
if (firstArg && !firstArg.startsWith("-") &&
|
|
1907
|
+
if (firstArg && !firstArg.startsWith("-") && subCommandNameSet.has(firstArg)) return {
|
|
1639
1908
|
helpRequested: false,
|
|
1640
1909
|
helpAllRequested: false,
|
|
1641
1910
|
versionRequested: false,
|
|
@@ -1653,6 +1922,7 @@ function parseArgs(argv, command, options = {}) {
|
|
|
1653
1922
|
validateDuplicateFields(extracted);
|
|
1654
1923
|
validateCaseVariantCollisions(extracted);
|
|
1655
1924
|
validateDuplicateAliases(extracted);
|
|
1925
|
+
validateDuplicateNegations(extracted);
|
|
1656
1926
|
validatePositionalConfig(extracted);
|
|
1657
1927
|
validateReservedAliases(extracted, hasSubCommands);
|
|
1658
1928
|
if (options.globalExtracted) validateCrossSchemaCollisions(options.globalExtracted, extracted);
|
|
@@ -1762,7 +2032,7 @@ function separateGlobalArgs(argv, globalExtracted, localExtracted) {
|
|
|
1762
2032
|
}
|
|
1763
2033
|
if (arg.startsWith("--")) {
|
|
1764
2034
|
const { resolvedName, withoutDashes, isNegated, isGlobal } = resolveGlobalLongOption(arg, lookup);
|
|
1765
|
-
const flagName =
|
|
2035
|
+
const flagName = resolvedName;
|
|
1766
2036
|
const isLocalCollision = localFieldNames.has(withoutDashes) || localFieldNames.has(flagName) || localCliNames.has(withoutDashes) || localCliNames.has(flagName) || localAliasMapKeys.has(withoutDashes) || localAliasMapKeys.has(flagName);
|
|
1767
2037
|
if (isGlobal && !isLocalCollision) {
|
|
1768
2038
|
i += collectGlobalFlag(argv, i, resolvedName, isNegated, lookup.booleanFlags, globalTokens) - 1;
|
|
@@ -1998,12 +2268,36 @@ async function runCommand(command, argv, options = {}) {
|
|
|
1998
2268
|
return result;
|
|
1999
2269
|
}
|
|
2000
2270
|
/**
|
|
2271
|
+
* Hidden internal subcommands (e.g. `__refresh-completion`) are spawned
|
|
2272
|
+
* by background hooks and must not run user-provided
|
|
2273
|
+
* `setup`/`cleanup`/`prompt` or required `globalArgs`. Those exist for
|
|
2274
|
+
* the foreground CLI run; replaying them in a detached child causes
|
|
2275
|
+
* duplicate side effects, stuck prompts, and validation failures the
|
|
2276
|
+
* user never opted into.
|
|
2277
|
+
*
|
|
2278
|
+
* We treat any registered subcommand whose name starts with `__` as
|
|
2279
|
+
* internal. We use `findFirstPositional` (schema-aware) instead of the
|
|
2280
|
+
* naive "first non-flag token" so an option *value* like
|
|
2281
|
+
* `--name __refresh-completion` doesn't trip the bypass — that would
|
|
2282
|
+
* silently skip lifecycle hooks for ordinary invocations.
|
|
2283
|
+
*/
|
|
2284
|
+
function isInternalSubcommandInvocation(command, argv, globalExtracted) {
|
|
2285
|
+
const firstPositional = findFirstPositional(argv, globalExtracted);
|
|
2286
|
+
if (!firstPositional || !firstPositional.startsWith("__")) return false;
|
|
2287
|
+
return Boolean(command.subCommands?.[firstPositional]);
|
|
2288
|
+
}
|
|
2289
|
+
/**
|
|
2001
2290
|
* Run a CLI command as the main entry point
|
|
2002
2291
|
*
|
|
2003
2292
|
* This function:
|
|
2004
2293
|
* - Uses process.argv for arguments
|
|
2005
2294
|
* - Handles SIGINT/SIGTERM signals
|
|
2006
2295
|
* - Calls process.exit with the appropriate exit code
|
|
2296
|
+
* - Invokes `command.runMainHook` once before parsing if set, so plug-ins
|
|
2297
|
+
* like `withCompletionCommand` can fire detached background work
|
|
2298
|
+
* - Bypasses user `setup`/`cleanup`/`prompt` and required `globalArgs`
|
|
2299
|
+
* for registered hidden subcommands whose name starts with `__`
|
|
2300
|
+
* (e.g. `__refresh-completion`)
|
|
2007
2301
|
*
|
|
2008
2302
|
* @param command - The command to run
|
|
2009
2303
|
* @param options - Main options (version, debug)
|
|
@@ -2021,38 +2315,51 @@ async function runCommand(command, argv, options = {}) {
|
|
|
2021
2315
|
* ```
|
|
2022
2316
|
*/
|
|
2023
2317
|
async function runMain(command, options = {}) {
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2318
|
+
if (command.runMainHook) try {
|
|
2319
|
+
command.runMainHook(process.argv.slice(2));
|
|
2320
|
+
} catch {}
|
|
2321
|
+
const argv = process.argv.slice(2);
|
|
2322
|
+
let globalExtractedForBypass;
|
|
2323
|
+
if (options.globalArgs) try {
|
|
2324
|
+
globalExtractedForBypass = extractFields(options.globalArgs);
|
|
2325
|
+
} catch {}
|
|
2326
|
+
let effectiveOptions = options;
|
|
2327
|
+
if (isInternalSubcommandInvocation(command, argv, globalExtractedForBypass)) {
|
|
2328
|
+
const { setup: _s, cleanup: _c, prompt: _p, globalArgs: _g, ...rest } = options;
|
|
2329
|
+
effectiveOptions = rest;
|
|
2330
|
+
}
|
|
2331
|
+
const globalExtracted = extractAndValidateGlobal(effectiveOptions);
|
|
2332
|
+
if (effectiveOptions.setup) try {
|
|
2333
|
+
await effectiveOptions.setup({});
|
|
2027
2334
|
} catch (e) {
|
|
2028
2335
|
const error = e instanceof Error ? e : new Error(String(e));
|
|
2029
|
-
if (
|
|
2030
|
-
await
|
|
2336
|
+
if (effectiveOptions.cleanup) try {
|
|
2337
|
+
await effectiveOptions.cleanup({ error });
|
|
2031
2338
|
} catch {}
|
|
2032
2339
|
process.exit(1);
|
|
2033
2340
|
}
|
|
2034
|
-
const result = await runCommandInternal(command,
|
|
2035
|
-
debug:
|
|
2036
|
-
captureLogs:
|
|
2037
|
-
skipValidation:
|
|
2341
|
+
const result = await runCommandInternal(command, argv, {
|
|
2342
|
+
debug: effectiveOptions.debug,
|
|
2343
|
+
captureLogs: effectiveOptions.captureLogs,
|
|
2344
|
+
skipValidation: effectiveOptions.skipValidation,
|
|
2038
2345
|
handleSignals: true,
|
|
2039
|
-
logger:
|
|
2040
|
-
globalArgs:
|
|
2041
|
-
prompt:
|
|
2346
|
+
logger: effectiveOptions.logger,
|
|
2347
|
+
globalArgs: effectiveOptions.globalArgs,
|
|
2348
|
+
prompt: effectiveOptions.prompt,
|
|
2042
2349
|
_globalExtracted: globalExtracted,
|
|
2043
|
-
_globalCleanup:
|
|
2350
|
+
_globalCleanup: effectiveOptions.cleanup,
|
|
2044
2351
|
_context: {
|
|
2045
2352
|
commandPath: [],
|
|
2046
2353
|
rootName: command.name,
|
|
2047
|
-
rootVersion:
|
|
2354
|
+
rootVersion: effectiveOptions.version,
|
|
2048
2355
|
globalExtracted
|
|
2049
2356
|
}
|
|
2050
2357
|
});
|
|
2051
|
-
if ((
|
|
2052
|
-
if (
|
|
2358
|
+
if ((effectiveOptions.displayErrors ?? true) && !result.success && result.error) (effectiveOptions.logger ?? defaultLogger).error(formatRuntimeError(result.error, effectiveOptions.debug ?? false));
|
|
2359
|
+
if (effectiveOptions.cleanup) {
|
|
2053
2360
|
const cleanupCtx = { error: !result.success ? result.error : void 0 };
|
|
2054
2361
|
try {
|
|
2055
|
-
await
|
|
2362
|
+
await effectiveOptions.cleanup(cleanupCtx);
|
|
2056
2363
|
} catch {}
|
|
2057
2364
|
}
|
|
2058
2365
|
if (process.stdout.writableLength > 0) await new Promise((resolve) => process.stdout.once("drain", resolve));
|
|
@@ -2086,9 +2393,10 @@ async function runCommandInternal(command, argv, options = {}) {
|
|
|
2086
2393
|
if (parseResult.helpRequested || parseResult.helpAllRequested) {
|
|
2087
2394
|
let hasUnknownSubcommand = false;
|
|
2088
2395
|
const subCmdNames = listSubCommands(command);
|
|
2396
|
+
const allSubCmdNameSet = listSubCommandNamesWithAliases(command);
|
|
2089
2397
|
if (subCmdNames.length > 0) {
|
|
2090
2398
|
const potentialSubCmd = findFirstPositional(argv, context.globalExtracted);
|
|
2091
|
-
if (potentialSubCmd && !
|
|
2399
|
+
if (potentialSubCmd && !allSubCmdNameSet.has(potentialSubCmd)) hasUnknownSubcommand = true;
|
|
2092
2400
|
}
|
|
2093
2401
|
const help = generateHelp(command, {
|
|
2094
2402
|
showSubcommands: options.showSubcommands ?? true,
|
|
@@ -2099,7 +2407,7 @@ async function runCommandInternal(command, argv, options = {}) {
|
|
|
2099
2407
|
collector?.stop();
|
|
2100
2408
|
if (hasUnknownSubcommand) {
|
|
2101
2409
|
const unknownCmd = findFirstPositional(argv, context.globalExtracted) ?? "";
|
|
2102
|
-
const similar = findSimilar(unknownCmd,
|
|
2410
|
+
const similar = findSimilar(unknownCmd, [...allSubCmdNameSet]);
|
|
2103
2411
|
const suggestion = similar.length > 0 ? ` Did you mean: ${similar.join(", ")}?` : "";
|
|
2104
2412
|
return {
|
|
2105
2413
|
success: false,
|
|
@@ -2127,16 +2435,33 @@ async function runCommandInternal(command, argv, options = {}) {
|
|
|
2127
2435
|
};
|
|
2128
2436
|
}
|
|
2129
2437
|
if (parseResult.subCommand) {
|
|
2130
|
-
|
|
2131
|
-
|
|
2438
|
+
if (parseResult.unknownFlags.length > 0) {
|
|
2439
|
+
const globalMode = context.globalExtracted?.unknownKeysMode ?? "strip";
|
|
2440
|
+
if (globalMode === "strict") {
|
|
2441
|
+
collector?.stop();
|
|
2442
|
+
return {
|
|
2443
|
+
success: false,
|
|
2444
|
+
error: /* @__PURE__ */ new Error(`Unknown flags: ${parseResult.unknownFlags.join(", ")}`),
|
|
2445
|
+
exitCode: 1,
|
|
2446
|
+
logs: getCurrentLogs()
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
if (globalMode === "strip") {
|
|
2450
|
+
const knownGlobalFlags = context.globalExtracted?.fields.map((f) => f.name) ?? [];
|
|
2451
|
+
for (const flag of parseResult.unknownFlags) logger.error(formatUnknownFlagWarning(flag, knownGlobalFlags));
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
const resolved = await resolveSubcommandWithAlias(command, parseResult.subCommand);
|
|
2455
|
+
if (resolved) {
|
|
2132
2456
|
const subContext = {
|
|
2133
2457
|
commandPath: [...context.commandPath ?? [], parseResult.subCommand],
|
|
2134
2458
|
rootName: context.rootName,
|
|
2135
2459
|
rootVersion: context.rootVersion,
|
|
2136
|
-
globalExtracted: context.globalExtracted
|
|
2460
|
+
globalExtracted: context.globalExtracted,
|
|
2461
|
+
aliasFor: resolved.aliasFor
|
|
2137
2462
|
};
|
|
2138
2463
|
collector?.stop();
|
|
2139
|
-
return runCommandInternal(
|
|
2464
|
+
return runCommandInternal(resolved.command, parseResult.remainingArgs, {
|
|
2140
2465
|
...options,
|
|
2141
2466
|
_context: subContext,
|
|
2142
2467
|
_existingLogs: getCurrentLogs(),
|
|
@@ -2266,6 +2591,7 @@ function extractAndValidateGlobal(options) {
|
|
|
2266
2591
|
validateDuplicateFields(extracted);
|
|
2267
2592
|
validateCaseVariantCollisions(extracted);
|
|
2268
2593
|
validateDuplicateAliases(extracted);
|
|
2594
|
+
validateDuplicateNegations(extracted);
|
|
2269
2595
|
validateReservedAliases(extracted, true);
|
|
2270
2596
|
const positionalNames = extracted.fields.filter((f) => f.positional).map((f) => f.name);
|
|
2271
2597
|
if (positionalNames.length > 0) throw new Error(`Global options schema must not contain positional arguments. Found: ${positionalNames.join(", ")}`);
|
|
@@ -2274,5 +2600,5 @@ function extractAndValidateGlobal(options) {
|
|
|
2274
2600
|
}
|
|
2275
2601
|
|
|
2276
2602
|
//#endregion
|
|
2277
|
-
export {
|
|
2278
|
-
//# sourceMappingURL=runner-
|
|
2603
|
+
export { renderMarkdown as C, styles as D, setColorEnabled as E, symbols as O, renderInline as S, logger as T, DuplicateFieldError as _, parseArgv as a, ReservedAliasError as b, validateCommand as c, validateDuplicateFields as d, validateDuplicateNegations as f, DuplicateAliasError as g, CaseVariantCollisionError as h, formatValidationErrors as i, createDualCaseProxy as k, validateCrossSchemaCollisions as l, validateReservedAliases as m, runMain as n, formatCommandValidationErrors as o, validatePositionalConfig as p, runner_exports as r, validateCaseVariantCollisions as s, runCommand as t, validateDuplicateAliases as u, DuplicateNegationError as v, isColorEnabled as w, generateHelp as x, PositionalConfigError as y };
|
|
2604
|
+
//# sourceMappingURL=runner-BHeCMEa5.js.map
|