zinkee 0.1.11 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +204 -29
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli-examples.ts +18 -36
- package/src/cli-runner.ts +10 -2
- package/src/index.test.ts +52 -0
- package/src/utils/argv-rewrite.test.ts +149 -0
- package/src/utils/argv-rewrite.ts +269 -0
package/dist/index.js
CHANGED
|
@@ -732,6 +732,197 @@ var commandRegistry = {
|
|
|
732
732
|
}
|
|
733
733
|
};
|
|
734
734
|
|
|
735
|
+
// src/utils/argv-rewrite.ts
|
|
736
|
+
var HOISTABLE_GLOBAL_FLAGS = {
|
|
737
|
+
"--profile": "value",
|
|
738
|
+
"--base-url": "value",
|
|
739
|
+
"--api-key": "value",
|
|
740
|
+
"--read-only": "boolean",
|
|
741
|
+
"--json": "boolean"
|
|
742
|
+
};
|
|
743
|
+
function isHoistableFlag(flagName) {
|
|
744
|
+
return Object.hasOwn(HOISTABLE_GLOBAL_FLAGS, flagName);
|
|
745
|
+
}
|
|
746
|
+
function getCommandPath(command) {
|
|
747
|
+
const parts = [];
|
|
748
|
+
let cursor = command;
|
|
749
|
+
while (cursor && cursor.parent) {
|
|
750
|
+
parts.unshift(cursor.name());
|
|
751
|
+
cursor = cursor.parent;
|
|
752
|
+
}
|
|
753
|
+
return parts.join(" ");
|
|
754
|
+
}
|
|
755
|
+
function buildOptionMetadata(program) {
|
|
756
|
+
const valueFlags = /* @__PURE__ */ new Set();
|
|
757
|
+
const booleanFlags = /* @__PURE__ */ new Set();
|
|
758
|
+
const localOptionsByCommand = /* @__PURE__ */ new Map();
|
|
759
|
+
function visit(command, isRoot) {
|
|
760
|
+
const localFlags = /* @__PURE__ */ new Set();
|
|
761
|
+
for (const option of command.options) {
|
|
762
|
+
if (!option.long) continue;
|
|
763
|
+
if (option.required || option.optional) {
|
|
764
|
+
valueFlags.add(option.long);
|
|
765
|
+
} else {
|
|
766
|
+
booleanFlags.add(option.long);
|
|
767
|
+
}
|
|
768
|
+
if (!isRoot) {
|
|
769
|
+
localFlags.add(option.long);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
if (!isRoot) {
|
|
773
|
+
localOptionsByCommand.set(getCommandPath(command), localFlags);
|
|
774
|
+
}
|
|
775
|
+
for (const sub of command.commands) {
|
|
776
|
+
visit(sub, false);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
visit(program, true);
|
|
780
|
+
return { valueFlags, booleanFlags, localOptionsByCommand };
|
|
781
|
+
}
|
|
782
|
+
function createDefaultOptionMetadata() {
|
|
783
|
+
return {
|
|
784
|
+
valueFlags: /* @__PURE__ */ new Set([
|
|
785
|
+
"--profile",
|
|
786
|
+
"--base-url",
|
|
787
|
+
"--api-key",
|
|
788
|
+
"--install-completion",
|
|
789
|
+
"--show-completion"
|
|
790
|
+
]),
|
|
791
|
+
booleanFlags: /* @__PURE__ */ new Set([
|
|
792
|
+
"--read-only",
|
|
793
|
+
"--json",
|
|
794
|
+
"--example",
|
|
795
|
+
"--help"
|
|
796
|
+
]),
|
|
797
|
+
localOptionsByCommand: /* @__PURE__ */ new Map()
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
function isFlagToken(token) {
|
|
801
|
+
return token.length > 1 && token.startsWith("-");
|
|
802
|
+
}
|
|
803
|
+
function splitFlagToken(token) {
|
|
804
|
+
if (token.startsWith("--") && token.includes("=")) {
|
|
805
|
+
const eqIdx = token.indexOf("=");
|
|
806
|
+
return {
|
|
807
|
+
flagName: token.slice(0, eqIdx),
|
|
808
|
+
inlineValue: token.slice(eqIdx + 1)
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
return { flagName: token, inlineValue: void 0 };
|
|
812
|
+
}
|
|
813
|
+
function flagConsumesValue(flagName, optionMeta) {
|
|
814
|
+
if (optionMeta.valueFlags.has(flagName)) {
|
|
815
|
+
return true;
|
|
816
|
+
}
|
|
817
|
+
if (optionMeta.booleanFlags.has(flagName)) {
|
|
818
|
+
return false;
|
|
819
|
+
}
|
|
820
|
+
return true;
|
|
821
|
+
}
|
|
822
|
+
function collectOperandTokens(userArgs, optionMeta, options = {}) {
|
|
823
|
+
const operands = [];
|
|
824
|
+
let i = 0;
|
|
825
|
+
while (i < userArgs.length) {
|
|
826
|
+
const token = userArgs[i];
|
|
827
|
+
if (token === "--") {
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
830
|
+
if (isFlagToken(token)) {
|
|
831
|
+
const { flagName, inlineValue } = splitFlagToken(token);
|
|
832
|
+
if (options.skipFlag !== void 0 && flagName === options.skipFlag) {
|
|
833
|
+
i += 1;
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
if (inlineValue !== void 0) {
|
|
837
|
+
i += 1;
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
840
|
+
const consumes = flagConsumesValue(flagName, optionMeta);
|
|
841
|
+
const next = userArgs[i + 1];
|
|
842
|
+
if (consumes && next !== void 0 && !isFlagToken(next)) {
|
|
843
|
+
i += 2;
|
|
844
|
+
} else {
|
|
845
|
+
i += 1;
|
|
846
|
+
}
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
operands.push({ index: i, token });
|
|
850
|
+
i += 1;
|
|
851
|
+
}
|
|
852
|
+
return operands;
|
|
853
|
+
}
|
|
854
|
+
function findCommandPath(operands, registry) {
|
|
855
|
+
if (operands.length === 0) return null;
|
|
856
|
+
const commandsByLength = Object.keys(registry).sort(
|
|
857
|
+
(left, right) => right.split(" ").length - left.split(" ").length
|
|
858
|
+
);
|
|
859
|
+
for (let start = 0; start < operands.length; start += 1) {
|
|
860
|
+
for (const commandName of commandsByLength) {
|
|
861
|
+
const parts = commandName.split(" ");
|
|
862
|
+
if (start + parts.length > operands.length) continue;
|
|
863
|
+
let matches = true;
|
|
864
|
+
for (let j = 0; j < parts.length; j += 1) {
|
|
865
|
+
if (operands[start + j].token !== parts[j]) {
|
|
866
|
+
matches = false;
|
|
867
|
+
break;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
if (matches) {
|
|
871
|
+
return {
|
|
872
|
+
commandName,
|
|
873
|
+
firstArgvIndex: operands[start].index,
|
|
874
|
+
lastArgvIndex: operands[start + parts.length - 1].index
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
function hoistGlobalOptions(argv, optionMeta, registry) {
|
|
882
|
+
if (argv.length < 3) return [...argv];
|
|
883
|
+
const userArgs = argv.slice(2);
|
|
884
|
+
const operands = collectOperandTokens(userArgs, optionMeta);
|
|
885
|
+
const cmdPath = findCommandPath(operands, registry);
|
|
886
|
+
if (!cmdPath) return [...argv];
|
|
887
|
+
const localOptions = optionMeta.localOptionsByCommand.get(cmdPath.commandName) ?? /* @__PURE__ */ new Set();
|
|
888
|
+
const hoisted = [];
|
|
889
|
+
const remaining = [];
|
|
890
|
+
let i = 0;
|
|
891
|
+
while (i < userArgs.length) {
|
|
892
|
+
const token = userArgs[i];
|
|
893
|
+
if (token === "--") {
|
|
894
|
+
remaining.push(...userArgs.slice(i));
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
if (!isFlagToken(token)) {
|
|
898
|
+
remaining.push(token);
|
|
899
|
+
i += 1;
|
|
900
|
+
continue;
|
|
901
|
+
}
|
|
902
|
+
const { flagName, inlineValue } = splitFlagToken(token);
|
|
903
|
+
if (!isHoistableFlag(flagName)) {
|
|
904
|
+
remaining.push(token);
|
|
905
|
+
i += 1;
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
const isAfterCommandPath = i > cmdPath.lastArgvIndex;
|
|
909
|
+
const collidesWithLocal = localOptions.has(flagName);
|
|
910
|
+
const target = isAfterCommandPath && collidesWithLocal ? remaining : hoisted;
|
|
911
|
+
target.push(token);
|
|
912
|
+
const spec = HOISTABLE_GLOBAL_FLAGS[flagName];
|
|
913
|
+
if (spec === "value" && inlineValue === void 0) {
|
|
914
|
+
const next = userArgs[i + 1];
|
|
915
|
+
if (next !== void 0 && !isFlagToken(next)) {
|
|
916
|
+
target.push(next);
|
|
917
|
+
i += 2;
|
|
918
|
+
continue;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
i += 1;
|
|
922
|
+
}
|
|
923
|
+
return [argv[0], argv[1], ...hoisted, ...remaining];
|
|
924
|
+
}
|
|
925
|
+
|
|
735
926
|
// src/client.ts
|
|
736
927
|
var ApiClientError = class extends Error {
|
|
737
928
|
name = "ApiClientError";
|
|
@@ -6392,26 +6583,6 @@ async function getResolvedCommandExamples(commandName, filters = {}, options = {
|
|
|
6392
6583
|
function getStdout(stdout) {
|
|
6393
6584
|
return stdout ?? process.stdout;
|
|
6394
6585
|
}
|
|
6395
|
-
function resolveExampleCommand(tokens) {
|
|
6396
|
-
const commands = Object.keys(commandRegistry).sort(
|
|
6397
|
-
(left, right) => right.split(" ").length - left.split(" ").length
|
|
6398
|
-
);
|
|
6399
|
-
for (const commandName of commands) {
|
|
6400
|
-
const commandTokens2 = commandName.split(" ");
|
|
6401
|
-
const matches = commandTokens2.every((token, index) => tokens[index] === token);
|
|
6402
|
-
if (matches) {
|
|
6403
|
-
return {
|
|
6404
|
-
commandName,
|
|
6405
|
-
remainingTokens: tokens.slice(commandTokens2.length)
|
|
6406
|
-
};
|
|
6407
|
-
}
|
|
6408
|
-
}
|
|
6409
|
-
const commandTokens = tokens.filter((token) => !token.startsWith("-"));
|
|
6410
|
-
return {
|
|
6411
|
-
commandName: commandTokens.join(" "),
|
|
6412
|
-
remainingTokens: []
|
|
6413
|
-
};
|
|
6414
|
-
}
|
|
6415
6586
|
function extractExampleFilters(tokens) {
|
|
6416
6587
|
const filters = {};
|
|
6417
6588
|
for (let index = 0; index < tokens.length; index += 1) {
|
|
@@ -6451,18 +6622,19 @@ function extractExampleOverrides(tokens) {
|
|
|
6451
6622
|
}
|
|
6452
6623
|
return overrides;
|
|
6453
6624
|
}
|
|
6454
|
-
function extractExampleRequest(argv) {
|
|
6455
|
-
|
|
6456
|
-
if (exampleIndex === -1) {
|
|
6625
|
+
function extractExampleRequest(argv, optionMeta = createDefaultOptionMetadata()) {
|
|
6626
|
+
if (!argv.includes("--example")) {
|
|
6457
6627
|
return null;
|
|
6458
6628
|
}
|
|
6459
|
-
const
|
|
6460
|
-
const
|
|
6461
|
-
|
|
6629
|
+
const userArgs = argv.slice(2);
|
|
6630
|
+
const operands = collectOperandTokens(userArgs, optionMeta, { skipFlag: "--example" });
|
|
6631
|
+
const cmdPath = findCommandPath(operands, commandRegistry);
|
|
6632
|
+
if (!cmdPath) {
|
|
6462
6633
|
throw new CliError("invalid_cli_usage", 'Provide a command after "--example".');
|
|
6463
6634
|
}
|
|
6635
|
+
const remainingTokens = userArgs.slice(cmdPath.lastArgvIndex + 1);
|
|
6464
6636
|
return {
|
|
6465
|
-
commandName,
|
|
6637
|
+
commandName: cmdPath.commandName,
|
|
6466
6638
|
filters: extractExampleFilters(remainingTokens),
|
|
6467
6639
|
overrides: extractExampleOverrides(argv),
|
|
6468
6640
|
json: argv.includes("--json")
|
|
@@ -11541,7 +11713,9 @@ async function runCli(argv) {
|
|
|
11541
11713
|
process.exitCode = exitCode;
|
|
11542
11714
|
return;
|
|
11543
11715
|
}
|
|
11544
|
-
const
|
|
11716
|
+
const program = buildProgram();
|
|
11717
|
+
const optionMeta = buildOptionMetadata(program);
|
|
11718
|
+
const exampleRequest = extractExampleRequest(argv, optionMeta);
|
|
11545
11719
|
if (exampleRequest) {
|
|
11546
11720
|
await showExamples(
|
|
11547
11721
|
exampleRequest.commandName,
|
|
@@ -11555,7 +11729,8 @@ async function runCli(argv) {
|
|
|
11555
11729
|
);
|
|
11556
11730
|
throw new ExampleDisplayed();
|
|
11557
11731
|
}
|
|
11558
|
-
|
|
11732
|
+
const rewrittenArgv = hoistGlobalOptions(argv, optionMeta, commandRegistry);
|
|
11733
|
+
await program.parseAsync(rewrittenArgv);
|
|
11559
11734
|
} catch (error) {
|
|
11560
11735
|
if (error instanceof ExampleDisplayed) {
|
|
11561
11736
|
process.exitCode = 0;
|