@reliverse/rempts 1.7.2 โ 1.7.3
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/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
- ๐จ Crash-safe (Ctrl+C, SIGINT, errors)
|
|
19
19
|
- ๐ช Minimal API surface, max expressiveness
|
|
20
20
|
- ๐งช Scriptable for testing, stable for production
|
|
21
|
-
- ๐ Automatic commands creation (via `dler init --cmd my-cool-cmd`)
|
|
21
|
+
- ๐ Automatic commands creation (via `dler rempts init --cmd my-cool-cmd`)
|
|
22
22
|
- ๐๏ธ No more hacking together `inquirer`, `citty`, `commander`, `chalk`
|
|
23
23
|
|
|
24
24
|
## Installation
|
|
@@ -145,6 +145,8 @@ await main();
|
|
|
145
145
|
|
|
146
146
|
#### Launcher Usage Example
|
|
147
147
|
|
|
148
|
+
**Important**: Ensure your commands don't have `await main();`, `await runMain();`, or something like that โ to prevent any unexpected behavior. Only main command should have it.
|
|
149
|
+
|
|
148
150
|
```ts
|
|
149
151
|
import { relinka } from "@reliverse/relinka";
|
|
150
152
|
|
|
@@ -220,7 +222,7 @@ export default defineCommand({
|
|
|
220
222
|
**Hint**:
|
|
221
223
|
|
|
222
224
|
- Install `bun add -D @reliverse/dler`
|
|
223
|
-
- Use `dler init --cmd cmd1 cmd2` to init commands for rempts launcher's automatically
|
|
225
|
+
- Use `dler rempts init --cmd cmd1 cmd2` to init commands for rempts launcher's automatically
|
|
224
226
|
|
|
225
227
|
### Advanced Minimal API
|
|
226
228
|
|
|
@@ -287,7 +289,7 @@ await runMain(defineCommand({}));
|
|
|
287
289
|
|
|
288
290
|
```bash
|
|
289
291
|
bun add -D @reliverse/dler # or: bun i -g @reliverse/dler
|
|
290
|
-
bun dler init --cmd my-cmd-1 # or: dler init my-cmd-1 my-cmd-2 --main src/mod.ts
|
|
292
|
+
bun dler rempts init --cmd my-cmd-1 # or: dler rempts init my-cmd-1 my-cmd-2 --main src/mod.ts
|
|
291
293
|
# * `--main` is optional, default is `./src/mod.ts`
|
|
292
294
|
# * you can specify multiple commands at once
|
|
293
295
|
```
|
|
@@ -53,6 +53,7 @@ type CommandContext<ARGS> = {
|
|
|
53
53
|
raw: string[];
|
|
54
54
|
};
|
|
55
55
|
type CommandRun<ARGS> = (ctx: CommandContext<ARGS>) => void | Promise<void>;
|
|
56
|
+
type CommandHook<ARGS> = (ctx: CommandContext<ARGS>) => void | Promise<void>;
|
|
56
57
|
type DefineCommandOptions<A extends ArgDefinitions = EmptyArgs> = {
|
|
57
58
|
meta?: CommandMeta;
|
|
58
59
|
args?: A;
|
|
@@ -66,21 +67,21 @@ type DefineCommandOptions<A extends ArgDefinitions = EmptyArgs> = {
|
|
|
66
67
|
*/
|
|
67
68
|
subCommands?: CommandsMap;
|
|
68
69
|
/**
|
|
69
|
-
* Called before the command runs
|
|
70
|
+
* Called before the command runs. Receives `{ args, raw }` (parsed args and raw argv).
|
|
70
71
|
*/
|
|
71
|
-
onCmdStart?:
|
|
72
|
+
onCmdStart?: CommandHook<InferArgTypes<A>>;
|
|
72
73
|
/**
|
|
73
|
-
* Called after the command finishes
|
|
74
|
+
* Called after the command finishes. Receives `{ args, raw }` (parsed args and raw argv).
|
|
74
75
|
*/
|
|
75
|
-
onCmdEnd?:
|
|
76
|
+
onCmdEnd?: CommandHook<InferArgTypes<A>>;
|
|
76
77
|
/**
|
|
77
78
|
* @deprecated Use onCmdStart instead
|
|
78
79
|
*/
|
|
79
|
-
setup?:
|
|
80
|
+
setup?: CommandHook<InferArgTypes<A>>;
|
|
80
81
|
/**
|
|
81
82
|
* @deprecated Use onCmdEnd instead
|
|
82
83
|
*/
|
|
83
|
-
cleanup?:
|
|
84
|
+
cleanup?: CommandHook<InferArgTypes<A>>;
|
|
84
85
|
/**
|
|
85
86
|
* Called once per CLI process, before any command/run() is executed
|
|
86
87
|
*/
|
|
@@ -103,21 +104,21 @@ export type Command<A extends ArgDefinitions = EmptyArgs> = {
|
|
|
103
104
|
*/
|
|
104
105
|
subCommands?: CommandsMap;
|
|
105
106
|
/**
|
|
106
|
-
* Called before the command runs
|
|
107
|
+
* Called before the command runs. Receives `{ args, raw }` (parsed args and raw argv).
|
|
107
108
|
*/
|
|
108
|
-
onCmdStart?:
|
|
109
|
+
onCmdStart?: CommandHook<InferArgTypes<A>>;
|
|
109
110
|
/**
|
|
110
|
-
* Called after the command finishes
|
|
111
|
+
* Called after the command finishes. Receives `{ args, raw }` (parsed args and raw argv).
|
|
111
112
|
*/
|
|
112
|
-
onCmdEnd?:
|
|
113
|
+
onCmdEnd?: CommandHook<InferArgTypes<A>>;
|
|
113
114
|
/**
|
|
114
115
|
* @deprecated Use onCmdStart instead
|
|
115
116
|
*/
|
|
116
|
-
setup?:
|
|
117
|
+
setup?: CommandHook<InferArgTypes<A>>;
|
|
117
118
|
/**
|
|
118
119
|
* @deprecated Use onCmdEnd instead
|
|
119
120
|
*/
|
|
120
|
-
cleanup?:
|
|
121
|
+
cleanup?: CommandHook<InferArgTypes<A>>;
|
|
121
122
|
/**
|
|
122
123
|
* Called once per CLI process, before any command/run() is executed
|
|
123
124
|
*/
|
|
@@ -167,7 +167,7 @@ export async function showUsage(command, parserOptions = {}, displayNotFoundMess
|
|
|
167
167
|
);
|
|
168
168
|
}
|
|
169
169
|
if (subCommandNames.length > 0) {
|
|
170
|
-
relinka("
|
|
170
|
+
relinka("info", "Available commands (run with `help` to see more):");
|
|
171
171
|
subCommandDefs.forEach(({ name, def }) => {
|
|
172
172
|
const desc = def?.meta?.description ?? "";
|
|
173
173
|
relinka("log", `\u2022 ${name}${desc ? ` | ${desc}` : ""}`);
|
|
@@ -217,14 +217,14 @@ export async function showUsage(command, parserOptions = {}, displayNotFoundMess
|
|
|
217
217
|
);
|
|
218
218
|
}
|
|
219
219
|
if (subCommandNames.length > 0) {
|
|
220
|
-
relinka("
|
|
220
|
+
relinka("info", "Available commands (run with `help` to see more):");
|
|
221
221
|
subCommandDefs.forEach(({ name, def }) => {
|
|
222
222
|
const desc = def?.meta?.description ?? "";
|
|
223
223
|
relinka("log", `\u2022 ${name}${desc ? ` | ${desc}` : ""}`);
|
|
224
224
|
});
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
|
-
relinka("
|
|
227
|
+
relinka("info", "Available options:");
|
|
228
228
|
relinka("log", "\u2022 -h, --help | Show help");
|
|
229
229
|
relinka("log", "\u2022 -v, --version | Show version");
|
|
230
230
|
relinka("log", "\u2022 --debug | Enable debug mode");
|
|
@@ -334,14 +334,17 @@ This can cause recursion or unexpected behavior.`
|
|
|
334
334
|
if (fileBasedEnabled && rawArgv.length > 0 && !isFlag(rawArgv[0])) {
|
|
335
335
|
const [subName, ...subCmdArgv] = rawArgv;
|
|
336
336
|
try {
|
|
337
|
+
const ctx = getParsedContext(command, rawArgv, parserOptions);
|
|
337
338
|
if (typeof command.onCmdStart === "function")
|
|
338
|
-
await command.onCmdStart();
|
|
339
|
+
await command.onCmdStart(ctx);
|
|
339
340
|
await runFileBasedSubCmd(
|
|
340
341
|
subName,
|
|
341
342
|
subCmdArgv,
|
|
342
343
|
parserOptions.fileBasedCmds,
|
|
343
344
|
parserOptions,
|
|
344
|
-
command.onCmdEnd
|
|
345
|
+
command.onCmdEnd ? async (_subCtx) => {
|
|
346
|
+
await command.onCmdEnd?.(ctx);
|
|
347
|
+
} : void 0
|
|
345
348
|
);
|
|
346
349
|
if (autoExit) process.exit(0);
|
|
347
350
|
return;
|
|
@@ -371,13 +374,16 @@ This can cause recursion or unexpected behavior.`
|
|
|
371
374
|
}
|
|
372
375
|
if (subSpec) {
|
|
373
376
|
try {
|
|
377
|
+
const ctx = getParsedContext(command, rawArgv, parserOptions);
|
|
374
378
|
if (typeof command.onCmdStart === "function")
|
|
375
|
-
await command.onCmdStart();
|
|
379
|
+
await command.onCmdStart(ctx);
|
|
376
380
|
await runSubCommand(
|
|
377
381
|
subSpec,
|
|
378
382
|
subCmdArgv,
|
|
379
383
|
parserOptions,
|
|
380
|
-
command.onCmdEnd
|
|
384
|
+
command.onCmdEnd ? async (_subCtx) => {
|
|
385
|
+
await command.onCmdEnd?.(ctx);
|
|
386
|
+
} : void 0
|
|
381
387
|
);
|
|
382
388
|
if (autoExit) process.exit(0);
|
|
383
389
|
return;
|
|
@@ -474,20 +480,32 @@ Info for this CLI's developer: No valid command directory found, expected: ${exp
|
|
|
474
480
|
);
|
|
475
481
|
}
|
|
476
482
|
try {
|
|
477
|
-
await runCommandWithArgs(
|
|
483
|
+
const subCtx = await runCommandWithArgs(
|
|
484
|
+
subCommand,
|
|
485
|
+
argv,
|
|
486
|
+
parserOptions,
|
|
487
|
+
true
|
|
488
|
+
);
|
|
489
|
+
if (typeof parentFinish === "function" && subCtx)
|
|
490
|
+
await parentFinish(subCtx);
|
|
478
491
|
} finally {
|
|
479
|
-
if (typeof parentFinish === "function") await parentFinish();
|
|
480
492
|
}
|
|
481
493
|
}
|
|
482
494
|
async function runSubCommand(spec, argv, parserOptions, parentFinish) {
|
|
483
495
|
const subCommand = await loadSubCommand(spec);
|
|
484
496
|
try {
|
|
485
|
-
await runCommandWithArgs(
|
|
497
|
+
const subCtx = await runCommandWithArgs(
|
|
498
|
+
subCommand,
|
|
499
|
+
argv,
|
|
500
|
+
parserOptions,
|
|
501
|
+
true
|
|
502
|
+
);
|
|
503
|
+
if (typeof parentFinish === "function" && subCtx)
|
|
504
|
+
await parentFinish(subCtx);
|
|
486
505
|
} finally {
|
|
487
|
-
if (typeof parentFinish === "function") await parentFinish();
|
|
488
506
|
}
|
|
489
507
|
}
|
|
490
|
-
async function runCommandWithArgs(command, argv, parserOptions) {
|
|
508
|
+
async function runCommandWithArgs(command, argv, parserOptions, returnCtx) {
|
|
491
509
|
const autoExit = parserOptions.autoExit !== false;
|
|
492
510
|
const booleanKeys = Object.keys(command.args || {}).filter(
|
|
493
511
|
(k) => command.args[k].type === "boolean"
|
|
@@ -593,6 +611,8 @@ ${String(err)}`);
|
|
|
593
611
|
if (autoExit) process.exit(1);
|
|
594
612
|
else throw err;
|
|
595
613
|
}
|
|
614
|
+
if (returnCtx) return ctx;
|
|
615
|
+
return void 0;
|
|
596
616
|
}
|
|
597
617
|
function castArgValue(def, rawVal, argName) {
|
|
598
618
|
if (rawVal == null) {
|
|
@@ -708,3 +728,47 @@ export async function runCmd(command, argv = [], parserOptions = {}) {
|
|
|
708
728
|
throw new Error("Command has no run() handler.");
|
|
709
729
|
}
|
|
710
730
|
}
|
|
731
|
+
function getParsedContext(command, argv, parserOptions) {
|
|
732
|
+
const booleanKeys = Object.keys(command.args || {}).filter(
|
|
733
|
+
(k) => command.args[k].type === "boolean"
|
|
734
|
+
);
|
|
735
|
+
const defaultMap = {};
|
|
736
|
+
for (const [argKey, def] of Object.entries(command.args || {})) {
|
|
737
|
+
if (def.default !== void 0) {
|
|
738
|
+
if (def.type === "array" && typeof def.default === "string") {
|
|
739
|
+
defaultMap[argKey] = [def.default];
|
|
740
|
+
} else {
|
|
741
|
+
defaultMap[argKey] = def.default;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
const mergedParserOptions = {
|
|
746
|
+
...parserOptions,
|
|
747
|
+
boolean: [...parserOptions.boolean || [], ...booleanKeys],
|
|
748
|
+
defaults: { ...defaultMap, ...parserOptions.defaults || {} }
|
|
749
|
+
};
|
|
750
|
+
const parsed = reliArgParser(argv, mergedParserOptions);
|
|
751
|
+
const finalArgs = {};
|
|
752
|
+
const positionalKeys = Object.keys(command.args || {}).filter(
|
|
753
|
+
(k) => command.args[k].type === "positional"
|
|
754
|
+
);
|
|
755
|
+
const leftoverPositionals = [...parsed._ || []];
|
|
756
|
+
for (let i = 0; i < positionalKeys.length; i++) {
|
|
757
|
+
const key = positionalKeys[i];
|
|
758
|
+
const def = command.args?.[key];
|
|
759
|
+
const val = leftoverPositionals[i];
|
|
760
|
+
finalArgs[key] = val != null ? castArgValue(def, val, key) : def.default;
|
|
761
|
+
}
|
|
762
|
+
const otherKeys = Object.keys(command.args || {}).filter(
|
|
763
|
+
(k) => command.args[k].type !== "positional"
|
|
764
|
+
);
|
|
765
|
+
for (const key of otherKeys) {
|
|
766
|
+
const def = command.args?.[key];
|
|
767
|
+
let rawVal = parsed[key];
|
|
768
|
+
if (def.type === "array" && rawVal !== void 0 && !Array.isArray(rawVal)) {
|
|
769
|
+
rawVal = [rawVal];
|
|
770
|
+
}
|
|
771
|
+
finalArgs[key] = castArgValue(def, rawVal, key);
|
|
772
|
+
}
|
|
773
|
+
return { args: finalArgs, raw: argv };
|
|
774
|
+
}
|