clerc 0.6.1 → 0.8.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 +157 -35
- package/dist/index.d.ts +47 -14
- package/dist/index.mjs +153 -36
- 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;
|
|
@@ -221,8 +336,8 @@ const _Clerc = class {
|
|
|
221
336
|
__privateGet(this, _commandEmitter).emit(command.name, handlerContext);
|
|
222
337
|
};
|
|
223
338
|
const inspectors = [...__privateGet(this, _inspectors), emitHandler];
|
|
224
|
-
const
|
|
225
|
-
|
|
339
|
+
const callInspector = compose(inspectors);
|
|
340
|
+
callInspector(getContext);
|
|
226
341
|
return this;
|
|
227
342
|
}
|
|
228
343
|
};
|
|
@@ -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,24 @@ type FlagOptions = FlagSchema & {
|
|
|
76
76
|
type Flag = FlagOptions & {
|
|
77
77
|
name: string;
|
|
78
78
|
};
|
|
79
|
-
interface
|
|
79
|
+
declare interface CommandCustomProperties {
|
|
80
|
+
}
|
|
81
|
+
interface CommandOptions<P extends string[] = string[], A extends MaybeArray<string> = MaybeArray<string>, F extends Dict<FlagOptions> = Dict<FlagOptions>> extends CommandCustomProperties {
|
|
80
82
|
alias?: A;
|
|
83
|
+
parameters?: P;
|
|
81
84
|
flags?: F;
|
|
82
85
|
examples?: [string, string][];
|
|
83
86
|
notes?: string[];
|
|
84
87
|
}
|
|
85
|
-
type Command<N extends string | SingleCommandType = string,
|
|
88
|
+
type Command<N extends string | SingleCommandType = string, O extends CommandOptions = CommandOptions> = O & {
|
|
86
89
|
name: N;
|
|
87
|
-
description:
|
|
90
|
+
description: string;
|
|
88
91
|
};
|
|
92
|
+
type CommandWithHandler<N extends string | SingleCommandType = string, O extends CommandOptions = CommandOptions> = Command<N, O> & {
|
|
93
|
+
handler?: HandlerInCommand<Record<N, Command<N, O>>, N>;
|
|
94
|
+
};
|
|
95
|
+
type StripBrackets<Parameter extends string> = (Parameter extends `<${infer ParameterName}>` | `[${infer ParameterName}]` ? (ParameterName extends `${infer SpreadName}...` ? SpreadName : ParameterName) : never);
|
|
96
|
+
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
97
|
type CommandRecord = Dict<Command> & {
|
|
90
98
|
[SingleCommand]?: Command;
|
|
91
99
|
};
|
|
@@ -94,17 +102,23 @@ type MakeEventMap<T extends CommandRecord> = {
|
|
|
94
102
|
};
|
|
95
103
|
type PossibleInputKind = string | number | boolean | Dict<any>;
|
|
96
104
|
type NonNullableFlag<T extends Dict<FlagOptions> | undefined> = T extends undefined ? {} : NonNullable<T>;
|
|
105
|
+
type NonNullableParameters<T extends string[] | undefined> = T extends undefined ? [] : NonNullable<T>;
|
|
97
106
|
interface HandlerContext<C extends CommandRecord = CommandRecord, N extends keyof C = keyof C> {
|
|
98
107
|
name?: N;
|
|
99
108
|
resolved: boolean;
|
|
100
109
|
isSingleCommand: boolean;
|
|
101
|
-
raw:
|
|
102
|
-
parameters:
|
|
110
|
+
raw: TypeFlag<NonNullableFlag<C[N]["flags"]>>;
|
|
111
|
+
parameters: {
|
|
112
|
+
[Parameter in [...NonNullableParameters<C[N]["parameters"]>][number] as CamelCase<StripBrackets<Parameter>>]: ParameterType<Parameter>;
|
|
113
|
+
};
|
|
103
114
|
unknownFlags: ParsedFlags["unknownFlags"];
|
|
104
115
|
flags: TypeFlag<NonNullableFlag<C[N]["flags"]>>["flags"];
|
|
105
116
|
cli: Clerc<C>;
|
|
106
117
|
}
|
|
107
118
|
type Handler<C extends CommandRecord = CommandRecord, K extends keyof C = keyof C> = (ctx: HandlerContext<C, K>) => void;
|
|
119
|
+
type HandlerInCommand<C extends CommandRecord = CommandRecord, K extends keyof C = keyof C> = (ctx: HandlerContext<C, K> & {
|
|
120
|
+
name: K;
|
|
121
|
+
}) => void;
|
|
108
122
|
type FallbackType<T, U> = {} extends T ? U : T;
|
|
109
123
|
type InspectorContext<C extends CommandRecord = CommandRecord> = HandlerContext<C> & {
|
|
110
124
|
flags: FallbackType<TypeFlag<NonNullableFlag<C[keyof C]["flags"]>>["flags"], Dict<any>>;
|
|
@@ -196,7 +210,8 @@ declare class Clerc<C extends CommandRecord = {}> {
|
|
|
196
210
|
* })
|
|
197
211
|
* ```
|
|
198
212
|
*/
|
|
199
|
-
command<N extends string | SingleCommandType,
|
|
213
|
+
command<N extends string | SingleCommandType, 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, O & CommandOptions<[...P], A, F>>): this & Clerc<C & Record<N, Command<N, O>>>;
|
|
214
|
+
command<N extends string | SingleCommandType, P extends string[], O extends CommandOptions<[...P]>>(name: N, description: string, options?: O & CommandOptions<[...P]>): this & Clerc<C & Record<N, Command<N, O>>>;
|
|
200
215
|
/**
|
|
201
216
|
* Register a handler
|
|
202
217
|
* @param name
|
|
@@ -252,12 +267,18 @@ declare class Clerc<C extends CommandRecord = {}> {
|
|
|
252
267
|
|
|
253
268
|
declare const definePlugin: <T extends Clerc<{}>, U extends Clerc<{}>>(p: Plugin<T, U>) => Plugin<T, U>;
|
|
254
269
|
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"]>;
|
|
270
|
+
declare const defineInspector: <C extends Clerc<{}>>(_cli: C, inspector: Inspector<C["_commands"]>) => Inspector<C["_commands"]>;
|
|
271
|
+
declare const defineCommand: <N extends string | typeof SingleCommand, P extends string[], O extends CommandOptions<[...P], MaybeArray<string>, Dict<FlagOptions>>>(c: Command<N, O>) => Command<N, O>;
|
|
272
|
+
declare const defineCommandWithHandler: <N extends string | typeof SingleCommand, 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, O & CommandOptions<[...P], A, F>>) => CommandWithHandler<N, O & CommandOptions<[...P], A, F>>;
|
|
256
273
|
|
|
257
274
|
declare class SingleCommandError extends Error {
|
|
258
275
|
constructor();
|
|
259
276
|
}
|
|
277
|
+
declare class SingleCommandAliasError extends Error {
|
|
278
|
+
constructor();
|
|
279
|
+
}
|
|
260
280
|
declare class CommandExistsError extends Error {
|
|
281
|
+
constructor(name: string);
|
|
261
282
|
}
|
|
262
283
|
declare class CommonCommandExistsError extends Error {
|
|
263
284
|
constructor();
|
|
@@ -270,15 +291,27 @@ declare class ParentCommandExistsError extends Error {
|
|
|
270
291
|
}
|
|
271
292
|
declare class SubcommandExistsError extends Error {
|
|
272
293
|
constructor(name: string);
|
|
294
|
+
}
|
|
295
|
+
declare class MultipleCommandsMatchedError extends Error {
|
|
296
|
+
constructor(name: string);
|
|
297
|
+
}
|
|
298
|
+
declare class CommandNameConflictError extends Error {
|
|
299
|
+
constructor(n1: string, n2: string);
|
|
273
300
|
}
|
|
274
301
|
|
|
275
|
-
declare const resolveFlagAlias: (_command: Command) => Dict<string[]>;
|
|
276
|
-
declare const resolveFlagDefault: (_command: Command) => Dict<any>;
|
|
277
302
|
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,
|
|
279
|
-
declare const resolveRootCommands: (commands: CommandRecord) => Command<string, string,
|
|
280
|
-
declare function resolveParametersBeforeFlag(argv: string[]): string[];
|
|
303
|
+
declare function resolveSubcommandsByParent(commands: CommandRecord, parent: string | string[], depth?: number): Command<string, CommandOptions<string[], _clerc_utils.MaybeArray<string>, _clerc_utils.Dict<FlagOptions>>>[];
|
|
304
|
+
declare const resolveRootCommands: (commands: CommandRecord) => Command<string, CommandOptions<string[], _clerc_utils.MaybeArray<string>, _clerc_utils.Dict<FlagOptions>>>[];
|
|
305
|
+
declare function resolveParametersBeforeFlag(argv: string[], isSingleCommand: boolean): string[];
|
|
281
306
|
declare const resolveArgv: () => string[];
|
|
282
307
|
declare function compose(inspectors: Inspector[]): (getCtx: () => InspectorContext) => void;
|
|
283
308
|
|
|
284
|
-
|
|
309
|
+
interface ParsedParameter {
|
|
310
|
+
name: string;
|
|
311
|
+
required: boolean;
|
|
312
|
+
spread: boolean;
|
|
313
|
+
}
|
|
314
|
+
declare function parseParameters(parameters: string[]): ParsedParameter[];
|
|
315
|
+
declare function mapParametersToArguments(mapping: Record<string, string | string[]>, parameters: ParsedParameter[], cliArguments: string[]): undefined;
|
|
316
|
+
|
|
317
|
+
export { Clerc, Command, CommandCustomProperties, 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;
|
|
@@ -217,8 +332,8 @@ const _Clerc = class {
|
|
|
217
332
|
__privateGet(this, _commandEmitter).emit(command.name, handlerContext);
|
|
218
333
|
};
|
|
219
334
|
const inspectors = [...__privateGet(this, _inspectors), emitHandler];
|
|
220
|
-
const
|
|
221
|
-
|
|
335
|
+
const callInspector = compose(inspectors);
|
|
336
|
+
callInspector(getContext);
|
|
222
337
|
return this;
|
|
223
338
|
}
|
|
224
339
|
};
|
|
@@ -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.8.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": "npm:@clerc/toolkit@0.8.0",
|
|
43
43
|
"is-platform": "^0.2.0",
|
|
44
44
|
"lite-emit": "^1.4.0",
|
|
45
45
|
"type-flag": "^3.0.0"
|