@reliverse/rempts 1.7.38 → 1.7.40
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 +73 -10
- package/bin/libs/launcher/launcher-mod.d.ts +49 -1
- package/bin/libs/launcher/launcher-mod.js +45 -2
- package/bin/libs/launcher/run-command.d.ts +16 -0
- package/bin/libs/launcher/run-command.js +0 -2
- package/bin/mod.d.ts +1 -1
- package/bin/mod.js +2 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# 📃 rempts • powerful js/ts cli builder
|
|
2
2
|
|
|
3
|
-
> @reliverse/rempts is a modern, type-safe toolkit for building delightful cli experiences. it's fast, flexible, and made for developer happiness. file-based commands keep things simple—no clutter, just clean and easy workflows. this is how cli should feel.
|
|
4
|
-
|
|
5
3
|
[sponsor](https://github.com/sponsors/blefnk) — [discord](https://discord.gg/Pb8uKbwpsJ) — [repo](https://github.com/reliverse/rempts) — [npm](https://npmjs.com/@reliverse/rempts)
|
|
6
4
|
|
|
5
|
+
> @reliverse/rempts is a modern, type-safe toolkit for building delightful cli experiences. it's fast, flexible, and made for developer happiness. file-based commands keep things simple—no clutter, just clean and easy workflows. this is how cli should feel.
|
|
6
|
+
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
- 😘 drop-in to libraries like `unjs/citty` and `@clack/prompts`
|
|
@@ -36,14 +36,6 @@
|
|
|
36
36
|
bun add @reliverse/rempts
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
**Coming soon**:
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
bun add -D @reliverse/dler
|
|
43
|
-
bun dler rempts --init cmd1 cmd2 # creates `src/app/cmd1/cmd.ts` and `src/app/cmd2/cmd.ts` files
|
|
44
|
-
bun dler rempts # creates `src/app/cmds.ts` file
|
|
45
|
-
```
|
|
46
|
-
|
|
47
39
|
## Usage Examples
|
|
48
40
|
|
|
49
41
|
- [Prompts](#prompts)
|
|
@@ -222,6 +214,14 @@ await main();
|
|
|
222
214
|
|
|
223
215
|
> **Note**: `runMain` is now an alias for `createCli` and is still supported for backward compatibility. The new `createCli` API provides a more intuitive object-based configuration format.
|
|
224
216
|
|
|
217
|
+
### Automatic command creation
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
bun add -D @reliverse/dler
|
|
221
|
+
bun dler rempts --init cmd1 cmd2 # creates `src/app/cmd1/cmd.ts` and `src/app/cmd2/cmd.ts` files
|
|
222
|
+
bun dler rempts # creates `src/app/cmds.ts` file
|
|
223
|
+
```
|
|
224
|
+
|
|
225
225
|
### Terminology
|
|
226
226
|
|
|
227
227
|
- **Launcher/Router**: The main entry point for your CLI. Visit [CLI Launcher (Router)](#cli-launcher-router) section to learn more.
|
|
@@ -837,6 +837,37 @@ export default defineCommand({
|
|
|
837
837
|
});
|
|
838
838
|
```
|
|
839
839
|
|
|
840
|
+
### Using `runCmd` with Flexible Argument Handling
|
|
841
|
+
|
|
842
|
+
The `runCmd` function supports flexible argument passing, automatically normalizing template literals and space-separated strings:
|
|
843
|
+
|
|
844
|
+
```ts
|
|
845
|
+
import { runCmd } from "@reliverse/rempts";
|
|
846
|
+
|
|
847
|
+
// Traditional way - each argument as separate array element
|
|
848
|
+
await runCmd(cmd, ["--dev", "true", "--name", "John"]);
|
|
849
|
+
|
|
850
|
+
// Template literals work automatically
|
|
851
|
+
await runCmd(cmd, [`--dev ${isDev}`]); // Automatically converted to ["--dev", "true"]
|
|
852
|
+
await runCmd(cmd, [`--dev ${isDev} --build mod.ts`]); // ["--dev", "true", "--build", "mod.ts"]
|
|
853
|
+
|
|
854
|
+
// Mixed arrays with template literals and regular strings
|
|
855
|
+
await runCmd(cmd, [
|
|
856
|
+
`--dev ${isDev} --build mod.ts`,
|
|
857
|
+
"--pub true",
|
|
858
|
+
"--someBoolean",
|
|
859
|
+
]);
|
|
860
|
+
|
|
861
|
+
// Multiple template literals
|
|
862
|
+
await runCmd(cmd, [`--dev ${isDev}`, `--name ${userName}`, `--count ${count}`]);
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
**Remember**:
|
|
866
|
+
|
|
867
|
+
- If you need to pass a value with spaces (e.g. a name like "John Doe"), you should quote it in your template literal: `await runCmd(cmd, ['--name "John Doe"']);`
|
|
868
|
+
- Otherwise, it will be split into two arguments: `"John"` and `"Doe"`.
|
|
869
|
+
- We do not handle this intentionally, because some library users might rely on this Node.js behavior and handle it themselves in their own way (e.g. space can serve as a separator for values).
|
|
870
|
+
|
|
840
871
|
### Loading Commands with `loadCommand`
|
|
841
872
|
|
|
842
873
|
The `loadCommand` utility helps you load command files from your filesystem. It automatically handles:
|
|
@@ -926,6 +957,37 @@ export default defineCommand({
|
|
|
926
957
|
});
|
|
927
958
|
```
|
|
928
959
|
|
|
960
|
+
### Using `runCmdWithSubcommands` for Subcommands and Nested Subcommands
|
|
961
|
+
|
|
962
|
+
If you need to programmatically run commands that support subcommands (including nested subcommands), use `runCmdWithSubcommands`:
|
|
963
|
+
|
|
964
|
+
```ts
|
|
965
|
+
import { runCmdWithSubcommands } from "@reliverse/rempts";
|
|
966
|
+
|
|
967
|
+
// Single-level subcommand
|
|
968
|
+
await runCmdWithSubcommands(mainCmd, [`build --input src/mod.ts --someBoolean`]);
|
|
969
|
+
|
|
970
|
+
// Subcommand with positional arguments
|
|
971
|
+
await runCmdWithSubcommands(mainCmd, [`build src/mod.ts --someBoolean`]);
|
|
972
|
+
|
|
973
|
+
// Nested subcommands
|
|
974
|
+
await runCmdWithSubcommands(mainCmd, [`build someSubCmd src/mod.ts --no-cjs`]);
|
|
975
|
+
await runCmdWithSubcommands(mainCmd, [`build sub1 sub2 sub3 file.ts --flag`]);
|
|
976
|
+
|
|
977
|
+
// Mixed array with subcommands
|
|
978
|
+
await runCmdWithSubcommands(mainCmd, [
|
|
979
|
+
`build someSubCmd src/mod.ts`,
|
|
980
|
+
"--no-cjs",
|
|
981
|
+
"--verbose"
|
|
982
|
+
]);
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
**Note:**
|
|
986
|
+
|
|
987
|
+
- `runCmdWithSubcommands` automatically normalizes template literals and space-separated strings, just like `runCmd`.
|
|
988
|
+
- If you need to pass a value with spaces (e.g. a name like "John Doe"), you should quote it in your template literal: `await runCmdWithSubcommands(cmd, ['--name "John Doe"']);`
|
|
989
|
+
- For subcommands, always use `runCmdWithSubcommands` for the most robust behavior.
|
|
990
|
+
|
|
929
991
|
## Argument Types: Usage Comparison
|
|
930
992
|
|
|
931
993
|
Below is a demonstration of how to define and use all supported argument types in rempts: positional, boolean, string, number, and array. This includes example CLI invocations and the resulting parsed output.
|
|
@@ -1179,6 +1241,7 @@ All APIs are fully typed. See [`src/types.ts`](./src/types.ts) for advanced cust
|
|
|
1179
1241
|
## TODO
|
|
1180
1242
|
|
|
1181
1243
|
- [ ] migrate to `dler libs` in the future (all main components will be published as separate packages; `@reliverse/rempts` will be a wrapper for all of them)
|
|
1244
|
+
- [ ] migrate all tests to `bun:test`
|
|
1182
1245
|
|
|
1183
1246
|
## Related
|
|
1184
1247
|
|
|
@@ -102,13 +102,61 @@ export declare function createCli<A extends ArgDefinitions = EmptyArgs>(options:
|
|
|
102
102
|
* for IntelliSense and validation for array defaults against options.
|
|
103
103
|
*/
|
|
104
104
|
export declare function defineArgs<A extends ArgDefinitions>(args: A): A;
|
|
105
|
+
/**
|
|
106
|
+
* Programmatically run a command with subcommand support and flexible argument handling.
|
|
107
|
+
* This function can handle subcommands (including nested), positional arguments, and automatically normalizes
|
|
108
|
+
* template literals and space-separated strings.
|
|
109
|
+
*
|
|
110
|
+
* @param command The command definition (from defineCommand)
|
|
111
|
+
* @param argv The argv array to parse (default: []). Supports template literals and subcommands.
|
|
112
|
+
* @param parserOptions Optional reliArgParser options
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* // ✅ Single command with template literals
|
|
117
|
+
* await runCmdWithSubcommands(cmd, [`--dev ${isDev}`]);
|
|
118
|
+
*
|
|
119
|
+
* // ✅ Subcommand with arguments
|
|
120
|
+
* await runCmdWithSubcommands(cmd, [`build --input src/mod.ts --someBoolean`]);
|
|
121
|
+
*
|
|
122
|
+
* // ✅ Subcommand with positional arguments
|
|
123
|
+
* await runCmdWithSubcommands(cmd, [`build src/mod.ts --someBoolean`]);
|
|
124
|
+
*
|
|
125
|
+
* // ✅ Nested subcommands
|
|
126
|
+
* await runCmdWithSubcommands(cmd, [`build someSubCmd src/mod.ts --no-cjs`]);
|
|
127
|
+
* await runCmdWithSubcommands(cmd, [`build sub1 sub2 sub3 file.ts --flag`]);
|
|
128
|
+
*
|
|
129
|
+
* // ✅ Mixed array with subcommands
|
|
130
|
+
* await runCmdWithSubcommands(cmd, [
|
|
131
|
+
* `build someSubCmd src/mod.ts`,
|
|
132
|
+
* "--no-cjs",
|
|
133
|
+
* "--verbose"
|
|
134
|
+
* ]);
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export declare function runCmdWithSubcommands<A extends ArgDefinitions = EmptyArgs>(command: Command<A>, argv?: string[], parserOptions?: ReliArgParserOptions & {
|
|
138
|
+
fileBased?: FileBasedOptions;
|
|
139
|
+
autoExit?: boolean;
|
|
140
|
+
}): Promise<any>;
|
|
105
141
|
/**
|
|
106
142
|
* Programmatically run a command's run() handler with parsed arguments.
|
|
107
143
|
* Does not handle subcommands, file-based commands, or global hooks.
|
|
108
144
|
* Suitable for use in demos, tests, or programmatic invocation.
|
|
109
145
|
*
|
|
110
146
|
* @param command The command definition (from defineCommand)
|
|
111
|
-
* @param argv The argv array to parse (default: [])
|
|
147
|
+
* @param argv The argv array to parse (default: []). Each argument should be a separate array element.
|
|
112
148
|
* @param parserOptions Optional reliArgParser options
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* **each argument as separate array element**:
|
|
152
|
+
* ```ts
|
|
153
|
+
* await runCmd(cmd, ["--dev", "true"]);
|
|
154
|
+
* await runCmd(cmd, ["--name", "John", "--verbose"]);
|
|
155
|
+
* ```
|
|
156
|
+
* **automatic normalization of template literals**:
|
|
157
|
+
* ```ts
|
|
158
|
+
* await runCmd(cmd, [`--dev ${isDev}`]); // Automatically converted to ["--dev", "true"]
|
|
159
|
+
* await runCmd(cmd, [`--dev ${isDev} --build mod.ts`]); // ["--dev", "true", "--build", "mod.ts"]
|
|
160
|
+
* ```
|
|
113
161
|
*/
|
|
114
162
|
export declare function runCmd<A extends ArgDefinitions = EmptyArgs>(command: Command<A>, argv?: string[], parserOptions?: ReliArgParserOptions): Promise<void>;
|
|
@@ -1002,7 +1002,49 @@ function renderPositional(args) {
|
|
|
1002
1002
|
export function defineArgs(args) {
|
|
1003
1003
|
return args;
|
|
1004
1004
|
}
|
|
1005
|
+
function normalizeArgv(argv) {
|
|
1006
|
+
const normalized = [];
|
|
1007
|
+
for (const arg of argv) {
|
|
1008
|
+
const parts = arg.split(/\s+/).filter((part) => part.length > 0);
|
|
1009
|
+
normalized.push(...parts);
|
|
1010
|
+
}
|
|
1011
|
+
return normalized;
|
|
1012
|
+
}
|
|
1013
|
+
export async function runCmdWithSubcommands(command, argv = [], parserOptions = {}) {
|
|
1014
|
+
const normalizedArgv = normalizeArgv(argv);
|
|
1015
|
+
let currentCommand = command;
|
|
1016
|
+
let currentArgv = normalizedArgv;
|
|
1017
|
+
while (currentCommand.commands && currentArgv.length > 0 && currentArgv[0] && !isFlag(currentArgv[0])) {
|
|
1018
|
+
const [maybeSub, ...restArgv] = currentArgv;
|
|
1019
|
+
let subSpec;
|
|
1020
|
+
for (const [key, spec] of Object.entries(currentCommand.commands)) {
|
|
1021
|
+
if (key === maybeSub) {
|
|
1022
|
+
subSpec = spec;
|
|
1023
|
+
break;
|
|
1024
|
+
}
|
|
1025
|
+
try {
|
|
1026
|
+
const cmd = await loadSubCommand(spec);
|
|
1027
|
+
if (cmd.meta?.aliases?.includes(maybeSub)) {
|
|
1028
|
+
subSpec = spec;
|
|
1029
|
+
break;
|
|
1030
|
+
}
|
|
1031
|
+
} catch (err) {
|
|
1032
|
+
debugLog(`Error checking alias for command ${key}:`, err);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
if (!subSpec) break;
|
|
1036
|
+
const loaded = await loadSubCommand(subSpec);
|
|
1037
|
+
currentCommand = loaded;
|
|
1038
|
+
currentArgv = restArgv;
|
|
1039
|
+
}
|
|
1040
|
+
return await runCommandWithArgs(currentCommand, currentArgv, {
|
|
1041
|
+
...parserOptions,
|
|
1042
|
+
autoExit: false
|
|
1043
|
+
// Don't exit process in programmatic usage
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1005
1046
|
export async function runCmd(command, argv = [], parserOptions = {}) {
|
|
1047
|
+
const normalizedArgv = normalizeArgv(argv);
|
|
1006
1048
|
const booleanKeys = Object.keys(command.args || {}).filter(
|
|
1007
1049
|
(k) => command.args?.[k]?.type === "boolean"
|
|
1008
1050
|
);
|
|
@@ -1019,7 +1061,7 @@ export async function runCmd(command, argv = [], parserOptions = {}) {
|
|
|
1019
1061
|
boolean: [...parserOptions.boolean || [], ...booleanKeys],
|
|
1020
1062
|
defaults: { ...defaultMap, ...parserOptions.defaults || {} }
|
|
1021
1063
|
};
|
|
1022
|
-
const parsed = reliArgParser(
|
|
1064
|
+
const parsed = reliArgParser(normalizedArgv, mergedParserOptions);
|
|
1023
1065
|
debugLog("Parsed arguments (runCmd):", parsed);
|
|
1024
1066
|
const finalArgs = {};
|
|
1025
1067
|
const positionalKeys = Object.keys(command.args || {}).filter(
|
|
@@ -1073,6 +1115,7 @@ export async function runCmd(command, argv = [], parserOptions = {}) {
|
|
|
1073
1115
|
}
|
|
1074
1116
|
}
|
|
1075
1117
|
function getParsedContext(command, argv, parserOptions) {
|
|
1118
|
+
const normalizedArgv = normalizeArgv(argv);
|
|
1076
1119
|
const booleanKeys = Object.keys(command.args || {}).filter(
|
|
1077
1120
|
(k) => command.args?.[k]?.type === "boolean"
|
|
1078
1121
|
);
|
|
@@ -1089,7 +1132,7 @@ function getParsedContext(command, argv, parserOptions) {
|
|
|
1089
1132
|
boolean: [...parserOptions.boolean || [], ...booleanKeys],
|
|
1090
1133
|
defaults: { ...defaultMap, ...parserOptions.defaults || {} }
|
|
1091
1134
|
};
|
|
1092
|
-
const parsed = reliArgParser(
|
|
1135
|
+
const parsed = reliArgParser(normalizedArgv, mergedParserOptions);
|
|
1093
1136
|
const finalArgs = {};
|
|
1094
1137
|
const positionalKeys = Object.keys(command.args || {}).filter(
|
|
1095
1138
|
(k) => command.args?.[k]?.type === "positional"
|
|
@@ -1,2 +1,18 @@
|
|
|
1
1
|
import type { Command } from "./launcher-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Load a command from the filesystem.
|
|
4
|
+
*
|
|
5
|
+
* @param cmdPath - Path to the command file or directory containing cmd.ts/cmd.js
|
|
6
|
+
* @returns Promise<Command> - The loaded command
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* // Load a command
|
|
11
|
+
* const cmd = await loadCommand("./web/cmd");
|
|
12
|
+
*
|
|
13
|
+
* // Use with runCmd - pass args as separate array elements
|
|
14
|
+
* await runCmd(cmd, ["--dev", "true"]); // ✅ Correct
|
|
15
|
+
* await runCmd(cmd, [`--dev ${isDev}`]); // ❌ Wrong - creates single string
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
2
18
|
export declare function loadCommand(cmdPath: string): Promise<Command>;
|
|
@@ -23,9 +23,7 @@ const getCallerDirectory = () => {
|
|
|
23
23
|
const tryLoadCommand = async (path) => {
|
|
24
24
|
if (!await fs.pathExists(path)) return null;
|
|
25
25
|
try {
|
|
26
|
-
relinka("verbose", `Attempting to load command from: ${path}`);
|
|
27
26
|
const cmd = await jiti.import(path, { default: true });
|
|
28
|
-
relinka("verbose", `Successfully loaded command from: ${path}`);
|
|
29
27
|
return cmd;
|
|
30
28
|
} catch {
|
|
31
29
|
relinka("verbose", `Failed to load ${path} as a command file`);
|
package/bin/mod.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export { inputPrompt } from "./libs/input/input-mod.js";
|
|
|
14
14
|
export { startPrompt, intro } from "./libs/intro/intro-alias.js";
|
|
15
15
|
export { introPrompt } from "./libs/intro/intro-mod.js";
|
|
16
16
|
export { runMain } from "./libs/launcher/launcher-alias.js";
|
|
17
|
-
export { defineCommand, showUsage, createCli, defineArgs, runCmd, } from "./libs/launcher/launcher-mod.js";
|
|
17
|
+
export { defineCommand, showUsage, createCli, defineArgs, runCmd, runCmdWithSubcommands, } from "./libs/launcher/launcher-mod.js";
|
|
18
18
|
export type { EmptyArgs, BaseArgProps, BaseArgDefinition, PositionalArgDefinition, BooleanArgDefinition, StringArgDefinition, NumberArgDefinition, ArrayArgDefinition, ArgDefinition, ArgDefinitions, CommandMeta, CommandSpec, CommandsMap, CommandContext, CommandRun, CommandHook, DefineCommandOptions, Command, InferArgTypes, FileBasedOptions, } from "./libs/launcher/launcher-types.js";
|
|
19
19
|
export { loadCommand } from "./libs/launcher/run-command.js";
|
|
20
20
|
export { addCompletions } from "./libs/launcher/trpc-orpc-support/completions.js";
|
package/bin/mod.js
CHANGED
|
@@ -30,7 +30,8 @@ export {
|
|
|
30
30
|
showUsage,
|
|
31
31
|
createCli,
|
|
32
32
|
defineArgs,
|
|
33
|
-
runCmd
|
|
33
|
+
runCmd,
|
|
34
|
+
runCmdWithSubcommands
|
|
34
35
|
} from "./libs/launcher/launcher-mod.js";
|
|
35
36
|
export { loadCommand } from "./libs/launcher/run-command.js";
|
|
36
37
|
export { addCompletions } from "./libs/launcher/trpc-orpc-support/completions.js";
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"@reliverse/reliarg": "^1.0.3",
|
|
9
9
|
"@reliverse/relico": "^1.1.2",
|
|
10
10
|
"@reliverse/relifso": "^1.4.5",
|
|
11
|
-
"@reliverse/relinka": "^1.5.
|
|
11
|
+
"@reliverse/relinka": "^1.5.3",
|
|
12
12
|
"@reliverse/runtime": "^1.0.3",
|
|
13
13
|
"@trpc/server": "^11.4.2",
|
|
14
14
|
"ansi-escapes": "^7.0.0",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"license": "MIT",
|
|
45
45
|
"name": "@reliverse/rempts",
|
|
46
46
|
"type": "module",
|
|
47
|
-
"version": "1.7.
|
|
47
|
+
"version": "1.7.40",
|
|
48
48
|
"author": "reliverse",
|
|
49
49
|
"bugs": {
|
|
50
50
|
"email": "blefnk@gmail.com",
|