@flowscripter/dynamic-cli-framework 12.1.0 → 12.2.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 +1 -1
- package/dist/src/runtime/runner.d.ts.map +1 -1
- package/dist/src/runtime/runner.js +4 -1
- package/dist/src/service/configuration/ConfigurationServiceProvider.d.ts +23 -13
- package/dist/src/service/configuration/ConfigurationServiceProvider.d.ts.map +1 -1
- package/dist/src/service/configuration/ConfigurationServiceProvider.js +69 -179
- package/dist/src/service/configuration/DefaultConfigurationService.d.ts +78 -0
- package/dist/src/service/configuration/DefaultConfigurationService.d.ts.map +1 -0
- package/dist/src/service/configuration/DefaultConfigurationService.js +296 -0
- package/dist/src/service/configuration/DefaultKeyValueService.d.ts.map +1 -1
- package/dist/src/service/configuration/DefaultKeyValueService.js +7 -3
- package/dist/src/service/configuration/DefaultSecretService.d.ts +17 -2
- package/dist/src/service/configuration/DefaultSecretService.d.ts.map +1 -1
- package/dist/src/service/configuration/DefaultSecretService.js +44 -5
- package/dist/src/service/configuration/KeyValueServiceProvider.d.ts +3 -1
- package/dist/src/service/configuration/KeyValueServiceProvider.d.ts.map +1 -1
- package/dist/src/service/configuration/KeyValueServiceProvider.js +6 -3
- package/dist/src/service/configuration/command/ConfigDumpSubCommand.d.ts +3 -7
- package/dist/src/service/configuration/command/ConfigDumpSubCommand.d.ts.map +1 -1
- package/dist/src/service/configuration/command/ConfigDumpSubCommand.js +5 -10
- package/dist/src/service/configuration/command/ConfigGetSubCommand.d.ts +16 -0
- package/dist/src/service/configuration/command/ConfigGetSubCommand.d.ts.map +1 -0
- package/dist/src/service/configuration/command/ConfigGetSubCommand.js +137 -0
- package/dist/src/service/configuration/command/ConfigSetSubCommand.d.ts +18 -0
- package/dist/src/service/configuration/command/ConfigSetSubCommand.d.ts.map +1 -0
- package/dist/src/service/configuration/command/ConfigSetSubCommand.js +289 -0
- package/dist/src/service/configuration/command/ConfigUnsetSubCommand.d.ts +15 -0
- package/dist/src/service/configuration/command/ConfigUnsetSubCommand.d.ts.map +1 -0
- package/dist/src/service/configuration/command/ConfigUnsetSubCommand.js +101 -0
- package/dist/src/service/configuration/configTargets.d.ts +91 -0
- package/dist/src/service/configuration/configTargets.d.ts.map +1 -0
- package/dist/src/service/configuration/configTargets.js +348 -0
- package/dist/src/service/configuration/resolveSecrets.d.ts.map +1 -1
- package/dist/src/service/configuration/resolveSecrets.js +7 -1
- package/package.json +1 -1
- package/src/cli/BaseCLI.ts +1 -0
- package/src/runtime/runner.ts +4 -1
- package/src/service/configuration/ConfigurationServiceProvider.ts +95 -227
- package/src/service/configuration/DefaultConfigurationService.ts +378 -0
- package/src/service/configuration/DefaultKeyValueService.ts +9 -3
- package/src/service/configuration/DefaultSecretService.ts +51 -8
- package/src/service/configuration/KeyValueServiceProvider.ts +7 -2
- package/src/service/configuration/command/ConfigDumpSubCommand.ts +6 -10
- package/src/service/configuration/command/ConfigGetSubCommand.ts +198 -0
- package/src/service/configuration/command/ConfigSetSubCommand.ts +401 -0
- package/src/service/configuration/command/ConfigUnsetSubCommand.ts +126 -0
- package/src/service/configuration/configTargets.ts +481 -0
- package/src/service/configuration/resolveSecrets.ts +7 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { PRINTER_SERVICE_ID, ValueTypeName, } from "@flowscripter/dynamic-cli-framework-api";
|
|
2
|
+
import { isComplexOption } from "../../../runtime/argument/ArgumentTypeGuards.js";
|
|
3
|
+
import { isOverriddenByEnvVar, maskDefault, } from "../configTargets.js";
|
|
4
|
+
function typeName(option) {
|
|
5
|
+
const name = isComplexOptionLike(option) ? "COMPLEX" : ValueTypeName[option.type];
|
|
6
|
+
return option.isArray === true ? `${name}[]` : name;
|
|
7
|
+
}
|
|
8
|
+
function isComplexOptionLike(option) {
|
|
9
|
+
return option.type === 5;
|
|
10
|
+
}
|
|
11
|
+
function constraints(option) {
|
|
12
|
+
const parts = [];
|
|
13
|
+
if (option.allowableValues !== undefined) {
|
|
14
|
+
parts.push(`one of: ${option.allowableValues.join(", ")}`);
|
|
15
|
+
}
|
|
16
|
+
if (option.minValueInclusive !== undefined || option.maxValueInclusive !== undefined) {
|
|
17
|
+
parts.push(`range: ${option.minValueInclusive ?? ""}..${option.maxValueInclusive ?? ""}`);
|
|
18
|
+
}
|
|
19
|
+
return parts.length === 0 ? "" : ` (${parts.join("; ")})`;
|
|
20
|
+
}
|
|
21
|
+
function mismatch(option, value) {
|
|
22
|
+
if (value === undefined || isComplexOption(option) || option.isArray === true) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
switch (option.type) {
|
|
26
|
+
case ValueTypeName.BOOLEAN:
|
|
27
|
+
return typeof value !== "boolean";
|
|
28
|
+
case ValueTypeName.INTEGER:
|
|
29
|
+
return !Number.isInteger(value);
|
|
30
|
+
case ValueTypeName.NUMBER:
|
|
31
|
+
return typeof value !== "number";
|
|
32
|
+
default:
|
|
33
|
+
return typeof value !== "string";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Member of the `config` group which shows the configurable commands, their options and the
|
|
38
|
+
* values currently stored for them. SECRET values are masked.
|
|
39
|
+
*/
|
|
40
|
+
export default class ConfigGetSubCommand {
|
|
41
|
+
name = "get";
|
|
42
|
+
description = "Show configurable commands, their options and stored default values";
|
|
43
|
+
options = [
|
|
44
|
+
{
|
|
45
|
+
name: "command",
|
|
46
|
+
type: ValueTypeName.STRING,
|
|
47
|
+
description: "Show only this command (or <group>:<member>)",
|
|
48
|
+
isOptional: true,
|
|
49
|
+
validate: (value) => {
|
|
50
|
+
const targets = this.#configurationService.getConfigTargets();
|
|
51
|
+
return targets.has(value)
|
|
52
|
+
? undefined
|
|
53
|
+
: `unknown or non-configurable command, valid commands: ${[...targets.keys()].join(", ")}`;
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
positionals = [];
|
|
58
|
+
#configurationService;
|
|
59
|
+
constructor(configurationService) {
|
|
60
|
+
this.#configurationService = configurationService;
|
|
61
|
+
}
|
|
62
|
+
async execute(context, argumentValues) {
|
|
63
|
+
const printer = context.getServiceById(PRINTER_SERVICE_ID);
|
|
64
|
+
const targets = this.#configurationService.getConfigTargets();
|
|
65
|
+
const selected = argumentValues["command"];
|
|
66
|
+
const keys = selected === undefined ? [...targets.keys()] : [selected];
|
|
67
|
+
if (selected === undefined) {
|
|
68
|
+
for (const key of this.#configurationService.defaultsData.keys()) {
|
|
69
|
+
if (!targets.has(key)) {
|
|
70
|
+
keys.push(key);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const lines = [];
|
|
75
|
+
for (const key of keys) {
|
|
76
|
+
const target = targets.get(key);
|
|
77
|
+
const stored = this.#configurationService.defaultsData.get(key);
|
|
78
|
+
if (target === undefined) {
|
|
79
|
+
lines.push(`${key} (unknown command, not configurable)`);
|
|
80
|
+
lines.push(` ${JSON.stringify(maskDefault(undefined, stored))}`);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
lines.push(key);
|
|
84
|
+
if (target.argument !== undefined) {
|
|
85
|
+
lines.push(` ${typeName(target.argument)}${constraints(target.argument)} = ${this.#show(context, target, [], stored)}`);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const values = (stored ?? {});
|
|
89
|
+
this.#listOptions(context, target, target.options, [], "", values, lines);
|
|
90
|
+
for (const name of Object.keys(values)) {
|
|
91
|
+
if (!target.options.some((o) => o.name === name)) {
|
|
92
|
+
lines.push(` ${name} (unknown option) = ${JSON.stringify(maskDefault(undefined, values[name]))}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
await printer.print(`${lines.join("\n")}\n`);
|
|
97
|
+
}
|
|
98
|
+
#show(context, target, steps, value) {
|
|
99
|
+
if (value === undefined) {
|
|
100
|
+
return isOverriddenByEnvVar(this.#configurationService, context.cliConfig, target, steps)
|
|
101
|
+
? "(not set; overridden by an environment variable)"
|
|
102
|
+
: "(not set)";
|
|
103
|
+
}
|
|
104
|
+
const text = JSON.stringify(maskDefault(target, value));
|
|
105
|
+
return isOverriddenByEnvVar(this.#configurationService, context.cliConfig, target, steps)
|
|
106
|
+
? `${text} (overridden by an environment variable)`
|
|
107
|
+
: text;
|
|
108
|
+
}
|
|
109
|
+
#listOptions(context, target, options, steps, prefix, values, lines) {
|
|
110
|
+
for (const option of options) {
|
|
111
|
+
const path = `${prefix}${option.name}`;
|
|
112
|
+
const optionSteps = [...steps, { name: option.name }];
|
|
113
|
+
const value = values?.[option.name];
|
|
114
|
+
const flag = mismatch(option, value) ? " (type mismatch)" : "";
|
|
115
|
+
const indent = " ".repeat(optionSteps.length);
|
|
116
|
+
const optional = option.isOptional === true || option.defaultValue !== undefined ? "" : " required";
|
|
117
|
+
const detail = isComplexOption(option) ? "" : constraints(option);
|
|
118
|
+
const shown = value === undefined
|
|
119
|
+
? this.#show(context, target, optionSteps, undefined)
|
|
120
|
+
: this.#showValue(context, target, optionSteps, option, value);
|
|
121
|
+
lines.push(`${indent}${path} ${typeName(option)}${optional}${detail} = ${shown}${flag}`);
|
|
122
|
+
if (isComplexOption(option) && option.isArray !== true) {
|
|
123
|
+
this.#listOptions(context, target, option.properties, optionSteps, `${path}.`, typeof value === "object" && value !== null
|
|
124
|
+
? value
|
|
125
|
+
: undefined, lines);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
#showValue(context, target, steps, option, value) {
|
|
130
|
+
const wrapper = { ...target, argument: undefined, options: [option] };
|
|
131
|
+
const masked = maskDefault(wrapper, { [option.name]: value });
|
|
132
|
+
const text = JSON.stringify(masked[option.name]);
|
|
133
|
+
return isOverriddenByEnvVar(this.#configurationService, context.cliConfig, target, steps)
|
|
134
|
+
? `${text} (overridden by an environment variable)`
|
|
135
|
+
: text;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Context, type Option, type Positional, type SubCommand, type Values } from "@flowscripter/dynamic-cli-framework-api";
|
|
2
|
+
import type DefaultConfigurationService from "../DefaultConfigurationService.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Member of the `config` group which sets a default value for an option of a configurable command.
|
|
5
|
+
*
|
|
6
|
+
* Values are validated against the option declared by the target command (type, allowable values,
|
|
7
|
+
* range and custom validators) but the target's required checks are not applied.
|
|
8
|
+
*/
|
|
9
|
+
export default class ConfigSetSubCommand implements SubCommand {
|
|
10
|
+
#private;
|
|
11
|
+
readonly name = "set";
|
|
12
|
+
readonly description = "Set a default value for an option of a command";
|
|
13
|
+
readonly options: ReadonlyArray<Option>;
|
|
14
|
+
readonly positionals: ReadonlyArray<Positional>;
|
|
15
|
+
constructor(configurationService: DefaultConfigurationService, readStdinFn?: () => Promise<string>);
|
|
16
|
+
execute(context: Context, argumentValues: Values): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=ConfigSetSubCommand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfigSetSubCommand.d.ts","sourceRoot":"","sources":["../../../../../src/service/configuration/command/ConfigSetSubCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,OAAO,EACZ,KAAK,MAAM,EACX,KAAK,UAAU,EAGf,KAAK,UAAU,EACf,KAAK,MAAM,EACZ,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,2BAA2B,MAAM,mCAAmC,CAAC;AAqBjF;;;;;GAKG;AACH,MAAM,CAAC,OAAO,OAAO,mBAAoB,YAAW,UAAU;;IAC5D,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,WAAW,oDAAoD;IACxE,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAwDrC;IACF,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,UAAU,CAAC,CAAM;IAKrD,YACE,oBAAoB,EAAE,2BAA2B,EACjD,WAAW,GAAE,MAAM,OAAO,CAAC,MAAM,CAAa,EAI/C;IAqEK,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2LrE;CA+BF"}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { ARGUMENT_PROMPTER_SERVICE_ID, PRINTER_SERVICE_ID, ValueTypeName, Icon, } from "@flowscripter/dynamic-cli-framework-api";
|
|
2
|
+
import { isComplexOption } from "../../../runtime/argument/ArgumentTypeGuards.js";
|
|
3
|
+
import { applyChanges, containsSecret, isOverriddenByEnvVar, prepareChange, prepareGlobalValue, resolveOptionPath, setAtPath, } from "../configTargets.js";
|
|
4
|
+
async function readStdin() {
|
|
5
|
+
return await Bun.stdin.text();
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Member of the `config` group which sets a default value for an option of a configurable command.
|
|
9
|
+
*
|
|
10
|
+
* Values are validated against the option declared by the target command (type, allowable values,
|
|
11
|
+
* range and custom validators) but the target's required checks are not applied.
|
|
12
|
+
*/
|
|
13
|
+
export default class ConfigSetSubCommand {
|
|
14
|
+
name = "set";
|
|
15
|
+
description = "Set a default value for an option of a command";
|
|
16
|
+
options = [
|
|
17
|
+
{
|
|
18
|
+
name: "command",
|
|
19
|
+
type: ValueTypeName.STRING,
|
|
20
|
+
description: "The command (or <group>:<member>) to set a default for",
|
|
21
|
+
isOptional: true,
|
|
22
|
+
validate: (value) => this.#validateCommand(value),
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: "option",
|
|
26
|
+
type: ValueTypeName.STRING,
|
|
27
|
+
description: "The option to set, for nested or array options a path such as 'address[1].port'. Omit for a global command.",
|
|
28
|
+
isOptional: true,
|
|
29
|
+
validate: (value, ctx) => {
|
|
30
|
+
const target = this.#targetOf(ctx.values);
|
|
31
|
+
if (target === undefined) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
if (target.argument !== undefined) {
|
|
35
|
+
return `command '${target.key}' has no options: omit --option`;
|
|
36
|
+
}
|
|
37
|
+
const resolved = resolveOptionPath(target, value);
|
|
38
|
+
return typeof resolved === "string" ? this.#withValidOptions(target, resolved) : undefined;
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "value",
|
|
43
|
+
type: ValueTypeName.STRING,
|
|
44
|
+
description: "The value to set. Arrays and complex options take a JSON value. Prefer a prompt or --value-stdin for SECRET options.",
|
|
45
|
+
isOptional: true,
|
|
46
|
+
validate: (value, ctx) => {
|
|
47
|
+
const target = this.#targetOf(ctx.values);
|
|
48
|
+
if (target === undefined) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
const values = ctx.values;
|
|
52
|
+
const result = this.#prepare(target, values["option"], value);
|
|
53
|
+
return typeof result === "string" ? result : undefined;
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "value-stdin",
|
|
58
|
+
type: ValueTypeName.BOOLEAN,
|
|
59
|
+
description: "Read the value from stdin instead of --value",
|
|
60
|
+
isOptional: true,
|
|
61
|
+
validate: (value, ctx) => value === true && ctx.values["value"] !== undefined
|
|
62
|
+
? "cannot be combined with --value"
|
|
63
|
+
: undefined,
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
positionals = [];
|
|
67
|
+
#configurationService;
|
|
68
|
+
#readStdin;
|
|
69
|
+
constructor(configurationService, readStdinFn = readStdin) {
|
|
70
|
+
this.#configurationService = configurationService;
|
|
71
|
+
this.#readStdin = readStdinFn;
|
|
72
|
+
}
|
|
73
|
+
#validateCommand(command) {
|
|
74
|
+
const targets = this.#configurationService.getConfigTargets();
|
|
75
|
+
return targets.has(command)
|
|
76
|
+
? undefined
|
|
77
|
+
: `unknown or non-configurable command, valid commands: ${[...targets.keys()].join(", ")}`;
|
|
78
|
+
}
|
|
79
|
+
#targetOf(values) {
|
|
80
|
+
const command = values["command"];
|
|
81
|
+
return typeof command === "string"
|
|
82
|
+
? this.#configurationService.getConfigTargets().get(command)
|
|
83
|
+
: undefined;
|
|
84
|
+
}
|
|
85
|
+
#withValidOptions(target, message) {
|
|
86
|
+
return `${message}, valid options: ${target.options.map((o) => o.name).join(", ")}`;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Validate and convert a raw value and apply it to a copy of the stored defaults (running the
|
|
90
|
+
* target's custom validators).
|
|
91
|
+
*/
|
|
92
|
+
#prepare(target, option, raw) {
|
|
93
|
+
const deferred = [];
|
|
94
|
+
if (target.argument !== undefined) {
|
|
95
|
+
if (option !== undefined) {
|
|
96
|
+
return `command '${target.key}' has no options: omit --option`;
|
|
97
|
+
}
|
|
98
|
+
return prepareGlobalValue(target, raw, deferred);
|
|
99
|
+
}
|
|
100
|
+
if (option === undefined) {
|
|
101
|
+
return "--option is required with --value";
|
|
102
|
+
}
|
|
103
|
+
const change = prepareChange(target, option, raw, deferred);
|
|
104
|
+
if (typeof change === "string") {
|
|
105
|
+
return change;
|
|
106
|
+
}
|
|
107
|
+
const applied = applyChanges(target, this.#configurationService.defaultsData.get(target.key), [change], deferred);
|
|
108
|
+
return typeof applied === "string" ? applied : { change, isSecret: change.isSecret };
|
|
109
|
+
}
|
|
110
|
+
async #promptFor(context, args, missing) {
|
|
111
|
+
if (context.doesServiceExist(ARGUMENT_PROMPTER_SERVICE_ID)) {
|
|
112
|
+
const prompter = context.getServiceById(ARGUMENT_PROMPTER_SERVICE_ID);
|
|
113
|
+
const values = await prompter.promptForArguments(args);
|
|
114
|
+
if (values !== undefined) {
|
|
115
|
+
return values;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
throw new Error(`${missing} (prompting is not available)`);
|
|
119
|
+
}
|
|
120
|
+
async execute(context, argumentValues) {
|
|
121
|
+
const printer = context.getServiceById(PRINTER_SERVICE_ID);
|
|
122
|
+
const targets = this.#configurationService.getConfigTargets();
|
|
123
|
+
const commandNames = [...targets.keys()];
|
|
124
|
+
let commandKey = argumentValues["command"];
|
|
125
|
+
if (commandKey === undefined) {
|
|
126
|
+
const prompted = await this.#promptFor(context, [
|
|
127
|
+
{
|
|
128
|
+
name: "command",
|
|
129
|
+
description: "Command to configure",
|
|
130
|
+
type: ValueTypeName.STRING,
|
|
131
|
+
allowableValues: commandNames,
|
|
132
|
+
},
|
|
133
|
+
], `--command is required, valid commands: ${commandNames.join(", ")}`);
|
|
134
|
+
commandKey = prompted["command"];
|
|
135
|
+
}
|
|
136
|
+
const target = targets.get(commandKey);
|
|
137
|
+
if (target === undefined) {
|
|
138
|
+
throw new Error(`Unknown or non-configurable command '${commandKey}'`);
|
|
139
|
+
}
|
|
140
|
+
const optionPath = argumentValues["option"];
|
|
141
|
+
let raw = argumentValues["value"];
|
|
142
|
+
if (argumentValues["value-stdin"] === true) {
|
|
143
|
+
if (context.isTty.stdin) {
|
|
144
|
+
throw new Error("--value-stdin requires the value to be piped to stdin, or use the prompt");
|
|
145
|
+
}
|
|
146
|
+
raw = (await this.#readStdin()).replace(/\r?\n$/, "");
|
|
147
|
+
if (raw === "") {
|
|
148
|
+
throw new Error("No value was provided on stdin");
|
|
149
|
+
}
|
|
150
|
+
if (target.argument === undefined && optionPath === undefined) {
|
|
151
|
+
throw new Error("--option is required with --value-stdin");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const deferred = [];
|
|
155
|
+
const changes = [];
|
|
156
|
+
let globalValue;
|
|
157
|
+
let globalIsSecret = false;
|
|
158
|
+
if (target.argument !== undefined) {
|
|
159
|
+
if (optionPath !== undefined) {
|
|
160
|
+
throw new Error(`Command '${target.key}' has no options: omit --option`);
|
|
161
|
+
}
|
|
162
|
+
if (raw === undefined) {
|
|
163
|
+
const prompted = await this.#promptFor(context, [
|
|
164
|
+
{
|
|
165
|
+
description: `Value for ${target.key}`,
|
|
166
|
+
...target.argument,
|
|
167
|
+
name: "value",
|
|
168
|
+
isOptional: false,
|
|
169
|
+
},
|
|
170
|
+
], "--value is required");
|
|
171
|
+
globalValue = prompted["value"];
|
|
172
|
+
globalIsSecret = target.argument.type === ValueTypeName.SECRET;
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
const result = prepareGlobalValue(target, raw, deferred);
|
|
176
|
+
if (typeof result === "string") {
|
|
177
|
+
throw new Error(result);
|
|
178
|
+
}
|
|
179
|
+
globalValue = result.value;
|
|
180
|
+
globalIsSecret = result.isSecret;
|
|
181
|
+
await this.#warnIfSecretArgument(context, printer, globalIsSecret, argumentValues);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else if (optionPath === undefined && raw !== undefined) {
|
|
185
|
+
throw new Error("--option is required with --value");
|
|
186
|
+
}
|
|
187
|
+
else if (optionPath === undefined) {
|
|
188
|
+
const mandatory = target.options.filter((o) => o.isOptional !== true && o.defaultValue === undefined);
|
|
189
|
+
if (mandatory.length > 0) {
|
|
190
|
+
const prompted = await this.#promptFor(context, mandatory, `--value is required, mandatory options: ${mandatory.map((o) => o.name).join(", ")}`);
|
|
191
|
+
for (const option of mandatory) {
|
|
192
|
+
changes.push(this.#promptedChange(option, prompted[option.name]));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
const names = target.options.map((o) => o.name);
|
|
197
|
+
const selected = await this.#promptFor(context, [
|
|
198
|
+
{
|
|
199
|
+
name: "option",
|
|
200
|
+
description: "Option to set",
|
|
201
|
+
type: ValueTypeName.STRING,
|
|
202
|
+
allowableValues: names,
|
|
203
|
+
},
|
|
204
|
+
], `--option is required, valid options: ${names.join(", ")}`);
|
|
205
|
+
const option = target.options.find((o) => o.name === selected["option"]);
|
|
206
|
+
const prompted = await this.#promptFor(context, [{ ...option, isOptional: false }], "--value is required");
|
|
207
|
+
changes.push(this.#promptedChange(option, prompted[option.name]));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
const resolved = resolveOptionPath(target, optionPath);
|
|
212
|
+
if (typeof resolved === "string") {
|
|
213
|
+
throw new Error(this.#withValidOptions(target, resolved));
|
|
214
|
+
}
|
|
215
|
+
if (raw === undefined) {
|
|
216
|
+
const { leaf, steps } = resolved;
|
|
217
|
+
const hasIndex = steps[steps.length - 1].index !== undefined;
|
|
218
|
+
const prompted = await this.#promptFor(context, [{ ...leaf, isArray: hasIndex ? false : leaf.isArray, isOptional: false }], "--value is required");
|
|
219
|
+
changes.push({
|
|
220
|
+
...this.#promptedChange(leaf, prompted[leaf.name]),
|
|
221
|
+
steps,
|
|
222
|
+
path: optionPath,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
const change = prepareChange(target, optionPath, raw, deferred);
|
|
227
|
+
if (typeof change === "string") {
|
|
228
|
+
throw new Error(change);
|
|
229
|
+
}
|
|
230
|
+
changes.push(change);
|
|
231
|
+
await this.#warnIfSecretArgument(context, printer, change.isSecret, argumentValues);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const existing = this.#configurationService.defaultsData.get(target.key);
|
|
235
|
+
if (target.argument === undefined) {
|
|
236
|
+
const applied = applyChanges(target, existing, changes, deferred);
|
|
237
|
+
if (typeof applied === "string") {
|
|
238
|
+
throw new Error(applied);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const secretChanges = changes.filter((c) => c.isSecret);
|
|
242
|
+
const secrets = target.argument !== undefined
|
|
243
|
+
? globalIsSecret
|
|
244
|
+
? [{ key: [target.key], value: globalValue }]
|
|
245
|
+
: []
|
|
246
|
+
: secretChanges.map((c) => ({ key: [target.key, c.path], value: c.value }));
|
|
247
|
+
await this.#configurationService.commitDefault(target.key, secrets, (sentinels) => {
|
|
248
|
+
if (target.argument !== undefined) {
|
|
249
|
+
return globalIsSecret ? sentinels[0] : globalValue;
|
|
250
|
+
}
|
|
251
|
+
const values = structuredClone(existing ?? {});
|
|
252
|
+
for (const change of changes) {
|
|
253
|
+
const secretIndex = secretChanges.indexOf(change);
|
|
254
|
+
setAtPath(values, change.steps, secretIndex >= 0 ? sentinels[secretIndex] : change.value);
|
|
255
|
+
}
|
|
256
|
+
return values;
|
|
257
|
+
});
|
|
258
|
+
for (const change of target.argument !== undefined ? [] : changes) {
|
|
259
|
+
await printer.info(`Set default ${target.key}.${change.path}\n`);
|
|
260
|
+
if (isOverriddenByEnvVar(this.#configurationService, context.cliConfig, target, change.steps)) {
|
|
261
|
+
await printer.warn(`An environment variable overrides the default for ${target.key}.${change.path}\n`, Icon.ALERT);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (target.argument !== undefined) {
|
|
265
|
+
await printer.info(`Set default ${target.key}\n`);
|
|
266
|
+
if (isOverriddenByEnvVar(this.#configurationService, context.cliConfig, target, [])) {
|
|
267
|
+
await printer.warn(`An environment variable overrides the default for ${target.key}\n`, Icon.ALERT);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
#promptedChange(option, value) {
|
|
272
|
+
if (containsSecret(option) && (isComplexOption(option) || option.isArray === true)) {
|
|
273
|
+
throw new Error(`Option '${option.name}' contains SECRET values: set each secret property individually using --option`);
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
steps: [{ name: option.name }],
|
|
277
|
+
path: option.name,
|
|
278
|
+
leaf: option,
|
|
279
|
+
value,
|
|
280
|
+
isSecret: !isComplexOption(option) && option.type === ValueTypeName.SECRET,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
async #warnIfSecretArgument(context, printer, isSecret, argumentValues) {
|
|
284
|
+
if (isSecret && argumentValues["value-stdin"] !== true && context.isTty.stdin) {
|
|
285
|
+
await printer.warn("SECRET value passed as a plain argument. This is not recommended as it may be exposed via shell history " +
|
|
286
|
+
"and process listings (and in debug logs). Use the prompt or --value-stdin instead.\n\n", Icon.ALERT);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Context, type Option, type Positional, type SubCommand, type Values } from "@flowscripter/dynamic-cli-framework-api";
|
|
2
|
+
import type DefaultConfigurationService from "../DefaultConfigurationService.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Member of the `config` group which removes a stored default value (and any OS secret it refers to).
|
|
5
|
+
*/
|
|
6
|
+
export default class ConfigUnsetSubCommand implements SubCommand {
|
|
7
|
+
#private;
|
|
8
|
+
readonly name = "unset";
|
|
9
|
+
readonly description = "Remove a default value for an option of a command";
|
|
10
|
+
readonly options: ReadonlyArray<Option>;
|
|
11
|
+
readonly positionals: ReadonlyArray<Positional>;
|
|
12
|
+
constructor(configurationService: DefaultConfigurationService);
|
|
13
|
+
execute(context: Context, argumentValues: Values): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=ConfigUnsetSubCommand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfigUnsetSubCommand.d.ts","sourceRoot":"","sources":["../../../../../src/service/configuration/command/ConfigUnsetSubCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,OAAO,EACZ,KAAK,MAAM,EACX,KAAK,UAAU,EAEf,KAAK,UAAU,EACf,KAAK,MAAM,EACZ,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,2BAA2B,MAAM,mCAAmC,CAAC;AAKjF;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,qBAAsB,YAAW,UAAU;;IAC9D,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,WAAW,uDAAuD;IAC3E,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAuCrC;IACF,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,UAAU,CAAC,CAAM;IAIrD,YAAmB,oBAAoB,EAAE,2BAA2B,EAEnE;IAEK,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDrE;CACF"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { ARGUMENT_PROMPTER_SERVICE_ID, PRINTER_SERVICE_ID, ValueTypeName, } from "@flowscripter/dynamic-cli-framework-api";
|
|
2
|
+
import { removeAtPath, resolveOptionPath } from "../configTargets.js";
|
|
3
|
+
/**
|
|
4
|
+
* Member of the `config` group which removes a stored default value (and any OS secret it refers to).
|
|
5
|
+
*/
|
|
6
|
+
export default class ConfigUnsetSubCommand {
|
|
7
|
+
name = "unset";
|
|
8
|
+
description = "Remove a default value for an option of a command";
|
|
9
|
+
options = [
|
|
10
|
+
{
|
|
11
|
+
name: "command",
|
|
12
|
+
type: ValueTypeName.STRING,
|
|
13
|
+
description: "The command (or <group>:<member>) to remove defaults from",
|
|
14
|
+
isOptional: true,
|
|
15
|
+
validate: (value) => {
|
|
16
|
+
const targets = this.#configurationService.getConfigTargets();
|
|
17
|
+
return targets.has(value) ||
|
|
18
|
+
this.#configurationService.defaultsData.has(value)
|
|
19
|
+
? undefined
|
|
20
|
+
: `unknown command, valid commands: ${[...targets.keys()].join(", ")}`;
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "option",
|
|
25
|
+
type: ValueTypeName.STRING,
|
|
26
|
+
description: "The option (or option path) to remove. Omit to remove all defaults of the command.",
|
|
27
|
+
isOptional: true,
|
|
28
|
+
validate: (value, ctx) => {
|
|
29
|
+
const target = this.#configurationService
|
|
30
|
+
.getConfigTargets()
|
|
31
|
+
.get(ctx.values["command"]);
|
|
32
|
+
if (target === undefined) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
if (target.argument !== undefined) {
|
|
36
|
+
return `command '${target.key}' has no options: omit --option`;
|
|
37
|
+
}
|
|
38
|
+
const resolved = resolveOptionPath(target, value);
|
|
39
|
+
if (typeof resolved === "string") {
|
|
40
|
+
return `${resolved}, valid options: ${target.options.map((o) => o.name).join(", ")}`;
|
|
41
|
+
}
|
|
42
|
+
return resolved.steps[resolved.steps.length - 1].index !== undefined
|
|
43
|
+
? "unsetting an array element is not supported: unset the whole option instead"
|
|
44
|
+
: undefined;
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
positionals = [];
|
|
49
|
+
#configurationService;
|
|
50
|
+
constructor(configurationService) {
|
|
51
|
+
this.#configurationService = configurationService;
|
|
52
|
+
}
|
|
53
|
+
async execute(context, argumentValues) {
|
|
54
|
+
const printer = context.getServiceById(PRINTER_SERVICE_ID);
|
|
55
|
+
const targets = this.#configurationService.getConfigTargets();
|
|
56
|
+
let commandKey = argumentValues["command"];
|
|
57
|
+
if (commandKey === undefined) {
|
|
58
|
+
const names = [...this.#configurationService.defaultsData.keys()];
|
|
59
|
+
const prompter = context.doesServiceExist(ARGUMENT_PROMPTER_SERVICE_ID)
|
|
60
|
+
? context.getServiceById(ARGUMENT_PROMPTER_SERVICE_ID)
|
|
61
|
+
: undefined;
|
|
62
|
+
const prompted = names.length > 0
|
|
63
|
+
? await prompter?.promptForArguments([
|
|
64
|
+
{
|
|
65
|
+
name: "command",
|
|
66
|
+
description: "Command to remove defaults from",
|
|
67
|
+
type: ValueTypeName.STRING,
|
|
68
|
+
allowableValues: names,
|
|
69
|
+
},
|
|
70
|
+
])
|
|
71
|
+
: undefined;
|
|
72
|
+
if (prompted === undefined) {
|
|
73
|
+
throw new Error(`--command is required, commands with defaults: ${names.join(", ")}`);
|
|
74
|
+
}
|
|
75
|
+
commandKey = prompted["command"];
|
|
76
|
+
}
|
|
77
|
+
const existing = this.#configurationService.defaultsData.get(commandKey);
|
|
78
|
+
const optionPath = argumentValues["option"];
|
|
79
|
+
const target = targets.get(commandKey);
|
|
80
|
+
if (optionPath !== undefined && target === undefined) {
|
|
81
|
+
throw new Error(`Unknown or non-configurable command '${commandKey}'`);
|
|
82
|
+
}
|
|
83
|
+
let next;
|
|
84
|
+
let removed = existing !== undefined;
|
|
85
|
+
if (optionPath !== undefined && existing !== undefined) {
|
|
86
|
+
const resolved = resolveOptionPath(target, optionPath);
|
|
87
|
+
if (typeof resolved === "string") {
|
|
88
|
+
throw new Error(resolved);
|
|
89
|
+
}
|
|
90
|
+
const values = structuredClone(existing);
|
|
91
|
+
removed = removeAtPath(values, resolved.steps);
|
|
92
|
+
next = Object.keys(values).length > 0 ? values : undefined;
|
|
93
|
+
}
|
|
94
|
+
if (!removed) {
|
|
95
|
+
await printer.info(`Nothing to unset for ${commandKey}${optionPath ? `.${optionPath}` : ""}\n`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
await this.#configurationService.commitDefault(commandKey, [], () => next);
|
|
99
|
+
await printer.info(`Removed default ${commandKey}${optionPath ? `.${optionPath}` : ""}\n`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { type Command, type ComplexOption, type GlobalCommandArgument, type GroupCommand, type Option, type CommandRegistry, type CLIConfig, type SingleValueType, type Values, type ValueNode } from "@flowscripter/dynamic-cli-framework-api";
|
|
2
|
+
import { type DeferredCustomValidation } from "../../runtime/values/argumentValueValidation.ts";
|
|
3
|
+
export declare const MASK = "********";
|
|
4
|
+
type Node = unknown;
|
|
5
|
+
/**
|
|
6
|
+
* A command whose default argument values can be managed via the `config` group commands.
|
|
7
|
+
*/
|
|
8
|
+
export interface ConfigTarget {
|
|
9
|
+
/** The key under `defaults`: the command name or `<group name>:<member name>`. */
|
|
10
|
+
readonly key: string;
|
|
11
|
+
readonly command: Command;
|
|
12
|
+
readonly group?: GroupCommand;
|
|
13
|
+
/** Set for global commands and global modifier commands. */
|
|
14
|
+
readonly argument?: GlobalCommandArgument;
|
|
15
|
+
/** Empty for global commands. */
|
|
16
|
+
readonly options: ReadonlyArray<Option | ComplexOption>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Collect all commands in the registry with `enableConfiguration` set, except the `config` modifier.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getConfigTargets(registry: CommandRegistry): Map<string, ConfigTarget>;
|
|
22
|
+
export interface PathStep {
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly index?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Parse an option path such as `address[1].port` into steps.
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseOptionPath(path: string): Array<PathStep> | string;
|
|
30
|
+
export interface ResolvedPath {
|
|
31
|
+
readonly steps: Array<PathStep>;
|
|
32
|
+
readonly leaf: Option | ComplexOption;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Walk the steps through the target's options returning the option the path refers to.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveOptionPath(target: ConfigTarget, path: string): ResolvedPath | string;
|
|
38
|
+
export declare function containsSecret(option: Option | ComplexOption): boolean;
|
|
39
|
+
export declare function getAtPath(root: Node, steps: ReadonlyArray<PathStep>): Node;
|
|
40
|
+
/**
|
|
41
|
+
* Set a value at the path in the provided (mutable) root creating parents as needed.
|
|
42
|
+
*/
|
|
43
|
+
export declare function setAtPath(root: Record<string, Node>, steps: ReadonlyArray<PathStep>, value: Node): void;
|
|
44
|
+
/**
|
|
45
|
+
* Remove the value at the path and any parent objects left empty. Returns false if there was no value.
|
|
46
|
+
*/
|
|
47
|
+
export declare function removeAtPath(root: Record<string, Node>, steps: ReadonlyArray<PathStep>): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* All `__SECRET__:` sentinel strings within the value.
|
|
50
|
+
*/
|
|
51
|
+
export declare function collectSentinels(value: Node): Array<string>;
|
|
52
|
+
/**
|
|
53
|
+
* A validated, converted change to a single option of a target.
|
|
54
|
+
*/
|
|
55
|
+
export interface ConfigChange {
|
|
56
|
+
readonly steps: ReadonlyArray<PathStep>;
|
|
57
|
+
readonly path: string;
|
|
58
|
+
readonly leaf: Option | ComplexOption;
|
|
59
|
+
/** Native value, or the plain text of a SECRET which must be stored via the secret service. */
|
|
60
|
+
readonly value: Node;
|
|
61
|
+
readonly isSecret: boolean;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Validate and convert the raw (string) value for the option path of the target. Required checks are
|
|
65
|
+
* not applied. Custom validators of the target are run later by {@link validateChanges}.
|
|
66
|
+
*/
|
|
67
|
+
export declare function prepareChange(target: ConfigTarget, path: string, raw: string, deferred: Array<DeferredCustomValidation>): ConfigChange | string;
|
|
68
|
+
/**
|
|
69
|
+
* Validate a raw value for a global command argument.
|
|
70
|
+
*/
|
|
71
|
+
export declare function prepareGlobalValue(target: ConfigTarget, raw: string, deferred: Array<DeferredCustomValidation>): {
|
|
72
|
+
value: SingleValueType;
|
|
73
|
+
isSecret: boolean;
|
|
74
|
+
} | string;
|
|
75
|
+
/**
|
|
76
|
+
* Apply the changes to a copy of the existing values and run the custom validators of the target.
|
|
77
|
+
* Returns the new values or an error message.
|
|
78
|
+
*/
|
|
79
|
+
export declare function applyChanges(target: ConfigTarget, existing: Values | undefined, changes: ReadonlyArray<ConfigChange>, deferred: Array<DeferredCustomValidation>): Values | string;
|
|
80
|
+
/**
|
|
81
|
+
* Copy of a stored default value with SECRET typed values and any secret sentinels masked.
|
|
82
|
+
*/
|
|
83
|
+
export declare function maskDefault(target: ConfigTarget | undefined, value: Node): Node;
|
|
84
|
+
export type { ValueNode };
|
|
85
|
+
/**
|
|
86
|
+
* Whether an environment variable would override the stored value at the path.
|
|
87
|
+
*/
|
|
88
|
+
export declare function isOverriddenByEnvVar(provider: {
|
|
89
|
+
readonly envVarsEnabled: boolean;
|
|
90
|
+
}, cliConfig: CLIConfig, target: ConfigTarget, steps: ReadonlyArray<PathStep>): boolean;
|
|
91
|
+
//# sourceMappingURL=configTargets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configTargets.d.ts","sourceRoot":"","sources":["../../../../src/service/configuration/configTargets.ts"],"names":[],"mappings":"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"}
|