@flowscripter/dynamic-cli-framework 9.1.3 → 10.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/command/MultiCommandCliHelpCommand.d.ts.map +1 -1
- package/dist/src/command/MultiCommandCliHelpCommand.js +1 -1
- package/dist/src/runtime/command/CommandValidator.d.ts.map +1 -1
- package/dist/src/runtime/command/CommandValidator.js +9 -2
- package/dist/src/runtime/parser.d.ts +8 -2
- package/dist/src/runtime/parser.d.ts.map +1 -1
- package/dist/src/runtime/parser.js +11 -6
- package/dist/src/runtime/runner.d.ts.map +1 -1
- package/dist/src/runtime/runner.js +5 -2
- package/dist/src/runtime/values/ValuePopulationResult.d.ts +4 -0
- package/dist/src/runtime/values/ValuePopulationResult.d.ts.map +1 -1
- package/dist/src/runtime/values/globalCommandValuePopulation.d.ts.map +1 -1
- package/dist/src/runtime/values/globalCommandValuePopulation.js +11 -3
- package/dist/src/runtime/values/subCommandValuePopulation.d.ts.map +1 -1
- package/dist/src/runtime/values/subCommandValuePopulation.js +39 -9
- package/dist/src/service/configuration/ConfigurationServiceProvider.d.ts +12 -3
- package/dist/src/service/configuration/ConfigurationServiceProvider.d.ts.map +1 -1
- package/dist/src/service/configuration/ConfigurationServiceProvider.js +16 -7
- package/dist/src/util/configHelper.d.ts +4 -1
- package/dist/src/util/configHelper.d.ts.map +1 -1
- package/dist/src/util/configHelper.js +6 -1
- package/dist/src/util/envVarHelper.d.ts +4 -1
- package/dist/src/util/envVarHelper.d.ts.map +1 -1
- package/dist/src/util/envVarHelper.js +8 -5
- package/dist/src/util/helpHelper.d.ts +1 -1
- package/dist/src/util/helpHelper.d.ts.map +1 -1
- package/dist/src/util/helpHelper.js +8 -16
- package/dist/src/util/runnerHelper.d.ts +2 -0
- package/dist/src/util/runnerHelper.d.ts.map +1 -1
- package/dist/src/util/runnerHelper.js +10 -0
- package/dist/src/util/secretRedaction.d.ts +11 -0
- package/dist/src/util/secretRedaction.d.ts.map +1 -0
- package/dist/src/util/secretRedaction.js +45 -0
- package/package.json +1 -1
- package/src/command/MultiCommandCliHelpCommand.ts +7 -1
- package/src/runtime/command/CommandValidator.ts +8 -1
- package/src/runtime/parser.ts +22 -16
- package/src/runtime/runner.ts +5 -0
- package/src/runtime/values/ValuePopulationResult.ts +5 -0
- package/src/runtime/values/globalCommandValuePopulation.ts +12 -5
- package/src/runtime/values/subCommandValuePopulation.ts +47 -12
- package/src/service/configuration/ConfigurationServiceProvider.ts +18 -6
- package/src/util/configHelper.ts +7 -0
- package/src/util/envVarHelper.ts +19 -3
- package/src/util/helpHelper.ts +34 -13
- package/src/util/runnerHelper.ts +18 -0
- package/src/util/secretRedaction.ts +81 -0
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
} from "@flowscripter/dynamic-cli-framework-api";
|
|
14
14
|
import getLogger from "../../util/logger.ts";
|
|
15
15
|
import type { Context } from "@flowscripter/dynamic-cli-framework-api";
|
|
16
|
+
import type { GroupCommand } from "@flowscripter/dynamic-cli-framework-api";
|
|
16
17
|
import DumpConfigCommand from "./command/DumpConfigCommand.ts";
|
|
17
18
|
import {
|
|
18
19
|
CONFIGURATION_SERVICE_ID,
|
|
@@ -77,7 +78,8 @@ class ConfigurationServiceImpl implements ConfigurationService {
|
|
|
77
78
|
*
|
|
78
79
|
* A JSON file where the structure matches {@link Values} and the defaults are stored
|
|
79
80
|
* under a top level `defaults` property. The second level of properties is used to refer to {@link Command.name}
|
|
80
|
-
*
|
|
81
|
+
* (or `<group name>:<member name>` for a member of a {@link GroupCommand}) and the contained values are treated as
|
|
82
|
+
* command {@link Values}. As an example:
|
|
81
83
|
*
|
|
82
84
|
* ```
|
|
83
85
|
* {
|
|
@@ -94,6 +96,9 @@ class ConfigurationServiceImpl implements ConfigurationService {
|
|
|
94
96
|
* "command2": {
|
|
95
97
|
* "arg4": true
|
|
96
98
|
* },
|
|
99
|
+
* "group1:member1": {
|
|
100
|
+
* "arg5": "bar"
|
|
101
|
+
* },
|
|
97
102
|
* "globalCommand": "globalArgumentValue"
|
|
98
103
|
* },
|
|
99
104
|
* "key-values": {
|
|
@@ -124,13 +129,15 @@ class ConfigurationServiceImpl implements ConfigurationService {
|
|
|
124
129
|
* Argument configuration keys are concatenated with a `_` separator.
|
|
125
130
|
* Any arguments which support array values must by suffixed with `_` and an explicit array index.
|
|
126
131
|
* If the root argument in the path does not use a custom {@link Argument.configurationKey} then the key path
|
|
127
|
-
* is additionally
|
|
132
|
+
* is additionally prefixed with the {@link CLIConfig.name}, the {@link GroupCommand.name} (if the command is a group
|
|
133
|
+
* member) and the {@link Command.name} with `_` separators.
|
|
128
134
|
* This is best explained with examples...
|
|
129
135
|
*
|
|
130
136
|
* No custom configuration key examples:
|
|
131
137
|
*
|
|
132
138
|
* * executable: `MyCLI`, command: `globalCommand1`, global command argument => environment variable: `MYCLI_GLOBALCOMMAND1`
|
|
133
139
|
* * executable: `MyCLI`, command: `command1`, simple root argument: `arg1` => environment variable: `MYCLI_COMMAND1_ARG1`
|
|
140
|
+
* * executable: `MyCLI`, group: `group1`, member command: `member1`, simple root argument: `arg1` => environment variable: `MYCLI_GROUP1_MEMBER1_ARG1`
|
|
134
141
|
* * executable: `MyCLI`, command: `command1`, array root argument, 1st element: `arg2[0]` => environment variable: `MYCLI_COMMAND1_ARG2_0`
|
|
135
142
|
* * executable: `MyCLI`, command: `command1`, argument is a digit so it is by default suffixed with `_`: `3` => environment variable: `MYCLI_COMMAND1__3`
|
|
136
143
|
* * executable: `MyCLI`, command: `command1`, nested sub-argument: `arg1.arg2` => environment variable: `MYCLI_COMMAND1_ARG1_ARG2`
|
|
@@ -238,17 +245,22 @@ export default class ConfigurationServiceProvider implements ServiceProvider {
|
|
|
238
245
|
*
|
|
239
246
|
* @param cliConfig the {@link CLIConfig} to use for retrieving configuration keys.
|
|
240
247
|
* @param command the {@link Command} instance to retrieve default argument values for.
|
|
248
|
+
* @param groupCommand the {@link GroupCommand} if the command is a group member. The configuration file key
|
|
249
|
+
* is then `<group name>:<command name>` and the env var names include the group name.
|
|
241
250
|
*/
|
|
242
251
|
public async getDefaultArgumentValues(
|
|
243
252
|
cliConfig: CLIConfig,
|
|
244
253
|
command: Command,
|
|
254
|
+
groupCommand?: GroupCommand,
|
|
245
255
|
): Promise<PopulatedValues | PopulatedValueType | undefined> {
|
|
246
256
|
if (!this.configEnabled) {
|
|
247
257
|
logger.debug("configuration of default values is not enabled");
|
|
248
258
|
return undefined;
|
|
249
259
|
}
|
|
250
260
|
|
|
251
|
-
|
|
261
|
+
const commandKey = groupCommand ? `${groupCommand.name}:${command.name}` : command.name;
|
|
262
|
+
|
|
263
|
+
logger.debug("getting default argument values for command: %s", commandKey);
|
|
252
264
|
|
|
253
265
|
if (command.enableConfiguration === undefined || command.enableConfiguration !== true) {
|
|
254
266
|
logger.debug("enableConfiguration for command: %s is not true", command.name);
|
|
@@ -258,16 +270,16 @@ export default class ConfigurationServiceProvider implements ServiceProvider {
|
|
|
258
270
|
let result: PopulatedValues | PopulatedValueType | undefined;
|
|
259
271
|
|
|
260
272
|
if (isGlobalModifierCommand(command) || isGlobalCommand(command)) {
|
|
261
|
-
const configuredValue = this.defaultsData.get(
|
|
273
|
+
const configuredValue = this.defaultsData.get(commandKey) as SingleValueType;
|
|
262
274
|
const envVarValue = this.envVarsEnabled
|
|
263
275
|
? getGlobalCommandValueFromEnvVars(cliConfig, command)
|
|
264
276
|
: undefined;
|
|
265
277
|
// default to environment variable value
|
|
266
278
|
result = envVarValue !== undefined ? envVarValue : configuredValue;
|
|
267
279
|
} else if (isSubCommand(command)) {
|
|
268
|
-
const configuredValues = this.defaultsData.get(
|
|
280
|
+
const configuredValues = this.defaultsData.get(commandKey) as Values;
|
|
269
281
|
const envVarValues = this.envVarsEnabled
|
|
270
|
-
? getSubCommandValuesFromEnvVars(cliConfig, command)
|
|
282
|
+
? getSubCommandValuesFromEnvVars(cliConfig, command, groupCommand)
|
|
271
283
|
: undefined;
|
|
272
284
|
if (envVarValues === undefined) {
|
|
273
285
|
result = configuredValues;
|
package/src/util/configHelper.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { GroupCommand } from "@flowscripter/dynamic-cli-framework-api";
|
|
1
2
|
import type { Command } from "@flowscripter/dynamic-cli-framework-api";
|
|
2
3
|
import type { CLIConfig } from "@flowscripter/dynamic-cli-framework-api";
|
|
3
4
|
import type { Option } from "@flowscripter/dynamic-cli-framework-api";
|
|
@@ -26,11 +27,14 @@ function getKeySegment(segment: string, isCustom = false, isArray = false) {
|
|
|
26
27
|
* @param command the {@link Command} to use for determining the default configuration key.
|
|
27
28
|
* @param argumentAncestry a list of {@link SubCommandArgument} instances from the root command arguments to a leaf argument.
|
|
28
29
|
* Apart from {@link ComplexOption} instances this will always only have a single entry.
|
|
30
|
+
* @param groupCommand the {@link GroupCommand} if the command is a member of a group, in which case the group name
|
|
31
|
+
* is an additional key segment.
|
|
29
32
|
*/
|
|
30
33
|
export function getSubCommandArgumentConfigurationKey(
|
|
31
34
|
cliConfig: CLIConfig,
|
|
32
35
|
command: Command,
|
|
33
36
|
argumentAncestry: Array<SubCommandArgument>,
|
|
37
|
+
groupCommand?: GroupCommand,
|
|
34
38
|
): string | undefined {
|
|
35
39
|
if (command.enableConfiguration === undefined || command.enableConfiguration !== true) {
|
|
36
40
|
return undefined;
|
|
@@ -43,6 +47,9 @@ export function getSubCommandArgumentConfigurationKey(
|
|
|
43
47
|
const firstArgument = argumentAncestry[0]!;
|
|
44
48
|
if (firstArgument.configurationKey === undefined) {
|
|
45
49
|
keySegments.push(getKeySegment(cliConfig.name));
|
|
50
|
+
if (groupCommand) {
|
|
51
|
+
keySegments.push(getKeySegment(groupCommand.name));
|
|
52
|
+
}
|
|
46
53
|
keySegments.push(getKeySegment(command.name));
|
|
47
54
|
}
|
|
48
55
|
|
package/src/util/envVarHelper.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { MAXIMUM_ARGUMENT_ARRAY_SIZE } from "@flowscripter/dynamic-cli-framework
|
|
|
14
14
|
import type { Option } from "@flowscripter/dynamic-cli-framework-api";
|
|
15
15
|
import type { GlobalCommandArgument } from "@flowscripter/dynamic-cli-framework-api";
|
|
16
16
|
import type { GlobalCommand } from "@flowscripter/dynamic-cli-framework-api";
|
|
17
|
+
import type { GroupCommand } from "@flowscripter/dynamic-cli-framework-api";
|
|
17
18
|
import type { SubCommand } from "@flowscripter/dynamic-cli-framework-api";
|
|
18
19
|
import type { ComplexOption } from "@flowscripter/dynamic-cli-framework-api";
|
|
19
20
|
|
|
@@ -29,11 +30,13 @@ function getSubCommandArgumentKeyPrefix(
|
|
|
29
30
|
cliConfig: CLIConfig,
|
|
30
31
|
command: Command,
|
|
31
32
|
subCommandArgument: SubCommandArgument,
|
|
33
|
+
groupCommand?: GroupCommand,
|
|
32
34
|
) {
|
|
33
35
|
if (subCommandArgument.configurationKey) {
|
|
34
36
|
return subCommandArgument.configurationKey;
|
|
35
37
|
}
|
|
36
|
-
|
|
38
|
+
const groupSegment = groupCommand ? `${getKeySegment(groupCommand.name)}_` : "";
|
|
39
|
+
return `${getKeySegment(cliConfig.name)}_${groupSegment}${getKeySegment(command.name)}_${getKeySegment(
|
|
37
40
|
subCommandArgument.name,
|
|
38
41
|
)}`;
|
|
39
42
|
}
|
|
@@ -214,16 +217,24 @@ function getOptionValuesFromEnvVars(
|
|
|
214
217
|
* @param cliConfig the {@link CLIConfig} to use for determining the default configuration key.
|
|
215
218
|
* @param command the {@link SubCommand} to use for determining the default configuration key and containing
|
|
216
219
|
* {@link Positional} and {@link Option} instances to populate values for.
|
|
220
|
+
* @param groupCommand the {@link GroupCommand} if the command is a group member, in which case the group name
|
|
221
|
+
* is an additional env var name segment.
|
|
217
222
|
*/
|
|
218
223
|
export function getSubCommandValuesFromEnvVars(
|
|
219
224
|
cliConfig: CLIConfig,
|
|
220
225
|
command: SubCommand,
|
|
226
|
+
groupCommand?: GroupCommand,
|
|
221
227
|
): PopulatedValues | undefined {
|
|
222
228
|
const envVarValues = Object.create(null) as PopulatedValues;
|
|
223
229
|
if (command.options) {
|
|
224
230
|
for (const option of command.options) {
|
|
225
231
|
const potentialEnvVarNames = Object.keys(process.env);
|
|
226
|
-
const optionPrefix = getSubCommandArgumentKeyPrefix(
|
|
232
|
+
const optionPrefix = getSubCommandArgumentKeyPrefix(
|
|
233
|
+
cliConfig,
|
|
234
|
+
command,
|
|
235
|
+
option as Option,
|
|
236
|
+
groupCommand,
|
|
237
|
+
);
|
|
227
238
|
getOptionValuesFromEnvVars(
|
|
228
239
|
envVarValues,
|
|
229
240
|
potentialEnvVarNames,
|
|
@@ -244,7 +255,12 @@ export function getSubCommandValuesFromEnvVars(
|
|
|
244
255
|
`Unsafe key name in use: ${positional.name}, CodeQL Rule ID: js/prototype-polluting-assignment`,
|
|
245
256
|
);
|
|
246
257
|
}
|
|
247
|
-
let envVarNamePrefix = getSubCommandArgumentKeyPrefix(
|
|
258
|
+
let envVarNamePrefix = getSubCommandArgumentKeyPrefix(
|
|
259
|
+
cliConfig,
|
|
260
|
+
command,
|
|
261
|
+
positional,
|
|
262
|
+
groupCommand,
|
|
263
|
+
);
|
|
248
264
|
|
|
249
265
|
if (positional.isVarargMultiple) {
|
|
250
266
|
envVarNamePrefix = `${envVarNamePrefix}_`;
|
package/src/util/helpHelper.ts
CHANGED
|
@@ -312,6 +312,7 @@ function getOptionHelpEntry(
|
|
|
312
312
|
option: Option | ComplexOption,
|
|
313
313
|
subEntryIndent = 0,
|
|
314
314
|
optionAncestry: Array<Option | ComplexOption> = [],
|
|
315
|
+
groupCommand?: GroupCommand,
|
|
315
316
|
): HelpEntry {
|
|
316
317
|
let subEntries: Array<HelpEntry> | undefined;
|
|
317
318
|
let optionCharacters = "--";
|
|
@@ -328,10 +329,15 @@ function getOptionHelpEntry(
|
|
|
328
329
|
subEntries = [];
|
|
329
330
|
option.properties.forEach((property) => {
|
|
330
331
|
subEntries!.push(
|
|
331
|
-
getOptionHelpEntry(
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
332
|
+
getOptionHelpEntry(
|
|
333
|
+
cliConfig,
|
|
334
|
+
includeEnvVars,
|
|
335
|
+
command,
|
|
336
|
+
property,
|
|
337
|
+
newSubEntryIndent,
|
|
338
|
+
[...optionAncestry, option],
|
|
339
|
+
groupCommand,
|
|
340
|
+
),
|
|
335
341
|
);
|
|
336
342
|
});
|
|
337
343
|
} else {
|
|
@@ -384,10 +390,12 @@ function getOptionHelpEntry(
|
|
|
384
390
|
}
|
|
385
391
|
|
|
386
392
|
if (includeEnvVars && option.type !== ComplexValueTypeName.COMPLEX) {
|
|
387
|
-
const configurationKey = getSubCommandArgumentConfigurationKey(
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
393
|
+
const configurationKey = getSubCommandArgumentConfigurationKey(
|
|
394
|
+
cliConfig,
|
|
395
|
+
command,
|
|
396
|
+
[...(optionAncestry as Array<SubCommandArgument>), option as unknown as SubCommandArgument],
|
|
397
|
+
groupCommand,
|
|
398
|
+
);
|
|
391
399
|
if (configurationKey !== undefined) {
|
|
392
400
|
notesItems.push(`env var: ${configurationKey}`);
|
|
393
401
|
}
|
|
@@ -418,6 +426,7 @@ function getPositionalHelpEntry(
|
|
|
418
426
|
includeEnvVars: boolean,
|
|
419
427
|
command: Command,
|
|
420
428
|
positional: Positional,
|
|
429
|
+
groupCommand?: GroupCommand,
|
|
421
430
|
): HelpEntry {
|
|
422
431
|
const notesItems: Array<string> = [];
|
|
423
432
|
if (positional.allowableValues !== undefined && positional.allowableValues.length > 0) {
|
|
@@ -458,9 +467,12 @@ function getPositionalHelpEntry(
|
|
|
458
467
|
}
|
|
459
468
|
|
|
460
469
|
if (includeEnvVars) {
|
|
461
|
-
const configurationKey = getSubCommandArgumentConfigurationKey(
|
|
462
|
-
|
|
463
|
-
|
|
470
|
+
const configurationKey = getSubCommandArgumentConfigurationKey(
|
|
471
|
+
cliConfig,
|
|
472
|
+
command,
|
|
473
|
+
[positional],
|
|
474
|
+
groupCommand,
|
|
475
|
+
);
|
|
464
476
|
if (configurationKey !== undefined) {
|
|
465
477
|
notesItems.push(`env var: ${configurationKey}`);
|
|
466
478
|
}
|
|
@@ -486,6 +498,7 @@ export function getCommandArgsHelpSections(
|
|
|
486
498
|
includeEnvVars: boolean,
|
|
487
499
|
subCommand: SubCommand,
|
|
488
500
|
isSingleCommandApp: boolean,
|
|
501
|
+
groupCommand?: GroupCommand,
|
|
489
502
|
): Array<HelpSection> {
|
|
490
503
|
const helpSections: Array<HelpSection> = [];
|
|
491
504
|
if (subCommand.options.length > 0 || subCommand.positionals.length > 0) {
|
|
@@ -495,12 +508,20 @@ export function getCommandArgsHelpSections(
|
|
|
495
508
|
};
|
|
496
509
|
subCommand.options.forEach((option) => {
|
|
497
510
|
argumentsSection.helpEntries.push(
|
|
498
|
-
getOptionHelpEntry(
|
|
511
|
+
getOptionHelpEntry(
|
|
512
|
+
cliConfig,
|
|
513
|
+
includeEnvVars,
|
|
514
|
+
subCommand,
|
|
515
|
+
option as Option,
|
|
516
|
+
0,
|
|
517
|
+
[],
|
|
518
|
+
groupCommand,
|
|
519
|
+
),
|
|
499
520
|
);
|
|
500
521
|
});
|
|
501
522
|
subCommand.positionals.forEach((positional) => {
|
|
502
523
|
argumentsSection.helpEntries.push(
|
|
503
|
-
getPositionalHelpEntry(cliConfig, includeEnvVars, subCommand, positional),
|
|
524
|
+
getPositionalHelpEntry(cliConfig, includeEnvVars, subCommand, positional, groupCommand),
|
|
504
525
|
);
|
|
505
526
|
});
|
|
506
527
|
helpSections.push(argumentsSection);
|
package/src/util/runnerHelper.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PrinterService } from "@flowscripter/dynamic-cli-framework-api";
|
|
2
2
|
import { Icon, PRINTER_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
|
|
3
|
+
import type { SecretAwareParseResult } from "../runtime/parser.ts";
|
|
3
4
|
import type { ParseResult } from "../runtime/parser.ts";
|
|
4
5
|
import { isGlobalCommand, isGlobalModifierCommand } from "../runtime/command/CommandTypeGuards.ts";
|
|
5
6
|
import type { Context } from "@flowscripter/dynamic-cli-framework-api";
|
|
@@ -122,3 +123,20 @@ export async function printUnusedArgsWarning(
|
|
|
122
123
|
await printerService.warn(`Unused args: ${overallUnusedArgs.join(" ")}\n\n`, Icon.ALERT);
|
|
123
124
|
}
|
|
124
125
|
}
|
|
126
|
+
|
|
127
|
+
export async function printSecretArgsWarning(
|
|
128
|
+
context: Context,
|
|
129
|
+
parseResult: SecretAwareParseResult,
|
|
130
|
+
) {
|
|
131
|
+
const secretArgumentNames = parseResult.secretArgumentNames;
|
|
132
|
+
if (!secretArgumentNames || secretArgumentNames.length === 0) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const printerService = context.getServiceById(PRINTER_SERVICE_ID) as PrinterService;
|
|
136
|
+
await printerService.warn(
|
|
137
|
+
`SECRET value passed as a plain argument: ${secretArgumentNames.join(", ")}. ` +
|
|
138
|
+
"This is not recommended as it may be exposed via shell history and process listings. " +
|
|
139
|
+
"Use an environment variable, a prompt or a configuration file default instead.\n\n",
|
|
140
|
+
Icon.ALERT,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ValueTypeName,
|
|
3
|
+
type ComplexOption,
|
|
4
|
+
type GlobalCommand,
|
|
5
|
+
type Option,
|
|
6
|
+
type PopulatedSingleValueType,
|
|
7
|
+
type PopulatedValues,
|
|
8
|
+
type PopulatedValueType,
|
|
9
|
+
type SubCommand,
|
|
10
|
+
} from "@flowscripter/dynamic-cli-framework-api";
|
|
11
|
+
import { isComplexOption } from "../runtime/argument/ArgumentTypeGuards.ts";
|
|
12
|
+
|
|
13
|
+
export const REDACTED = "***";
|
|
14
|
+
|
|
15
|
+
type NamedArgument = { readonly name: string; readonly type?: unknown };
|
|
16
|
+
|
|
17
|
+
type RedactableValue =
|
|
18
|
+
| PopulatedValueType
|
|
19
|
+
| PopulatedValues
|
|
20
|
+
| Array<PopulatedValues | undefined>
|
|
21
|
+
| undefined;
|
|
22
|
+
|
|
23
|
+
function redactValue(
|
|
24
|
+
definition: NamedArgument | ComplexOption,
|
|
25
|
+
value: RedactableValue | PopulatedValues,
|
|
26
|
+
): unknown {
|
|
27
|
+
if (value === undefined || value === null) {
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
if (isComplexOption(definition as ComplexOption)) {
|
|
31
|
+
const properties = (definition as ComplexOption).properties;
|
|
32
|
+
if (Array.isArray(value)) {
|
|
33
|
+
return value.map((v) => redactValue(definition, v));
|
|
34
|
+
}
|
|
35
|
+
return redactDefinedValues(properties, [], value as PopulatedValues);
|
|
36
|
+
}
|
|
37
|
+
if (definition.type === ValueTypeName.SECRET) {
|
|
38
|
+
return Array.isArray(value) ? value.map(() => REDACTED) : REDACTED;
|
|
39
|
+
}
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function redactDefinedValues(
|
|
44
|
+
options: ReadonlyArray<Option | ComplexOption>,
|
|
45
|
+
positionals: ReadonlyArray<NamedArgument>,
|
|
46
|
+
values: PopulatedValues,
|
|
47
|
+
): PopulatedValues {
|
|
48
|
+
const redacted: Record<string, unknown> = {};
|
|
49
|
+
for (const [name, value] of Object.entries(values)) {
|
|
50
|
+
const definition =
|
|
51
|
+
options.find((o) => o.name === name) ?? positionals.find((p) => p.name === name);
|
|
52
|
+
redacted[name] = definition ? redactValue(definition, value) : value;
|
|
53
|
+
}
|
|
54
|
+
return redacted as PopulatedValues;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Copy of the provided values suitable for logging, with the values of any SECRET options or positionals replaced.
|
|
59
|
+
*/
|
|
60
|
+
export function redactSubCommandValues<T extends PopulatedValues | undefined>(
|
|
61
|
+
subCommand: SubCommand,
|
|
62
|
+
values: T,
|
|
63
|
+
): T {
|
|
64
|
+
if (values === undefined) {
|
|
65
|
+
return values;
|
|
66
|
+
}
|
|
67
|
+
return redactDefinedValues(subCommand.options, subCommand.positionals, values) as T;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Copy of the provided value suitable for logging, with the value replaced if the global command argument is a SECRET.
|
|
72
|
+
*/
|
|
73
|
+
export function redactGlobalCommandValue(
|
|
74
|
+
globalCommand: GlobalCommand,
|
|
75
|
+
value: PopulatedSingleValueType,
|
|
76
|
+
): PopulatedSingleValueType {
|
|
77
|
+
if (value !== undefined && globalCommand.argument?.type === ValueTypeName.SECRET) {
|
|
78
|
+
return REDACTED;
|
|
79
|
+
}
|
|
80
|
+
return value;
|
|
81
|
+
}
|