@reliverse/rempts 1.7.5 → 1.7.7
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.
|
@@ -163,7 +163,10 @@ export declare function showUsage<A extends ArgDefinitions>(command: Command<A>,
|
|
|
163
163
|
metaSettings?: {
|
|
164
164
|
showDescriptionOnMain?: boolean;
|
|
165
165
|
};
|
|
166
|
-
|
|
166
|
+
_fileBasedCurrentDir?: string;
|
|
167
|
+
_fileBasedPathSegments?: string[];
|
|
168
|
+
_isSubcommand?: boolean;
|
|
169
|
+
}): Promise<void>;
|
|
167
170
|
/**
|
|
168
171
|
* Primary entry point to run a command. This function supports:
|
|
169
172
|
*
|
|
@@ -105,11 +105,34 @@ async function getDefaultCliNameAndVersion() {
|
|
|
105
105
|
return { name: "cli", version: void 0 };
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
-
|
|
108
|
+
async function findDirectFileBasedSubcommands(currentDir) {
|
|
109
|
+
const results = [];
|
|
110
|
+
const items = await fs.readdir(currentDir, { withFileTypes: true });
|
|
111
|
+
for (const dirent of items) {
|
|
112
|
+
if (dirent.isDirectory()) {
|
|
113
|
+
for (const fname of ["cmd.ts", "cmd.js"]) {
|
|
114
|
+
const fpath = path.join(currentDir, dirent.name, fname);
|
|
115
|
+
if (await fs.pathExists(fpath)) {
|
|
116
|
+
try {
|
|
117
|
+
const imported = await import(path.resolve(fpath));
|
|
118
|
+
if (imported.default && !imported.default.meta?.hidden) {
|
|
119
|
+
results.push({ name: dirent.name, def: imported.default });
|
|
120
|
+
}
|
|
121
|
+
} catch (err) {
|
|
122
|
+
debugLog(`Skipping file-based subcommand in ${fpath}:`, err);
|
|
123
|
+
}
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return results;
|
|
130
|
+
}
|
|
131
|
+
export async function showUsage(command, parserOptions = {}) {
|
|
109
132
|
const { name: fallbackName, version: fallbackVersion } = await getDefaultCliNameAndVersion();
|
|
110
133
|
const cliName = command.meta?.name || fallbackName;
|
|
111
134
|
const cliVersion = command.meta?.version || fallbackVersion;
|
|
112
|
-
relinka("
|
|
135
|
+
relinka("info", `${cliName}${cliVersion ? ` v${cliVersion}` : ""}`);
|
|
113
136
|
if (parserOptions.metaSettings?.showDescriptionOnMain) {
|
|
114
137
|
let description = command.meta?.description;
|
|
115
138
|
if (!description) {
|
|
@@ -123,64 +146,40 @@ export async function showUsage(command, parserOptions = {}, displayNotFoundMess
|
|
|
123
146
|
relinka("log", description);
|
|
124
147
|
}
|
|
125
148
|
}
|
|
149
|
+
const { name: pkgName } = await getDefaultCliNameAndVersion();
|
|
126
150
|
const fileCmds = parserOptions.fileBasedCmds;
|
|
127
151
|
if (fileCmds?.enable) {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
} catch (err) {
|
|
156
|
-
debugLog(`Skipping file-based subcommand in ${name}:`, err);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
if (subCommandDefs.length > 0) {
|
|
161
|
-
const randomIdx = Math.floor(Math.random() * subCommandDefs.length);
|
|
162
|
-
const { name: exampleCmd, def: exampleDef } = subCommandDefs[randomIdx];
|
|
163
|
-
const exampleArgs = buildExampleArgs(exampleDef.args || {});
|
|
152
|
+
const commandsDir = path.resolve(fileCmds.cmdsRootPath);
|
|
153
|
+
const currentDir = parserOptions._fileBasedCurrentDir || commandsDir;
|
|
154
|
+
const pathSegments = parserOptions._fileBasedPathSegments || [];
|
|
155
|
+
let usageLine = [pkgName, ...pathSegments].join(" ");
|
|
156
|
+
const directSubs = await findDirectFileBasedSubcommands(currentDir);
|
|
157
|
+
if (directSubs.length > 0) {
|
|
158
|
+
usageLine += " <command> [command's options]";
|
|
159
|
+
} else {
|
|
160
|
+
usageLine += " [command's options]";
|
|
161
|
+
const pos = renderPositional(command.args);
|
|
162
|
+
if (pos) usageLine += ` ${pos}`;
|
|
163
|
+
}
|
|
164
|
+
relinka("log", `Usage: ${usageLine}`);
|
|
165
|
+
if (directSubs.length > 0) {
|
|
166
|
+
const randomIdx = Math.floor(Math.random() * directSubs.length);
|
|
167
|
+
const { name: exampleCmd, def: exampleDef } = directSubs[randomIdx];
|
|
168
|
+
const exampleArgs = buildExampleArgs(exampleDef.args || {});
|
|
169
|
+
relinka(
|
|
170
|
+
"log",
|
|
171
|
+
`Example: ${pkgName} ${[...pathSegments, exampleCmd].join(" ")}${exampleArgs ? ` ${exampleArgs}` : ""}`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
if (directSubs.length > 0) {
|
|
175
|
+
relinka("info", "Available commands (run with `help` to see more):");
|
|
176
|
+
directSubs.forEach(({ name, def }) => {
|
|
177
|
+
const desc = def?.meta?.description ?? "";
|
|
164
178
|
relinka(
|
|
165
179
|
"log",
|
|
166
|
-
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
if (subCommandNames.length > 0) {
|
|
170
|
-
relinka("info", "Available commands (run with `help` to see more):");
|
|
171
|
-
subCommandDefs.forEach(({ name, def }) => {
|
|
172
|
-
const desc = def?.meta?.description ?? "";
|
|
173
|
-
relinka("log", `\u2022 ${name}${desc ? ` | ${desc}` : ""}`);
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
} catch (err) {
|
|
177
|
-
if (displayNotFoundMessage) {
|
|
178
|
-
relinka(
|
|
179
|
-
"warn",
|
|
180
|
-
`No file-based subcommands found in ${fileCmds.cmdsRootPath}`
|
|
180
|
+
`\u2022 ${[...pathSegments, name].join(" ")}${desc ? ` | ${desc}` : ""}`
|
|
181
181
|
);
|
|
182
|
-
}
|
|
183
|
-
debugLog("Error reading file-based commands:", err);
|
|
182
|
+
});
|
|
184
183
|
}
|
|
185
184
|
} else {
|
|
186
185
|
const subCommandNames = [];
|
|
@@ -200,7 +199,10 @@ export async function showUsage(command, parserOptions = {}, displayNotFoundMess
|
|
|
200
199
|
}
|
|
201
200
|
}
|
|
202
201
|
}
|
|
203
|
-
let usageLine =
|
|
202
|
+
let usageLine = pkgName;
|
|
203
|
+
if (parserOptions._isSubcommand) {
|
|
204
|
+
usageLine += ` ${cliName}`;
|
|
205
|
+
}
|
|
204
206
|
if (subCommandNames.length > 0) {
|
|
205
207
|
usageLine += " <command> [command's options]";
|
|
206
208
|
} else {
|
|
@@ -213,7 +215,7 @@ export async function showUsage(command, parserOptions = {}, displayNotFoundMess
|
|
|
213
215
|
const exampleArgs = buildExampleArgs(exampleDef.args || {});
|
|
214
216
|
relinka(
|
|
215
217
|
"log",
|
|
216
|
-
`Example: ${cliName} ${exampleCmd}${exampleArgs ? ` ${exampleArgs}` : ""}`
|
|
218
|
+
`Example: ${pkgName}${parserOptions._isSubcommand ? ` ${cliName}` : ""} ${exampleCmd}${exampleArgs ? ` ${exampleArgs}` : ""}`
|
|
217
219
|
);
|
|
218
220
|
}
|
|
219
221
|
if (subCommandNames.length > 0) {
|
|
@@ -309,26 +311,26 @@ This can cause recursion or unexpected behavior.`
|
|
|
309
311
|
);
|
|
310
312
|
process.exit(1);
|
|
311
313
|
}
|
|
312
|
-
if (rawArgv
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
if (checkVersion(rawArgv)) {
|
|
324
|
-
if (command.meta?.name) {
|
|
325
|
-
relinka(
|
|
326
|
-
"log",
|
|
327
|
-
`${command.meta?.name} ${command.meta?.version ? `v${command.meta?.version}` : ""}`
|
|
314
|
+
if (parserOptions.fileBasedCmds?.enable && rawArgv.length > 0) {
|
|
315
|
+
const commandsDir = path.resolve(
|
|
316
|
+
parserOptions.fileBasedCmds.cmdsRootPath
|
|
317
|
+
);
|
|
318
|
+
const resolved = await resolveFileBasedCommandPath(commandsDir, rawArgv);
|
|
319
|
+
if (resolved) {
|
|
320
|
+
const { def: subCommand, leftoverArgv, path: pathSegments } = resolved;
|
|
321
|
+
const helpIdx = leftoverArgv.findIndex(
|
|
322
|
+
(arg) => arg === "help" || arg === "--help" || arg === "-h"
|
|
328
323
|
);
|
|
324
|
+
if (helpIdx !== -1) {
|
|
325
|
+
await showUsage(subCommand, {
|
|
326
|
+
...parserOptions,
|
|
327
|
+
_fileBasedCurrentDir: pathSegments.length ? path.join(commandsDir, ...pathSegments) : commandsDir,
|
|
328
|
+
_fileBasedPathSegments: pathSegments
|
|
329
|
+
});
|
|
330
|
+
if (autoExit) process.exit(0);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
329
333
|
}
|
|
330
|
-
if (autoExit) process.exit(0);
|
|
331
|
-
return;
|
|
332
334
|
}
|
|
333
335
|
const fileBasedEnabled = parserOptions.fileBasedCmds?.enable;
|
|
334
336
|
if (fileBasedEnabled && rawArgv.length > 0 && !isFlag(rawArgv[0])) {
|
|
@@ -373,6 +375,18 @@ This can cause recursion or unexpected behavior.`
|
|
|
373
375
|
}
|
|
374
376
|
}
|
|
375
377
|
if (subSpec) {
|
|
378
|
+
const helpIdx = subCmdArgv.findIndex(
|
|
379
|
+
(arg) => arg === "help" || arg === "--help" || arg === "-h"
|
|
380
|
+
);
|
|
381
|
+
if (helpIdx !== -1) {
|
|
382
|
+
const subCommandDef = await loadSubCommand(subSpec);
|
|
383
|
+
await showUsage(subCommandDef, {
|
|
384
|
+
...parserOptions,
|
|
385
|
+
_isSubcommand: true
|
|
386
|
+
});
|
|
387
|
+
if (autoExit) process.exit(0);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
376
390
|
try {
|
|
377
391
|
const ctx = getParsedContext(command, rawArgv, parserOptions);
|
|
378
392
|
if (typeof command.onCmdInit === "function")
|
|
@@ -380,7 +394,7 @@ This can cause recursion or unexpected behavior.`
|
|
|
380
394
|
await runSubCommand(
|
|
381
395
|
subSpec,
|
|
382
396
|
subCmdArgv,
|
|
383
|
-
parserOptions,
|
|
397
|
+
{ ...parserOptions, _isSubcommand: true },
|
|
384
398
|
command.onCmdExit ? async (_subCtx) => {
|
|
385
399
|
await command.onCmdExit?.(ctx);
|
|
386
400
|
} : void 0
|
|
@@ -394,6 +408,22 @@ This can cause recursion or unexpected behavior.`
|
|
|
394
408
|
}
|
|
395
409
|
}
|
|
396
410
|
}
|
|
411
|
+
await relinkaConfig;
|
|
412
|
+
if (rawArgv[0] === "help" || checkHelp(rawArgv)) {
|
|
413
|
+
await showUsage(command, parserOptions);
|
|
414
|
+
if (autoExit) process.exit(0);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (checkVersion(rawArgv)) {
|
|
418
|
+
if (command.meta?.name) {
|
|
419
|
+
relinka(
|
|
420
|
+
"info",
|
|
421
|
+
`${command.meta?.name} ${command.meta?.version ? `v${command.meta?.version}` : ""}`
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
if (autoExit) process.exit(0);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
397
427
|
try {
|
|
398
428
|
await runCommandWithArgs(command, rawArgv, parserOptions);
|
|
399
429
|
} finally {
|
|
@@ -500,6 +530,14 @@ Info for this CLI's developer: No valid command directory found, expected: ${exp
|
|
|
500
530
|
async function runSubCommand(spec, argv, parserOptions, parentFinish) {
|
|
501
531
|
const subCommand = await loadSubCommand(spec);
|
|
502
532
|
try {
|
|
533
|
+
const helpIdx = argv.findIndex(
|
|
534
|
+
(arg) => arg === "help" || arg === "--help" || arg === "-h"
|
|
535
|
+
);
|
|
536
|
+
if (helpIdx !== -1) {
|
|
537
|
+
await showUsage(subCommand, { ...parserOptions, _isSubcommand: true });
|
|
538
|
+
if (parserOptions.autoExit !== false) process.exit(0);
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
503
541
|
const subCtx = await runCommandWithArgs(
|
|
504
542
|
subCommand,
|
|
505
543
|
argv,
|
|
@@ -603,7 +641,7 @@ async function runCommandWithArgs(command, argv, parserOptions, returnCtx) {
|
|
|
603
641
|
const noSubcommandArgInCurrentCall = !argv.some((arg) => !isFlag(arg));
|
|
604
642
|
if (isDispatcher && noSubcommandArgInCurrentCall) {
|
|
605
643
|
relinka("warn", "Please specify a command");
|
|
606
|
-
await showUsage(command, parserOptions
|
|
644
|
+
await showUsage(command, parserOptions);
|
|
607
645
|
if (autoExit) process.exit(0);
|
|
608
646
|
return;
|
|
609
647
|
}
|
|
@@ -792,3 +830,32 @@ function getParsedContext(command, argv, parserOptions) {
|
|
|
792
830
|
}
|
|
793
831
|
return { args: finalArgs, raw: argv };
|
|
794
832
|
}
|
|
833
|
+
async function resolveFileBasedCommandPath(cmdsRoot, argv) {
|
|
834
|
+
let currentDir = cmdsRoot;
|
|
835
|
+
const pathSegments = [];
|
|
836
|
+
let leftover = [...argv];
|
|
837
|
+
while (leftover.length > 0 && !isFlag(leftover[0])) {
|
|
838
|
+
const nextDir = path.join(currentDir, leftover[0]);
|
|
839
|
+
if (await fs.pathExists(nextDir) && (await fs.stat(nextDir)).isDirectory()) {
|
|
840
|
+
currentDir = nextDir;
|
|
841
|
+
pathSegments.push(leftover[0]);
|
|
842
|
+
leftover = leftover.slice(1);
|
|
843
|
+
} else {
|
|
844
|
+
break;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
for (const fname of ["cmd.ts", "cmd.js"]) {
|
|
848
|
+
const fpath = path.join(currentDir, fname);
|
|
849
|
+
if (await fs.pathExists(fpath)) {
|
|
850
|
+
const imported = await import(path.resolve(fpath));
|
|
851
|
+
if (imported.default) {
|
|
852
|
+
return {
|
|
853
|
+
def: imported.default,
|
|
854
|
+
path: pathSegments,
|
|
855
|
+
leftoverArgv: leftover
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
return null;
|
|
861
|
+
}
|
package/bin/mod.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { mainSymbols, fallbackSymbols, } from "./components/figures/figures-mod.
|
|
|
5
5
|
export { confirmPrompt } from "./components/input/confirm-prompt.js";
|
|
6
6
|
export { inputPrompt } from "./components/input/input-prompt.js";
|
|
7
7
|
export type { ArgDefinition, ArgDefinitions, CommandsMap, Command, InferArgTypes, FileBasedCmdsOptions, } from "./components/launcher/launcher-mod.js";
|
|
8
|
-
export { defineCommand, defineArgs, showUsage, runMain, } from "./components/launcher/launcher-mod.js";
|
|
8
|
+
export { defineCommand, defineArgs, showUsage, runMain, runCmd, } from "./components/launcher/launcher-mod.js";
|
|
9
9
|
export { toBaseColor, toSolidColor } from "./components/msg-fmt/colors.js";
|
|
10
10
|
export { relinkaByRemptsDeprecated, relinkaAsyncByRemptsDeprecated, throwError, } from "./components/msg-fmt/logger.js";
|
|
11
11
|
export { colorMap, typographyMap } from "./components/msg-fmt/mapping.js";
|
package/bin/mod.js
CHANGED