@twin.org/cli-core 0.0.2-next.8 → 0.0.3-next.1

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.
Files changed (38) hide show
  1. package/dist/es/cliBase.js +122 -0
  2. package/dist/es/cliBase.js.map +1 -0
  3. package/dist/es/cliDisplay.js +166 -0
  4. package/dist/es/cliDisplay.js.map +1 -0
  5. package/dist/es/cliOptions.js +36 -0
  6. package/dist/es/cliOptions.js.map +1 -0
  7. package/dist/es/cliParam.js +248 -0
  8. package/dist/es/cliParam.js.map +1 -0
  9. package/dist/es/cliUtils.js +235 -0
  10. package/dist/es/cliUtils.js.map +1 -0
  11. package/dist/es/commands/global.js +61 -0
  12. package/dist/es/commands/global.js.map +1 -0
  13. package/dist/es/index.js +14 -0
  14. package/dist/es/index.js.map +1 -0
  15. package/dist/es/models/ICliOptions.js +2 -0
  16. package/dist/es/models/ICliOptions.js.map +1 -0
  17. package/dist/es/models/ICliOutputOptionsConsole.js +2 -0
  18. package/dist/es/models/ICliOutputOptionsConsole.js.map +1 -0
  19. package/dist/es/models/ICliOutputOptionsEnv.js +2 -0
  20. package/dist/es/models/ICliOutputOptionsEnv.js.map +1 -0
  21. package/dist/es/models/ICliOutputOptionsJson.js +2 -0
  22. package/dist/es/models/ICliOutputOptionsJson.js.map +1 -0
  23. package/dist/es/models/cliOutputOptions.js +2 -0
  24. package/dist/es/models/cliOutputOptions.js.map +1 -0
  25. package/dist/types/cliBase.d.ts +1 -1
  26. package/dist/types/cliDisplay.d.ts +5 -0
  27. package/dist/types/cliParam.d.ts +10 -9
  28. package/dist/types/index.d.ts +11 -11
  29. package/dist/types/models/cliOutputOptions.d.ts +3 -3
  30. package/docs/changelog.md +297 -0
  31. package/docs/reference/classes/CLIDisplay.md +20 -0
  32. package/docs/reference/classes/CLIParam.md +62 -50
  33. package/docs/reference/classes/CLIUtils.md +10 -10
  34. package/locales/.validate-ignore +1 -0
  35. package/locales/en.json +0 -1
  36. package/package.json +25 -14
  37. package/dist/cjs/index.cjs +0 -878
  38. package/dist/esm/index.mjs +0 -849
@@ -1,849 +0,0 @@
1
- import { I18n, ErrorHelper, Is, Coerce, ObjectHelper, GeneralError, Guards, Url, Converter } from '@twin.org/core';
2
- import { Command } from 'commander';
3
- import { clearLine, cursorTo } from 'node:readline';
4
- import { inspect } from 'node:util';
5
- import chalk from 'chalk';
6
- import path from 'node:path';
7
- import * as dotenv from 'dotenv';
8
- import { exec, spawn } from 'node:child_process';
9
- import { statSync, accessSync, readFileSync } from 'node:fs';
10
- import { stat, access, readFile, mkdir, writeFile } from 'node:fs/promises';
11
- import { Bech32 } from '@twin.org/crypto';
12
-
13
- // Copyright 2024 IOTA Stiftung.
14
- // SPDX-License-Identifier: Apache-2.0.
15
- /**
16
- * Display utilities for the CLI.
17
- */
18
- class CLIDisplay {
19
- /**
20
- * The interval ID for the spinner.
21
- * @internal
22
- */
23
- static _spinnerIntervalId;
24
- /**
25
- * The default output method for writing standard messages.
26
- * @param buffer The message to output.
27
- */
28
- static write = buffer => process.stdout.write(buffer);
29
- /**
30
- * The default output method for writing error messages.
31
- * @param buffer The message to output.
32
- */
33
- static writeError = buffer => process.stderr.write(buffer);
34
- /**
35
- * The default output method for clearing the current line.
36
- */
37
- static clearLine = () => {
38
- clearLine(process.stdout, 0);
39
- cursorTo(process.stdout, 0);
40
- };
41
- /**
42
- * Display the header for the CLI.
43
- * @param title The title of the CLI.
44
- * @param version The version of the CLI.
45
- * @param icon The icon for the CLI.
46
- */
47
- static header(title, version, icon) {
48
- const titleVersion = `${title} v${version}`;
49
- CLIDisplay.write(`${icon} ${chalk.underline.bold.blue(titleVersion)}\n`);
50
- CLIDisplay.write("\n");
51
- }
52
- /**
53
- * Display an error message.
54
- * @param error The error to display.
55
- * @param lineBreaks Whether to add a line break after the error.
56
- */
57
- static error(error, lineBreaks = true) {
58
- CLIDisplay.writeError("❗ ");
59
- CLIDisplay.writeError(chalk.red(I18n.formatMessage("cli.progress.error")));
60
- if (lineBreaks) {
61
- CLIDisplay.writeError("\n");
62
- }
63
- const formatted = ErrorHelper.formatErrors(error, true);
64
- CLIDisplay.writeError(chalk.red(formatted.map(e => `\t${e}`).join("\n")));
65
- if (lineBreaks) {
66
- CLIDisplay.writeError("\n");
67
- }
68
- }
69
- /**
70
- * Display a section.
71
- * @param label The label for the section.
72
- */
73
- static section(label) {
74
- CLIDisplay.write(chalk.hex("#FFA500").bold.underline(label));
75
- CLIDisplay.write("\n\n");
76
- }
77
- /**
78
- * Display a value with a label.
79
- * @param label The label for the value.
80
- * @param value The value to display.
81
- * @param indentLevel The level of indentation.
82
- */
83
- static value(label, value, indentLevel = 0) {
84
- CLIDisplay.write("\t".repeat(indentLevel));
85
- if (Is.stringValue(label)) {
86
- CLIDisplay.write(chalk.hex("#FFA500").bold(`${label}: `));
87
- }
88
- CLIDisplay.write(Coerce.string(value) ?? "");
89
- CLIDisplay.write("\n");
90
- }
91
- /**
92
- * Display a task with a label.
93
- * @param label The label for the value.
94
- * @param task The task to display.
95
- */
96
- static task(label, task) {
97
- CLIDisplay.write("➡️ ");
98
- if (Is.empty(task)) {
99
- CLIDisplay.write(chalk.cyan(label));
100
- }
101
- else {
102
- CLIDisplay.write(chalk.cyan(`${label}: `));
103
- CLIDisplay.write(task);
104
- }
105
- CLIDisplay.write("\n");
106
- }
107
- /**
108
- * Display a break.
109
- */
110
- static break() {
111
- CLIDisplay.write("\n");
112
- }
113
- /**
114
- * Display formatted and colorized JSON.
115
- * @param obj The object to display.
116
- */
117
- static json(obj) {
118
- CLIDisplay.write(inspect(obj, false, undefined, true));
119
- CLIDisplay.write("\n");
120
- }
121
- /**
122
- * Display a warning.
123
- * @param label The label for the warning.
124
- */
125
- static warning(label) {
126
- CLIDisplay.write("⚠️ ");
127
- CLIDisplay.write(chalk.hex("#FFA500").bold(label));
128
- CLIDisplay.write("\n\n");
129
- }
130
- /**
131
- * Display the processing is done.
132
- */
133
- static done() {
134
- CLIDisplay.write("🎉 ");
135
- CLIDisplay.write(chalk.greenBright.bold(I18n.formatMessage("cli.progress.done")));
136
- CLIDisplay.write("\n");
137
- }
138
- /**
139
- * Start the spinner.
140
- * @param i18nMessage The message to display with the spinner.
141
- * @param spinnerCharacters The characters to use in the spinner.
142
- * @param interval The interval for the spinner.
143
- */
144
- static spinnerStart(i18nMessage = "cli.progress.pleaseWait", spinnerCharacters = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"], interval = 100) {
145
- let spinnerIndex = 0;
146
- if (CLIDisplay._spinnerIntervalId) {
147
- clearInterval(CLIDisplay._spinnerIntervalId);
148
- }
149
- CLIDisplay._spinnerIntervalId = setInterval(() => {
150
- CLIDisplay.clearLine();
151
- CLIDisplay.write(`${spinnerCharacters[spinnerIndex++ % spinnerCharacters.length]} ${I18n.formatMessage(i18nMessage)}`);
152
- }, interval);
153
- }
154
- /**
155
- * Stop the spinner.
156
- */
157
- static spinnerStop() {
158
- if (CLIDisplay._spinnerIntervalId) {
159
- clearInterval(CLIDisplay._spinnerIntervalId);
160
- CLIDisplay._spinnerIntervalId = undefined;
161
- }
162
- CLIDisplay.clearLine();
163
- }
164
- }
165
-
166
- // Copyright 2024 IOTA Stiftung.
167
- // SPDX-License-Identifier: Apache-2.0.
168
- /**
169
- * Utilities function for helping in the CLI.
170
- */
171
- class CLIUtils {
172
- /**
173
- * Does the specified file exist.
174
- * @param filename The filename to check for existence.
175
- * @returns True if the file exists.
176
- */
177
- static async fileExists(filename) {
178
- try {
179
- const stats = await stat(filename);
180
- return stats.isFile();
181
- }
182
- catch {
183
- return false;
184
- }
185
- }
186
- /**
187
- * Does the specified file exist, synchronously.
188
- * @param filename The filename to check for existence.
189
- * @returns True if the file exists.
190
- */
191
- static fileExistsSync(filename) {
192
- try {
193
- const stats = statSync(filename);
194
- return stats.isFile();
195
- }
196
- catch {
197
- return false;
198
- }
199
- }
200
- /**
201
- * Check if the dir exists.
202
- * @param dir The directory to check.
203
- * @returns True if the dir exists.
204
- */
205
- static async dirExists(dir) {
206
- try {
207
- await access(dir);
208
- return true;
209
- }
210
- catch {
211
- return false;
212
- }
213
- }
214
- /**
215
- * Check if the dir exists, synchronously.
216
- * @param dir The directory to check.
217
- * @returns True if the dir exists.
218
- */
219
- static dirExistsSync(dir) {
220
- try {
221
- accessSync(dir);
222
- return true;
223
- }
224
- catch {
225
- return false;
226
- }
227
- }
228
- /**
229
- * Read a JSON file and parse it.
230
- * @param filename The filename to read.
231
- * @returns The parsed JSON.
232
- */
233
- static async readJsonFile(filename) {
234
- if (await CLIUtils.fileExists(filename)) {
235
- const content = await readFile(filename, "utf8");
236
- return JSON.parse(content);
237
- }
238
- }
239
- /**
240
- * Read a JSON file and parse it, synchronously.
241
- * @param filename The filename to read.
242
- * @returns The parsed JSON.
243
- */
244
- static readJsonFileSync(filename) {
245
- if (CLIUtils.fileExistsSync(filename)) {
246
- const content = readFileSync(filename, "utf8");
247
- return JSON.parse(content);
248
- }
249
- }
250
- /**
251
- * Read a file as lines.
252
- * @param filename The filename to read.
253
- * @returns The lines.
254
- */
255
- static async readLinesFile(filename) {
256
- if (await CLIUtils.fileExists(filename)) {
257
- const content = await readFile(filename, "utf8");
258
- return content.split("\n");
259
- }
260
- }
261
- /**
262
- * Read a file as lines, synchronously.
263
- * @param filename The filename to read.
264
- * @returns The lines.
265
- */
266
- static readLinesFileSync(filename) {
267
- if (CLIUtils.fileExistsSync(filename)) {
268
- const content = readFileSync(filename, "utf8");
269
- return content.split("\n");
270
- }
271
- }
272
- /**
273
- * Find the NPM root based on a package.json path.
274
- * @param rootFolder The path to the package.json.
275
- * @returns The root path.
276
- */
277
- static async findNpmRoot(rootFolder) {
278
- return new Promise((resolve, reject) => {
279
- exec("npm root", { cwd: rootFolder }, (error, stdout, stderr) => {
280
- if (error) {
281
- reject(error);
282
- }
283
- else {
284
- resolve(stdout.trim());
285
- }
286
- });
287
- });
288
- }
289
- /**
290
- * Run a shell command.
291
- * @param command The app to run in the shell.
292
- * @param args The args for the app.
293
- * @param cwd The working directory to execute the command in.
294
- * @returns Promise to wait for command execution to complete.
295
- */
296
- static async runShellCmd(command, args, cwd) {
297
- const osCommand = process.platform.startsWith("win") ? `${command}.cmd` : command;
298
- return CLIUtils.runShellApp(osCommand, args, cwd);
299
- }
300
- /**
301
- * Run a shell app.
302
- * @param app The app to run in the shell.
303
- * @param args The args for the app.
304
- * @param cwd The working directory to execute the command in.
305
- * @returns Promise to wait for command execution to complete.
306
- */
307
- static async runShellApp(app, args, cwd) {
308
- return new Promise((resolve, reject) => {
309
- const sp = spawn(app, args, {
310
- shell: true,
311
- cwd
312
- });
313
- sp.stdout?.on("data", data => {
314
- CLIDisplay.write(data);
315
- });
316
- sp.stderr?.on("data", data => {
317
- CLIDisplay.writeError(data);
318
- });
319
- sp.on("exit", (exitCode, signals) => {
320
- if (Coerce.number(exitCode) !== 0 || signals?.length) {
321
- // eslint-disable-next-line no-restricted-syntax
322
- reject(new Error("Run failed"));
323
- }
324
- else {
325
- resolve();
326
- }
327
- });
328
- });
329
- }
330
- /**
331
- * Write a JSON file.
332
- * @param jsonFilename The filename to write.
333
- * @param data The data to write.
334
- * @param append Append to the file.
335
- */
336
- static async writeJsonFile(jsonFilename, data, append) {
337
- if (Is.stringValue(jsonFilename)) {
338
- const filename = path.resolve(jsonFilename);
339
- let currentJson = {};
340
- if (append) {
341
- CLIDisplay.task(I18n.formatMessage("cli.progress.readingJsonFile"), filename);
342
- currentJson = (await CLIUtils.readJsonFile(filename)) ?? {};
343
- }
344
- CLIDisplay.task(I18n.formatMessage("cli.progress.writingJsonFile"), filename);
345
- CLIDisplay.break();
346
- await mkdir(path.dirname(filename), { recursive: true });
347
- await writeFile(filename, `${JSON.stringify(ObjectHelper.merge(currentJson, data), undefined, "\t")}\n`);
348
- }
349
- }
350
- /**
351
- * Write an env file.
352
- * @param envFilename The filename to write.
353
- * @param data The data to write.
354
- * @param append Append to the file.
355
- */
356
- static async writeEnvFile(envFilename, data, append) {
357
- if (Is.stringValue(envFilename)) {
358
- const filename = path.resolve(envFilename);
359
- const outputKeys = [];
360
- const outputDict = {};
361
- if (append) {
362
- CLIDisplay.task(I18n.formatMessage("cli.progress.readingEnvFile"), filename);
363
- const lines = await CLIUtils.readLinesFile(filename);
364
- if (Is.arrayValue(lines)) {
365
- for (const line of lines) {
366
- const parts = line.split("=");
367
- outputKeys.push(parts[0]);
368
- outputDict[parts[0]] = parts.slice(1).join("=");
369
- }
370
- }
371
- }
372
- CLIDisplay.task(I18n.formatMessage("cli.progress.writingEnvFile"), filename);
373
- CLIDisplay.break();
374
- if (Is.arrayValue(data)) {
375
- for (const line of data) {
376
- const parts = line.split("=");
377
- const currentIndex = outputKeys.indexOf(parts[0]);
378
- if (currentIndex !== -1) {
379
- outputKeys.splice(currentIndex, 1);
380
- }
381
- outputKeys.push(parts[0]);
382
- outputDict[parts[0]] = parts.slice(1).join("=");
383
- }
384
- }
385
- const output = [];
386
- for (const outputKey of outputKeys) {
387
- output.push(`${outputKey}=${outputDict[outputKey]}`);
388
- }
389
- await mkdir(path.dirname(filename), { recursive: true });
390
- await writeFile(filename, output.join("\n"));
391
- }
392
- }
393
- }
394
-
395
- // Copyright 2024 IOTA Stiftung.
396
- // SPDX-License-Identifier: Apache-2.0.
397
- let localesDir;
398
- /**
399
- * Initialize the global options.
400
- * @param localesDirectory The path to load the locales from.
401
- */
402
- function initGlobalOptions(localesDirectory) {
403
- localesDir = localesDirectory;
404
- }
405
- /**
406
- * Add the global options.
407
- * @param program The program to add the options to.
408
- * @param supportsLang Whether the CLI supports different languages.
409
- * @param supportsEnvFiles Whether the CLI supports loading env files
410
- */
411
- function addGlobalOptions(program, supportsLang, supportsEnvFiles) {
412
- if (supportsLang) {
413
- program.option(I18n.formatMessage("cli.options.lang.param"), I18n.formatMessage("cli.options.lang.description"), "en");
414
- }
415
- if (supportsEnvFiles) {
416
- program.option(I18n.formatMessage("cli.options.load-env.param"), I18n.formatMessage("cli.options.load-env.description"));
417
- }
418
- }
419
- /**
420
- * Handle the global options.
421
- * @param command The command to use for context.
422
- * @internal
423
- */
424
- function handleGlobalOptions(command) {
425
- const globalOpts = command.optsWithGlobals();
426
- if (Is.stringValue(globalOpts?.lang)) {
427
- initLocales(globalOpts.lang);
428
- }
429
- const loadEnv = globalOpts?.loadEnv;
430
- if (Is.arrayValue(loadEnv)) {
431
- const resolvedEnv = loadEnv.map(e => path.resolve(e));
432
- CLIDisplay.task(I18n.formatMessage("cli.progress.loadingEnvFiles"), resolvedEnv.join(", "));
433
- CLIDisplay.break();
434
- dotenv.config({ path: resolvedEnv, quiet: true });
435
- }
436
- }
437
- /**
438
- * Initialize the locales for the CLI.
439
- * @param locale The locale to use.
440
- * @internal
441
- */
442
- function initLocales(locale) {
443
- const localePath = path.join(localesDir, `${locale}.json`);
444
- const localeContent = CLIUtils.readJsonFileSync(localePath);
445
- if (Is.objectValue(localeContent)) {
446
- I18n.addDictionary(locale, localeContent);
447
- I18n.setLocale(locale);
448
- }
449
- }
450
-
451
- // Copyright 2024 IOTA Stiftung.
452
- // SPDX-License-Identifier: Apache-2.0.
453
- /**
454
- * The main entry point for the CLI.
455
- */
456
- class CLIBase {
457
- /**
458
- * Execute the command line processing.
459
- * @param options The options for the CLI.
460
- * @param localesDirectory The path to load the locales from.
461
- * @param argv The process arguments.
462
- * @returns The exit code.
463
- */
464
- async execute(options, localesDirectory, argv) {
465
- initGlobalOptions(localesDirectory);
466
- initLocales("en");
467
- try {
468
- process.title = options.title;
469
- if (!argv.includes("--version") && !argv.includes("-v")) {
470
- CLIDisplay.header(options.title, options.version, options.icon);
471
- }
472
- const program = new Command();
473
- let outputWidth = options.overrideOutputWidth;
474
- let outputErrWidth = options.overrideOutputWidth;
475
- if (Is.undefined(outputWidth) && process.stdout.isTTY) {
476
- outputWidth = process.stdout.columns;
477
- outputErrWidth = process.stderr.columns;
478
- }
479
- program
480
- .name(options.appName)
481
- .version(options.version)
482
- .usage("[command]")
483
- .showHelpAfterError()
484
- .configureOutput({
485
- writeOut: str => CLIDisplay.write(str),
486
- writeErr: str => CLIDisplay.writeError(str),
487
- getOutHelpWidth: () => outputWidth,
488
- getErrHelpWidth: () => outputErrWidth,
489
- outputError: (str, write) => CLIDisplay.error(str.replace(/^error: /, ""), false)
490
- })
491
- .exitOverride(err => {
492
- // By default commander still calls process.exit on exit
493
- // which we don't want as we might have subsequent
494
- // processing to handle, so instead we throw the exit code
495
- // as a way to skip the process.exit call.
496
- // If the error code is commander.help then we return 0 as
497
- // we don't want displaying help to be an error.
498
- // eslint-disable-next-line no-restricted-syntax
499
- throw new Error(err.code === "commander.help" ? "0" : err.exitCode.toString());
500
- });
501
- if (options.showDevToolWarning ?? false) {
502
- program.hook("preAction", () => CLIDisplay.warning(I18n.formatMessage("warn.common.devOnlyTool")));
503
- }
504
- this.configureRoot(program);
505
- addGlobalOptions(program, options.supportsLang ?? true, options.supportsEnvFiles ?? false);
506
- // We parse the options before building the command
507
- // in case the language has been set, then the
508
- // help for the options will be in the correct language.
509
- program.parseOptions(argv);
510
- handleGlobalOptions(program);
511
- const commandCount = this.buildCommands(program);
512
- if (commandCount === 0) {
513
- program.usage(" ");
514
- }
515
- await program.parseAsync(argv);
516
- }
517
- catch (error) {
518
- CLIDisplay.spinnerStop();
519
- let exitCode;
520
- if (error instanceof Error) {
521
- // This error could be the exit code we errored with
522
- // from the exitOverride so parse and resolve with it
523
- exitCode = Coerce.number(error.message);
524
- }
525
- if (Is.integer(exitCode)) {
526
- return exitCode;
527
- }
528
- CLIDisplay.error(error);
529
- return 1;
530
- }
531
- return 0;
532
- }
533
- /**
534
- * Configure any options or actions at the root program level.
535
- * @param program The root program command.
536
- */
537
- configureRoot(program) {
538
- program.action(() => {
539
- program.help();
540
- });
541
- }
542
- /**
543
- * Get the commands for the CLI, override in derived class to supply your own.
544
- * @param program The main program that the commands will be added to.
545
- * @returns The commands for the CLI.
546
- */
547
- getCommands(program) {
548
- return [];
549
- }
550
- /**
551
- * Build the commands for the CLI.
552
- * @param program The main program that the commands are added to.
553
- * @returns The number of commands added.
554
- * @internal
555
- */
556
- buildCommands(program) {
557
- const commands = this.getCommands(program);
558
- for (const command of commands) {
559
- program.addCommand(command.copyInheritedSettings(program));
560
- }
561
- return commands.length;
562
- }
563
- }
564
-
565
- // Copyright 2024 IOTA Stiftung.
566
- // SPDX-License-Identifier: Apache-2.0.
567
- /**
568
- * Utilities for getting standard options.
569
- */
570
- class CLIOptions {
571
- /**
572
- * Get the options for output.
573
- * @param command The command to add the options to.
574
- * @param opts The options of what to include.
575
- * @param opts.noConsole Do not output to the console.
576
- * @param opts.json Output to a JSON file.
577
- * @param opts.env Output to an environment file.
578
- * @param opts.mergeJson Merge existing JSON file.
579
- * @param opts.mergeEnv Merge existing environment file.
580
- */
581
- static output(command, opts) {
582
- if (opts.noConsole) {
583
- command.option(I18n.formatMessage("cli.options.no-console.param"), I18n.formatMessage("cli.options.no-console.description"));
584
- }
585
- if (opts.json) {
586
- command.option(I18n.formatMessage("cli.options.json.param"), I18n.formatMessage("cli.options.json.description"));
587
- }
588
- if (opts.mergeJson) {
589
- command.option(I18n.formatMessage("cli.options.merge-json.param"), I18n.formatMessage("cli.options.merge-json.description"));
590
- }
591
- if (opts.env) {
592
- command.option(I18n.formatMessage("cli.options.env.param"), I18n.formatMessage("cli.options.env.description"));
593
- }
594
- if (opts.mergeEnv) {
595
- command.option(I18n.formatMessage("cli.options.merge-env.param"), I18n.formatMessage("cli.options.merge-env.description"));
596
- }
597
- }
598
- }
599
-
600
- // Copyright 2024 IOTA Stiftung.
601
- // SPDX-License-Identifier: Apache-2.0.
602
- /**
603
- * Parameter utilities for the CLI.
604
- */
605
- class CLIParam {
606
- /**
607
- * Check the option to see if it exists.
608
- * @param optionName The name of the option.
609
- * @param optionValue The option value.
610
- * @param allowEnvVar Allow the option to be read from an env var.
611
- * @returns The final option value.
612
- * @throws An error if the option is invalid.
613
- */
614
- static env(optionName, optionValue, allowEnvVar) {
615
- if (allowEnvVar && optionValue?.startsWith("!")) {
616
- const envValueName = optionValue.slice(1);
617
- const envValue = process.env[envValueName];
618
- if (Is.empty(envValue)) {
619
- throw new GeneralError("commands", "commands.common.missingEnv", {
620
- option: optionName,
621
- value: envValueName
622
- });
623
- }
624
- else {
625
- optionValue = envValue;
626
- }
627
- }
628
- return optionValue;
629
- }
630
- /**
631
- * Check the option to see if the String exists.
632
- * @param optionName The name of the option.
633
- * @param optionValue The option value.
634
- * @param allowEnvVar Allow the option to be read from an env var.
635
- * @returns The final option value.
636
- * @throws An error if the option is invalid.
637
- */
638
- static stringValue(optionName, optionValue, allowEnvVar = true) {
639
- optionValue = CLIParam.env(optionName, optionValue, allowEnvVar);
640
- Guards.stringValue("commands", optionName, optionValue);
641
- return optionValue;
642
- }
643
- /**
644
- * Check the option to see if it is a url.
645
- * @param optionName The name of the option.
646
- * @param optionValue The option value.
647
- * @param allowEnvVar Allow the option to be read from an env var.
648
- * @returns The final option value.
649
- * @throws An error if the option is invalid.
650
- */
651
- static url(optionName, optionValue, allowEnvVar = true) {
652
- optionValue = CLIParam.env(optionName, optionValue, allowEnvVar);
653
- Url.guard("commands", optionName, optionValue);
654
- return optionValue;
655
- }
656
- /**
657
- * Check the option to see if it exists and is a number.
658
- * @param optionName The name of the option.
659
- * @param optionValue The option value.
660
- * @param allowEnvVar Allow the option to be read from an env var.
661
- * @param minValue The minimum value.
662
- * @param maxValue The maximum value.
663
- * @returns The final option value.
664
- * @throws An error if the option is invalid.
665
- */
666
- static number(optionName, optionValue, allowEnvVar = true, minValue = 0, maxValue) {
667
- optionValue = CLIParam.env(optionName, optionValue, allowEnvVar);
668
- const coerced = Coerce.number(optionValue);
669
- if (Is.number(coerced)) {
670
- if (Is.number(minValue) && coerced < minValue) {
671
- throw new GeneralError("commands", "commands.common.optionMinValue", {
672
- option: optionName,
673
- value: optionValue,
674
- minValue
675
- });
676
- }
677
- else if (Is.number(maxValue) && coerced > maxValue) {
678
- throw new GeneralError("commands", "commands.common.optionMaxValue", {
679
- option: optionName,
680
- value: optionValue,
681
- maxValue
682
- });
683
- }
684
- return coerced;
685
- }
686
- Guards.number("commands", optionName, optionValue);
687
- return 0;
688
- }
689
- /**
690
- * Check the option to see if it exists and is an integer.
691
- * @param optionName The name of the option.
692
- * @param optionValue The option value.
693
- * @param allowEnvVar Allow the option to be read from an env var.
694
- * @param minValue The minimum value.
695
- * @param maxValue The maximum value.
696
- * @returns The final option value.
697
- * @throws An error if the option is invalid.
698
- */
699
- static integer(optionName, optionValue, allowEnvVar = true, minValue = 0, maxValue) {
700
- optionValue = CLIParam.env(optionName, optionValue, allowEnvVar);
701
- const coerced = Coerce.number(optionValue);
702
- if (Is.integer(coerced)) {
703
- if (Is.number(minValue) && coerced < minValue) {
704
- throw new GeneralError("commands", "commands.common.optionMinValue", {
705
- option: optionName,
706
- value: optionValue,
707
- minValue
708
- });
709
- }
710
- else if (Is.number(maxValue) && coerced > maxValue) {
711
- throw new GeneralError("commands", "commands.common.optionMaxValue", {
712
- option: optionName,
713
- value: optionValue,
714
- maxValue
715
- });
716
- }
717
- return coerced;
718
- }
719
- Guards.integer("commands", optionName, optionValue);
720
- return 0;
721
- }
722
- /**
723
- * Check the option to see if it exists and is a big number.
724
- * @param optionName The name of the option.
725
- * @param optionValue The option value.
726
- * @param allowEnvVar Allow the option to be read from an env var.
727
- * @param minValue The minimum value.
728
- * @param maxValue The maximum value.
729
- * @returns The final option value.
730
- * @throws An error if the option is invalid.
731
- */
732
- static bigint(optionName, optionValue, allowEnvVar = true, minValue = 0n, maxValue) {
733
- optionValue = CLIParam.env(optionName, optionValue, allowEnvVar);
734
- const coerced = Coerce.bigint(optionValue);
735
- if (Is.bigint(coerced)) {
736
- if (Is.bigint(minValue) && coerced < minValue) {
737
- throw new GeneralError("commands", "commands.common.optionMinValue", {
738
- option: optionName,
739
- value: optionValue,
740
- minValue
741
- });
742
- }
743
- else if (Is.bigint(maxValue) && coerced > maxValue) {
744
- throw new GeneralError("commands", "commands.common.optionMaxValue", {
745
- option: optionName,
746
- value: optionValue,
747
- maxValue
748
- });
749
- }
750
- return coerced;
751
- }
752
- Guards.bigint("commands", optionName, optionValue);
753
- return 0n;
754
- }
755
- /**
756
- * Check the option to see if it exists and is a boolean.
757
- * @param optionName The name of the option.
758
- * @param optionValue The option value.
759
- * @param allowEnvVar Allow the option to be read from an env var.
760
- * @returns The final option value.
761
- * @throws An error if the option is invalid.
762
- */
763
- static boolean(optionName, optionValue, allowEnvVar = true) {
764
- optionValue = CLIParam.env(optionName, optionValue, allowEnvVar);
765
- const coerced = Coerce.boolean(optionValue);
766
- if (Is.boolean(coerced)) {
767
- return coerced;
768
- }
769
- Guards.boolean("commands", optionName, optionValue);
770
- return false;
771
- }
772
- /**
773
- * Check the option to see if it exists and is hex.
774
- * @param optionName The name of the option.
775
- * @param optionValue The option value.
776
- * @param allowEnvVar Allow the option to be read from an env var.
777
- * @returns The final option value.
778
- * @throws An error if the option is invalid.
779
- */
780
- static hex(optionName, optionValue, allowEnvVar = true) {
781
- optionValue = CLIParam.env(optionName, optionValue, allowEnvVar);
782
- if (Is.stringHex(optionValue, true)) {
783
- return Converter.hexToBytes(optionValue);
784
- }
785
- throw new GeneralError("commands", "commands.common.optionInvalidHex", {
786
- option: optionName,
787
- value: optionValue
788
- });
789
- }
790
- /**
791
- * Check the option to see if it exists and is base64.
792
- * @param optionName The name of the option.
793
- * @param optionValue The option value.
794
- * @param allowEnvVar Allow the option to be read from an env var.
795
- * @returns The final option value.
796
- * @throws An error if the option is invalid.
797
- */
798
- static base64(optionName, optionValue, allowEnvVar = true) {
799
- optionValue = CLIParam.env(optionName, optionValue, allowEnvVar);
800
- if (Is.stringBase64(optionValue)) {
801
- return Converter.base64ToBytes(optionValue);
802
- }
803
- throw new GeneralError("commands", "commands.common.optionInvalidBase64", {
804
- option: optionName,
805
- value: optionValue
806
- });
807
- }
808
- /**
809
- * Check the option to see if it exists and is hex or base64.
810
- * @param optionName The name of the option.
811
- * @param optionValue The option value.
812
- * @param allowEnvVar Allow the option to be read from an env var.
813
- * @returns The final option value.
814
- * @throws An error if the option is invalid.
815
- */
816
- static hexBase64(optionName, optionValue, allowEnvVar = true) {
817
- optionValue = CLIParam.env(optionName, optionValue, allowEnvVar);
818
- if (Is.stringHex(optionValue, true)) {
819
- return Converter.hexToBytes(optionValue);
820
- }
821
- else if (Is.stringBase64(optionValue)) {
822
- return Converter.base64ToBytes(optionValue);
823
- }
824
- throw new GeneralError("commands", "commands.common.optionInvalidHexBase64", {
825
- option: optionName,
826
- value: optionValue
827
- });
828
- }
829
- /**
830
- * Check the option to see if it exists and is bech32.
831
- * @param optionName The name of the option.
832
- * @param optionValue The option value.
833
- * @param allowEnvVar Allow the option to be read from an env var.
834
- * @returns The final option value.
835
- * @throws An error if the option is invalid.
836
- */
837
- static bech32(optionName, optionValue, allowEnvVar = true) {
838
- optionValue = CLIParam.env(optionName, optionValue, allowEnvVar);
839
- if (Bech32.isBech32(optionValue)) {
840
- return optionValue;
841
- }
842
- throw new GeneralError("commands", "commands.common.optionInvalidBech32", {
843
- option: optionName,
844
- value: optionValue
845
- });
846
- }
847
- }
848
-
849
- export { CLIBase, CLIDisplay, CLIOptions, CLIParam, CLIUtils, addGlobalOptions, handleGlobalOptions, initGlobalOptions, initLocales };