@reliverse/rempts 1.7.11 → 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 +150 -48
- 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/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
|
-
}
|