@flowscripter/dynamic-cli-framework 11.0.0 → 11.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/dist/src/cli/BaseCLI.d.ts.map +1 -1
- package/dist/src/cli/BaseCLI.js +6 -2
- package/dist/src/runtime/DefaultContext.d.ts +2 -1
- package/dist/src/runtime/DefaultContext.d.ts.map +1 -1
- package/dist/src/runtime/DefaultContext.js +3 -1
- package/dist/src/runtime/command/CommandValidator.d.ts.map +1 -1
- package/dist/src/runtime/command/CommandValidator.js +18 -6
- package/dist/src/runtime/parser.d.ts.map +1 -1
- package/dist/src/runtime/parser.js +13 -4
- package/dist/src/runtime/values/argumentValueValidation.d.ts +26 -4
- package/dist/src/runtime/values/argumentValueValidation.d.ts.map +1 -1
- package/dist/src/runtime/values/argumentValueValidation.js +53 -50
- package/dist/src/service/argumentPrompter/DefaultArgumentPrompterService.d.ts +4 -0
- package/dist/src/service/argumentPrompter/DefaultArgumentPrompterService.d.ts.map +1 -1
- package/dist/src/service/argumentPrompter/DefaultArgumentPrompterService.js +53 -21
- package/dist/src/service/configuration/KeyValueServiceProvider.d.ts.map +1 -1
- package/dist/src/service/configuration/KeyValueServiceProvider.js +1 -0
- package/package.json +2 -2
- package/src/cli/BaseCLI.ts +6 -2
- package/src/runtime/DefaultContext.ts +4 -1
- package/src/runtime/command/CommandValidator.ts +35 -5
- package/src/runtime/parser.ts +14 -0
- package/src/runtime/values/argumentValueValidation.ts +82 -50
- package/src/service/argumentPrompter/DefaultArgumentPrompterService.ts +92 -26
- package/src/service/configuration/KeyValueServiceProvider.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeyValueServiceProvider.d.ts","sourceRoot":"","sources":["../../../../src/service/configuration/KeyValueServiceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,yCAAyC,CAAC;AAIjD,OAAO,KAAK,4BAA4B,MAAM,mCAAmC,CAAC;AAClF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAoClF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,MAAM,CAAC,OAAO,OAAO,uBAAwB,YAAW,eAAe;;IACrE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAwB;IAClD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAIjC,SAAgB,sBAAsB,EAAE,OAAO,CAAC;IAChD,SAAgB,oBAAoB,EAAE,OAAO,CAAC;IAW9C;;;;;;;;OAQG;IACH,YACE,eAAe,EAAE,MAAM,EACvB,4BAA4B,EAAE,4BAA4B,EAC1D,sBAAsB,UAAQ,EAC9B,oBAAoB,UAAQ,EAY7B;IAEM,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAUhE;IAED;;;;;;;;;;OAUG;IACI,wBAAwB,CAC7B,SAAS,EAAE,wBAAwB,EACnC,QAAQ,EAAE,MAAM,GACf,eAAe,CAwBjB;IAED;;;;;;;;;;;;;;OAcG;IACI,kBAAkB,CACvB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,wBAAwB,EACnC,QAAQ,EAAE,MAAM,GACf,OAAO,
|
|
1
|
+
{"version":3,"file":"KeyValueServiceProvider.d.ts","sourceRoot":"","sources":["../../../../src/service/configuration/KeyValueServiceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC5F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,yCAAyC,CAAC;AAIjD,OAAO,KAAK,4BAA4B,MAAM,mCAAmC,CAAC;AAClF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAoClF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,MAAM,CAAC,OAAO,OAAO,uBAAwB,YAAW,eAAe;;IACrE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAwB;IAClD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAIjC,SAAgB,sBAAsB,EAAE,OAAO,CAAC;IAChD,SAAgB,oBAAoB,EAAE,OAAO,CAAC;IAW9C;;;;;;;;OAQG;IACH,YACE,eAAe,EAAE,MAAM,EACvB,4BAA4B,EAAE,4BAA4B,EAC1D,sBAAsB,UAAQ,EAC9B,oBAAoB,UAAQ,EAY7B;IAEM,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAUhE;IAED;;;;;;;;;;OAUG;IACI,wBAAwB,CAC7B,SAAS,EAAE,wBAAwB,EACnC,QAAQ,EAAE,MAAM,GACf,eAAe,CAwBjB;IAED;;;;;;;;;;;;;;OAcG;IACI,kBAAkB,CACvB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,wBAAwB,EACnC,QAAQ,EAAE,MAAM,GACf,OAAO,CAcT;IAqBY,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CASxD;CACF"}
|
|
@@ -180,6 +180,7 @@ export default class KeyValueServiceProvider {
|
|
|
180
180
|
const scopedKeyValueService = this.getScopedKeyValueService(scopeType, scopeKey);
|
|
181
181
|
return {
|
|
182
182
|
cliConfig: context.cliConfig,
|
|
183
|
+
isTty: context.isTty,
|
|
183
184
|
getServiceById: (id) => id === KEY_VALUE_SERVICE_ID ? scopedKeyValueService : context.getServiceById(id),
|
|
184
185
|
doesServiceExist: (id) => context.doesServiceExist(id),
|
|
185
186
|
addServiceInstance: (id, serviceInstance) => context.addServiceInstance(id, serviceInstance),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowscripter/dynamic-cli-framework",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.1.0",
|
|
4
4
|
"description": "A framework for developing CLI applications which supports dynamic discovery and installation of new commands",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"build": "tsc -p tsconfig.build.json"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@flowscripter/dynamic-cli-framework-api": "^5.0
|
|
52
|
+
"@flowscripter/dynamic-cli-framework-api": "^5.1.0",
|
|
53
53
|
"@flowscripter/dynamic-plugin-framework": "^2.2.22",
|
|
54
54
|
"emphasize": "^7.0.0",
|
|
55
55
|
"fastest-levenshtein": "^1.0.16",
|
package/src/cli/BaseCLI.ts
CHANGED
|
@@ -196,7 +196,11 @@ export default class BaseCLI implements CLI {
|
|
|
196
196
|
this.#commandRegistry = new DefaultCommandRegistry([], commandValidator);
|
|
197
197
|
|
|
198
198
|
// create a context
|
|
199
|
-
this.#context = new DefaultContext(this.#cliConfig
|
|
199
|
+
this.#context = new DefaultContext(this.#cliConfig, {
|
|
200
|
+
stdin: keyReader !== undefined,
|
|
201
|
+
stdout: stdoutTerminal.isTty(),
|
|
202
|
+
stderr: stderrTerminal.isTty(),
|
|
203
|
+
});
|
|
200
204
|
|
|
201
205
|
this.#startupServiceProvider = new StartupServiceProvider(STARTUP_SERVICE_PRIORITY);
|
|
202
206
|
|
|
@@ -277,7 +281,7 @@ export default class BaseCLI implements CLI {
|
|
|
277
281
|
);
|
|
278
282
|
this.addServiceProvider(new TableGeneratorServiceProvider(TABLE_GENERATOR_SERVICE_PRIORITY));
|
|
279
283
|
|
|
280
|
-
const canPrompt = this.#
|
|
284
|
+
const canPrompt = this.#context.isTty.stdin && this.#context.isTty.stderr;
|
|
281
285
|
|
|
282
286
|
if (this.#options.promptingEnabled && !canPrompt) {
|
|
283
287
|
throw new Error("promptingEnabled requires a keyReader and a TTY stderr terminal");
|
|
@@ -7,7 +7,10 @@ import type { CLIConfig } from "@flowscripter/dynamic-cli-framework-api";
|
|
|
7
7
|
export default class DefaultContext implements Context {
|
|
8
8
|
readonly #serviceInstancesById: Map<string, unknown> = new Map();
|
|
9
9
|
|
|
10
|
-
public constructor(
|
|
10
|
+
public constructor(
|
|
11
|
+
readonly cliConfig: CLIConfig,
|
|
12
|
+
readonly isTty: Context["isTty"] = { stdin: false, stdout: false, stderr: false },
|
|
13
|
+
) {}
|
|
11
14
|
|
|
12
15
|
public addServiceInstance(id: string, serviceInstance: unknown) {
|
|
13
16
|
if (this.#serviceInstancesById.has(id)) {
|
|
@@ -4,7 +4,7 @@ import type { GlobalCommand } from "@flowscripter/dynamic-cli-framework-api";
|
|
|
4
4
|
import type { Argument } from "@flowscripter/dynamic-cli-framework-api";
|
|
5
5
|
import type { GroupCommand } from "@flowscripter/dynamic-cli-framework-api";
|
|
6
6
|
import type { SubCommand } from "@flowscripter/dynamic-cli-framework-api";
|
|
7
|
-
import type { SingleValueType } from "@flowscripter/dynamic-cli-framework-api";
|
|
7
|
+
import type { PopulatedValues, SingleValueType } from "@flowscripter/dynamic-cli-framework-api";
|
|
8
8
|
import { ValueTypeName, ComplexValueTypeName } from "@flowscripter/dynamic-cli-framework-api";
|
|
9
9
|
import type { Option } from "@flowscripter/dynamic-cli-framework-api";
|
|
10
10
|
import type { ComplexOption } from "@flowscripter/dynamic-cli-framework-api";
|
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
getInvalidArgumentString,
|
|
14
14
|
validateGlobalCommandArgumentValue,
|
|
15
15
|
validateOptionValue,
|
|
16
|
+
runCustomValidation,
|
|
17
|
+
type DeferredCustomValidation,
|
|
16
18
|
} from "../values/argumentValueValidation.ts";
|
|
17
19
|
import getLogger from "../../util/logger.ts";
|
|
18
20
|
import type { CLIConfig } from "@flowscripter/dynamic-cli-framework-api";
|
|
@@ -219,7 +221,16 @@ export default class CommandValidator {
|
|
|
219
221
|
validateArgument(argument, globalCommand.name);
|
|
220
222
|
if (argument.defaultValue) {
|
|
221
223
|
const invalidArguments: Array<InvalidArgument> = [];
|
|
222
|
-
|
|
224
|
+
const deferred: Array<DeferredCustomValidation> = [];
|
|
225
|
+
validateGlobalCommandArgumentValue(
|
|
226
|
+
globalCommand,
|
|
227
|
+
argument.defaultValue,
|
|
228
|
+
invalidArguments,
|
|
229
|
+
deferred,
|
|
230
|
+
);
|
|
231
|
+
if (invalidArguments.length === 0) {
|
|
232
|
+
runCustomValidation(deferred, globalCommand, argument.defaultValue, invalidArguments);
|
|
233
|
+
}
|
|
223
234
|
if (invalidArguments.length > 0) {
|
|
224
235
|
throw new Error(
|
|
225
236
|
`Illegal default value for global command: '${globalCommand.name}' => ${invalidArguments
|
|
@@ -440,12 +451,13 @@ export default class CommandValidator {
|
|
|
440
451
|
option as unknown as SubCommandArgument,
|
|
441
452
|
]);
|
|
442
453
|
} else {
|
|
443
|
-
this.#validateOption(option, currentOptionPaths, allOptionPaths);
|
|
454
|
+
this.#validateOption(subCommand, option, currentOptionPaths, allOptionPaths);
|
|
444
455
|
this.#validateSubCommandArgumentConfigurationKey(subCommand, [...argumentAncestry, option]);
|
|
445
456
|
}
|
|
446
457
|
}
|
|
447
458
|
|
|
448
459
|
#validateOption(
|
|
460
|
+
subCommand: SubCommand,
|
|
449
461
|
option: Option,
|
|
450
462
|
currentOptionPaths: Array<string>,
|
|
451
463
|
allOptionPaths: Array<string>,
|
|
@@ -460,7 +472,16 @@ export default class CommandValidator {
|
|
|
460
472
|
}
|
|
461
473
|
if (option.defaultValue) {
|
|
462
474
|
const invalidArguments: Array<InvalidArgument> = [];
|
|
463
|
-
|
|
475
|
+
const deferred: Array<DeferredCustomValidation> = [];
|
|
476
|
+
validateOptionValue(option, option.defaultValue, invalidArguments, deferred);
|
|
477
|
+
if (invalidArguments.length === 0) {
|
|
478
|
+
runCustomValidation(
|
|
479
|
+
deferred,
|
|
480
|
+
subCommand,
|
|
481
|
+
{ [option.name]: option.defaultValue } as PopulatedValues,
|
|
482
|
+
invalidArguments,
|
|
483
|
+
);
|
|
484
|
+
}
|
|
464
485
|
if (invalidArguments.length > 0) {
|
|
465
486
|
throw new Error(
|
|
466
487
|
`Illegal default value for option: '${option.name}' => ${invalidArguments
|
|
@@ -515,7 +536,16 @@ export default class CommandValidator {
|
|
|
515
536
|
}
|
|
516
537
|
if (complexOption.defaultValue) {
|
|
517
538
|
const invalidArguments: Array<InvalidArgument> = [];
|
|
518
|
-
|
|
539
|
+
const deferred: Array<DeferredCustomValidation> = [];
|
|
540
|
+
validateOptionValue(complexOption, complexOption.defaultValue, invalidArguments, deferred);
|
|
541
|
+
if (invalidArguments.length === 0) {
|
|
542
|
+
runCustomValidation(
|
|
543
|
+
deferred,
|
|
544
|
+
subCommand,
|
|
545
|
+
{ [complexOption.name]: complexOption.defaultValue } as PopulatedValues,
|
|
546
|
+
invalidArguments,
|
|
547
|
+
);
|
|
548
|
+
}
|
|
519
549
|
if (invalidArguments.length > 0) {
|
|
520
550
|
throw new Error(
|
|
521
551
|
`Illegal default value for option: '${complexOption.name}' => ${invalidArguments
|
package/src/runtime/parser.ts
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
validateGlobalCommandArgumentValue,
|
|
12
12
|
validateOptionValue,
|
|
13
13
|
validatePositionalValue,
|
|
14
|
+
runCustomValidation,
|
|
15
|
+
type DeferredCustomValidation,
|
|
14
16
|
} from "./values/argumentValueValidation.ts";
|
|
15
17
|
import getLogger from "../util/logger.ts";
|
|
16
18
|
import { redactGlobalCommandValue, redactSubCommandValues } from "../util/secretRedaction.ts";
|
|
@@ -64,12 +66,14 @@ export function parseSubCommandClause(
|
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
if (invalidArguments.length === 0) {
|
|
69
|
+
const deferred: Array<DeferredCustomValidation> = [];
|
|
67
70
|
// validate the option values
|
|
68
71
|
command.options.forEach((option) => {
|
|
69
72
|
const validatedValue = validateOptionValue(
|
|
70
73
|
option,
|
|
71
74
|
populatedArgumentValues[option.name] || option.defaultValue,
|
|
72
75
|
invalidArguments,
|
|
76
|
+
deferred,
|
|
73
77
|
);
|
|
74
78
|
if (validatedValue !== undefined) {
|
|
75
79
|
populatedArgumentValues[option.name] = validatedValue;
|
|
@@ -89,11 +93,16 @@ export function parseSubCommandClause(
|
|
|
89
93
|
positional,
|
|
90
94
|
populatedArgumentValues[positional.name] as ValueType,
|
|
91
95
|
invalidArguments,
|
|
96
|
+
deferred,
|
|
92
97
|
);
|
|
93
98
|
if (validatedValue !== undefined) {
|
|
94
99
|
populatedArgumentValues[positional.name] = validatedValue;
|
|
95
100
|
}
|
|
96
101
|
});
|
|
102
|
+
if (invalidArguments.length === 0) {
|
|
103
|
+
// custom validators run once all built-in validation has passed and see all values
|
|
104
|
+
runCustomValidation(deferred, command, populatedArgumentValues, invalidArguments);
|
|
105
|
+
}
|
|
97
106
|
logger.debug(
|
|
98
107
|
"Command arguments after positionals validated: %O with invalid args: %O",
|
|
99
108
|
redactSubCommandValues(command, populatedArgumentValues),
|
|
@@ -162,14 +171,19 @@ export function parseGlobalCommandClause(
|
|
|
162
171
|
|
|
163
172
|
// don't validate the value if the argument is already invalid
|
|
164
173
|
if (invalidArguments.length === 0) {
|
|
174
|
+
const deferred: Array<DeferredCustomValidation> = [];
|
|
165
175
|
const validatedValue = validateGlobalCommandArgumentValue(
|
|
166
176
|
command,
|
|
167
177
|
populatedArgumentValue,
|
|
168
178
|
invalidArguments,
|
|
179
|
+
deferred,
|
|
169
180
|
);
|
|
170
181
|
if (validatedValue !== undefined) {
|
|
171
182
|
populatedArgumentValue = validatedValue;
|
|
172
183
|
}
|
|
184
|
+
if (invalidArguments.length === 0) {
|
|
185
|
+
runCustomValidation(deferred, command, populatedArgumentValue, invalidArguments);
|
|
186
|
+
}
|
|
173
187
|
}
|
|
174
188
|
|
|
175
189
|
logger.debug(
|
|
@@ -16,6 +16,7 @@ import { InvalidArgumentReason } from "@flowscripter/dynamic-cli-framework-api";
|
|
|
16
16
|
import type { SubCommandArgument } from "@flowscripter/dynamic-cli-framework-api";
|
|
17
17
|
import type { Argument } from "@flowscripter/dynamic-cli-framework-api";
|
|
18
18
|
import type { GlobalCommand } from "@flowscripter/dynamic-cli-framework-api";
|
|
19
|
+
import type { Command } from "@flowscripter/dynamic-cli-framework-api";
|
|
19
20
|
|
|
20
21
|
interface ValidationResult {
|
|
21
22
|
invalidArgument?: InvalidArgument;
|
|
@@ -41,32 +42,61 @@ function withPrefix(invalidArgument: InvalidArgument, prefix: string): InvalidAr
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
/**
|
|
44
|
-
*
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
* A custom validation to be invoked once all built-in validation has passed.
|
|
46
|
+
*/
|
|
47
|
+
export interface DeferredCustomValidation {
|
|
48
|
+
readonly argument: Argument | ComplexOption;
|
|
49
|
+
readonly path: string;
|
|
50
|
+
readonly value: SingleValueType | Values | Array<SingleValueType | Values>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Records a custom validation of the provided {@link Argument} (if it has one) for later invocation by
|
|
55
|
+
* {@link runCustomValidation}. Deferred validations are recorded bottom-up and depth-first.
|
|
50
56
|
*/
|
|
51
|
-
function
|
|
57
|
+
function deferCustomValidation(
|
|
58
|
+
deferred: Array<DeferredCustomValidation> | undefined,
|
|
52
59
|
argument: Argument | ComplexOption,
|
|
53
|
-
|
|
60
|
+
path: string,
|
|
54
61
|
value: SingleValueType | Values | Array<SingleValueType | Values>,
|
|
55
|
-
):
|
|
56
|
-
if (argument.validate
|
|
57
|
-
|
|
62
|
+
): void {
|
|
63
|
+
if (deferred !== undefined && argument.validate !== undefined) {
|
|
64
|
+
deferred.push({ argument, path, value });
|
|
58
65
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Invokes the recorded custom validations in order, stopping at the first failure.
|
|
70
|
+
*
|
|
71
|
+
* @param deferred the validations recorded while validating the values of the command.
|
|
72
|
+
* @param command the {@link Command} the validated values belong to.
|
|
73
|
+
* @param values all validated and converted values of the command.
|
|
74
|
+
* @param invalidArguments an array of {@link InvalidArgument} which is added to if a custom validation fails.
|
|
75
|
+
*/
|
|
76
|
+
export function runCustomValidation(
|
|
77
|
+
deferred: ReadonlyArray<DeferredCustomValidation>,
|
|
78
|
+
command: Command,
|
|
79
|
+
values: PopulatedValues | PopulatedSingleValueType,
|
|
80
|
+
invalidArguments: Array<InvalidArgument>,
|
|
81
|
+
): void {
|
|
82
|
+
for (const { argument, path, value } of deferred) {
|
|
83
|
+
const message = argument.validate!(value as ValueType | Values | Array<Values>, {
|
|
84
|
+
argument: argument as Argument,
|
|
85
|
+
path,
|
|
86
|
+
values,
|
|
87
|
+
command,
|
|
88
|
+
});
|
|
89
|
+
if (message !== undefined) {
|
|
90
|
+
invalidArguments.push({
|
|
91
|
+
argument,
|
|
92
|
+
name: path,
|
|
93
|
+
value: value as PopulatedValueType | PopulatedValues,
|
|
94
|
+
reason: InvalidArgumentReason.CUSTOM_VALIDATION,
|
|
95
|
+
message,
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
62
99
|
}
|
|
63
|
-
return {
|
|
64
|
-
argument,
|
|
65
|
-
name,
|
|
66
|
-
value: value as PopulatedValueType | PopulatedValues,
|
|
67
|
-
reason: InvalidArgumentReason.CUSTOM_VALIDATION,
|
|
68
|
-
message,
|
|
69
|
-
};
|
|
70
100
|
}
|
|
71
101
|
|
|
72
102
|
/**
|
|
@@ -193,6 +223,8 @@ function validatePrimitiveValue(
|
|
|
193
223
|
function validateArrayValue(
|
|
194
224
|
subCommandArgument: SubCommandArgument | ComplexOption,
|
|
195
225
|
arrayValue: Array<PopulatedSingleValueType | PopulatedValues | undefined>,
|
|
226
|
+
path: string,
|
|
227
|
+
deferred: Array<DeferredCustomValidation> | undefined,
|
|
196
228
|
): ArrayValueValidationResult {
|
|
197
229
|
const convertedArrayValue: Array<SingleValueType | Values> = [];
|
|
198
230
|
|
|
@@ -228,7 +260,12 @@ function validateArrayValue(
|
|
|
228
260
|
},
|
|
229
261
|
};
|
|
230
262
|
}
|
|
231
|
-
validationResult = validateObjectValue(
|
|
263
|
+
validationResult = validateObjectValue(
|
|
264
|
+
subCommandArgument as ComplexOption,
|
|
265
|
+
singleValue,
|
|
266
|
+
`${path}[${i}]`,
|
|
267
|
+
deferred,
|
|
268
|
+
);
|
|
232
269
|
} // if not array and not object, then must be primitive
|
|
233
270
|
else {
|
|
234
271
|
if (isComplexOption(subCommandArgument)) {
|
|
@@ -267,11 +304,14 @@ function validateArrayValue(
|
|
|
267
304
|
function validateObjectValue(
|
|
268
305
|
argument: ComplexOption,
|
|
269
306
|
objectValue: PopulatedValues,
|
|
307
|
+
path: string,
|
|
308
|
+
deferred: Array<DeferredCustomValidation> | undefined,
|
|
270
309
|
): ObjectValueValidationResult {
|
|
271
310
|
const convertedObjectValue: Values = {};
|
|
272
311
|
|
|
273
312
|
for (let i = 0; i < argument.properties.length; i++) {
|
|
274
313
|
const propertyArg = argument.properties[i]!;
|
|
314
|
+
const propertyPath = `${path}.${propertyArg.name}`;
|
|
275
315
|
let propertyValue = objectValue[propertyArg.name];
|
|
276
316
|
|
|
277
317
|
if (propertyValue === undefined && propertyArg.defaultValue !== undefined) {
|
|
@@ -311,6 +351,8 @@ function validateObjectValue(
|
|
|
311
351
|
validationResult = validateArrayValue(
|
|
312
352
|
propertyArg as ComplexOption | SubCommandArgument,
|
|
313
353
|
propertyValue,
|
|
354
|
+
propertyPath,
|
|
355
|
+
deferred,
|
|
314
356
|
);
|
|
315
357
|
} else if (typeof propertyValue === "object") {
|
|
316
358
|
if (propertyArg.type !== ComplexValueTypeName.COMPLEX) {
|
|
@@ -327,6 +369,8 @@ function validateObjectValue(
|
|
|
327
369
|
validationResult = validateObjectValue(
|
|
328
370
|
propertyArg as ComplexOption,
|
|
329
371
|
propertyValue as PopulatedValues,
|
|
372
|
+
propertyPath,
|
|
373
|
+
deferred,
|
|
330
374
|
);
|
|
331
375
|
} // if not array and not object, then must be primitive
|
|
332
376
|
else {
|
|
@@ -356,18 +400,8 @@ function validateObjectValue(
|
|
|
356
400
|
invalidArgument: withPrefix(validationResult.invalidArgument, `.${propertyArg.name}`),
|
|
357
401
|
};
|
|
358
402
|
}
|
|
359
|
-
// custom validation
|
|
360
|
-
|
|
361
|
-
propertyArg,
|
|
362
|
-
`.${propertyArg.name}`,
|
|
363
|
-
validationResult.validValue!,
|
|
364
|
-
);
|
|
365
|
-
if (customInvalidArgument !== undefined) {
|
|
366
|
-
return {
|
|
367
|
-
validValue: convertedObjectValue,
|
|
368
|
-
invalidArgument: customInvalidArgument,
|
|
369
|
-
};
|
|
370
|
-
}
|
|
403
|
+
// custom validation is deferred until all built-in validation has passed
|
|
404
|
+
deferCustomValidation(deferred, propertyArg, propertyPath, validationResult.validValue!);
|
|
371
405
|
}
|
|
372
406
|
return {
|
|
373
407
|
validValue: convertedObjectValue,
|
|
@@ -380,6 +414,7 @@ function doSubCommandArgumentValidation(
|
|
|
380
414
|
isArray: boolean,
|
|
381
415
|
isOptional: boolean,
|
|
382
416
|
invalidArguments: Array<InvalidArgument>,
|
|
417
|
+
deferred: Array<DeferredCustomValidation> | undefined,
|
|
383
418
|
): PopulatedValueType | PopulatedValues | Array<PopulatedValues> {
|
|
384
419
|
// if there is a value, check if it is valid
|
|
385
420
|
if (value !== undefined) {
|
|
@@ -395,7 +430,7 @@ function doSubCommandArgumentValidation(
|
|
|
395
430
|
});
|
|
396
431
|
return undefined;
|
|
397
432
|
}
|
|
398
|
-
validationResult = validateArrayValue(argument, value);
|
|
433
|
+
validationResult = validateArrayValue(argument, value, argument.name, deferred);
|
|
399
434
|
} else if (typeof value === "object") {
|
|
400
435
|
if (!isComplexOption(argument)) {
|
|
401
436
|
invalidArguments.push({
|
|
@@ -406,7 +441,7 @@ function doSubCommandArgumentValidation(
|
|
|
406
441
|
});
|
|
407
442
|
return undefined;
|
|
408
443
|
}
|
|
409
|
-
validationResult = validateObjectValue(argument, value);
|
|
444
|
+
validationResult = validateObjectValue(argument, value, argument.name, deferred);
|
|
410
445
|
} else {
|
|
411
446
|
if (isComplexOption(argument)) {
|
|
412
447
|
invalidArguments.push({
|
|
@@ -424,15 +459,7 @@ function doSubCommandArgumentValidation(
|
|
|
424
459
|
invalidArguments.push(withPrefix(validationResult.invalidArgument, argument.name));
|
|
425
460
|
return undefined;
|
|
426
461
|
}
|
|
427
|
-
|
|
428
|
-
argument,
|
|
429
|
-
argument.name,
|
|
430
|
-
validationResult.validValue!,
|
|
431
|
-
);
|
|
432
|
-
if (customInvalidArgument !== undefined) {
|
|
433
|
-
invalidArguments.push(customInvalidArgument);
|
|
434
|
-
return undefined;
|
|
435
|
-
}
|
|
462
|
+
deferCustomValidation(deferred, argument, argument.name, validationResult.validValue!);
|
|
436
463
|
return validationResult.validValue as PopulatedValueType | PopulatedValues | undefined;
|
|
437
464
|
}
|
|
438
465
|
|
|
@@ -453,11 +480,13 @@ function doSubCommandArgumentValidation(
|
|
|
453
480
|
* @param option the {@link Option} to validate against.
|
|
454
481
|
* @param value the value (if any) for the {@link Option}.
|
|
455
482
|
* @param invalidArguments an array of {@link InvalidArgument} which may be added to if the provided value is invalid.
|
|
483
|
+
* @param deferred if provided, custom validations are recorded here for later invocation by {@link runCustomValidation}. If omitted, custom validations are not invoked.
|
|
456
484
|
*/
|
|
457
485
|
export function validateOptionValue(
|
|
458
486
|
option: Option | ComplexOption,
|
|
459
487
|
value: PopulatedValueType | PopulatedValues | Array<PopulatedValues | undefined>,
|
|
460
488
|
invalidArguments: Array<InvalidArgument>,
|
|
489
|
+
deferred?: Array<DeferredCustomValidation>,
|
|
461
490
|
): PopulatedValueType | PopulatedValues | Array<PopulatedValues> {
|
|
462
491
|
return doSubCommandArgumentValidation(
|
|
463
492
|
option,
|
|
@@ -465,6 +494,7 @@ export function validateOptionValue(
|
|
|
465
494
|
option.isArray || false,
|
|
466
495
|
option.isOptional || false,
|
|
467
496
|
invalidArguments,
|
|
497
|
+
deferred,
|
|
468
498
|
);
|
|
469
499
|
}
|
|
470
500
|
|
|
@@ -474,11 +504,13 @@ export function validateOptionValue(
|
|
|
474
504
|
* @param positional the {@link Positional} to validate against.
|
|
475
505
|
* @param value the value (if any) for the {@link Positional}.
|
|
476
506
|
* @param invalidArguments an array of {@link InvalidArgument} which may be added to if the provided value is invalid.
|
|
507
|
+
* @param deferred if provided, custom validations are recorded here for later invocation by {@link runCustomValidation}. If omitted, custom validations are not invoked.
|
|
477
508
|
*/
|
|
478
509
|
export function validatePositionalValue(
|
|
479
510
|
positional: Positional,
|
|
480
511
|
value: PopulatedValueType,
|
|
481
512
|
invalidArguments: Array<InvalidArgument>,
|
|
513
|
+
deferred?: Array<DeferredCustomValidation>,
|
|
482
514
|
): PopulatedValueType {
|
|
483
515
|
return doSubCommandArgumentValidation(
|
|
484
516
|
positional,
|
|
@@ -486,6 +518,7 @@ export function validatePositionalValue(
|
|
|
486
518
|
positional.isVarargMultiple || false,
|
|
487
519
|
positional.isVarargOptional || false,
|
|
488
520
|
invalidArguments,
|
|
521
|
+
deferred,
|
|
489
522
|
) as PopulatedValueType;
|
|
490
523
|
}
|
|
491
524
|
|
|
@@ -496,11 +529,13 @@ export function validatePositionalValue(
|
|
|
496
529
|
* @param globalCommand the {@link GlobalCommand} providing the {@link GlobalCommandArgument}.
|
|
497
530
|
* @param value the value (if any) for the {@link GlobalCommandArgument}.
|
|
498
531
|
* @param invalidArguments an array of {@link InvalidArgument} which may be added to if the provided value is invalid.
|
|
532
|
+
* @param deferred if provided, custom validations are recorded here for later invocation by {@link runCustomValidation}. If omitted, custom validations are not invoked.
|
|
499
533
|
*/
|
|
500
534
|
export function validateGlobalCommandArgumentValue(
|
|
501
535
|
globalCommand: GlobalCommand,
|
|
502
536
|
value: PopulatedSingleValueType,
|
|
503
537
|
invalidArguments: Array<InvalidArgument>,
|
|
538
|
+
deferred?: Array<DeferredCustomValidation>,
|
|
504
539
|
): PopulatedSingleValueType {
|
|
505
540
|
// if this function is called it is because the argument is defined
|
|
506
541
|
const globalCommandArgument = globalCommand.argument!;
|
|
@@ -527,15 +562,12 @@ export function validateGlobalCommandArgumentValue(
|
|
|
527
562
|
return undefined;
|
|
528
563
|
}
|
|
529
564
|
|
|
530
|
-
|
|
565
|
+
deferCustomValidation(
|
|
566
|
+
deferred,
|
|
531
567
|
globalCommandArgument,
|
|
532
568
|
globalCommand.name,
|
|
533
569
|
validationResult.validValue!,
|
|
534
570
|
);
|
|
535
|
-
if (customInvalidArgument !== undefined) {
|
|
536
|
-
invalidArguments.push(customInvalidArgument);
|
|
537
|
-
return undefined;
|
|
538
|
-
}
|
|
539
571
|
return validationResult.validValue as PopulatedSingleValueType;
|
|
540
572
|
}
|
|
541
573
|
|