@reliverse/rempts-core 1.6.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 (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +102 -0
  3. package/bin/core-impl/anykey/anykey-mod.d.ts +12 -0
  4. package/bin/core-impl/anykey/anykey-mod.js +125 -0
  5. package/bin/core-impl/date/date.d.ts +2 -0
  6. package/bin/core-impl/date/date.js +236 -0
  7. package/bin/core-impl/editor/editor-mod.d.ts +25 -0
  8. package/bin/core-impl/editor/editor-mod.js +896 -0
  9. package/bin/core-impl/figures/figures-mod.d.ts +233 -0
  10. package/bin/core-impl/figures/figures-mod.js +286 -0
  11. package/bin/core-impl/figures/figures.test.d.ts +1 -0
  12. package/bin/core-impl/figures/figures.test.js +474 -0
  13. package/bin/core-impl/input/confirm-prompt.d.ts +5 -0
  14. package/bin/core-impl/input/confirm-prompt.js +173 -0
  15. package/bin/core-impl/input/input-prompt.d.ts +16 -0
  16. package/bin/core-impl/input/input-prompt.js +370 -0
  17. package/bin/core-impl/launcher/_parser.d.ts +2 -0
  18. package/bin/core-impl/launcher/_parser.js +122 -0
  19. package/bin/core-impl/launcher/_utils.d.ts +8 -0
  20. package/bin/core-impl/launcher/_utils.js +29 -0
  21. package/bin/core-impl/launcher/args.d.ts +3 -0
  22. package/bin/core-impl/launcher/args.js +89 -0
  23. package/bin/core-impl/launcher/command.d.ts +8 -0
  24. package/bin/core-impl/launcher/command.js +68 -0
  25. package/bin/core-impl/launcher/launcher-mod.d.ts +8 -0
  26. package/bin/core-impl/launcher/launcher-mod.js +34 -0
  27. package/bin/core-impl/launcher/usage.d.ts +3 -0
  28. package/bin/core-impl/launcher/usage.js +104 -0
  29. package/bin/core-impl/msg-fmt/colors.d.ts +30 -0
  30. package/bin/core-impl/msg-fmt/colors.js +42 -0
  31. package/bin/core-impl/msg-fmt/logger.d.ts +17 -0
  32. package/bin/core-impl/msg-fmt/logger.js +106 -0
  33. package/bin/core-impl/msg-fmt/mapping.d.ts +3 -0
  34. package/bin/core-impl/msg-fmt/mapping.js +49 -0
  35. package/bin/core-impl/msg-fmt/messages.d.ts +35 -0
  36. package/bin/core-impl/msg-fmt/messages.js +314 -0
  37. package/bin/core-impl/msg-fmt/terminal.d.ts +15 -0
  38. package/bin/core-impl/msg-fmt/terminal.js +59 -0
  39. package/bin/core-impl/msg-fmt/variants.d.ts +11 -0
  40. package/bin/core-impl/msg-fmt/variants.js +52 -0
  41. package/bin/core-impl/next-steps/next-steps.d.ts +14 -0
  42. package/bin/core-impl/next-steps/next-steps.js +24 -0
  43. package/bin/core-impl/number/number-mod.d.ts +28 -0
  44. package/bin/core-impl/number/number-mod.js +197 -0
  45. package/bin/core-impl/results/results.d.ts +7 -0
  46. package/bin/core-impl/results/results.js +27 -0
  47. package/bin/core-impl/select/multiselect-prompt.d.ts +2 -0
  48. package/bin/core-impl/select/multiselect-prompt.js +341 -0
  49. package/bin/core-impl/select/nummultiselect-prompt.d.ts +6 -0
  50. package/bin/core-impl/select/nummultiselect-prompt.js +105 -0
  51. package/bin/core-impl/select/numselect-prompt.d.ts +7 -0
  52. package/bin/core-impl/select/numselect-prompt.js +115 -0
  53. package/bin/core-impl/select/select-prompt.d.ts +33 -0
  54. package/bin/core-impl/select/select-prompt.js +302 -0
  55. package/bin/core-impl/select/toggle-prompt.d.ts +5 -0
  56. package/bin/core-impl/select/toggle-prompt.js +208 -0
  57. package/bin/core-impl/st-end/end.d.ts +2 -0
  58. package/bin/core-impl/st-end/end.js +42 -0
  59. package/bin/core-impl/st-end/start.d.ts +17 -0
  60. package/bin/core-impl/st-end/start.js +66 -0
  61. package/bin/core-impl/task/progress.d.ts +2 -0
  62. package/bin/core-impl/task/progress.js +57 -0
  63. package/bin/core-impl/task/spinner.d.ts +15 -0
  64. package/bin/core-impl/task/spinner.js +110 -0
  65. package/bin/core-impl/utils/colorize.d.ts +2 -0
  66. package/bin/core-impl/utils/colorize.js +134 -0
  67. package/bin/core-impl/utils/errors.d.ts +1 -0
  68. package/bin/core-impl/utils/errors.js +15 -0
  69. package/bin/core-impl/utils/prevent.d.ts +10 -0
  70. package/bin/core-impl/utils/prevent.js +69 -0
  71. package/bin/core-impl/utils/prompt-end.d.ts +8 -0
  72. package/bin/core-impl/utils/prompt-end.js +33 -0
  73. package/bin/core-impl/utils/stream-text.d.ts +18 -0
  74. package/bin/core-impl/utils/stream-text.js +136 -0
  75. package/bin/core-impl/utils/system.d.ts +6 -0
  76. package/bin/core-impl/utils/system.js +7 -0
  77. package/bin/core-impl/utils/validate.d.ts +22 -0
  78. package/bin/core-impl/utils/validate.js +17 -0
  79. package/bin/core-impl/visual/animate/animate.d.ts +14 -0
  80. package/bin/core-impl/visual/animate/animate.js +64 -0
  81. package/bin/core-impl/visual/ascii-art/ascii-art.d.ts +6 -0
  82. package/bin/core-impl/visual/ascii-art/ascii-art.js +12 -0
  83. package/bin/core-types.d.ts +434 -0
  84. package/bin/core-types.js +0 -0
  85. package/bin/main.d.ts +41 -0
  86. package/bin/main.js +96 -0
  87. package/package.json +58 -0
@@ -0,0 +1,370 @@
1
+ import { re } from "@reliverse/relico";
2
+ import { isUnicodeSupported } from "@reliverse/runtime";
3
+ import readline from "node:readline/promises";
4
+ import {
5
+ bar,
6
+ msg,
7
+ msgUndoAll
8
+ } from "../msg-fmt/messages.js";
9
+ import { deleteLastLine } from "../msg-fmt/terminal.js";
10
+ import { completePrompt } from "../utils/prompt-end.js";
11
+ import { streamText } from "../utils/stream-text.js";
12
+ const unicode = isUnicodeSupported();
13
+ const S_MASK = unicode ? "\u258B" : "*";
14
+ function getMaskChar(customMask) {
15
+ if (!unicode) return "*";
16
+ return customMask ?? S_MASK;
17
+ }
18
+ async function ask(terminal, prompt, mode, mask) {
19
+ if (mode === "password") {
20
+ return new Promise((resolve) => {
21
+ let buffer = "";
22
+ const maskChar = getMaskChar(mask);
23
+ process.stdout.write(prompt);
24
+ const onData = (data) => {
25
+ const str = data.toString("utf-8");
26
+ for (const char of str) {
27
+ if (char === "\n" || char === "\r") {
28
+ process.stdout.write("\n");
29
+ cleanup();
30
+ resolve(buffer);
31
+ return;
32
+ }
33
+ if (char === "") {
34
+ cleanup();
35
+ resolve(null);
36
+ return;
37
+ }
38
+ if (char === "\x7F" || char === "\b") {
39
+ if (buffer.length > 0) {
40
+ buffer = buffer.slice(0, -1);
41
+ }
42
+ redrawPrompt(buffer, prompt);
43
+ continue;
44
+ }
45
+ buffer += char;
46
+ redrawPrompt(buffer, prompt);
47
+ }
48
+ };
49
+ process.stdin.on("data", onData);
50
+ const cleanup = () => {
51
+ process.stdin.removeListener("data", onData);
52
+ };
53
+ const redrawPrompt = (maskedBuffer, textPrompt) => {
54
+ process.stdout.clearLine(0);
55
+ process.stdout.cursorTo(0);
56
+ process.stdout.write(textPrompt + maskChar.repeat(maskedBuffer.length));
57
+ };
58
+ });
59
+ }
60
+ return terminal.question(prompt);
61
+ }
62
+ function renderPromptUI(params) {
63
+ const {
64
+ title,
65
+ hint = "",
66
+ hintPlaceholderColor = "blue",
67
+ content = "",
68
+ contentColor = "dim",
69
+ contentTypography = "italic",
70
+ contentVariant = "none",
71
+ titleColor = "cyan",
72
+ titleTypography = "none",
73
+ titleVariant = "none",
74
+ borderColor = "dim",
75
+ placeholder = "",
76
+ userInput,
77
+ errorMessage,
78
+ symbol = "step_active",
79
+ customSymbol = "",
80
+ symbolColor = "cyan",
81
+ shouldStream = false,
82
+ streamDelay = 30
83
+ } = params;
84
+ const type = errorMessage !== "" ? "M_ERROR" : "M_GENERAL";
85
+ if (shouldStream) {
86
+ return new Promise((resolve) => {
87
+ msg({
88
+ type,
89
+ title: "",
90
+ titleColor,
91
+ titleTypography,
92
+ titleVariant,
93
+ content: "",
94
+ contentColor,
95
+ contentTypography,
96
+ contentVariant,
97
+ borderColor,
98
+ hint,
99
+ hintPlaceholderColor,
100
+ placeholder: userInput === "" ? placeholder : "",
101
+ errorMessage,
102
+ symbol,
103
+ customSymbol,
104
+ symbolColor
105
+ });
106
+ void streamText({
107
+ text: title,
108
+ delay: streamDelay,
109
+ color: titleColor,
110
+ newline: false
111
+ }).then(async () => {
112
+ msgUndoAll();
113
+ msg({
114
+ type,
115
+ title,
116
+ titleColor,
117
+ titleTypography,
118
+ titleVariant,
119
+ content: "",
120
+ contentColor,
121
+ contentTypography,
122
+ contentVariant,
123
+ borderColor,
124
+ hint,
125
+ hintPlaceholderColor,
126
+ placeholder: userInput === "" ? placeholder : "",
127
+ errorMessage,
128
+ symbol,
129
+ customSymbol,
130
+ symbolColor
131
+ });
132
+ if (content) {
133
+ await streamText({
134
+ text: content,
135
+ delay: streamDelay,
136
+ color: contentColor,
137
+ newline: false
138
+ });
139
+ }
140
+ msgUndoAll();
141
+ deleteLastLine();
142
+ msg({
143
+ type,
144
+ title,
145
+ titleColor,
146
+ titleTypography,
147
+ titleVariant,
148
+ content,
149
+ contentColor,
150
+ contentTypography,
151
+ contentVariant,
152
+ borderColor,
153
+ hint,
154
+ hintPlaceholderColor,
155
+ placeholder: userInput === "" ? placeholder : "",
156
+ errorMessage,
157
+ symbol,
158
+ customSymbol,
159
+ symbolColor
160
+ });
161
+ resolve();
162
+ });
163
+ });
164
+ }
165
+ msg({
166
+ type,
167
+ title,
168
+ titleColor,
169
+ titleTypography,
170
+ titleVariant,
171
+ content,
172
+ contentColor,
173
+ contentTypography,
174
+ contentVariant,
175
+ borderColor,
176
+ hint,
177
+ hintPlaceholderColor,
178
+ placeholder: userInput === "" ? placeholder : "",
179
+ errorMessage,
180
+ symbol,
181
+ customSymbol,
182
+ symbolColor
183
+ });
184
+ if (userInput !== "") {
185
+ msg({ type: "M_MIDDLE", title: ` ${userInput}` });
186
+ }
187
+ return Promise.resolve();
188
+ }
189
+ async function validateInput(input, validate) {
190
+ let isValid = true;
191
+ let errorMessage = "";
192
+ if (validate && isValid) {
193
+ const validationResult = await validate(input);
194
+ if (typeof validationResult === "string") {
195
+ isValid = false;
196
+ errorMessage = validationResult;
197
+ } else if (validationResult === false) {
198
+ isValid = false;
199
+ errorMessage = "Invalid input.";
200
+ }
201
+ }
202
+ return { isValid, errorMessage };
203
+ }
204
+ export async function inputPrompt(options) {
205
+ const {
206
+ title,
207
+ hint,
208
+ hintPlaceholderColor = "blue",
209
+ validate,
210
+ defaultValue = "",
211
+ titleColor = "cyan",
212
+ titleTypography = "none",
213
+ titleVariant = "none",
214
+ content,
215
+ contentColor = "dim",
216
+ contentTypography = "italic",
217
+ contentVariant = "none",
218
+ borderColor = "dim",
219
+ placeholder,
220
+ hardcoded,
221
+ endTitle = "",
222
+ endTitleColor = "dim",
223
+ border = true,
224
+ symbol,
225
+ customSymbol,
226
+ symbolColor,
227
+ mode = "plain",
228
+ mask,
229
+ shouldStream = false,
230
+ streamDelay = 20
231
+ } = options;
232
+ const terminal = readline.createInterface({
233
+ input: process.stdin,
234
+ output: process.stdout
235
+ });
236
+ async function endPrompt(isCtrlC) {
237
+ await completePrompt(
238
+ "input",
239
+ isCtrlC,
240
+ endTitle,
241
+ endTitleColor,
242
+ titleTypography,
243
+ titleVariant,
244
+ border,
245
+ borderColor,
246
+ void 0,
247
+ false
248
+ );
249
+ terminal.close();
250
+ if (isCtrlC) {
251
+ process.exit(0);
252
+ }
253
+ }
254
+ terminal.on("SIGINT", () => {
255
+ void endPrompt(true);
256
+ });
257
+ let currentInput = hardcoded?.userInput ?? "";
258
+ let errorMessage = hardcoded?.errorMessage ?? "";
259
+ let showPlaceholder = hardcoded?.showPlaceholder ?? true;
260
+ let isRerender = false;
261
+ async function handleHardcodedInput() {
262
+ msgUndoAll();
263
+ await renderPromptUI({
264
+ title,
265
+ hint,
266
+ hintPlaceholderColor,
267
+ content,
268
+ contentColor,
269
+ contentTypography,
270
+ contentVariant,
271
+ titleColor,
272
+ titleTypography,
273
+ titleVariant,
274
+ borderColor,
275
+ placeholder: showPlaceholder ? placeholder : "",
276
+ userInput: currentInput,
277
+ errorMessage,
278
+ border,
279
+ symbol,
280
+ customSymbol,
281
+ symbolColor,
282
+ mask,
283
+ shouldStream,
284
+ streamDelay
285
+ });
286
+ const finalAnswer = currentInput || defaultValue;
287
+ const validated = await validateInput(finalAnswer, validate);
288
+ if (!validated.isValid) {
289
+ terminal.close();
290
+ throw new Error(validated.errorMessage || "Invalid input.");
291
+ }
292
+ msg({ type: "M_MIDDLE", title: ` ${finalAnswer}` });
293
+ msg({ type: "M_BAR", borderColor });
294
+ terminal.close();
295
+ return finalAnswer;
296
+ }
297
+ if (hardcoded?.userInput !== void 0) {
298
+ return handleHardcodedInput();
299
+ }
300
+ while (true) {
301
+ if (isRerender) {
302
+ msgUndoAll();
303
+ }
304
+ const displayedUserInput = mode === "password" ? getMaskChar(mask).repeat(currentInput.length) : currentInput;
305
+ if (errorMessage) {
306
+ deleteLastLine();
307
+ deleteLastLine();
308
+ }
309
+ await renderPromptUI({
310
+ title,
311
+ hint,
312
+ hintPlaceholderColor,
313
+ content,
314
+ contentColor,
315
+ contentTypography,
316
+ contentVariant,
317
+ titleColor,
318
+ titleTypography,
319
+ titleVariant,
320
+ borderColor,
321
+ placeholder: showPlaceholder ? placeholder : "",
322
+ userInput: displayedUserInput,
323
+ errorMessage,
324
+ border,
325
+ symbol,
326
+ customSymbol,
327
+ symbolColor,
328
+ mask,
329
+ shouldStream,
330
+ streamDelay
331
+ });
332
+ if (errorMessage) {
333
+ deleteLastLine();
334
+ }
335
+ const formattedBar = bar({ borderColor });
336
+ const userInputRaw = await ask(terminal, `${formattedBar} `, mode, mask);
337
+ isRerender = true;
338
+ if (userInputRaw === null) {
339
+ return "";
340
+ }
341
+ currentInput = userInputRaw.trim();
342
+ if (showPlaceholder && currentInput !== "") {
343
+ showPlaceholder = false;
344
+ }
345
+ const finalAnswer = currentInput || defaultValue;
346
+ const validated = await validateInput(finalAnswer, validate);
347
+ if (validated.isValid) {
348
+ if (!currentInput && defaultValue) {
349
+ if (mode === "password") {
350
+ deleteLastLine();
351
+ deleteLastLine();
352
+ msg({
353
+ type: "M_MIDDLE",
354
+ title: ` ${getMaskChar(mask).repeat(defaultValue.length)}`
355
+ });
356
+ } else {
357
+ deleteLastLine();
358
+ msg({ type: "M_MIDDLE", title: ` ${re.reset(defaultValue)}` });
359
+ }
360
+ }
361
+ if (errorMessage) {
362
+ deleteLastLine();
363
+ }
364
+ msg({ type: "M_BAR", borderColor });
365
+ terminal.close();
366
+ return finalAnswer;
367
+ }
368
+ errorMessage = validated.errorMessage;
369
+ }
370
+ }
@@ -0,0 +1,2 @@
1
+ import type { Default, ParserArgv, ParserOptions } from "../../core-types.js";
2
+ export declare function parseRawArgs<T = Default>(args?: string[], opts?: ParserOptions): ParserArgv<T>;
@@ -0,0 +1,122 @@
1
+ function toArr(any) {
2
+ return any == void 0 ? [] : Array.isArray(any) ? any : [any];
3
+ }
4
+ function toVal(out, key, val, opts) {
5
+ let x;
6
+ const old = out[key];
7
+ const nxt = ~opts.string.indexOf(key) ? (
8
+ // biome-ignore lint/suspicious/noDoubleEquals: <explanation>
9
+ val == void 0 || val === true ? "" : String(val)
10
+ ) : typeof val === "boolean" ? val : ~opts.boolean.indexOf(key) ? val === "false" ? false : val === "true" || // biome-ignore lint/style/noCommaOperator: <explanation>
11
+ (out._.push((x = +val, x * 0 === 0) ? x : val), !!val) : (
12
+ // biome-ignore lint/style/noCommaOperator: <explanation>
13
+ (x = +val, x * 0 === 0) ? x : val
14
+ );
15
+ out[key] = // biome-ignore lint/suspicious/noDoubleEquals: <explanation>
16
+ old == void 0 ? nxt : Array.isArray(old) ? old.concat(nxt) : [old, nxt];
17
+ }
18
+ export function parseRawArgs(args = [], opts = {}) {
19
+ let k;
20
+ let arr;
21
+ let arg;
22
+ let name;
23
+ let val;
24
+ const out = { _: [] };
25
+ let i = 0;
26
+ let j = 0;
27
+ let idx = 0;
28
+ const len = args.length;
29
+ const alibi = opts.alias !== void 0;
30
+ const strict = opts.unknown !== void 0;
31
+ const defaults = opts.default !== void 0;
32
+ opts.alias = opts.alias || {};
33
+ opts.string = toArr(opts.string);
34
+ opts.boolean = toArr(opts.boolean);
35
+ if (alibi) {
36
+ for (k in opts.alias) {
37
+ arr = opts.alias[k] = toArr(opts.alias[k]);
38
+ for (i = 0; i < arr.length; i++) {
39
+ (opts.alias[arr[i]] = arr.concat(k)).splice(i, 1);
40
+ }
41
+ }
42
+ }
43
+ for (i = opts.boolean.length; i-- > 0; ) {
44
+ arr = opts.alias[opts.boolean[i]] || [];
45
+ for (j = arr.length; j-- > 0; ) {
46
+ opts.boolean.push(arr[j]);
47
+ }
48
+ }
49
+ for (i = opts.string.length; i-- > 0; ) {
50
+ arr = opts.alias[opts.string[i]] || [];
51
+ for (j = arr.length; j-- > 0; ) {
52
+ opts.string.push(arr[j]);
53
+ }
54
+ }
55
+ if (defaults) {
56
+ for (k in opts.default) {
57
+ name = typeof opts.default[k];
58
+ arr = opts.alias[k] = opts.alias[k] || [];
59
+ if (opts[name] !== void 0) {
60
+ opts[name].push(k);
61
+ for (i = 0; i < arr.length; i++) {
62
+ opts[name].push(arr[i]);
63
+ }
64
+ }
65
+ }
66
+ }
67
+ const keys = strict ? Object.keys(opts.alias) : [];
68
+ for (i = 0; i < len; i++) {
69
+ arg = args[i];
70
+ if (arg === "--") {
71
+ out._ = out._.concat(args.slice(++i));
72
+ break;
73
+ }
74
+ for (j = 0; j < arg.length; j++) {
75
+ if (arg.charCodeAt(j) !== 45) {
76
+ break;
77
+ }
78
+ }
79
+ if (j === 0) {
80
+ out._.push(arg);
81
+ } else if (arg.substring(j, j + 3) === "no-") {
82
+ name = arg.slice(Math.max(0, j + 3));
83
+ if (strict && !~keys.indexOf(name)) {
84
+ return opts.unknown(arg);
85
+ }
86
+ out[name] = false;
87
+ } else {
88
+ for (idx = j + 1; idx < arg.length; idx++) {
89
+ if (arg.charCodeAt(idx) === 61) {
90
+ break;
91
+ }
92
+ }
93
+ name = arg.substring(j, idx);
94
+ val = arg.slice(Math.max(0, ++idx)) || i + 1 === len || // biome-ignore lint/style/useTemplate: <explanation>
95
+ ("" + args[i + 1]).charCodeAt(0) === 45 || args[++i];
96
+ arr = j === 2 ? [name] : name;
97
+ for (idx = 0; idx < arr.length; idx++) {
98
+ name = arr[idx];
99
+ if (strict && !~keys.indexOf(name)) {
100
+ return opts.unknown("-".repeat(j) + name);
101
+ }
102
+ toVal(out, name, idx + 1 < arr.length || val, opts);
103
+ }
104
+ }
105
+ }
106
+ if (defaults) {
107
+ for (k in opts.default) {
108
+ if (out[k] === void 0) {
109
+ out[k] = opts.default[k];
110
+ }
111
+ }
112
+ }
113
+ if (alibi) {
114
+ for (k in out) {
115
+ arr = opts.alias[k] || [];
116
+ while (arr.length > 0) {
117
+ out[arr.shift()] = out[k];
118
+ }
119
+ }
120
+ }
121
+ return out;
122
+ }
@@ -0,0 +1,8 @@
1
+ import type { Resolvable } from "../../core-types.js";
2
+ export declare function toArray(val: any): any[];
3
+ export declare function formatLineColumns(lines: string[][], linePrefix?: string): string;
4
+ export declare function resolveValue<T>(input: Resolvable<T>): T | Promise<T>;
5
+ export declare class CLIError extends Error {
6
+ code?: string | undefined;
7
+ constructor(message: string, code?: string | undefined);
8
+ }
@@ -0,0 +1,29 @@
1
+ export function toArray(val) {
2
+ if (Array.isArray(val)) {
3
+ return val;
4
+ }
5
+ return val === void 0 ? [] : [val];
6
+ }
7
+ export function formatLineColumns(lines, linePrefix = "") {
8
+ const maxLength = [];
9
+ for (const line of lines) {
10
+ for (const [i, element] of line.entries()) {
11
+ maxLength[i] = Math.max(maxLength[i] || 0, element.length);
12
+ }
13
+ }
14
+ return lines.map(
15
+ (l) => l.map(
16
+ (c, i) => linePrefix + c[i === 0 ? "padStart" : "padEnd"](maxLength[i])
17
+ ).join(" ")
18
+ ).join("\n");
19
+ }
20
+ export function resolveValue(input) {
21
+ return typeof input === "function" ? input() : input;
22
+ }
23
+ export class CLIError extends Error {
24
+ constructor(message, code) {
25
+ super(message);
26
+ this.code = code;
27
+ this.name = "CLIError";
28
+ }
29
+ }
@@ -0,0 +1,3 @@
1
+ import type { Arg, ArgsDef, ParsedArgs } from "../../core-types.js";
2
+ export declare function parseArgs<T extends ArgsDef = ArgsDef>(rawArgs: string[], argsDef: ArgsDef): ParsedArgs<T>;
3
+ export declare function resolveArgs(argsDef: ArgsDef): Arg[];
@@ -0,0 +1,89 @@
1
+ import { kebabCase, camelCase } from "scule";
2
+ import { parseRawArgs } from "./_parser.js";
3
+ import { CLIError, toArray } from "./_utils.js";
4
+ export function parseArgs(rawArgs, argsDef) {
5
+ const parseOptions = {
6
+ boolean: [],
7
+ string: [],
8
+ number: [],
9
+ enum: [],
10
+ mixed: [],
11
+ alias: {},
12
+ default: {}
13
+ };
14
+ const args = resolveArgs(argsDef);
15
+ for (const arg of args) {
16
+ if (arg.type === "positional") {
17
+ continue;
18
+ }
19
+ if (arg.type === "string" || arg.type === "number") {
20
+ parseOptions.string.push(arg.name);
21
+ } else if (arg.type === "boolean") {
22
+ parseOptions.boolean.push(arg.name);
23
+ } else if (arg.type === "enum") {
24
+ parseOptions.enum.push(...arg.options || []);
25
+ }
26
+ if (arg.default !== void 0) {
27
+ parseOptions.default[arg.name] = arg.default;
28
+ }
29
+ if (arg.alias) {
30
+ parseOptions.alias[arg.name] = arg.alias;
31
+ }
32
+ }
33
+ const parsed = parseRawArgs(rawArgs, parseOptions);
34
+ const [...positionalArguments] = parsed._;
35
+ const parsedArgsProxy = new Proxy(parsed, {
36
+ get(target, prop) {
37
+ return target[prop] ?? target[camelCase(prop)] ?? target[kebabCase(prop)];
38
+ }
39
+ });
40
+ for (const [, arg] of args.entries()) {
41
+ if (arg.type === "positional") {
42
+ const nextPositionalArgument = positionalArguments.shift();
43
+ if (nextPositionalArgument !== void 0) {
44
+ parsedArgsProxy[arg.name] = nextPositionalArgument;
45
+ } else if (arg.default === void 0 && arg.required !== false) {
46
+ throw new CLIError(
47
+ `Missing required positional argument: ${arg.name.toUpperCase()}`,
48
+ "EARG"
49
+ );
50
+ } else {
51
+ parsedArgsProxy[arg.name] = arg.default;
52
+ }
53
+ } else if (arg.type === "enum") {
54
+ const argument = parsedArgsProxy[arg.name];
55
+ const options = arg.options || [];
56
+ if (argument !== void 0 && options.length > 0 && !options.includes(argument)) {
57
+ throw new CLIError(
58
+ `Invalid value for argument: \`--${arg.name}\` (\`${argument}\`). Expected one of: ${options.map((o) => `\`${o}\``).join(", ")}.`,
59
+ "EARG"
60
+ );
61
+ }
62
+ } else if (arg.type === "number") {
63
+ const _originalValue = parsedArgsProxy[arg.name];
64
+ parsedArgsProxy[arg.name] = Number.parseFloat(
65
+ parsedArgsProxy[arg.name]
66
+ );
67
+ if (Number.isNaN(parsedArgsProxy[arg.name])) {
68
+ throw new CLIError(
69
+ `Invalid value for argument: \`--${arg.name}\` (\`${_originalValue}\`). Expected a number.`,
70
+ "EARG"
71
+ );
72
+ }
73
+ } else if (arg.required && parsedArgsProxy[arg.name] === void 0) {
74
+ throw new CLIError(`Missing required argument: --${arg.name}`, "EARG");
75
+ }
76
+ }
77
+ return parsedArgsProxy;
78
+ }
79
+ export function resolveArgs(argsDef) {
80
+ const args = [];
81
+ for (const [name, argDef] of Object.entries(argsDef || {})) {
82
+ args.push({
83
+ ...argDef,
84
+ name,
85
+ alias: toArray(argDef.alias)
86
+ });
87
+ }
88
+ return args;
89
+ }
@@ -0,0 +1,8 @@
1
+ import type { ArgsDef, CommandDef, RunCommandOptions } from "../../core-types.js";
2
+ export declare function defineCommand(): any;
3
+ declare const ArgsDef: any, CommandDef: any;
4
+ export declare function runCommand<T extends ArgsDef = ArgsDef>(cmd: CommandDef<T>, opts: RunCommandOptions): Promise<{
5
+ result: unknown;
6
+ }>;
7
+ export declare function resolveSubCommand<T extends ArgsDef = ArgsDef>(cmd: CommandDef<T>, rawArgs: string[], parent?: CommandDef<T>): Promise<[CommandDef<T>, CommandDef<T>?]>;
8
+ export {};
@@ -0,0 +1,68 @@
1
+ import { CLIError, resolveValue } from "./_utils.js";
2
+ import { parseArgs } from "./args.js";
3
+ export function defineCommand(def) {
4
+ return def;
5
+ }
6
+ export async function runCommand(cmd, opts) {
7
+ const cmdArgs = await resolveValue(cmd.args || {});
8
+ const parsedArgs = parseArgs(opts.rawArgs, cmdArgs);
9
+ const context = {
10
+ rawArgs: opts.rawArgs,
11
+ args: parsedArgs,
12
+ data: opts.data,
13
+ cmd
14
+ };
15
+ if (typeof cmd.setup === "function") {
16
+ await cmd.setup(context);
17
+ }
18
+ let result;
19
+ try {
20
+ const subCommands = await resolveValue(cmd.subCommands);
21
+ if (subCommands && Object.keys(subCommands).length > 0) {
22
+ const subCommandArgIndex = opts.rawArgs.findIndex(
23
+ (arg) => !arg.startsWith("-")
24
+ );
25
+ const subCommandName = opts.rawArgs[subCommandArgIndex];
26
+ if (subCommandName) {
27
+ if (!subCommands[subCommandName]) {
28
+ throw new CLIError(
29
+ `Unknown command \`${subCommandName}\``,
30
+ "E_UNKNOWN_COMMAND"
31
+ );
32
+ }
33
+ const subCommand = await resolveValue(subCommands[subCommandName]);
34
+ if (subCommand) {
35
+ await runCommand(subCommand, {
36
+ rawArgs: opts.rawArgs.slice(subCommandArgIndex + 1)
37
+ });
38
+ }
39
+ } else if (!cmd.run) {
40
+ throw new CLIError(`No command specified.`, "E_NO_COMMAND");
41
+ }
42
+ }
43
+ if (typeof cmd.run === "function") {
44
+ result = await cmd.run(context);
45
+ }
46
+ } finally {
47
+ if (typeof cmd.cleanup === "function") {
48
+ await cmd.cleanup(context);
49
+ }
50
+ }
51
+ return { result };
52
+ }
53
+ export async function resolveSubCommand(cmd, rawArgs, parent) {
54
+ const subCommands = await resolveValue(cmd.subCommands);
55
+ if (subCommands && Object.keys(subCommands).length > 0) {
56
+ const subCommandArgIndex = rawArgs.findIndex((arg) => !arg.startsWith("-"));
57
+ const subCommandName = rawArgs[subCommandArgIndex];
58
+ const subCommand = await resolveValue(subCommands[subCommandName]);
59
+ if (subCommand) {
60
+ return resolveSubCommand(
61
+ subCommand,
62
+ rawArgs.slice(subCommandArgIndex + 1),
63
+ cmd
64
+ );
65
+ }
66
+ }
67
+ return [cmd, parent];
68
+ }