expensify-common 2.0.187 → 2.0.189
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/CLI.d.ts +160 -0
- package/dist/CLI.js +282 -0
- package/dist/esm/API.d.ts +11 -0
- package/dist/esm/API.js +786 -0
- package/dist/esm/APIDeferred.d.ts +7 -0
- package/dist/esm/APIDeferred.js +216 -0
- package/dist/esm/BrowserDetect.d.ts +19 -0
- package/dist/esm/BrowserDetect.js +105 -0
- package/dist/esm/CLI.d.ts +160 -0
- package/dist/esm/CLI.js +244 -0
- package/dist/esm/CONST.d.ts +1727 -0
- package/dist/esm/CONST.js +1847 -0
- package/dist/esm/Cookie.d.ts +68 -0
- package/dist/esm/Cookie.js +159 -0
- package/dist/esm/CredentialsWrapper.d.ts +32 -0
- package/dist/esm/CredentialsWrapper.js +46 -0
- package/dist/esm/Device.d.ts +8 -0
- package/dist/esm/Device.js +24 -0
- package/dist/esm/ExpenseRule.d.ts +39 -0
- package/dist/esm/ExpenseRule.js +77 -0
- package/dist/esm/ExpensiMark.d.ts +197 -0
- package/dist/esm/ExpensiMark.js +1374 -0
- package/dist/esm/Func.d.ts +40 -0
- package/dist/esm/Func.js +69 -0
- package/dist/esm/Log.d.ts +3 -0
- package/dist/esm/Log.js +35 -0
- package/dist/esm/Logger.d.ts +82 -0
- package/dist/esm/Logger.js +138 -0
- package/dist/esm/Network.d.ts +6 -0
- package/dist/esm/Network.js +168 -0
- package/dist/esm/Num.d.ts +95 -0
- package/dist/esm/Num.js +190 -0
- package/dist/esm/PageEvent.d.ts +25 -0
- package/dist/esm/PageEvent.js +22 -0
- package/dist/esm/PubSub.d.ts +2 -0
- package/dist/esm/PubSub.js +111 -0
- package/dist/esm/ReportHistoryStore.d.ts +8 -0
- package/dist/esm/ReportHistoryStore.js +199 -0
- package/dist/esm/SafeString.d.ts +8 -0
- package/{lib/SafeString.ts → dist/esm/SafeString.js} +8 -13
- package/dist/esm/Templates.d.ts +58 -0
- package/dist/esm/Templates.js +196 -0
- package/dist/esm/Url.d.ts +10 -0
- package/dist/esm/Url.js +15 -0
- package/dist/esm/components/CopyText.d.ts +45 -0
- package/dist/esm/components/CopyText.js +56 -0
- package/dist/esm/components/StepProgressBar.d.ts +26 -0
- package/dist/esm/components/StepProgressBar.js +40 -0
- package/dist/esm/components/form/element/combobox.d.ts +231 -0
- package/dist/esm/components/form/element/combobox.js +812 -0
- package/dist/esm/components/form/element/dropdown.d.ts +35 -0
- package/dist/esm/components/form/element/dropdown.js +61 -0
- package/dist/esm/components/form/element/dropdownItem.d.ts +55 -0
- package/dist/esm/components/form/element/dropdownItem.js +113 -0
- package/dist/esm/components/form/element/onOffSwitch.d.ts +94 -0
- package/dist/esm/components/form/element/onOffSwitch.js +167 -0
- package/dist/esm/components/form/element/switch.d.ts +58 -0
- package/dist/esm/components/form/element/switch.js +98 -0
- package/dist/esm/fastMerge.d.ts +9 -0
- package/dist/esm/fastMerge.js +58 -0
- package/dist/esm/index.d.ts +22 -0
- package/dist/esm/index.js +22 -0
- package/dist/esm/jquery.expensifyIframify.d.ts +9 -0
- package/dist/esm/jquery.expensifyIframify.js +397 -0
- package/dist/esm/md5.d.ts +2 -0
- package/dist/esm/md5.js +170 -0
- package/dist/esm/mixins/PubSub.d.ts +20 -0
- package/dist/esm/mixins/PubSub.js +47 -0
- package/dist/esm/mixins/extraClasses.d.ts +8 -0
- package/dist/esm/mixins/extraClasses.js +37 -0
- package/dist/esm/mixins/validationClasses.d.ts +12 -0
- package/dist/esm/mixins/validationClasses.js +30 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/str.d.ts +604 -0
- package/dist/esm/str.js +1036 -0
- package/dist/esm/tlds.d.ts +2 -0
- package/dist/esm/tlds.js +2 -0
- package/dist/esm/utils.d.ts +30 -0
- package/dist/esm/utils.js +65 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -1
- package/package.json +228 -8
- package/lib/CLI.ts +0 -409
package/lib/CLI.ts
DELETED
|
@@ -1,409 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file contains a CLI utility class which can be used to declaratively implement a strongly-typed CLI.
|
|
3
|
-
* You provide a CLIConfig defining your arguments, then the class will handle parsing argv, type validation, error handling, and help messages.
|
|
4
|
-
*/
|
|
5
|
-
import * as readline from 'readline';
|
|
6
|
-
import type {NonEmptyObject, NonEmptyTuple, ValueOf, Writable} from 'type-fest';
|
|
7
|
-
import SafeString from './SafeString';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* A base CLI arg has only a description, which we will use in the help/usage message (built-in to any CLI).
|
|
11
|
-
*/
|
|
12
|
-
type CLIArg = {
|
|
13
|
-
description: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* A boolean arg is characterized only by its presence or absence so has no other fields,
|
|
18
|
-
* but we'll create a type alias to clearly distinguish it from other argument types.
|
|
19
|
-
*/
|
|
20
|
-
type BooleanArg = CLIArg;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Any other argument is provided raw in process.argv as a string.
|
|
24
|
-
* It can remain a string, or can be transformed into another type by a custom `parse` function.
|
|
25
|
-
* It can be optional (by providing a default) or required (no default value).
|
|
26
|
-
* It can also supersede other named arguments when provided.
|
|
27
|
-
*/
|
|
28
|
-
type StringArg<T = unknown> = CLIArg & {
|
|
29
|
-
default?: T;
|
|
30
|
-
parse?: (val: string) => T;
|
|
31
|
-
supersedes?: string[];
|
|
32
|
-
required?: boolean;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* A positional argument is just a string arg, but also must be assigned a name which we will eventually expose the CLI consumer.
|
|
37
|
-
* If `variadic` is true, this must be the last positional arg and it collects all remaining positional args into a string[].
|
|
38
|
-
*/
|
|
39
|
-
type PositionalArg<T = unknown> = StringArg<T> & {
|
|
40
|
-
name: string;
|
|
41
|
-
variadic?: true;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* This type represents the config for a CLI.
|
|
46
|
-
* The last positional arg can be marked `variadic: true` to collect all remaining positional args into a string[].
|
|
47
|
-
*/
|
|
48
|
-
type CLIConfig = NonEmptyObject<{
|
|
49
|
-
/**
|
|
50
|
-
* Record of named flags that are fully characterized by their presence or absence (present=true,absent=false).
|
|
51
|
-
* @example `--verbose`
|
|
52
|
-
*/
|
|
53
|
-
flags?: Record<string, BooleanArg>;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Record of named arguments that are represented by a key and a value.
|
|
57
|
-
* @example `--threads=8`
|
|
58
|
-
* @example `--name Rory`
|
|
59
|
-
*/
|
|
60
|
-
namedArgs?: Record<string, StringArg>;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Tuple of positional args.
|
|
64
|
-
* @example `myScript.ts arg1 arg2 arg3`
|
|
65
|
-
*/
|
|
66
|
-
positionalArgs?: NonEmptyTuple<PositionalArg>;
|
|
67
|
-
}>;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Record of flags to boolean after parsing.
|
|
71
|
-
*/
|
|
72
|
-
type ParsedFlags<Flags extends CLIConfig['flags']> = {
|
|
73
|
-
[K in keyof NonNullable<Flags>]: boolean;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Utility type to infer the final value of a string param. Either:
|
|
78
|
-
* - it's a plain string, or
|
|
79
|
-
* - it has a parse function and the final value is inferred from the return type of that function
|
|
80
|
-
*/
|
|
81
|
-
type InferStringArgParsedValue<T extends StringArg> = T extends {
|
|
82
|
-
parse: (val: string) => infer R;
|
|
83
|
-
}
|
|
84
|
-
? R
|
|
85
|
-
: string;
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Record of named args after parsing.
|
|
89
|
-
*/
|
|
90
|
-
type ParsedNamedArgs<NamedArgs extends CLIConfig['namedArgs']> = {
|
|
91
|
-
[K in keyof NonNullable<NamedArgs>]: InferStringArgParsedValue<NonNullable<NamedArgs>[K]>;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Record of positional args after parsing.
|
|
96
|
-
* Variadic args are parsed as string[]; all others use InferStringArgParsedValue.
|
|
97
|
-
*/
|
|
98
|
-
type ParsedPositionalArgs<PositionalArgs extends CLIConfig['positionalArgs']> = {
|
|
99
|
-
[K in NonNullable<PositionalArgs>[number] as K['name']]: K extends {
|
|
100
|
-
variadic: true;
|
|
101
|
-
}
|
|
102
|
-
? string[]
|
|
103
|
-
: InferStringArgParsedValue<K>;
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Utility to parse command-line arguments to a script.
|
|
108
|
-
*
|
|
109
|
-
* @example
|
|
110
|
-
* ```
|
|
111
|
-
* const cli = new CLI({
|
|
112
|
-
* flags: {
|
|
113
|
-
* verbose: {
|
|
114
|
-
* description: 'Enable verbose logging',
|
|
115
|
-
* },
|
|
116
|
-
* },
|
|
117
|
-
* namedArgs: {
|
|
118
|
-
* time: {
|
|
119
|
-
* description: 'Time of day to greet (morning or evening)',
|
|
120
|
-
* default: 'morning',
|
|
121
|
-
* parse: (val) => {
|
|
122
|
-
* if (val !== 'morning' && val !== 'evening') {
|
|
123
|
-
* throw new Error('Must be "morning" or "evening"');
|
|
124
|
-
* }
|
|
125
|
-
* return val as 'morning' | 'evening';
|
|
126
|
-
* },
|
|
127
|
-
* },
|
|
128
|
-
* },
|
|
129
|
-
* positionalArgs: [
|
|
130
|
-
* {
|
|
131
|
-
* name: 'firstName'
|
|
132
|
-
* description: 'First name to greet',
|
|
133
|
-
* },
|
|
134
|
-
* {
|
|
135
|
-
* name: 'lastName',
|
|
136
|
-
* description: 'Last name to greet',
|
|
137
|
-
* default: '',
|
|
138
|
-
* },
|
|
139
|
-
* ],
|
|
140
|
-
* });
|
|
141
|
-
*
|
|
142
|
-
* let fullName = cli.positionalArgs.firstName;
|
|
143
|
-
* if (cli.flags.verbose) {
|
|
144
|
-
* fullName += cli.positionalArgs.lastName;
|
|
145
|
-
* }
|
|
146
|
-
* console.log(fullName);
|
|
147
|
-
* console.log(cli.namedArgs.time);
|
|
148
|
-
* ```
|
|
149
|
-
*/
|
|
150
|
-
/**
|
|
151
|
-
* Built-in flags that are always available on any CLI.
|
|
152
|
-
*/
|
|
153
|
-
type BuiltInFlags = {
|
|
154
|
-
yes: boolean;
|
|
155
|
-
no: boolean;
|
|
156
|
-
help: boolean;
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
class CLI<TConfig extends CLIConfig> {
|
|
160
|
-
/**
|
|
161
|
-
* Flags after parsing (includes built-in flags like --yes, --no, and --help).
|
|
162
|
-
*/
|
|
163
|
-
public readonly flags: ParsedFlags<TConfig['flags']> & BuiltInFlags;
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Named args after parsing.
|
|
167
|
-
*/
|
|
168
|
-
public readonly namedArgs: ParsedNamedArgs<TConfig['namedArgs']>;
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Positional args after parsing, collected into a record keyed by the name of each arg.
|
|
172
|
-
*/
|
|
173
|
-
public readonly positionalArgs: ParsedPositionalArgs<TConfig['positionalArgs']>;
|
|
174
|
-
|
|
175
|
-
constructor(private readonly config: TConfig) {
|
|
176
|
-
const rawArgs = process.argv.slice(2);
|
|
177
|
-
|
|
178
|
-
// Initialize all flags to false by default (including built-in flags)
|
|
179
|
-
this.flags = {
|
|
180
|
-
...Object.fromEntries(Object.keys(config.flags ?? {}).map((key) => [key, false])),
|
|
181
|
-
yes: false,
|
|
182
|
-
no: false,
|
|
183
|
-
help: false,
|
|
184
|
-
} as typeof this.flags;
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
const parsedNamedArgs: Partial<Writable<typeof this.namedArgs>> = {};
|
|
188
|
-
const parsedPositionalArgs: Partial<Writable<typeof this.positionalArgs>> = {};
|
|
189
|
-
const providedNamedArgs = new Set<string>();
|
|
190
|
-
|
|
191
|
-
let positionalIndex = 0;
|
|
192
|
-
for (let i = 0; i < rawArgs.length; i++) {
|
|
193
|
-
const rawArg = rawArgs.at(i);
|
|
194
|
-
if (rawArg === undefined) {
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (rawArg.startsWith('--')) {
|
|
199
|
-
// Either a flag or a named param
|
|
200
|
-
const [rawArgName, rawArgValue] = rawArg.slice(2).split('=');
|
|
201
|
-
if (rawArgName in this.flags) {
|
|
202
|
-
// Arg is a flag
|
|
203
|
-
(this.flags as Record<string, boolean>)[rawArgName] = true;
|
|
204
|
-
} else if (config.namedArgs && rawArgName in config.namedArgs) {
|
|
205
|
-
// Arg is a named arg
|
|
206
|
-
providedNamedArgs.add(rawArgName);
|
|
207
|
-
|
|
208
|
-
// Grab the value from the split token, otherwise go for the next token
|
|
209
|
-
let argValueBeforeParse = '';
|
|
210
|
-
if (rawArgValue) {
|
|
211
|
-
argValueBeforeParse = rawArgValue;
|
|
212
|
-
} else {
|
|
213
|
-
argValueBeforeParse = rawArgs.at(++i) ?? '';
|
|
214
|
-
if (!argValueBeforeParse || argValueBeforeParse.startsWith('--')) {
|
|
215
|
-
throw new Error(`Missing value for --${rawArgName}`);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const spec = config.namedArgs[rawArgName];
|
|
220
|
-
parsedNamedArgs[rawArgName as keyof typeof parsedNamedArgs] = CLI.parseStringArg(argValueBeforeParse, rawArgName, spec) as ValueOf<typeof parsedNamedArgs>;
|
|
221
|
-
} else {
|
|
222
|
-
console.error(`Unknown flag: --${rawArgName}`);
|
|
223
|
-
process.exit(1);
|
|
224
|
-
}
|
|
225
|
-
} else {
|
|
226
|
-
// Arg is a positional arg
|
|
227
|
-
const spec = config.positionalArgs?.at(positionalIndex);
|
|
228
|
-
if (spec === undefined) {
|
|
229
|
-
throw new Error(`Unexpected arg: ${rawArg}`);
|
|
230
|
-
}
|
|
231
|
-
if (spec.variadic) {
|
|
232
|
-
// Variadic: collect this and all remaining non-flag args into an array
|
|
233
|
-
const collected: string[] = [];
|
|
234
|
-
for (let j = i; j < rawArgs.length; j++) {
|
|
235
|
-
const remaining = rawArgs.at(j);
|
|
236
|
-
if (remaining === undefined || remaining.startsWith('--')) {
|
|
237
|
-
break;
|
|
238
|
-
}
|
|
239
|
-
collected.push(remaining);
|
|
240
|
-
}
|
|
241
|
-
parsedPositionalArgs[spec.name as keyof typeof parsedPositionalArgs] = collected as ValueOf<typeof parsedPositionalArgs>;
|
|
242
|
-
break;
|
|
243
|
-
}
|
|
244
|
-
parsedPositionalArgs[spec.name as keyof typeof parsedPositionalArgs] = CLI.parseStringArg(rawArg, spec.name, spec) as ValueOf<typeof parsedPositionalArgs>;
|
|
245
|
-
positionalIndex++;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Handle help command
|
|
250
|
-
if (this.flags.help) {
|
|
251
|
-
this.printHelp();
|
|
252
|
-
process.exit(0);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Handle supersession logic
|
|
256
|
-
const supersededArgs = new Set<string>();
|
|
257
|
-
for (const [name, spec] of Object.entries(config.namedArgs ?? {})) {
|
|
258
|
-
if (providedNamedArgs.has(name) && spec.supersedes) {
|
|
259
|
-
for (const supersededArg of spec.supersedes) {
|
|
260
|
-
supersededArgs.add(supersededArg);
|
|
261
|
-
if (providedNamedArgs.has(supersededArg)) {
|
|
262
|
-
console.warn(`⚠️ Warning: --${supersededArg} is superseded by --${name} and will be ignored.`);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// Validate that all required args are present, assign defaults where values are not parsed
|
|
269
|
-
for (const [name, spec] of Object.entries(config.namedArgs ?? {})) {
|
|
270
|
-
if (name in parsedNamedArgs) {
|
|
271
|
-
if (supersededArgs.has(name)) {
|
|
272
|
-
parsedNamedArgs[name as keyof typeof parsedNamedArgs] = undefined as ValueOf<typeof parsedNamedArgs>;
|
|
273
|
-
}
|
|
274
|
-
} else if (supersededArgs.has(name)) {
|
|
275
|
-
// This arg was superseded, so don't require it and don't assign a default
|
|
276
|
-
continue;
|
|
277
|
-
} else if (spec.default !== undefined) {
|
|
278
|
-
parsedNamedArgs[name as keyof typeof parsedNamedArgs] = spec.default as ValueOf<typeof parsedNamedArgs>;
|
|
279
|
-
} else if (spec.required === false) {
|
|
280
|
-
// Explicitly marked as optional, leave undefined
|
|
281
|
-
continue;
|
|
282
|
-
} else {
|
|
283
|
-
// Arguments without defaults are required by default (unless explicitly marked as optional)
|
|
284
|
-
throw new Error(`Missing required named argument --${name}`);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
for (const spec of config.positionalArgs ?? []) {
|
|
289
|
-
if (!(spec.name in parsedPositionalArgs)) {
|
|
290
|
-
if (spec.default !== undefined) {
|
|
291
|
-
parsedPositionalArgs[spec.name as keyof typeof parsedPositionalArgs] = spec.default as ValueOf<typeof parsedPositionalArgs>;
|
|
292
|
-
} else if (spec.variadic) {
|
|
293
|
-
parsedPositionalArgs[spec.name as keyof typeof parsedPositionalArgs] = [] as ValueOf<typeof parsedPositionalArgs>;
|
|
294
|
-
} else {
|
|
295
|
-
throw new Error(`Missing required positional argument --${spec.name}`);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
this.namedArgs = parsedNamedArgs as typeof this.namedArgs;
|
|
301
|
-
this.positionalArgs = parsedPositionalArgs as unknown as typeof this.positionalArgs;
|
|
302
|
-
} catch (err) {
|
|
303
|
-
// If help flag was set, the error is from process.exit(0) in tests (where it's mocked to throw) - just rethrow it
|
|
304
|
-
if (this.flags.help) {
|
|
305
|
-
throw err;
|
|
306
|
-
}
|
|
307
|
-
if (err instanceof Error) {
|
|
308
|
-
console.error(err.message);
|
|
309
|
-
this.printHelp();
|
|
310
|
-
} else {
|
|
311
|
-
console.error('An unexpected error occurred initializing the CLI.');
|
|
312
|
-
}
|
|
313
|
-
process.exit(1);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
private printHelp(): void {
|
|
318
|
-
const {flags = {}, namedArgs = {}, positionalArgs = []} = this.config;
|
|
319
|
-
const scriptName = process.argv.at(1) ?? 'script.ts';
|
|
320
|
-
const positionalUsage = positionalArgs
|
|
321
|
-
.map((arg) => {
|
|
322
|
-
const label = arg.variadic ? `${arg.name}...` : arg.name;
|
|
323
|
-
return arg.default === undefined ? `<${label}>` : `[${label}]`;
|
|
324
|
-
})
|
|
325
|
-
.join(' ');
|
|
326
|
-
const namedArgUsage = Object.keys(namedArgs)
|
|
327
|
-
.map((key) => `[--${key} <value>]`)
|
|
328
|
-
.join(' ');
|
|
329
|
-
const flagUsage = [...Object.keys(flags), '--yes', '--no', '--help'].map((key) => `[${key.startsWith('--') ? key : `--${key}`}]`).join(' ');
|
|
330
|
-
|
|
331
|
-
console.log(`\nUsage: npx ts-node ${scriptName} ${flagUsage} ${namedArgUsage} ${positionalUsage}\n`);
|
|
332
|
-
|
|
333
|
-
console.log('Flags:');
|
|
334
|
-
for (const [name, spec] of Object.entries(flags)) {
|
|
335
|
-
console.log(` --${name.padEnd(20)} ${spec.description}`);
|
|
336
|
-
}
|
|
337
|
-
// Built-in flags
|
|
338
|
-
console.log(` --${'yes'.padEnd(20)} Automatically answer "yes" to all confirmation prompts.`);
|
|
339
|
-
console.log(` --${'no'.padEnd(20)} Automatically answer "no" to all confirmation prompts.`);
|
|
340
|
-
console.log(` --${'help'.padEnd(20)} Show this help message.`);
|
|
341
|
-
console.log('');
|
|
342
|
-
|
|
343
|
-
if (Object.keys(namedArgs).length > 0) {
|
|
344
|
-
console.log('Named Arguments:');
|
|
345
|
-
for (const [name, spec] of Object.entries(namedArgs)) {
|
|
346
|
-
const defaultLabel = spec.default !== undefined ? ` (default: ${SafeString(spec.default)})` : '';
|
|
347
|
-
const supersededLabel = spec.supersedes && spec.supersedes.length > 0 ? ` (supersedes: ${spec.supersedes.join(', ')})` : '';
|
|
348
|
-
console.log(` --${name.padEnd(20)} ${spec.description}${defaultLabel}${supersededLabel}`);
|
|
349
|
-
}
|
|
350
|
-
console.log('');
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
if (positionalArgs.length > 0) {
|
|
354
|
-
console.log('Positional Arguments:');
|
|
355
|
-
for (const arg of positionalArgs) {
|
|
356
|
-
const defaultLabel = arg.default !== undefined ? ` (default: ${SafeString(arg.default)})` : '';
|
|
357
|
-
console.log(` ${arg.name.padEnd(22)} ${arg.description}${defaultLabel}`);
|
|
358
|
-
}
|
|
359
|
-
console.log('');
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
private static parseStringArg<T extends StringArg>(rawString: string, paramName: string, spec: T): InferStringArgParsedValue<T> {
|
|
364
|
-
if ('parse' in spec && !!spec.parse) {
|
|
365
|
-
try {
|
|
366
|
-
return spec.parse(rawString) as InferStringArgParsedValue<T>;
|
|
367
|
-
} catch (error) {
|
|
368
|
-
let errorMessage = '';
|
|
369
|
-
if (error instanceof Error) {
|
|
370
|
-
errorMessage = error.message;
|
|
371
|
-
}
|
|
372
|
-
console.error(`Invalid value for --${paramName}: ${errorMessage}`);
|
|
373
|
-
process.exit(1);
|
|
374
|
-
}
|
|
375
|
-
} else {
|
|
376
|
-
return rawString as InferStringArgParsedValue<T>;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Prompts the user for confirmation and returns true if they confirm (y/yes), false otherwise.
|
|
382
|
-
* If --yes flag was passed, returns true immediately without prompting.
|
|
383
|
-
* If --no flag was passed, returns false immediately without prompting.
|
|
384
|
-
*/
|
|
385
|
-
async promptUserConfirmation(message: string): Promise<boolean> {
|
|
386
|
-
// Check for built-in flags first
|
|
387
|
-
if (this.flags.yes) {
|
|
388
|
-
return true;
|
|
389
|
-
}
|
|
390
|
-
if (this.flags.no) {
|
|
391
|
-
return false;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
const rl = readline.createInterface({
|
|
395
|
-
input: process.stdin,
|
|
396
|
-
output: process.stdout,
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
return new Promise((resolve) => {
|
|
400
|
-
rl.question(message, (answer) => {
|
|
401
|
-
rl.close();
|
|
402
|
-
const normalizedAnswer = answer.trim().toLowerCase();
|
|
403
|
-
resolve(normalizedAnswer === 'y' || normalizedAnswer === 'yes');
|
|
404
|
-
});
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
export default CLI;
|