@reliverse/rempts 1.7.12 → 1.7.13
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 +6 -5
- package/bin/components/editor/editor-mod.js +1 -1
- package/bin/components/launcher/launcher-mod.d.ts +1 -137
- package/bin/components/launcher/launcher-mod.js +49 -7
- package/bin/components/launcher/launcher-types.d.ts +136 -0
- package/bin/components/launcher/launcher-types.js +0 -0
- package/bin/components/launcher/run-command.d.ts +2 -0
- package/bin/components/launcher/run-command.js +18 -0
- package/bin/mod.d.ts +2 -1
- package/bin/mod.js +2 -0
- package/package.json +7 -27
- package/bin/components/launcher/deprecated/_parser.ts.txt +0 -167
- package/bin/components/launcher/deprecated/_utils.ts.txt +0 -41
- package/bin/components/launcher/deprecated/args.ts.txt +0 -108
- package/bin/components/launcher/deprecated/command.ts.txt +0 -95
- package/bin/components/launcher/deprecated/launcher-mod.ts.txt +0 -50
- package/bin/components/launcher/deprecated/usage.ts.txt +0 -157
package/README.md
CHANGED
|
@@ -6,19 +6,20 @@
|
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
+
- 😘 drop-in alternative to `citty` + built-in prompts
|
|
10
|
+
- 📂 file-based commands (app-router style by default)
|
|
9
11
|
- 🫂 rempts keeps you from fighting with your CLI tool
|
|
12
|
+
- 🏎️ prompt engine that *feels* modern — and actually is
|
|
10
13
|
- ✨ rempts is your end-to-end CLI UI + command framework
|
|
11
14
|
- 🌿 multi-level file-based subcommands (sibling + nested)
|
|
12
15
|
- 💪 built for DX precision and high-context terminal UX
|
|
13
|
-
- 🏎️ prompt engine that *feels* modern — and actually is
|
|
14
|
-
- 📂 file-based commands (app-router style by default)
|
|
15
16
|
- 🎭 looks great in plain scripts or full CLI apps
|
|
16
|
-
- 🧠 type-safe from args to prompts
|
|
17
|
-
- ⚡ blazing-fast, zero runtime baggage
|
|
18
|
-
- 🧩 router + argument parser built-in
|
|
19
17
|
- 🎨 customizable themes and styled output
|
|
20
18
|
- 📦 built-in output formatter and logger
|
|
21
19
|
- 🚨 crash-safe (Ctrl+C, SIGINT, errors)
|
|
20
|
+
- ⚡ blazing-fast, zero runtime baggage
|
|
21
|
+
- 🧩 router + argument parser built-in
|
|
22
|
+
- 🧠 type-safe from args to prompts
|
|
22
23
|
- 📐 smart layout for small terminals
|
|
23
24
|
- 🎛️ override styles via prompt options
|
|
24
25
|
- 🪄 minimal API surface, maximum expressiveness
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import path from "@reliverse/pathkit";
|
|
1
2
|
import { re } from "@reliverse/relico";
|
|
2
3
|
import { relinka } from "@reliverse/relinka";
|
|
3
4
|
import { loadConfig } from "c12";
|
|
4
5
|
import fs from "fs-extra";
|
|
5
|
-
import path from "pathe";
|
|
6
6
|
import termkit from "terminal-kit";
|
|
7
7
|
const { terminal: term } = termkit;
|
|
8
8
|
let state = {
|
|
@@ -1,140 +1,5 @@
|
|
|
1
1
|
import type { ReliArgParserOptions } from "@reliverse/reliarg";
|
|
2
|
-
type
|
|
3
|
-
type BaseArgProps = {
|
|
4
|
-
description?: string;
|
|
5
|
-
required?: boolean;
|
|
6
|
-
allowed?: string[];
|
|
7
|
-
};
|
|
8
|
-
type PositionalArgDefinition = {
|
|
9
|
-
type: "positional";
|
|
10
|
-
default?: string;
|
|
11
|
-
} & BaseArgProps;
|
|
12
|
-
type BooleanArgDefinition = {
|
|
13
|
-
type: "boolean";
|
|
14
|
-
default?: boolean;
|
|
15
|
-
allowed?: boolean[];
|
|
16
|
-
} & BaseArgProps;
|
|
17
|
-
type StringArgDefinition = {
|
|
18
|
-
type: "string";
|
|
19
|
-
default?: string;
|
|
20
|
-
} & BaseArgProps;
|
|
21
|
-
type NumberArgDefinition = {
|
|
22
|
-
type: "number";
|
|
23
|
-
default?: number;
|
|
24
|
-
allowed?: number[];
|
|
25
|
-
} & BaseArgProps;
|
|
26
|
-
type ArrayArgDefinition = {
|
|
27
|
-
type: "array";
|
|
28
|
-
default?: string | readonly string[];
|
|
29
|
-
} & BaseArgProps;
|
|
30
|
-
export type ArgDefinition = PositionalArgDefinition | BooleanArgDefinition | StringArgDefinition | NumberArgDefinition | ArrayArgDefinition;
|
|
31
|
-
export type ArgDefinitions = Record<string, ArgDefinition>;
|
|
32
|
-
type CommandMeta = {
|
|
33
|
-
name: string;
|
|
34
|
-
version?: string;
|
|
35
|
-
description?: string;
|
|
36
|
-
hidden?: boolean;
|
|
37
|
-
aliases?: string[];
|
|
38
|
-
};
|
|
39
|
-
/**
|
|
40
|
-
* A subcommand can be either:
|
|
41
|
-
* 1) A string path to a module with a default export of type Command.
|
|
42
|
-
* 2) A lazy import function returning a Promise that resolves to
|
|
43
|
-
* { default: Command<any> } or directly to a Command instance.
|
|
44
|
-
*/
|
|
45
|
-
type CommandSpec = string | (() => Promise<{
|
|
46
|
-
default: Command<any>;
|
|
47
|
-
} | Command<any>>);
|
|
48
|
-
export type CommandsMap = Record<string, CommandSpec>;
|
|
49
|
-
type CommandContext<ARGS> = {
|
|
50
|
-
args: ARGS;
|
|
51
|
-
raw: string[];
|
|
52
|
-
};
|
|
53
|
-
type CommandRun<ARGS> = (ctx: CommandContext<ARGS>) => void | Promise<void>;
|
|
54
|
-
type CommandHook<ARGS> = (ctx: CommandContext<ARGS>) => void | Promise<void>;
|
|
55
|
-
type DefineCommandOptions<A extends ArgDefinitions = EmptyArgs> = {
|
|
56
|
-
meta?: CommandMeta;
|
|
57
|
-
args?: A;
|
|
58
|
-
run?: CommandRun<InferArgTypes<A>>;
|
|
59
|
-
/**
|
|
60
|
-
* Object subcommands for this command.
|
|
61
|
-
*/
|
|
62
|
-
commands?: CommandsMap;
|
|
63
|
-
/**
|
|
64
|
-
* @deprecated Use `commands` instead. Will be removed in a future major version.
|
|
65
|
-
*/
|
|
66
|
-
subCommands?: CommandsMap;
|
|
67
|
-
/**
|
|
68
|
-
* Called before the command runs. Receives `{ args, raw }` (parsed args and raw argv).
|
|
69
|
-
*/
|
|
70
|
-
onCmdInit?: CommandHook<InferArgTypes<A>>;
|
|
71
|
-
/**
|
|
72
|
-
* Called after the command finishes. Receives `{ args, raw }` (parsed args and raw argv).
|
|
73
|
-
*/
|
|
74
|
-
onCmdExit?: CommandHook<InferArgTypes<A>>;
|
|
75
|
-
/**
|
|
76
|
-
* @deprecated Use onCmdInit instead
|
|
77
|
-
*/
|
|
78
|
-
setup?: CommandHook<InferArgTypes<A>>;
|
|
79
|
-
/**
|
|
80
|
-
* @deprecated Use onCmdExit instead
|
|
81
|
-
*/
|
|
82
|
-
cleanup?: CommandHook<InferArgTypes<A>>;
|
|
83
|
-
/**
|
|
84
|
-
* Called once per CLI process, before any command/run() is executed
|
|
85
|
-
*/
|
|
86
|
-
onLauncherInit?: () => void | Promise<void>;
|
|
87
|
-
/**
|
|
88
|
-
* Called once per CLI process, after all command/run() logic is finished
|
|
89
|
-
*/
|
|
90
|
-
onLauncherExit?: () => void | Promise<void>;
|
|
91
|
-
};
|
|
92
|
-
export type Command<A extends ArgDefinitions = EmptyArgs> = {
|
|
93
|
-
meta?: CommandMeta;
|
|
94
|
-
args: A;
|
|
95
|
-
run?: CommandRun<InferArgTypes<A>>;
|
|
96
|
-
/**
|
|
97
|
-
* Object subcommands for this command.
|
|
98
|
-
*/
|
|
99
|
-
commands?: CommandsMap;
|
|
100
|
-
/**
|
|
101
|
-
* @deprecated Use `commands` instead. Will be removed in a future major version.
|
|
102
|
-
*/
|
|
103
|
-
subCommands?: CommandsMap;
|
|
104
|
-
/**
|
|
105
|
-
* Called before the command runs. Receives `{ args, raw }` (parsed args and raw argv).
|
|
106
|
-
*/
|
|
107
|
-
onCmdInit?: CommandHook<InferArgTypes<A>>;
|
|
108
|
-
/**
|
|
109
|
-
* Called after the command finishes. Receives `{ args, raw }` (parsed args and raw argv).
|
|
110
|
-
*/
|
|
111
|
-
onCmdExit?: CommandHook<InferArgTypes<A>>;
|
|
112
|
-
/**
|
|
113
|
-
* @deprecated Use onCmdInit instead
|
|
114
|
-
*/
|
|
115
|
-
setup?: CommandHook<InferArgTypes<A>>;
|
|
116
|
-
/**
|
|
117
|
-
* @deprecated Use onCmdExit instead
|
|
118
|
-
*/
|
|
119
|
-
cleanup?: CommandHook<InferArgTypes<A>>;
|
|
120
|
-
/**
|
|
121
|
-
* Called once per CLI process, before any command/run() is executed
|
|
122
|
-
*/
|
|
123
|
-
onLauncherInit?: () => void | Promise<void>;
|
|
124
|
-
/**
|
|
125
|
-
* Called once per CLI process, after all command/run() logic is finished
|
|
126
|
-
*/
|
|
127
|
-
onLauncherExit?: () => void | Promise<void>;
|
|
128
|
-
};
|
|
129
|
-
export type InferArgTypes<A extends ArgDefinitions> = {
|
|
130
|
-
[K in keyof A]: A[K] extends PositionalArgDefinition ? string : A[K] extends BooleanArgDefinition ? boolean : A[K] extends StringArgDefinition ? string : A[K] extends NumberArgDefinition ? number : A[K] extends {
|
|
131
|
-
type: "array";
|
|
132
|
-
} ? string[] : never;
|
|
133
|
-
};
|
|
134
|
-
export type FileBasedCmdsOptions = {
|
|
135
|
-
enable: boolean;
|
|
136
|
-
cmdsRootPath: string;
|
|
137
|
-
};
|
|
2
|
+
import type { ArgDefinitions, Command, DefineCommandOptions, EmptyArgs, FileBasedCmdsOptions } from "./launcher-types.js";
|
|
138
3
|
/**
|
|
139
4
|
* Defines a command with metadata, argument definitions,
|
|
140
5
|
* an execution function, and (optional) subCommands.
|
|
@@ -185,4 +50,3 @@ export declare function defineArgs<A extends ArgDefinitions>(args: A): A;
|
|
|
185
50
|
* @param parserOptions Optional reliArgParser options
|
|
186
51
|
*/
|
|
187
52
|
export declare function runCmd<A extends ArgDefinitions = EmptyArgs>(command: Command<A>, argv?: string[], parserOptions?: ReliArgParserOptions): Promise<void>;
|
|
188
|
-
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import path from "@reliverse/pathkit";
|
|
1
2
|
import { reliArgParser } from "@reliverse/reliarg";
|
|
2
3
|
import { re } from "@reliverse/relico";
|
|
3
4
|
import { relinka, relinkaConfig, relinkaShutdown } from "@reliverse/relinka";
|
|
4
5
|
import fs from "fs-extra";
|
|
5
6
|
import process from "node:process";
|
|
6
|
-
import path from "pathe";
|
|
7
7
|
import { readPackageJSON } from "pkg-types";
|
|
8
8
|
function buildExampleArgs(args) {
|
|
9
9
|
const parts = [];
|
|
@@ -524,8 +524,8 @@ async function runFileBasedSubCmd(subName, argv, fileCmdOpts, parserOptions, par
|
|
|
524
524
|
}
|
|
525
525
|
}
|
|
526
526
|
throw new Error(
|
|
527
|
-
`
|
|
528
|
-
|
|
527
|
+
`
|
|
528
|
+
Unknown command or arguments: ${args.join(" ")}
|
|
529
529
|
Info for this CLI's developer: No valid command file found in ${baseDir}`
|
|
530
530
|
);
|
|
531
531
|
}
|
|
@@ -543,8 +543,8 @@ Info for this CLI's developer: No valid command file found in ${baseDir}`
|
|
|
543
543
|
}
|
|
544
544
|
}
|
|
545
545
|
throw new Error(
|
|
546
|
-
`
|
|
547
|
-
|
|
546
|
+
`
|
|
547
|
+
Unknown command or arguments: ${args.join(" ")}
|
|
548
548
|
Info for this CLI's developer: No valid command file found in ${baseDir}`
|
|
549
549
|
);
|
|
550
550
|
}
|
|
@@ -555,9 +555,23 @@ Info for this CLI's developer: No valid command file found in ${baseDir}`
|
|
|
555
555
|
process.cwd(),
|
|
556
556
|
path.join(fileCmdOpts.cmdsRootPath, subName, "cmd.{ts,js}")
|
|
557
557
|
);
|
|
558
|
+
const allCommands = await findRecursiveFileBasedCommands(
|
|
559
|
+
fileCmdOpts.cmdsRootPath
|
|
560
|
+
);
|
|
561
|
+
const commandNames = allCommands.map((cmd) => cmd.path.join(" "));
|
|
562
|
+
let closestMatch = "";
|
|
563
|
+
let minDistance = Number.POSITIVE_INFINITY;
|
|
564
|
+
for (const cmd of commandNames) {
|
|
565
|
+
const distance = levenshteinDistance(subName, cmd.split(" ")[0]);
|
|
566
|
+
if (distance < minDistance) {
|
|
567
|
+
minDistance = distance;
|
|
568
|
+
closestMatch = cmd;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
const suggestion = minDistance <= 3 ? ` (Did you mean: \`${closestMatch}\`?)` : "";
|
|
558
572
|
throw new Error(
|
|
559
|
-
`
|
|
560
|
-
|
|
573
|
+
`
|
|
574
|
+
Unknown command or arguments: ${attempted}${suggestion}
|
|
561
575
|
Info for this CLI's developer: No valid command directory found, expected: ${expectedPath}`
|
|
562
576
|
);
|
|
563
577
|
}
|
|
@@ -964,3 +978,31 @@ async function resolveFileBasedCommandPath(cmdsRoot, argv) {
|
|
|
964
978
|
}
|
|
965
979
|
return null;
|
|
966
980
|
}
|
|
981
|
+
function levenshteinDistance(a, b) {
|
|
982
|
+
if (a.length === 0) return b.length;
|
|
983
|
+
if (b.length === 0) return a.length;
|
|
984
|
+
const matrix = [];
|
|
985
|
+
for (let i = 0; i <= b.length; i++) {
|
|
986
|
+
matrix[i] = [i];
|
|
987
|
+
}
|
|
988
|
+
for (let j = 0; j <= a.length; j++) {
|
|
989
|
+
matrix[0][j] = j;
|
|
990
|
+
}
|
|
991
|
+
for (let i = 1; i <= b.length; i++) {
|
|
992
|
+
for (let j = 1; j <= a.length; j++) {
|
|
993
|
+
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
994
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
995
|
+
} else {
|
|
996
|
+
matrix[i][j] = Math.min(
|
|
997
|
+
matrix[i - 1][j - 1] + 1,
|
|
998
|
+
// substitution
|
|
999
|
+
matrix[i][j - 1] + 1,
|
|
1000
|
+
// insertion
|
|
1001
|
+
matrix[i - 1][j] + 1
|
|
1002
|
+
// deletion
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
return matrix[b.length][a.length];
|
|
1008
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
export type EmptyArgs = Record<string, never>;
|
|
2
|
+
export type BaseArgProps = {
|
|
3
|
+
description?: string;
|
|
4
|
+
required?: boolean;
|
|
5
|
+
allowed?: string[];
|
|
6
|
+
};
|
|
7
|
+
export type PositionalArgDefinition = {
|
|
8
|
+
type: "positional";
|
|
9
|
+
default?: string;
|
|
10
|
+
} & BaseArgProps;
|
|
11
|
+
export type BooleanArgDefinition = {
|
|
12
|
+
type: "boolean";
|
|
13
|
+
default?: boolean;
|
|
14
|
+
allowed?: boolean[];
|
|
15
|
+
} & BaseArgProps;
|
|
16
|
+
export type StringArgDefinition = {
|
|
17
|
+
type: "string";
|
|
18
|
+
default?: string;
|
|
19
|
+
} & BaseArgProps;
|
|
20
|
+
export type NumberArgDefinition = {
|
|
21
|
+
type: "number";
|
|
22
|
+
default?: number;
|
|
23
|
+
allowed?: number[];
|
|
24
|
+
} & BaseArgProps;
|
|
25
|
+
export type ArrayArgDefinition = {
|
|
26
|
+
type: "array";
|
|
27
|
+
default?: string | readonly string[];
|
|
28
|
+
} & BaseArgProps;
|
|
29
|
+
export type ArgDefinition = PositionalArgDefinition | BooleanArgDefinition | StringArgDefinition | NumberArgDefinition | ArrayArgDefinition;
|
|
30
|
+
export type ArgDefinitions = Record<string, ArgDefinition>;
|
|
31
|
+
export type CommandMeta = {
|
|
32
|
+
name: string;
|
|
33
|
+
version?: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
hidden?: boolean;
|
|
36
|
+
aliases?: string[];
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* A subcommand can be either:
|
|
40
|
+
* 1) A string path to a module with a default export of type Command.
|
|
41
|
+
* 2) A lazy import function returning a Promise that resolves to
|
|
42
|
+
* { default: Command<any> } or directly to a Command instance.
|
|
43
|
+
*/
|
|
44
|
+
export type CommandSpec = string | (() => Promise<{
|
|
45
|
+
default: Command<any>;
|
|
46
|
+
} | Command<any>>);
|
|
47
|
+
export type CommandsMap = Record<string, CommandSpec>;
|
|
48
|
+
export type CommandContext<ARGS> = {
|
|
49
|
+
args: ARGS;
|
|
50
|
+
raw: string[];
|
|
51
|
+
};
|
|
52
|
+
export type CommandRun<ARGS> = (ctx: CommandContext<ARGS>) => void | Promise<void>;
|
|
53
|
+
export type CommandHook<ARGS> = (ctx: CommandContext<ARGS>) => void | Promise<void>;
|
|
54
|
+
export type DefineCommandOptions<A extends ArgDefinitions = EmptyArgs> = {
|
|
55
|
+
meta?: CommandMeta;
|
|
56
|
+
args?: A;
|
|
57
|
+
run?: CommandRun<InferArgTypes<A>>;
|
|
58
|
+
/**
|
|
59
|
+
* Object subcommands for this command.
|
|
60
|
+
*/
|
|
61
|
+
commands?: CommandsMap;
|
|
62
|
+
/**
|
|
63
|
+
* @deprecated Use `commands` instead. Will be removed in a future major version.
|
|
64
|
+
*/
|
|
65
|
+
subCommands?: CommandsMap;
|
|
66
|
+
/**
|
|
67
|
+
* Called before the command runs. Receives `{ args, raw }` (parsed args and raw argv).
|
|
68
|
+
*/
|
|
69
|
+
onCmdInit?: CommandHook<InferArgTypes<A>>;
|
|
70
|
+
/**
|
|
71
|
+
* Called after the command finishes. Receives `{ args, raw }` (parsed args and raw argv).
|
|
72
|
+
*/
|
|
73
|
+
onCmdExit?: CommandHook<InferArgTypes<A>>;
|
|
74
|
+
/**
|
|
75
|
+
* @deprecated Use onCmdInit instead
|
|
76
|
+
*/
|
|
77
|
+
setup?: CommandHook<InferArgTypes<A>>;
|
|
78
|
+
/**
|
|
79
|
+
* @deprecated Use onCmdExit instead
|
|
80
|
+
*/
|
|
81
|
+
cleanup?: CommandHook<InferArgTypes<A>>;
|
|
82
|
+
/**
|
|
83
|
+
* Called once per CLI process, before any command/run() is executed
|
|
84
|
+
*/
|
|
85
|
+
onLauncherInit?: () => void | Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Called once per CLI process, after all command/run() logic is finished
|
|
88
|
+
*/
|
|
89
|
+
onLauncherExit?: () => void | Promise<void>;
|
|
90
|
+
};
|
|
91
|
+
export type Command<A extends ArgDefinitions = EmptyArgs> = {
|
|
92
|
+
meta?: CommandMeta;
|
|
93
|
+
args: A;
|
|
94
|
+
run?: CommandRun<InferArgTypes<A>>;
|
|
95
|
+
/**
|
|
96
|
+
* Object subcommands for this command.
|
|
97
|
+
*/
|
|
98
|
+
commands?: CommandsMap;
|
|
99
|
+
/**
|
|
100
|
+
* @deprecated Use `commands` instead. Will be removed in a future major version.
|
|
101
|
+
*/
|
|
102
|
+
subCommands?: CommandsMap;
|
|
103
|
+
/**
|
|
104
|
+
* Called before the command runs. Receives `{ args, raw }` (parsed args and raw argv).
|
|
105
|
+
*/
|
|
106
|
+
onCmdInit?: CommandHook<InferArgTypes<A>>;
|
|
107
|
+
/**
|
|
108
|
+
* Called after the command finishes. Receives `{ args, raw }` (parsed args and raw argv).
|
|
109
|
+
*/
|
|
110
|
+
onCmdExit?: CommandHook<InferArgTypes<A>>;
|
|
111
|
+
/**
|
|
112
|
+
* @deprecated Use onCmdInit instead
|
|
113
|
+
*/
|
|
114
|
+
setup?: CommandHook<InferArgTypes<A>>;
|
|
115
|
+
/**
|
|
116
|
+
* @deprecated Use onCmdExit instead
|
|
117
|
+
*/
|
|
118
|
+
cleanup?: CommandHook<InferArgTypes<A>>;
|
|
119
|
+
/**
|
|
120
|
+
* Called once per CLI process, before any command/run() is executed
|
|
121
|
+
*/
|
|
122
|
+
onLauncherInit?: () => void | Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* Called once per CLI process, after all command/run() logic is finished
|
|
125
|
+
*/
|
|
126
|
+
onLauncherExit?: () => void | Promise<void>;
|
|
127
|
+
};
|
|
128
|
+
export type InferArgTypes<A extends ArgDefinitions> = {
|
|
129
|
+
[K in keyof A]: A[K] extends PositionalArgDefinition ? string : A[K] extends BooleanArgDefinition ? boolean : A[K] extends StringArgDefinition ? string : A[K] extends NumberArgDefinition ? number : A[K] extends {
|
|
130
|
+
type: "array";
|
|
131
|
+
} ? string[] : never;
|
|
132
|
+
};
|
|
133
|
+
export type FileBasedCmdsOptions = {
|
|
134
|
+
enable: boolean;
|
|
135
|
+
cmdsRootPath: string;
|
|
136
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { relinka } from "@reliverse/relinka";
|
|
2
|
+
import { createJiti } from "jiti";
|
|
3
|
+
const jiti = createJiti(import.meta.url, {
|
|
4
|
+
debug: process.env.NODE_ENV === "development",
|
|
5
|
+
fsCache: true,
|
|
6
|
+
sourceMaps: true
|
|
7
|
+
});
|
|
8
|
+
export async function loadCommand(path) {
|
|
9
|
+
try {
|
|
10
|
+
relinka("verbose", `Loading command from: ${path}`);
|
|
11
|
+
const cmd = await jiti.import(path, { default: true });
|
|
12
|
+
relinka("verbose", `Successfully loaded command from: ${path}`);
|
|
13
|
+
return cmd;
|
|
14
|
+
} catch (error) {
|
|
15
|
+
relinka("error", `Failed to load command from ${path}:`, error);
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
}
|
package/bin/mod.d.ts
CHANGED
|
@@ -4,8 +4,9 @@ export { startEditor } from "./components/editor/editor-mod.js";
|
|
|
4
4
|
export { mainSymbols, fallbackSymbols, } from "./components/figures/figures-mod.js";
|
|
5
5
|
export { confirmPrompt } from "./components/input/confirm-prompt.js";
|
|
6
6
|
export { inputPrompt } from "./components/input/input-prompt.js";
|
|
7
|
-
export
|
|
7
|
+
export * from "./components/launcher/launcher-types.js";
|
|
8
8
|
export { defineCommand, defineArgs, showUsage, runMain, runCmd, } from "./components/launcher/launcher-mod.js";
|
|
9
|
+
export { loadCommand } from "./components/launcher/run-command.js";
|
|
9
10
|
export { toBaseColor, toSolidColor } from "./components/msg-fmt/colors.js";
|
|
10
11
|
export { relinkaByRemptsDeprecated, relinkaAsyncByRemptsDeprecated, throwError, } from "./components/msg-fmt/logger.js";
|
|
11
12
|
export { colorMap, typographyMap } from "./components/msg-fmt/mapping.js";
|
package/bin/mod.js
CHANGED
|
@@ -7,6 +7,7 @@ export {
|
|
|
7
7
|
} from "./components/figures/figures-mod.js";
|
|
8
8
|
export { confirmPrompt } from "./components/input/confirm-prompt.js";
|
|
9
9
|
export { inputPrompt } from "./components/input/input-prompt.js";
|
|
10
|
+
export * from "./components/launcher/launcher-types.js";
|
|
10
11
|
export {
|
|
11
12
|
defineCommand,
|
|
12
13
|
defineArgs,
|
|
@@ -14,6 +15,7 @@ export {
|
|
|
14
15
|
runMain,
|
|
15
16
|
runCmd
|
|
16
17
|
} from "./components/launcher/launcher-mod.js";
|
|
18
|
+
export { loadCommand } from "./components/launcher/run-command.js";
|
|
17
19
|
export { toBaseColor, toSolidColor } from "./components/msg-fmt/colors.js";
|
|
18
20
|
export {
|
|
19
21
|
relinkaByRemptsDeprecated,
|
package/package.json
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
3
|
"@figliolia/chalk-animation": "^1.0.4",
|
|
4
|
+
"@reliverse/pathkit": "^1.2.1",
|
|
4
5
|
"@reliverse/reliarg": "^1.0.3",
|
|
5
6
|
"@reliverse/relico": "^1.1.2",
|
|
6
|
-
"@reliverse/relinka": "^1.4.
|
|
7
|
+
"@reliverse/relinka": "^1.4.7",
|
|
7
8
|
"@reliverse/runtime": "^1.0.3",
|
|
8
9
|
"ansi-escapes": "^7.0.0",
|
|
9
|
-
"c12": "^3.0.
|
|
10
|
+
"c12": "^3.0.4",
|
|
10
11
|
"cli-spinners": "^3.2.0",
|
|
11
12
|
"detect-package-manager": "^3.0.2",
|
|
12
13
|
"figlet": "^1.8.1",
|
|
13
14
|
"fs-extra": "^11.3.0",
|
|
14
15
|
"gradient-string": "^3.0.0",
|
|
16
|
+
"jiti": "^2.4.2",
|
|
15
17
|
"log-update": "^6.1.0",
|
|
16
18
|
"node-emoji": "^2.2.0",
|
|
17
19
|
"ora": "^8.2.0",
|
|
18
|
-
"pathe": "^2.0.3",
|
|
19
20
|
"pkg-types": "^2.1.0",
|
|
20
21
|
"sisteransi": "^1.0.5",
|
|
21
22
|
"terminal-kit": "^3.1.2",
|
|
@@ -28,7 +29,7 @@
|
|
|
28
29
|
"license": "MIT",
|
|
29
30
|
"name": "@reliverse/rempts",
|
|
30
31
|
"type": "module",
|
|
31
|
-
"version": "1.7.
|
|
32
|
+
"version": "1.7.13",
|
|
32
33
|
"author": "reliverse",
|
|
33
34
|
"bugs": {
|
|
34
35
|
"email": "blefnk@gmail.com",
|
|
@@ -41,28 +42,7 @@
|
|
|
41
42
|
"type": "git",
|
|
42
43
|
"url": "git+https://github.com/reliverse/rempts.git"
|
|
43
44
|
},
|
|
44
|
-
"devDependencies": {
|
|
45
|
-
"@biomejs/biome": "1.9.4",
|
|
46
|
-
"@eslint/js": "^9.26.0",
|
|
47
|
-
"@reliverse/dler": "^1.2.5",
|
|
48
|
-
"@reliverse/relidler-cfg": "^1.1.3",
|
|
49
|
-
"@stylistic/eslint-plugin": "^4.2.0",
|
|
50
|
-
"@total-typescript/ts-reset": "^0.6.1",
|
|
51
|
-
"@types/bun": "^1.2.13",
|
|
52
|
-
"@types/figlet": "^1.7.0",
|
|
53
|
-
"@types/fs-extra": "^11.0.4",
|
|
54
|
-
"@types/node": "^22.15.18",
|
|
55
|
-
"@types/terminal-kit": "^2.5.7",
|
|
56
|
-
"@types/wrap-ansi": "^8.1.0",
|
|
57
|
-
"eslint": "^9.26.0",
|
|
58
|
-
"eslint-plugin-no-relative-import-paths": "^1.6.1",
|
|
59
|
-
"eslint-plugin-perfectionist": "^4.13.0",
|
|
60
|
-
"jiti": "^2.4.2",
|
|
61
|
-
"knip": "^5.56.0",
|
|
62
|
-
"typescript": "^5.8.3",
|
|
63
|
-
"typescript-eslint": "^8.32.1",
|
|
64
|
-
"vitest": "^3.1.3"
|
|
65
|
-
},
|
|
45
|
+
"devDependencies": {},
|
|
66
46
|
"exports": {
|
|
67
47
|
".": "./bin/mod.js"
|
|
68
48
|
},
|
|
@@ -77,4 +57,4 @@
|
|
|
77
57
|
"publishConfig": {
|
|
78
58
|
"access": "public"
|
|
79
59
|
}
|
|
80
|
-
}
|
|
60
|
+
}
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Default,
|
|
3
|
-
ParserArgv,
|
|
4
|
-
ParserOptions,
|
|
5
|
-
} from "~/types.js";
|
|
6
|
-
|
|
7
|
-
function toArr(any: any) {
|
|
8
|
-
// biome-ignore lint/suspicious/noDoubleEquals: <explanation>
|
|
9
|
-
return any == undefined ? [] : Array.isArray(any) ? any : [any];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function toVal(out, key, val, opts) {
|
|
13
|
-
let x;
|
|
14
|
-
const old = out[key];
|
|
15
|
-
const nxt = ~opts.string.indexOf(key)
|
|
16
|
-
? // biome-ignore lint/suspicious/noDoubleEquals: <explanation>
|
|
17
|
-
val == undefined || val === true
|
|
18
|
-
? ""
|
|
19
|
-
: String(val)
|
|
20
|
-
: typeof val === "boolean"
|
|
21
|
-
? val
|
|
22
|
-
: ~opts.boolean.indexOf(key)
|
|
23
|
-
? val === "false"
|
|
24
|
-
? false
|
|
25
|
-
: val === "true" ||
|
|
26
|
-
// biome-ignore lint/style/noCommaOperator: <explanation>
|
|
27
|
-
(out._.push(((x = +val), x * 0 === 0) ? x : val), !!val)
|
|
28
|
-
: // biome-ignore lint/style/noCommaOperator: <explanation>
|
|
29
|
-
((x = +val), x * 0 === 0)
|
|
30
|
-
? x
|
|
31
|
-
: val;
|
|
32
|
-
out[key] =
|
|
33
|
-
// biome-ignore lint/suspicious/noDoubleEquals: <explanation>
|
|
34
|
-
old == undefined ? nxt : Array.isArray(old) ? old.concat(nxt) : [old, nxt];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function parseRawArgs<T = Default>(
|
|
38
|
-
args: string[] = [],
|
|
39
|
-
opts: ParserOptions = {},
|
|
40
|
-
): ParserArgv<T> {
|
|
41
|
-
let k;
|
|
42
|
-
let arr;
|
|
43
|
-
let arg;
|
|
44
|
-
let name;
|
|
45
|
-
let val;
|
|
46
|
-
const out = { _: [] };
|
|
47
|
-
let i = 0;
|
|
48
|
-
let j = 0;
|
|
49
|
-
let idx = 0;
|
|
50
|
-
const len = args.length;
|
|
51
|
-
|
|
52
|
-
const alibi = opts.alias !== void 0;
|
|
53
|
-
const strict = opts.unknown !== void 0;
|
|
54
|
-
const defaults = opts.default !== void 0;
|
|
55
|
-
|
|
56
|
-
opts.alias = opts.alias || {};
|
|
57
|
-
opts.string = toArr(opts.string);
|
|
58
|
-
opts.boolean = toArr(opts.boolean);
|
|
59
|
-
|
|
60
|
-
if (alibi) {
|
|
61
|
-
for (k in opts.alias) {
|
|
62
|
-
arr = opts.alias[k] = toArr(opts.alias[k]);
|
|
63
|
-
for (i = 0; i < arr.length; i++) {
|
|
64
|
-
(opts.alias[arr[i]] = arr.concat(k)).splice(i, 1);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
for (i = opts.boolean.length; i-- > 0; ) {
|
|
70
|
-
arr = opts.alias[opts.boolean[i]] || [];
|
|
71
|
-
for (j = arr.length; j-- > 0; ) {
|
|
72
|
-
opts.boolean.push(arr[j]);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
for (i = opts.string.length; i-- > 0; ) {
|
|
77
|
-
arr = opts.alias[opts.string[i]] || [];
|
|
78
|
-
for (j = arr.length; j-- > 0; ) {
|
|
79
|
-
opts.string.push(arr[j]);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (defaults) {
|
|
84
|
-
for (k in opts.default) {
|
|
85
|
-
name = typeof opts.default[k];
|
|
86
|
-
arr = opts.alias[k] = opts.alias[k] || [];
|
|
87
|
-
if (opts[name] !== void 0) {
|
|
88
|
-
opts[name].push(k);
|
|
89
|
-
for (i = 0; i < arr.length; i++) {
|
|
90
|
-
opts[name].push(arr[i]);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const keys = strict ? Object.keys(opts.alias) : [];
|
|
97
|
-
|
|
98
|
-
for (i = 0; i < len; i++) {
|
|
99
|
-
arg = args[i];
|
|
100
|
-
|
|
101
|
-
if (arg === "--") {
|
|
102
|
-
out._ = out._.concat(args.slice(++i));
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
for (j = 0; j < arg.length; j++) {
|
|
107
|
-
if (arg.charCodeAt(j) !== 45) {
|
|
108
|
-
break;
|
|
109
|
-
} // "-"
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (j === 0) {
|
|
113
|
-
out._.push(arg);
|
|
114
|
-
} else if (arg.substring(j, j + 3) === "no-") {
|
|
115
|
-
name = arg.slice(Math.max(0, j + 3));
|
|
116
|
-
if (strict && !~keys.indexOf(name)) {
|
|
117
|
-
// @ts-expect-error TODO: fix ts
|
|
118
|
-
return opts.unknown(arg);
|
|
119
|
-
}
|
|
120
|
-
out[name] = false;
|
|
121
|
-
} else {
|
|
122
|
-
for (idx = j + 1; idx < arg.length; idx++) {
|
|
123
|
-
if (arg.charCodeAt(idx) === 61) {
|
|
124
|
-
break;
|
|
125
|
-
} // "="
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
name = arg.substring(j, idx);
|
|
129
|
-
val =
|
|
130
|
-
arg.slice(Math.max(0, ++idx)) ||
|
|
131
|
-
i + 1 === len ||
|
|
132
|
-
// biome-ignore lint/style/useTemplate: <explanation>
|
|
133
|
-
("" + args[i + 1]).charCodeAt(0) === 45 ||
|
|
134
|
-
args[++i];
|
|
135
|
-
arr = j === 2 ? [name] : name;
|
|
136
|
-
|
|
137
|
-
for (idx = 0; idx < arr.length; idx++) {
|
|
138
|
-
name = arr[idx];
|
|
139
|
-
if (strict && !~keys.indexOf(name)) {
|
|
140
|
-
// @ts-expect-error TODO: fix ts
|
|
141
|
-
return opts.unknown("-".repeat(j) + name);
|
|
142
|
-
}
|
|
143
|
-
toVal(out, name, idx + 1 < arr.length || val, opts);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (defaults) {
|
|
149
|
-
for (k in opts.default) {
|
|
150
|
-
if (out[k] === void 0) {
|
|
151
|
-
out[k] = opts.default[k];
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (alibi) {
|
|
157
|
-
for (k in out) {
|
|
158
|
-
arr = opts.alias[k] || [];
|
|
159
|
-
while (arr.length > 0) {
|
|
160
|
-
out[arr.shift()] = out[k];
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// @ts-expect-error TODO: fix ts
|
|
166
|
-
return out;
|
|
167
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { Resolvable } from "~/types.js";
|
|
2
|
-
|
|
3
|
-
export function toArray(val: any) {
|
|
4
|
-
if (Array.isArray(val)) {
|
|
5
|
-
return val;
|
|
6
|
-
}
|
|
7
|
-
return val === undefined ? [] : [val];
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function formatLineColumns(lines: string[][], linePrefix = "") {
|
|
11
|
-
const maxLength: number[] = [];
|
|
12
|
-
for (const line of lines) {
|
|
13
|
-
for (const [i, element] of line.entries()) {
|
|
14
|
-
maxLength[i] = Math.max(maxLength[i] || 0, element.length);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return lines
|
|
18
|
-
.map((l) =>
|
|
19
|
-
l
|
|
20
|
-
.map(
|
|
21
|
-
(c, i) =>
|
|
22
|
-
linePrefix + c[i === 0 ? "padStart" : "padEnd"](maxLength[i]),
|
|
23
|
-
)
|
|
24
|
-
.join(" "),
|
|
25
|
-
)
|
|
26
|
-
.join("\n");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function resolveValue<T>(input: Resolvable<T>): T | Promise<T> {
|
|
30
|
-
return typeof input === "function" ? (input as any)() : input;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class CLIError extends Error {
|
|
34
|
-
constructor(
|
|
35
|
-
message: string,
|
|
36
|
-
public code?: string,
|
|
37
|
-
) {
|
|
38
|
-
super(message);
|
|
39
|
-
this.name = "CLIError";
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { kebabCase, camelCase } from "scule";
|
|
2
|
-
|
|
3
|
-
import type { Arg, ArgsDef, ParsedArgs } from "~/types.js";
|
|
4
|
-
|
|
5
|
-
import { parseRawArgs } from "./_parser.js";
|
|
6
|
-
import { CLIError, toArray } from "./_utils.js";
|
|
7
|
-
|
|
8
|
-
export function parseArgs<T extends ArgsDef = ArgsDef>(
|
|
9
|
-
rawArgs: string[],
|
|
10
|
-
argsDef: ArgsDef,
|
|
11
|
-
): ParsedArgs<T> {
|
|
12
|
-
const parseOptions = {
|
|
13
|
-
boolean: [] as string[],
|
|
14
|
-
string: [] as string[],
|
|
15
|
-
number: [] as string[],
|
|
16
|
-
enum: [] as (number | string)[],
|
|
17
|
-
mixed: [] as string[],
|
|
18
|
-
alias: {} as Record<string, string | string[]>,
|
|
19
|
-
default: {} as Record<string, boolean | number | string>,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const args = resolveArgs(argsDef);
|
|
23
|
-
|
|
24
|
-
for (const arg of args) {
|
|
25
|
-
if (arg.type === "positional") {
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
if (arg.type === "string" || arg.type === "number") {
|
|
29
|
-
parseOptions.string.push(arg.name);
|
|
30
|
-
} else if (arg.type === "boolean") {
|
|
31
|
-
parseOptions.boolean.push(arg.name);
|
|
32
|
-
} else if (arg.type === "enum") {
|
|
33
|
-
parseOptions.enum.push(...(arg.options || []));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (arg.default !== undefined) {
|
|
37
|
-
parseOptions.default[arg.name] = arg.default;
|
|
38
|
-
}
|
|
39
|
-
if (arg.alias) {
|
|
40
|
-
parseOptions.alias[arg.name] = arg.alias;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const parsed = parseRawArgs(rawArgs, parseOptions);
|
|
45
|
-
const [...positionalArguments] = parsed._;
|
|
46
|
-
|
|
47
|
-
const parsedArgsProxy = new Proxy(parsed, {
|
|
48
|
-
get(target: ParsedArgs<any>, prop: string) {
|
|
49
|
-
return target[prop] ?? target[camelCase(prop)] ?? target[kebabCase(prop)];
|
|
50
|
-
},
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
for (const [, arg] of args.entries()) {
|
|
54
|
-
if (arg.type === "positional") {
|
|
55
|
-
const nextPositionalArgument = positionalArguments.shift();
|
|
56
|
-
if (nextPositionalArgument !== undefined) {
|
|
57
|
-
parsedArgsProxy[arg.name] = nextPositionalArgument;
|
|
58
|
-
} else if (arg.default === undefined && arg.required !== false) {
|
|
59
|
-
throw new CLIError(
|
|
60
|
-
`Missing required positional argument: ${arg.name.toUpperCase()}`,
|
|
61
|
-
"EARG",
|
|
62
|
-
);
|
|
63
|
-
} else {
|
|
64
|
-
parsedArgsProxy[arg.name] = arg.default;
|
|
65
|
-
}
|
|
66
|
-
} else if (arg.type === "enum") {
|
|
67
|
-
const argument = parsedArgsProxy[arg.name];
|
|
68
|
-
const options = arg.options || [];
|
|
69
|
-
if (
|
|
70
|
-
argument !== undefined &&
|
|
71
|
-
options.length > 0 &&
|
|
72
|
-
!options.includes(argument)
|
|
73
|
-
) {
|
|
74
|
-
throw new CLIError(
|
|
75
|
-
`Invalid value for argument: \`--${arg.name}\` (\`${argument}\`). Expected one of: ${options.map((o) => `\`${o}\``).join(", ")}.`,
|
|
76
|
-
"EARG",
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
} else if (arg.type === "number") {
|
|
80
|
-
const _originalValue = parsedArgsProxy[arg.name];
|
|
81
|
-
parsedArgsProxy[arg.name] = Number.parseFloat(
|
|
82
|
-
parsedArgsProxy[arg.name] as string,
|
|
83
|
-
);
|
|
84
|
-
if (Number.isNaN(parsedArgsProxy[arg.name])) {
|
|
85
|
-
throw new CLIError(
|
|
86
|
-
`Invalid value for argument: \`--${arg.name}\` (\`${_originalValue}\`). Expected a number.`,
|
|
87
|
-
"EARG",
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
} else if (arg.required && parsedArgsProxy[arg.name] === undefined) {
|
|
91
|
-
throw new CLIError(`Missing required argument: --${arg.name}`, "EARG");
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return parsedArgsProxy as ParsedArgs<T>;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function resolveArgs(argsDef: ArgsDef): Arg[] {
|
|
99
|
-
const args: Arg[] = [];
|
|
100
|
-
for (const [name, argDef] of Object.entries(argsDef || {})) {
|
|
101
|
-
args.push({
|
|
102
|
-
...argDef,
|
|
103
|
-
name,
|
|
104
|
-
alias: toArray((argDef as any).alias),
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
return args;
|
|
108
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ArgsDef,
|
|
3
|
-
CommandContext,
|
|
4
|
-
CommandDef,
|
|
5
|
-
RunCommandOptions,
|
|
6
|
-
} from "~/types.js";
|
|
7
|
-
|
|
8
|
-
import { CLIError, resolveValue } from "./_utils.js";
|
|
9
|
-
import { parseArgs } from "./args.js";
|
|
10
|
-
|
|
11
|
-
export function defineCommand<const T extends ArgsDef = ArgsDef>(
|
|
12
|
-
def: CommandDef<T>,
|
|
13
|
-
): CommandDef<T> {
|
|
14
|
-
return def;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function runCommand<T extends ArgsDef = ArgsDef>(
|
|
18
|
-
cmd: CommandDef<T>,
|
|
19
|
-
opts: RunCommandOptions,
|
|
20
|
-
): Promise<{ result: unknown }> {
|
|
21
|
-
const cmdArgs = await resolveValue(cmd.args || {});
|
|
22
|
-
const parsedArgs = parseArgs<T>(opts.rawArgs, cmdArgs);
|
|
23
|
-
|
|
24
|
-
const context: CommandContext<T> = {
|
|
25
|
-
rawArgs: opts.rawArgs,
|
|
26
|
-
args: parsedArgs,
|
|
27
|
-
data: opts.data,
|
|
28
|
-
cmd,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// Setup hook
|
|
32
|
-
if (typeof cmd.setup === "function") {
|
|
33
|
-
await cmd.setup(context);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Handle sub command
|
|
37
|
-
let result: unknown;
|
|
38
|
-
try {
|
|
39
|
-
const subCommands = await resolveValue(cmd.subCommands);
|
|
40
|
-
if (subCommands && Object.keys(subCommands).length > 0) {
|
|
41
|
-
const subCommandArgIndex = opts.rawArgs.findIndex(
|
|
42
|
-
(arg) => !arg.startsWith("-"),
|
|
43
|
-
);
|
|
44
|
-
const subCommandName = opts.rawArgs[subCommandArgIndex];
|
|
45
|
-
if (subCommandName) {
|
|
46
|
-
if (!subCommands[subCommandName]) {
|
|
47
|
-
throw new CLIError(
|
|
48
|
-
`Unknown command \`${subCommandName}\``,
|
|
49
|
-
"E_UNKNOWN_COMMAND",
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
const subCommand = await resolveValue(subCommands[subCommandName]);
|
|
53
|
-
if (subCommand) {
|
|
54
|
-
await runCommand(subCommand, {
|
|
55
|
-
rawArgs: opts.rawArgs.slice(subCommandArgIndex + 1),
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
} else if (!cmd.run) {
|
|
59
|
-
// biome-ignore lint/style/noUnusedTemplateLiteral: <explanation>
|
|
60
|
-
throw new CLIError(`No command specified.`, "E_NO_COMMAND");
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Handle main command
|
|
65
|
-
if (typeof cmd.run === "function") {
|
|
66
|
-
result = await cmd.run(context);
|
|
67
|
-
}
|
|
68
|
-
} finally {
|
|
69
|
-
if (typeof cmd.cleanup === "function") {
|
|
70
|
-
await cmd.cleanup(context);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return { result };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export async function resolveSubCommand<T extends ArgsDef = ArgsDef>(
|
|
77
|
-
cmd: CommandDef<T>,
|
|
78
|
-
rawArgs: string[],
|
|
79
|
-
parent?: CommandDef<T>,
|
|
80
|
-
): Promise<[CommandDef<T>, CommandDef<T>?]> {
|
|
81
|
-
const subCommands = await resolveValue(cmd.subCommands);
|
|
82
|
-
if (subCommands && Object.keys(subCommands).length > 0) {
|
|
83
|
-
const subCommandArgIndex = rawArgs.findIndex((arg) => !arg.startsWith("-"));
|
|
84
|
-
const subCommandName = rawArgs[subCommandArgIndex];
|
|
85
|
-
const subCommand = await resolveValue(subCommands[subCommandName]);
|
|
86
|
-
if (subCommand) {
|
|
87
|
-
return resolveSubCommand(
|
|
88
|
-
subCommand,
|
|
89
|
-
rawArgs.slice(subCommandArgIndex + 1),
|
|
90
|
-
cmd,
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return [cmd, parent];
|
|
95
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { relinka } from "@reliverse/relinka";
|
|
2
|
-
|
|
3
|
-
import type { ArgsDef, CommandDef } from "~/types.js";
|
|
4
|
-
|
|
5
|
-
import { CLIError } from "./_utils.js";
|
|
6
|
-
import { resolveSubCommand, runCommand } from "./command.js";
|
|
7
|
-
import { showUsage as _showUsage } from "./usage.js";
|
|
8
|
-
|
|
9
|
-
export type RunMainOptions = {
|
|
10
|
-
rawArgs?: string[];
|
|
11
|
-
showUsage?: typeof _showUsage;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export async function runMain<T extends ArgsDef = ArgsDef>(
|
|
15
|
-
cmd: CommandDef<T>,
|
|
16
|
-
opts: RunMainOptions = {},
|
|
17
|
-
) {
|
|
18
|
-
const rawArgs = opts.rawArgs || process.argv.slice(2);
|
|
19
|
-
const showUsage = opts.showUsage || _showUsage;
|
|
20
|
-
try {
|
|
21
|
-
if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
|
|
22
|
-
await showUsage(...(await resolveSubCommand(cmd, rawArgs)));
|
|
23
|
-
process.exit(0);
|
|
24
|
-
} else if (rawArgs.length === 1 && rawArgs[0] === "--version") {
|
|
25
|
-
const meta =
|
|
26
|
-
typeof cmd.meta === "function" ? await cmd.meta() : await cmd.meta;
|
|
27
|
-
if (!meta?.version) {
|
|
28
|
-
throw new CLIError("No version specified", "E_NO_VERSION");
|
|
29
|
-
}
|
|
30
|
-
relinka("log", meta.version);
|
|
31
|
-
} else {
|
|
32
|
-
await runCommand(cmd, { rawArgs });
|
|
33
|
-
}
|
|
34
|
-
} catch (error: any) {
|
|
35
|
-
const isCLIError = error instanceof CLIError;
|
|
36
|
-
if (isCLIError) {
|
|
37
|
-
await showUsage(...(await resolveSubCommand(cmd, rawArgs)));
|
|
38
|
-
relinka("error", error.message);
|
|
39
|
-
} else {
|
|
40
|
-
relinka("error", error, "\n");
|
|
41
|
-
}
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function createMain<T extends ArgsDef = ArgsDef>(
|
|
47
|
-
cmd: CommandDef<T>,
|
|
48
|
-
): (opts?: RunMainOptions) => Promise<void> {
|
|
49
|
-
return (opts: RunMainOptions = {}) => runMain(cmd, opts);
|
|
50
|
-
}
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { re } from "@reliverse/relico";
|
|
2
|
-
import { relinka } from "@reliverse/relinka";
|
|
3
|
-
|
|
4
|
-
import type { ArgsDef, CommandDef } from "~/types.js";
|
|
5
|
-
|
|
6
|
-
import { formatLineColumns, resolveValue } from "./_utils.js";
|
|
7
|
-
import { resolveArgs } from "./args.js";
|
|
8
|
-
|
|
9
|
-
export async function showUsage<T extends ArgsDef = ArgsDef>(
|
|
10
|
-
cmd: CommandDef<T>,
|
|
11
|
-
parent?: CommandDef<T>,
|
|
12
|
-
) {
|
|
13
|
-
try {
|
|
14
|
-
// biome-ignore lint/style/useTemplate: <explanation>
|
|
15
|
-
relinka("log", (await renderUsage(cmd, parent)) + "\n");
|
|
16
|
-
} catch (error) {
|
|
17
|
-
relinka("error", String(error));
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// `no` prefix matcher (kebab-case or camelCase)
|
|
22
|
-
const negativePrefixRe = /^no[-A-Z]/;
|
|
23
|
-
|
|
24
|
-
export async function renderUsage<T extends ArgsDef = ArgsDef>(
|
|
25
|
-
cmd: CommandDef<T>,
|
|
26
|
-
parent?: CommandDef<T>,
|
|
27
|
-
) {
|
|
28
|
-
const cmdMeta = await resolveValue(cmd.meta || {});
|
|
29
|
-
const cmdArgs = resolveArgs(await resolveValue(cmd.args || {}));
|
|
30
|
-
const parentMeta = await resolveValue(parent?.meta || {});
|
|
31
|
-
|
|
32
|
-
const commandName =
|
|
33
|
-
(parentMeta.name ? `${parentMeta.name} ` : "") +
|
|
34
|
-
(cmdMeta.name || process.argv[1]);
|
|
35
|
-
|
|
36
|
-
const argLines: string[][] = [];
|
|
37
|
-
const posLines: string[][] = [];
|
|
38
|
-
const commandsLines: string[][] = [];
|
|
39
|
-
const usageLine = [];
|
|
40
|
-
|
|
41
|
-
for (const arg of cmdArgs) {
|
|
42
|
-
if (arg.type === "positional") {
|
|
43
|
-
const name = arg.name.toUpperCase();
|
|
44
|
-
const isRequired = arg.required !== false && arg.default === undefined;
|
|
45
|
-
// (isRequired ? " (required)" : " (optional)"
|
|
46
|
-
const defaultHint = arg.default ? `="${arg.default}"` : "";
|
|
47
|
-
posLines.push([
|
|
48
|
-
// biome-ignore lint/style/useTemplate: <explanation>
|
|
49
|
-
"`" + name + defaultHint + "`",
|
|
50
|
-
arg.description || "",
|
|
51
|
-
arg.valueHint ? `<${arg.valueHint}>` : "",
|
|
52
|
-
]);
|
|
53
|
-
usageLine.push(isRequired ? `<${name}>` : `[${name}]`);
|
|
54
|
-
} else {
|
|
55
|
-
const isRequired = arg.required === true && arg.default === undefined;
|
|
56
|
-
const argStr =
|
|
57
|
-
[...(arg.alias || []).map((a) => `-${a}`), `--${arg.name}`].join(", ") +
|
|
58
|
-
(arg.type === "string" && (arg.valueHint || arg.default)
|
|
59
|
-
? `=${
|
|
60
|
-
arg.valueHint ? `<${arg.valueHint}>` : `"${arg.default || ""}"`
|
|
61
|
-
}`
|
|
62
|
-
: "") +
|
|
63
|
-
(arg.type === "enum" && arg.options
|
|
64
|
-
? `=<${arg.options.join("|")}>`
|
|
65
|
-
: "");
|
|
66
|
-
argLines.push([
|
|
67
|
-
// biome-ignore lint/style/useTemplate: <explanation>
|
|
68
|
-
"`" + argStr + (isRequired ? " (required)" : "") + "`",
|
|
69
|
-
arg.description || "",
|
|
70
|
-
]);
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* print negative boolean arg variant usage when
|
|
74
|
-
* - enabled by default or has `negativeDescription`
|
|
75
|
-
* - not prefixed with `no-` or `no[A-Z]`
|
|
76
|
-
*/
|
|
77
|
-
if (
|
|
78
|
-
arg.type === "boolean" &&
|
|
79
|
-
(arg.default === true || arg.negativeDescription) &&
|
|
80
|
-
!negativePrefixRe.test(arg.name)
|
|
81
|
-
) {
|
|
82
|
-
const negativeArgStr = [
|
|
83
|
-
...(arg.alias || []).map((a) => `--no-${a}`),
|
|
84
|
-
`--no-${arg.name}`,
|
|
85
|
-
].join(", ");
|
|
86
|
-
argLines.push([
|
|
87
|
-
// biome-ignore lint/style/useTemplate: <explanation>
|
|
88
|
-
"`" + negativeArgStr + (isRequired ? " (required)" : "") + "`",
|
|
89
|
-
arg.negativeDescription || "",
|
|
90
|
-
]);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (isRequired) {
|
|
94
|
-
usageLine.push(argStr);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (cmd.subCommands) {
|
|
100
|
-
const commandNames: string[] = [];
|
|
101
|
-
const subCommands = await resolveValue(cmd.subCommands);
|
|
102
|
-
for (const [name, sub] of Object.entries(subCommands)) {
|
|
103
|
-
const subCmd = await resolveValue(sub);
|
|
104
|
-
const meta = await resolveValue(subCmd?.meta);
|
|
105
|
-
if (meta?.hidden) {
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
commandsLines.push([`\`${name}\``, meta?.description || ""]);
|
|
109
|
-
commandNames.push(name);
|
|
110
|
-
}
|
|
111
|
-
usageLine.push(commandNames.join("|"));
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const usageLines: (string | undefined)[] = [];
|
|
115
|
-
|
|
116
|
-
const version = cmdMeta.version || parentMeta.version;
|
|
117
|
-
|
|
118
|
-
usageLines.push(
|
|
119
|
-
re.gray(
|
|
120
|
-
`${cmdMeta.description} (${
|
|
121
|
-
commandName + (version ? ` v${version}` : "")
|
|
122
|
-
})`,
|
|
123
|
-
),
|
|
124
|
-
"",
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
const hasOptions = argLines.length > 0 || posLines.length > 0;
|
|
128
|
-
usageLines.push(
|
|
129
|
-
`${re.underline(re.bold("USAGE"))} \`${commandName}${
|
|
130
|
-
hasOptions ? " [OPTIONS]" : ""
|
|
131
|
-
} ${usageLine.join(" ")}\``,
|
|
132
|
-
"",
|
|
133
|
-
);
|
|
134
|
-
|
|
135
|
-
if (posLines.length > 0) {
|
|
136
|
-
usageLines.push(re.underline(re.bold("ARGUMENTS")), "");
|
|
137
|
-
usageLines.push(formatLineColumns(posLines, " "));
|
|
138
|
-
usageLines.push("");
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (argLines.length > 0) {
|
|
142
|
-
usageLines.push(re.underline(re.bold("OPTIONS")), "");
|
|
143
|
-
usageLines.push(formatLineColumns(argLines, " "));
|
|
144
|
-
usageLines.push("");
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (commandsLines.length > 0) {
|
|
148
|
-
usageLines.push(re.underline(re.bold("COMMANDS")), "");
|
|
149
|
-
usageLines.push(formatLineColumns(commandsLines, " "));
|
|
150
|
-
usageLines.push(
|
|
151
|
-
"",
|
|
152
|
-
`Use \`${commandName} <command> --help\` for more information about a command.`,
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return usageLines.filter((l) => typeof l === "string").join("\n");
|
|
157
|
-
}
|