clerc 0.6.0 → 0.7.0
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/dist/index.cjs +155 -33
- package/dist/index.d.ts +43 -12
- package/dist/index.mjs +151 -34
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -12,7 +12,15 @@ class SingleCommandError extends Error {
|
|
|
12
12
|
super("Single command mode enabled.");
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
class SingleCommandAliasError extends Error {
|
|
16
|
+
constructor() {
|
|
17
|
+
super("Single command cannot have alias.");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
15
20
|
class CommandExistsError extends Error {
|
|
21
|
+
constructor(name) {
|
|
22
|
+
super(`Command "${name}" exists.`);
|
|
23
|
+
}
|
|
16
24
|
}
|
|
17
25
|
class CommonCommandExistsError extends Error {
|
|
18
26
|
constructor() {
|
|
@@ -34,32 +42,44 @@ class SubcommandExistsError extends Error {
|
|
|
34
42
|
super(`Command "${name}" cannot exist with its subcommand`);
|
|
35
43
|
}
|
|
36
44
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const item = utils.mustArray(command.alias).map(utils.kebabCase);
|
|
41
|
-
acc[utils.kebabCase(name)] = item;
|
|
45
|
+
class MultipleCommandsMatchedError extends Error {
|
|
46
|
+
constructor(name) {
|
|
47
|
+
super(`Multiple commands matched: ${name}`);
|
|
42
48
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (item) {
|
|
48
|
-
acc[name] = item;
|
|
49
|
+
}
|
|
50
|
+
class CommandNameConflictError extends Error {
|
|
51
|
+
constructor(n1, n2) {
|
|
52
|
+
super(`Command name ${n1} conflicts with ${n2}. Maybe caused by alias.`);
|
|
49
53
|
}
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
}
|
|
55
|
+
|
|
52
56
|
function resolveCommand(commands, name) {
|
|
53
57
|
if (name === SingleCommand) {
|
|
54
58
|
return commands[SingleCommand];
|
|
55
59
|
}
|
|
56
|
-
const nameArr =
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
const nameArr = utils.mustArray(name);
|
|
61
|
+
const commandsMap = /* @__PURE__ */ new Map();
|
|
62
|
+
for (const command of Object.values(commands)) {
|
|
63
|
+
if (command.alias) {
|
|
64
|
+
const aliases = utils.mustArray(command.alias);
|
|
65
|
+
for (const alias of aliases) {
|
|
66
|
+
if (alias in commands) {
|
|
67
|
+
throw new CommandNameConflictError(commands[alias].name, command.name);
|
|
68
|
+
}
|
|
69
|
+
commandsMap.set(alias.split(" "), command);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
commandsMap.set(command.name.split(" "), command);
|
|
73
|
+
}
|
|
74
|
+
const possibleCommands = [];
|
|
75
|
+
commandsMap.forEach((v, k) => {
|
|
76
|
+
if (utils.arrayStartsWith(nameArr, k)) {
|
|
77
|
+
possibleCommands.push(v);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
61
80
|
if (possibleCommands.length > 1) {
|
|
62
|
-
|
|
81
|
+
const matchedCommandNames = possibleCommands.map((c) => c.name).join(", ");
|
|
82
|
+
throw new MultipleCommandsMatchedError(matchedCommandNames);
|
|
63
83
|
}
|
|
64
84
|
return possibleCommands[0];
|
|
65
85
|
}
|
|
@@ -71,7 +91,10 @@ function resolveSubcommandsByParent(commands, parent, depth = Infinity) {
|
|
|
71
91
|
});
|
|
72
92
|
}
|
|
73
93
|
const resolveRootCommands = (commands) => resolveSubcommandsByParent(commands, "", 1);
|
|
74
|
-
function resolveParametersBeforeFlag(argv) {
|
|
94
|
+
function resolveParametersBeforeFlag(argv, isSingleCommand) {
|
|
95
|
+
if (isSingleCommand) {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
75
98
|
const parameters = [];
|
|
76
99
|
for (const arg of argv) {
|
|
77
100
|
if (arg.startsWith("-")) {
|
|
@@ -92,6 +115,65 @@ function compose(inspectors) {
|
|
|
92
115
|
};
|
|
93
116
|
}
|
|
94
117
|
|
|
118
|
+
const { stringify } = JSON;
|
|
119
|
+
function parseParameters(parameters) {
|
|
120
|
+
const parsedParameters = [];
|
|
121
|
+
let hasOptional;
|
|
122
|
+
let hasSpread;
|
|
123
|
+
for (const parameter of parameters) {
|
|
124
|
+
if (hasSpread) {
|
|
125
|
+
throw new Error(`Invalid parameter: Spread parameter ${stringify(hasSpread)} must be last`);
|
|
126
|
+
}
|
|
127
|
+
const firstCharacter = parameter[0];
|
|
128
|
+
const lastCharacter = parameter[parameter.length - 1];
|
|
129
|
+
let required;
|
|
130
|
+
if (firstCharacter === "<" && lastCharacter === ">") {
|
|
131
|
+
required = true;
|
|
132
|
+
if (hasOptional) {
|
|
133
|
+
throw new Error(`Invalid parameter: Required parameter ${stringify(parameter)} cannot come after optional parameter ${stringify(hasOptional)}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (firstCharacter === "[" && lastCharacter === "]") {
|
|
137
|
+
required = false;
|
|
138
|
+
hasOptional = parameter;
|
|
139
|
+
}
|
|
140
|
+
if (required === void 0) {
|
|
141
|
+
throw new Error(`Invalid parameter: ${stringify(parameter)}. Must be wrapped in <> (required parameter) or [] (optional parameter)`);
|
|
142
|
+
}
|
|
143
|
+
let name = parameter.slice(1, -1);
|
|
144
|
+
const spread = name.slice(-3) === "...";
|
|
145
|
+
if (spread) {
|
|
146
|
+
hasSpread = parameter;
|
|
147
|
+
name = name.slice(0, -3);
|
|
148
|
+
}
|
|
149
|
+
parsedParameters.push({
|
|
150
|
+
name,
|
|
151
|
+
required,
|
|
152
|
+
spread
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return parsedParameters;
|
|
156
|
+
}
|
|
157
|
+
function mapParametersToArguments(mapping, parameters, cliArguments) {
|
|
158
|
+
for (let i = 0; i < parameters.length; i += 1) {
|
|
159
|
+
const { name, required, spread } = parameters[i];
|
|
160
|
+
const camelCaseName = utils.camelCase(name);
|
|
161
|
+
if (camelCaseName in mapping) {
|
|
162
|
+
throw new Error(`Invalid parameter: ${stringify(name)} is used more than once.`);
|
|
163
|
+
}
|
|
164
|
+
const value = spread ? cliArguments.slice(i) : cliArguments[i];
|
|
165
|
+
if (spread) {
|
|
166
|
+
i = parameters.length;
|
|
167
|
+
}
|
|
168
|
+
if (required && (!value || spread && value.length === 0)) {
|
|
169
|
+
console.error(`Error: Missing required parameter ${stringify(name)}
|
|
170
|
+
`);
|
|
171
|
+
return process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
mapping[camelCaseName] = value;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
95
177
|
var __accessCheck = (obj, member, msg) => {
|
|
96
178
|
if (!member.has(obj))
|
|
97
179
|
throw TypeError("Cannot " + msg);
|
|
@@ -153,12 +235,14 @@ const _Clerc = class {
|
|
|
153
235
|
__privateSet(this, _version, version);
|
|
154
236
|
return this;
|
|
155
237
|
}
|
|
156
|
-
command(
|
|
238
|
+
command(nameOrCommand, description, options) {
|
|
239
|
+
const checkIsCommandObject = (nameOrCommand2) => !(typeof nameOrCommand2 === "string" || nameOrCommand2 === SingleCommand);
|
|
240
|
+
const isCommandObject = checkIsCommandObject(nameOrCommand);
|
|
241
|
+
const name = !isCommandObject ? nameOrCommand : nameOrCommand.name;
|
|
157
242
|
if (__privateGet(this, _commands)[name]) {
|
|
158
243
|
if (name === SingleCommand) {
|
|
159
|
-
throw new CommandExistsError("
|
|
244
|
+
throw new CommandExistsError("SingleCommand");
|
|
160
245
|
}
|
|
161
|
-
throw new CommandExistsError(`Command "${name === SingleCommand ? "[SingleCommand]" : name}" already exists`);
|
|
162
246
|
}
|
|
163
247
|
if (__privateGet(this, _isSingleCommand, isSingleCommand_get)) {
|
|
164
248
|
throw new SingleCommandError();
|
|
@@ -166,6 +250,9 @@ const _Clerc = class {
|
|
|
166
250
|
if (name === SingleCommand && __privateGet(this, _hasCommands, hasCommands_get)) {
|
|
167
251
|
throw new CommonCommandExistsError();
|
|
168
252
|
}
|
|
253
|
+
if (name === SingleCommand && (isCommandObject ? nameOrCommand : options).alias) {
|
|
254
|
+
throw new SingleCommandAliasError();
|
|
255
|
+
}
|
|
169
256
|
if (name !== SingleCommand) {
|
|
170
257
|
const splitedName = name.split(" ");
|
|
171
258
|
const existedCommandNames = Object.keys(__privateGet(this, _commands)).filter((name2) => typeof name2 === "string").map((name2) => name2.split(" "));
|
|
@@ -176,7 +263,10 @@ const _Clerc = class {
|
|
|
176
263
|
throw new SubcommandExistsError(splitedName.join(" "));
|
|
177
264
|
}
|
|
178
265
|
}
|
|
179
|
-
__privateGet(this, _commands)[name] = { name, description, ...options };
|
|
266
|
+
__privateGet(this, _commands)[name] = !isCommandObject ? { name, description, ...options } : nameOrCommand;
|
|
267
|
+
if (isCommandObject && nameOrCommand.handler) {
|
|
268
|
+
this.on(nameOrCommand.name, nameOrCommand.handler);
|
|
269
|
+
}
|
|
180
270
|
return this;
|
|
181
271
|
}
|
|
182
272
|
on(name, handler) {
|
|
@@ -191,23 +281,48 @@ const _Clerc = class {
|
|
|
191
281
|
return this;
|
|
192
282
|
}
|
|
193
283
|
parse(argv = resolveArgv()) {
|
|
194
|
-
const name = resolveParametersBeforeFlag(argv);
|
|
284
|
+
const name = resolveParametersBeforeFlag(argv, __privateGet(this, _isSingleCommand, isSingleCommand_get));
|
|
195
285
|
const stringName = name.join(" ");
|
|
196
286
|
const getCommand = () => __privateGet(this, _isSingleCommand, isSingleCommand_get) ? __privateGet(this, _commands)[SingleCommand] : resolveCommand(__privateGet(this, _commands), name);
|
|
197
287
|
const getContext = () => {
|
|
198
288
|
const command = getCommand();
|
|
199
289
|
const isCommandResolved = !!command;
|
|
200
|
-
const
|
|
201
|
-
const { _: args, flags } =
|
|
202
|
-
|
|
290
|
+
const parsed = typeFlag.typeFlag((command == null ? void 0 : command.flags) || {}, [...argv]);
|
|
291
|
+
const { _: args, flags } = parsed;
|
|
292
|
+
let parameters = __privateGet(this, _isSingleCommand, isSingleCommand_get) || !isCommandResolved ? args : args.slice(command.name.split(" ").length);
|
|
293
|
+
let commandParameters = (command == null ? void 0 : command.parameters) || [];
|
|
294
|
+
const hasEof = commandParameters.indexOf("--");
|
|
295
|
+
const eofParameters = commandParameters.slice(hasEof + 1) || [];
|
|
296
|
+
const mapping = /* @__PURE__ */ Object.create(null);
|
|
297
|
+
if (hasEof > -1 && eofParameters.length > 0) {
|
|
298
|
+
commandParameters = commandParameters.slice(0, hasEof);
|
|
299
|
+
const eofArguments = parsed._["--"];
|
|
300
|
+
parameters = parameters.slice(0, -eofArguments.length || void 0);
|
|
301
|
+
mapParametersToArguments(
|
|
302
|
+
mapping,
|
|
303
|
+
parseParameters(commandParameters),
|
|
304
|
+
parameters
|
|
305
|
+
);
|
|
306
|
+
mapParametersToArguments(
|
|
307
|
+
mapping,
|
|
308
|
+
parseParameters(eofParameters),
|
|
309
|
+
eofArguments
|
|
310
|
+
);
|
|
311
|
+
} else {
|
|
312
|
+
mapParametersToArguments(
|
|
313
|
+
mapping,
|
|
314
|
+
parseParameters(commandParameters),
|
|
315
|
+
parameters
|
|
316
|
+
);
|
|
317
|
+
}
|
|
203
318
|
const context = {
|
|
204
319
|
name: command == null ? void 0 : command.name,
|
|
205
320
|
resolved: isCommandResolved,
|
|
206
321
|
isSingleCommand: __privateGet(this, _isSingleCommand, isSingleCommand_get),
|
|
207
|
-
raw:
|
|
208
|
-
parameters,
|
|
322
|
+
raw: parsed,
|
|
323
|
+
parameters: mapping,
|
|
209
324
|
flags,
|
|
210
|
-
unknownFlags:
|
|
325
|
+
unknownFlags: parsed.unknownFlags,
|
|
211
326
|
cli: this
|
|
212
327
|
};
|
|
213
328
|
return context;
|
|
@@ -245,23 +360,30 @@ hasCommands_get = function() {
|
|
|
245
360
|
const definePlugin = (p) => p;
|
|
246
361
|
const defineHandler = (_cli, _key, handler) => handler;
|
|
247
362
|
const defineInspector = (_cli, inspector) => inspector;
|
|
363
|
+
const defineCommand = (c) => c;
|
|
364
|
+
const defineCommandWithHandler = (c) => c;
|
|
248
365
|
|
|
249
366
|
exports.Clerc = Clerc;
|
|
250
367
|
exports.CommandExistsError = CommandExistsError;
|
|
368
|
+
exports.CommandNameConflictError = CommandNameConflictError;
|
|
251
369
|
exports.CommonCommandExistsError = CommonCommandExistsError;
|
|
370
|
+
exports.MultipleCommandsMatchedError = MultipleCommandsMatchedError;
|
|
252
371
|
exports.NoSuchCommandError = NoSuchCommandError;
|
|
253
372
|
exports.ParentCommandExistsError = ParentCommandExistsError;
|
|
254
373
|
exports.SingleCommand = SingleCommand;
|
|
374
|
+
exports.SingleCommandAliasError = SingleCommandAliasError;
|
|
255
375
|
exports.SingleCommandError = SingleCommandError;
|
|
256
376
|
exports.SubcommandExistsError = SubcommandExistsError;
|
|
257
377
|
exports.compose = compose;
|
|
378
|
+
exports.defineCommand = defineCommand;
|
|
379
|
+
exports.defineCommandWithHandler = defineCommandWithHandler;
|
|
258
380
|
exports.defineHandler = defineHandler;
|
|
259
381
|
exports.defineInspector = defineInspector;
|
|
260
382
|
exports.definePlugin = definePlugin;
|
|
383
|
+
exports.mapParametersToArguments = mapParametersToArguments;
|
|
384
|
+
exports.parseParameters = parseParameters;
|
|
261
385
|
exports.resolveArgv = resolveArgv;
|
|
262
386
|
exports.resolveCommand = resolveCommand;
|
|
263
|
-
exports.resolveFlagAlias = resolveFlagAlias;
|
|
264
|
-
exports.resolveFlagDefault = resolveFlagDefault;
|
|
265
387
|
exports.resolveParametersBeforeFlag = resolveParametersBeforeFlag;
|
|
266
388
|
exports.resolveRootCommands = resolveRootCommands;
|
|
267
389
|
exports.resolveSubcommandsByParent = resolveSubcommandsByParent;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _clerc_utils from '@clerc/utils';
|
|
2
|
-
import { MaybeArray, Dict, LiteralUnion } from '@clerc/utils';
|
|
2
|
+
import { MaybeArray, Dict, CamelCase, LiteralUnion } from '@clerc/utils';
|
|
3
3
|
|
|
4
4
|
declare const DOUBLE_DASH = "--";
|
|
5
5
|
type TypeFunction<ReturnType = any> = (value: any) => ReturnType;
|
|
@@ -76,16 +76,22 @@ type FlagOptions = FlagSchema & {
|
|
|
76
76
|
type Flag = FlagOptions & {
|
|
77
77
|
name: string;
|
|
78
78
|
};
|
|
79
|
-
interface CommandOptions<A extends MaybeArray<string> = MaybeArray<string>, F extends Dict<FlagOptions> = Dict<FlagOptions>> {
|
|
79
|
+
interface CommandOptions<P extends string[] = string[], A extends MaybeArray<string> = MaybeArray<string>, F extends Dict<FlagOptions> = Dict<FlagOptions>> {
|
|
80
80
|
alias?: A;
|
|
81
|
+
parameters?: P;
|
|
81
82
|
flags?: F;
|
|
82
83
|
examples?: [string, string][];
|
|
83
84
|
notes?: string[];
|
|
84
85
|
}
|
|
85
|
-
type Command<N extends string | SingleCommandType = string, D extends string = string,
|
|
86
|
+
type Command<N extends string | SingleCommandType = string, D extends string = string, O extends CommandOptions = CommandOptions> = O & {
|
|
86
87
|
name: N;
|
|
87
88
|
description: D;
|
|
88
89
|
};
|
|
90
|
+
type CommandWithHandler<N extends string | SingleCommandType = string, D extends string = string, O extends CommandOptions = CommandOptions> = Command<N, D, O> & {
|
|
91
|
+
handler?: HandlerInCommand<Record<N, Command<N, D, O>>, N>;
|
|
92
|
+
};
|
|
93
|
+
type StripBrackets<Parameter extends string> = (Parameter extends `<${infer ParameterName}>` | `[${infer ParameterName}]` ? (ParameterName extends `${infer SpreadName}...` ? SpreadName : ParameterName) : never);
|
|
94
|
+
type ParameterType<Parameter extends string> = (Parameter extends `<${infer _ParameterName}...>` | `[${infer _ParameterName}...]` ? string[] : Parameter extends `<${infer _ParameterName}>` ? string : Parameter extends `[${infer _ParameterName}]` ? string | undefined : never);
|
|
89
95
|
type CommandRecord = Dict<Command> & {
|
|
90
96
|
[SingleCommand]?: Command;
|
|
91
97
|
};
|
|
@@ -94,17 +100,23 @@ type MakeEventMap<T extends CommandRecord> = {
|
|
|
94
100
|
};
|
|
95
101
|
type PossibleInputKind = string | number | boolean | Dict<any>;
|
|
96
102
|
type NonNullableFlag<T extends Dict<FlagOptions> | undefined> = T extends undefined ? {} : NonNullable<T>;
|
|
103
|
+
type NonNullableParameters<T extends string[] | undefined> = T extends undefined ? [] : NonNullable<T>;
|
|
97
104
|
interface HandlerContext<C extends CommandRecord = CommandRecord, N extends keyof C = keyof C> {
|
|
98
105
|
name?: N;
|
|
99
106
|
resolved: boolean;
|
|
100
107
|
isSingleCommand: boolean;
|
|
101
108
|
raw: ParsedFlags;
|
|
102
|
-
parameters:
|
|
109
|
+
parameters: {
|
|
110
|
+
[Parameter in [...NonNullableParameters<C[N]["parameters"]>][number] as CamelCase<StripBrackets<Parameter>>]: ParameterType<Parameter>;
|
|
111
|
+
};
|
|
103
112
|
unknownFlags: ParsedFlags["unknownFlags"];
|
|
104
113
|
flags: TypeFlag<NonNullableFlag<C[N]["flags"]>>["flags"];
|
|
105
114
|
cli: Clerc<C>;
|
|
106
115
|
}
|
|
107
116
|
type Handler<C extends CommandRecord = CommandRecord, K extends keyof C = keyof C> = (ctx: HandlerContext<C, K>) => void;
|
|
117
|
+
type HandlerInCommand<C extends CommandRecord = CommandRecord, K extends keyof C = keyof C> = (ctx: HandlerContext<C, K> & {
|
|
118
|
+
name: K;
|
|
119
|
+
}) => void;
|
|
108
120
|
type FallbackType<T, U> = {} extends T ? U : T;
|
|
109
121
|
type InspectorContext<C extends CommandRecord = CommandRecord> = HandlerContext<C> & {
|
|
110
122
|
flags: FallbackType<TypeFlag<NonNullableFlag<C[keyof C]["flags"]>>["flags"], Dict<any>>;
|
|
@@ -196,7 +208,8 @@ declare class Clerc<C extends CommandRecord = {}> {
|
|
|
196
208
|
* })
|
|
197
209
|
* ```
|
|
198
210
|
*/
|
|
199
|
-
command<N extends string | SingleCommandType, D extends string, O extends CommandOptions>(
|
|
211
|
+
command<N extends string | SingleCommandType, D extends string, O extends CommandOptions<[...P], A, F>, P extends string[] = string[], A extends MaybeArray<string> = MaybeArray<string>, F extends Dict<FlagOptions> = Dict<FlagOptions>>(c: CommandWithHandler<N, D, O & CommandOptions<[...P], A, F>>): this & Clerc<C & Record<N, Command<N, D, O>>>;
|
|
212
|
+
command<N extends string | SingleCommandType, D extends string, P extends string[], O extends CommandOptions<[...P]>>(name: N, description: D, options: O & CommandOptions<[...P]>): this & Clerc<C & Record<N, Command<N, D, O>>>;
|
|
200
213
|
/**
|
|
201
214
|
* Register a handler
|
|
202
215
|
* @param name
|
|
@@ -252,12 +265,18 @@ declare class Clerc<C extends CommandRecord = {}> {
|
|
|
252
265
|
|
|
253
266
|
declare const definePlugin: <T extends Clerc<{}>, U extends Clerc<{}>>(p: Plugin<T, U>) => Plugin<T, U>;
|
|
254
267
|
declare const defineHandler: <C extends Clerc<{}>, K extends keyof C["_commands"]>(_cli: C, _key: K, handler: Handler<C["_commands"], K>) => Handler<C["_commands"], K>;
|
|
255
|
-
declare const defineInspector: <C extends Clerc<{}>>(_cli: C, inspector: Inspector<C["_commands"]>) => Inspector<C["_commands"]>;
|
|
268
|
+
declare const defineInspector: <C extends Clerc<{}>>(_cli: C, inspector: Inspector<C["_commands"]>) => Inspector<C["_commands"]>;
|
|
269
|
+
declare const defineCommand: <N extends string | typeof SingleCommand, D extends string, P extends string[], O extends CommandOptions<[...P], MaybeArray<string>, Dict<FlagOptions>>>(c: Command<N, D, O>) => Command<N, D, O>;
|
|
270
|
+
declare const defineCommandWithHandler: <N extends string | typeof SingleCommand, D extends string, O extends CommandOptions<[...P], A, F>, P extends string[] = string[], A extends MaybeArray<string> = MaybeArray<string>, F extends Dict<FlagOptions> = Dict<FlagOptions>>(c: CommandWithHandler<N, D, O & CommandOptions<[...P], A, F>>) => CommandWithHandler<N, D, O & CommandOptions<[...P], A, F>>;
|
|
256
271
|
|
|
257
272
|
declare class SingleCommandError extends Error {
|
|
258
273
|
constructor();
|
|
259
274
|
}
|
|
275
|
+
declare class SingleCommandAliasError extends Error {
|
|
276
|
+
constructor();
|
|
277
|
+
}
|
|
260
278
|
declare class CommandExistsError extends Error {
|
|
279
|
+
constructor(name: string);
|
|
261
280
|
}
|
|
262
281
|
declare class CommonCommandExistsError extends Error {
|
|
263
282
|
constructor();
|
|
@@ -270,15 +289,27 @@ declare class ParentCommandExistsError extends Error {
|
|
|
270
289
|
}
|
|
271
290
|
declare class SubcommandExistsError extends Error {
|
|
272
291
|
constructor(name: string);
|
|
292
|
+
}
|
|
293
|
+
declare class MultipleCommandsMatchedError extends Error {
|
|
294
|
+
constructor(name: string);
|
|
295
|
+
}
|
|
296
|
+
declare class CommandNameConflictError extends Error {
|
|
297
|
+
constructor(n1: string, n2: string);
|
|
273
298
|
}
|
|
274
299
|
|
|
275
|
-
declare const resolveFlagAlias: (_command: Command) => Dict<string[]>;
|
|
276
|
-
declare const resolveFlagDefault: (_command: Command) => Dict<any>;
|
|
277
300
|
declare function resolveCommand(commands: CommandRecord, name: string | string[] | SingleCommandType): Command | undefined;
|
|
278
|
-
declare function resolveSubcommandsByParent(commands: CommandRecord, parent: string | string[], depth?: number): Command<string, string, CommandOptions<_clerc_utils.MaybeArray<string>, Dict<FlagOptions>>>[];
|
|
279
|
-
declare const resolveRootCommands: (commands: CommandRecord) => Command<string, string, CommandOptions<_clerc_utils.MaybeArray<string>, Dict<FlagOptions>>>[];
|
|
280
|
-
declare function resolveParametersBeforeFlag(argv: string[]): string[];
|
|
301
|
+
declare function resolveSubcommandsByParent(commands: CommandRecord, parent: string | string[], depth?: number): Command<string, string, CommandOptions<string[], _clerc_utils.MaybeArray<string>, _clerc_utils.Dict<FlagOptions>>>[];
|
|
302
|
+
declare const resolveRootCommands: (commands: CommandRecord) => Command<string, string, CommandOptions<string[], _clerc_utils.MaybeArray<string>, _clerc_utils.Dict<FlagOptions>>>[];
|
|
303
|
+
declare function resolveParametersBeforeFlag(argv: string[], isSingleCommand: boolean): string[];
|
|
281
304
|
declare const resolveArgv: () => string[];
|
|
282
305
|
declare function compose(inspectors: Inspector[]): (getCtx: () => InspectorContext) => void;
|
|
283
306
|
|
|
284
|
-
|
|
307
|
+
interface ParsedParameter {
|
|
308
|
+
name: string;
|
|
309
|
+
required: boolean;
|
|
310
|
+
spread: boolean;
|
|
311
|
+
}
|
|
312
|
+
declare function parseParameters(parameters: string[]): ParsedParameter[];
|
|
313
|
+
declare function mapParametersToArguments(mapping: Record<string, string | string[]>, parameters: ParsedParameter[], cliArguments: string[]): undefined;
|
|
314
|
+
|
|
315
|
+
export { Clerc, Command, CommandExistsError, CommandNameConflictError, CommandOptions, CommandRecord, CommandWithHandler, CommonCommandExistsError, FallbackType, Flag, FlagOptions, Handler, HandlerContext, HandlerInCommand, Inspector, InspectorContext, MakeEventMap, MultipleCommandsMatchedError, NoSuchCommandError, ParentCommandExistsError, Plugin, PossibleInputKind, SingleCommand, SingleCommandAliasError, SingleCommandError, SingleCommandType, SubcommandExistsError, compose, defineCommand, defineCommandWithHandler, defineHandler, defineInspector, definePlugin, mapParametersToArguments, parseParameters, resolveArgv, resolveCommand, resolveParametersBeforeFlag, resolveRootCommands, resolveSubcommandsByParent };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LiteEmit } from 'lite-emit';
|
|
2
2
|
import { typeFlag } from 'type-flag';
|
|
3
|
-
import { mustArray,
|
|
3
|
+
import { mustArray, arrayStartsWith, camelCase } from '@clerc/utils';
|
|
4
4
|
import { isNode, isDeno } from 'is-platform';
|
|
5
5
|
|
|
6
6
|
class SingleCommandError extends Error {
|
|
@@ -8,7 +8,15 @@ class SingleCommandError extends Error {
|
|
|
8
8
|
super("Single command mode enabled.");
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
|
+
class SingleCommandAliasError extends Error {
|
|
12
|
+
constructor() {
|
|
13
|
+
super("Single command cannot have alias.");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
11
16
|
class CommandExistsError extends Error {
|
|
17
|
+
constructor(name) {
|
|
18
|
+
super(`Command "${name}" exists.`);
|
|
19
|
+
}
|
|
12
20
|
}
|
|
13
21
|
class CommonCommandExistsError extends Error {
|
|
14
22
|
constructor() {
|
|
@@ -30,32 +38,44 @@ class SubcommandExistsError extends Error {
|
|
|
30
38
|
super(`Command "${name}" cannot exist with its subcommand`);
|
|
31
39
|
}
|
|
32
40
|
}
|
|
41
|
+
class MultipleCommandsMatchedError extends Error {
|
|
42
|
+
constructor(name) {
|
|
43
|
+
super(`Multiple commands matched: ${name}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
class CommandNameConflictError extends Error {
|
|
47
|
+
constructor(n1, n2) {
|
|
48
|
+
super(`Command name ${n1} conflicts with ${n2}. Maybe caused by alias.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
33
51
|
|
|
34
|
-
const resolveFlagAlias = (_command) => Object.entries((_command == null ? void 0 : _command.flags) || {}).reduce((acc, [name, command]) => {
|
|
35
|
-
if (command.alias) {
|
|
36
|
-
const item = mustArray(command.alias).map(kebabCase);
|
|
37
|
-
acc[kebabCase(name)] = item;
|
|
38
|
-
}
|
|
39
|
-
return acc;
|
|
40
|
-
}, {});
|
|
41
|
-
const resolveFlagDefault = (_command) => Object.entries((_command == null ? void 0 : _command.flags) || {}).reduce((acc, [name, command]) => {
|
|
42
|
-
const item = command.default;
|
|
43
|
-
if (item) {
|
|
44
|
-
acc[name] = item;
|
|
45
|
-
}
|
|
46
|
-
return acc;
|
|
47
|
-
}, {});
|
|
48
52
|
function resolveCommand(commands, name) {
|
|
49
53
|
if (name === SingleCommand) {
|
|
50
54
|
return commands[SingleCommand];
|
|
51
55
|
}
|
|
52
|
-
const nameArr =
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
const nameArr = mustArray(name);
|
|
57
|
+
const commandsMap = /* @__PURE__ */ new Map();
|
|
58
|
+
for (const command of Object.values(commands)) {
|
|
59
|
+
if (command.alias) {
|
|
60
|
+
const aliases = mustArray(command.alias);
|
|
61
|
+
for (const alias of aliases) {
|
|
62
|
+
if (alias in commands) {
|
|
63
|
+
throw new CommandNameConflictError(commands[alias].name, command.name);
|
|
64
|
+
}
|
|
65
|
+
commandsMap.set(alias.split(" "), command);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
commandsMap.set(command.name.split(" "), command);
|
|
69
|
+
}
|
|
70
|
+
const possibleCommands = [];
|
|
71
|
+
commandsMap.forEach((v, k) => {
|
|
72
|
+
if (arrayStartsWith(nameArr, k)) {
|
|
73
|
+
possibleCommands.push(v);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
57
76
|
if (possibleCommands.length > 1) {
|
|
58
|
-
|
|
77
|
+
const matchedCommandNames = possibleCommands.map((c) => c.name).join(", ");
|
|
78
|
+
throw new MultipleCommandsMatchedError(matchedCommandNames);
|
|
59
79
|
}
|
|
60
80
|
return possibleCommands[0];
|
|
61
81
|
}
|
|
@@ -67,7 +87,10 @@ function resolveSubcommandsByParent(commands, parent, depth = Infinity) {
|
|
|
67
87
|
});
|
|
68
88
|
}
|
|
69
89
|
const resolveRootCommands = (commands) => resolveSubcommandsByParent(commands, "", 1);
|
|
70
|
-
function resolveParametersBeforeFlag(argv) {
|
|
90
|
+
function resolveParametersBeforeFlag(argv, isSingleCommand) {
|
|
91
|
+
if (isSingleCommand) {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
71
94
|
const parameters = [];
|
|
72
95
|
for (const arg of argv) {
|
|
73
96
|
if (arg.startsWith("-")) {
|
|
@@ -88,6 +111,65 @@ function compose(inspectors) {
|
|
|
88
111
|
};
|
|
89
112
|
}
|
|
90
113
|
|
|
114
|
+
const { stringify } = JSON;
|
|
115
|
+
function parseParameters(parameters) {
|
|
116
|
+
const parsedParameters = [];
|
|
117
|
+
let hasOptional;
|
|
118
|
+
let hasSpread;
|
|
119
|
+
for (const parameter of parameters) {
|
|
120
|
+
if (hasSpread) {
|
|
121
|
+
throw new Error(`Invalid parameter: Spread parameter ${stringify(hasSpread)} must be last`);
|
|
122
|
+
}
|
|
123
|
+
const firstCharacter = parameter[0];
|
|
124
|
+
const lastCharacter = parameter[parameter.length - 1];
|
|
125
|
+
let required;
|
|
126
|
+
if (firstCharacter === "<" && lastCharacter === ">") {
|
|
127
|
+
required = true;
|
|
128
|
+
if (hasOptional) {
|
|
129
|
+
throw new Error(`Invalid parameter: Required parameter ${stringify(parameter)} cannot come after optional parameter ${stringify(hasOptional)}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (firstCharacter === "[" && lastCharacter === "]") {
|
|
133
|
+
required = false;
|
|
134
|
+
hasOptional = parameter;
|
|
135
|
+
}
|
|
136
|
+
if (required === void 0) {
|
|
137
|
+
throw new Error(`Invalid parameter: ${stringify(parameter)}. Must be wrapped in <> (required parameter) or [] (optional parameter)`);
|
|
138
|
+
}
|
|
139
|
+
let name = parameter.slice(1, -1);
|
|
140
|
+
const spread = name.slice(-3) === "...";
|
|
141
|
+
if (spread) {
|
|
142
|
+
hasSpread = parameter;
|
|
143
|
+
name = name.slice(0, -3);
|
|
144
|
+
}
|
|
145
|
+
parsedParameters.push({
|
|
146
|
+
name,
|
|
147
|
+
required,
|
|
148
|
+
spread
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return parsedParameters;
|
|
152
|
+
}
|
|
153
|
+
function mapParametersToArguments(mapping, parameters, cliArguments) {
|
|
154
|
+
for (let i = 0; i < parameters.length; i += 1) {
|
|
155
|
+
const { name, required, spread } = parameters[i];
|
|
156
|
+
const camelCaseName = camelCase(name);
|
|
157
|
+
if (camelCaseName in mapping) {
|
|
158
|
+
throw new Error(`Invalid parameter: ${stringify(name)} is used more than once.`);
|
|
159
|
+
}
|
|
160
|
+
const value = spread ? cliArguments.slice(i) : cliArguments[i];
|
|
161
|
+
if (spread) {
|
|
162
|
+
i = parameters.length;
|
|
163
|
+
}
|
|
164
|
+
if (required && (!value || spread && value.length === 0)) {
|
|
165
|
+
console.error(`Error: Missing required parameter ${stringify(name)}
|
|
166
|
+
`);
|
|
167
|
+
return process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
mapping[camelCaseName] = value;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
91
173
|
var __accessCheck = (obj, member, msg) => {
|
|
92
174
|
if (!member.has(obj))
|
|
93
175
|
throw TypeError("Cannot " + msg);
|
|
@@ -149,12 +231,14 @@ const _Clerc = class {
|
|
|
149
231
|
__privateSet(this, _version, version);
|
|
150
232
|
return this;
|
|
151
233
|
}
|
|
152
|
-
command(
|
|
234
|
+
command(nameOrCommand, description, options) {
|
|
235
|
+
const checkIsCommandObject = (nameOrCommand2) => !(typeof nameOrCommand2 === "string" || nameOrCommand2 === SingleCommand);
|
|
236
|
+
const isCommandObject = checkIsCommandObject(nameOrCommand);
|
|
237
|
+
const name = !isCommandObject ? nameOrCommand : nameOrCommand.name;
|
|
153
238
|
if (__privateGet(this, _commands)[name]) {
|
|
154
239
|
if (name === SingleCommand) {
|
|
155
|
-
throw new CommandExistsError("
|
|
240
|
+
throw new CommandExistsError("SingleCommand");
|
|
156
241
|
}
|
|
157
|
-
throw new CommandExistsError(`Command "${name === SingleCommand ? "[SingleCommand]" : name}" already exists`);
|
|
158
242
|
}
|
|
159
243
|
if (__privateGet(this, _isSingleCommand, isSingleCommand_get)) {
|
|
160
244
|
throw new SingleCommandError();
|
|
@@ -162,6 +246,9 @@ const _Clerc = class {
|
|
|
162
246
|
if (name === SingleCommand && __privateGet(this, _hasCommands, hasCommands_get)) {
|
|
163
247
|
throw new CommonCommandExistsError();
|
|
164
248
|
}
|
|
249
|
+
if (name === SingleCommand && (isCommandObject ? nameOrCommand : options).alias) {
|
|
250
|
+
throw new SingleCommandAliasError();
|
|
251
|
+
}
|
|
165
252
|
if (name !== SingleCommand) {
|
|
166
253
|
const splitedName = name.split(" ");
|
|
167
254
|
const existedCommandNames = Object.keys(__privateGet(this, _commands)).filter((name2) => typeof name2 === "string").map((name2) => name2.split(" "));
|
|
@@ -172,7 +259,10 @@ const _Clerc = class {
|
|
|
172
259
|
throw new SubcommandExistsError(splitedName.join(" "));
|
|
173
260
|
}
|
|
174
261
|
}
|
|
175
|
-
__privateGet(this, _commands)[name] = { name, description, ...options };
|
|
262
|
+
__privateGet(this, _commands)[name] = !isCommandObject ? { name, description, ...options } : nameOrCommand;
|
|
263
|
+
if (isCommandObject && nameOrCommand.handler) {
|
|
264
|
+
this.on(nameOrCommand.name, nameOrCommand.handler);
|
|
265
|
+
}
|
|
176
266
|
return this;
|
|
177
267
|
}
|
|
178
268
|
on(name, handler) {
|
|
@@ -187,23 +277,48 @@ const _Clerc = class {
|
|
|
187
277
|
return this;
|
|
188
278
|
}
|
|
189
279
|
parse(argv = resolveArgv()) {
|
|
190
|
-
const name = resolveParametersBeforeFlag(argv);
|
|
280
|
+
const name = resolveParametersBeforeFlag(argv, __privateGet(this, _isSingleCommand, isSingleCommand_get));
|
|
191
281
|
const stringName = name.join(" ");
|
|
192
282
|
const getCommand = () => __privateGet(this, _isSingleCommand, isSingleCommand_get) ? __privateGet(this, _commands)[SingleCommand] : resolveCommand(__privateGet(this, _commands), name);
|
|
193
283
|
const getContext = () => {
|
|
194
284
|
const command = getCommand();
|
|
195
285
|
const isCommandResolved = !!command;
|
|
196
|
-
const
|
|
197
|
-
const { _: args, flags } =
|
|
198
|
-
|
|
286
|
+
const parsed = typeFlag((command == null ? void 0 : command.flags) || {}, [...argv]);
|
|
287
|
+
const { _: args, flags } = parsed;
|
|
288
|
+
let parameters = __privateGet(this, _isSingleCommand, isSingleCommand_get) || !isCommandResolved ? args : args.slice(command.name.split(" ").length);
|
|
289
|
+
let commandParameters = (command == null ? void 0 : command.parameters) || [];
|
|
290
|
+
const hasEof = commandParameters.indexOf("--");
|
|
291
|
+
const eofParameters = commandParameters.slice(hasEof + 1) || [];
|
|
292
|
+
const mapping = /* @__PURE__ */ Object.create(null);
|
|
293
|
+
if (hasEof > -1 && eofParameters.length > 0) {
|
|
294
|
+
commandParameters = commandParameters.slice(0, hasEof);
|
|
295
|
+
const eofArguments = parsed._["--"];
|
|
296
|
+
parameters = parameters.slice(0, -eofArguments.length || void 0);
|
|
297
|
+
mapParametersToArguments(
|
|
298
|
+
mapping,
|
|
299
|
+
parseParameters(commandParameters),
|
|
300
|
+
parameters
|
|
301
|
+
);
|
|
302
|
+
mapParametersToArguments(
|
|
303
|
+
mapping,
|
|
304
|
+
parseParameters(eofParameters),
|
|
305
|
+
eofArguments
|
|
306
|
+
);
|
|
307
|
+
} else {
|
|
308
|
+
mapParametersToArguments(
|
|
309
|
+
mapping,
|
|
310
|
+
parseParameters(commandParameters),
|
|
311
|
+
parameters
|
|
312
|
+
);
|
|
313
|
+
}
|
|
199
314
|
const context = {
|
|
200
315
|
name: command == null ? void 0 : command.name,
|
|
201
316
|
resolved: isCommandResolved,
|
|
202
317
|
isSingleCommand: __privateGet(this, _isSingleCommand, isSingleCommand_get),
|
|
203
|
-
raw:
|
|
204
|
-
parameters,
|
|
318
|
+
raw: parsed,
|
|
319
|
+
parameters: mapping,
|
|
205
320
|
flags,
|
|
206
|
-
unknownFlags:
|
|
321
|
+
unknownFlags: parsed.unknownFlags,
|
|
207
322
|
cli: this
|
|
208
323
|
};
|
|
209
324
|
return context;
|
|
@@ -241,5 +356,7 @@ hasCommands_get = function() {
|
|
|
241
356
|
const definePlugin = (p) => p;
|
|
242
357
|
const defineHandler = (_cli, _key, handler) => handler;
|
|
243
358
|
const defineInspector = (_cli, inspector) => inspector;
|
|
359
|
+
const defineCommand = (c) => c;
|
|
360
|
+
const defineCommandWithHandler = (c) => c;
|
|
244
361
|
|
|
245
|
-
export { Clerc, CommandExistsError, CommonCommandExistsError, NoSuchCommandError, ParentCommandExistsError, SingleCommand, SingleCommandError, SubcommandExistsError, compose, defineHandler, defineInspector, definePlugin,
|
|
362
|
+
export { Clerc, CommandExistsError, CommandNameConflictError, CommonCommandExistsError, MultipleCommandsMatchedError, NoSuchCommandError, ParentCommandExistsError, SingleCommand, SingleCommandAliasError, SingleCommandError, SubcommandExistsError, compose, defineCommand, defineCommandWithHandler, defineHandler, defineInspector, definePlugin, mapParametersToArguments, parseParameters, resolveArgv, resolveCommand, resolveParametersBeforeFlag, resolveRootCommands, resolveSubcommandsByParent };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clerc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"author": "Ray <nn_201312@163.com> (https://github.com/so1ve)",
|
|
5
5
|
"description": "Clerc is a simple and easy-to-use cli framework.",
|
|
6
6
|
"keywords": [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@clerc/utils": "0.
|
|
42
|
+
"@clerc/utils": "0.7.0",
|
|
43
43
|
"is-platform": "^0.2.0",
|
|
44
44
|
"lite-emit": "^1.4.0",
|
|
45
45
|
"type-flag": "^3.0.0"
|