clerc 0.0.3 → 0.1.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 +99 -46
- package/dist/index.d.ts +176 -24
- package/dist/index.mjs +91 -47
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -4,47 +4,76 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var liteEmit = require('lite-emit');
|
|
6
6
|
var minimist = require('minimist');
|
|
7
|
+
var isPlatform = require('is-platform');
|
|
7
8
|
|
|
8
9
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
9
10
|
|
|
10
11
|
var minimist__default = /*#__PURE__*/_interopDefaultLegacy(minimist);
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
class SingleCommandError extends Error {
|
|
14
|
+
}
|
|
15
|
+
class CommandExistsError extends Error {
|
|
16
|
+
}
|
|
17
|
+
class CommonCommandExistsError extends Error {
|
|
18
|
+
}
|
|
19
|
+
class NoSuchCommandsError extends Error {
|
|
19
20
|
}
|
|
21
|
+
|
|
22
|
+
const mustArray = (a) => Array.isArray(a) ? a : [a];
|
|
23
|
+
const camelCase = (s) => s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
24
|
+
const kebabCase = (s) => s.replace(/([A-Z])/g, (_, c) => `-${c.toLowerCase()}`);
|
|
25
|
+
const resolveFlagAlias = (_command) => Object.entries((_command == null ? void 0 : _command.flags) || {}).reduce((acc, [name, command]) => {
|
|
26
|
+
if (command.alias) {
|
|
27
|
+
const item = mustArray(command.alias).map(kebabCase);
|
|
28
|
+
acc[kebabCase(name)] = item;
|
|
29
|
+
}
|
|
30
|
+
return acc;
|
|
31
|
+
}, {});
|
|
32
|
+
const resolveFlagDefault = (_command) => Object.entries((_command == null ? void 0 : _command.flags) || {}).reduce((acc, [name, command]) => {
|
|
33
|
+
const item = command.default;
|
|
34
|
+
if (item) {
|
|
35
|
+
acc[name] = item;
|
|
36
|
+
}
|
|
37
|
+
return acc;
|
|
38
|
+
}, {});
|
|
20
39
|
function resolveCommand(commands, name) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
40
|
+
if (name === SingleCommand) {
|
|
41
|
+
return commands[SingleCommand];
|
|
42
|
+
}
|
|
43
|
+
const possibleCommands = Object.values(commands).filter(
|
|
44
|
+
(c) => c.name === name || mustArray(c.alias || []).map(String).includes(name)
|
|
45
|
+
);
|
|
25
46
|
if (possibleCommands.length > 1) {
|
|
26
47
|
throw new Error(`Multiple commands found with name "${name}"`);
|
|
27
48
|
}
|
|
28
49
|
return possibleCommands[0];
|
|
29
50
|
}
|
|
30
|
-
|
|
31
|
-
|
|
51
|
+
const resolveArgv = () => isPlatform.isNode() ? process.argv.slice(2) : isPlatform.isDeno() ? Deno.args : [];
|
|
52
|
+
function compose(inspectors) {
|
|
53
|
+
return (ctx) => {
|
|
32
54
|
return dispatch(0);
|
|
33
55
|
function dispatch(i) {
|
|
34
|
-
const
|
|
35
|
-
return
|
|
56
|
+
const inspector = inspectors[i];
|
|
57
|
+
return inspector(ctx, dispatch.bind(null, i + 1));
|
|
36
58
|
}
|
|
37
59
|
};
|
|
38
60
|
}
|
|
39
61
|
|
|
62
|
+
const SingleCommand = Symbol("SingleCommand");
|
|
40
63
|
class Clerc {
|
|
41
64
|
constructor() {
|
|
42
65
|
this._name = "";
|
|
43
66
|
this._description = "";
|
|
44
67
|
this._version = "";
|
|
45
|
-
this.
|
|
68
|
+
this._inspectors = [];
|
|
46
69
|
this._commands = {};
|
|
47
|
-
this.
|
|
70
|
+
this.__commandEmitter = new liteEmit.LiteEmit();
|
|
71
|
+
}
|
|
72
|
+
get __isSingleCommand() {
|
|
73
|
+
return this._commands[SingleCommand] !== void 0;
|
|
74
|
+
}
|
|
75
|
+
get __hasCommands() {
|
|
76
|
+
return Object.keys(this._commands).length > 0;
|
|
48
77
|
}
|
|
49
78
|
static create() {
|
|
50
79
|
return new Clerc();
|
|
@@ -62,57 +91,81 @@ class Clerc {
|
|
|
62
91
|
return this;
|
|
63
92
|
}
|
|
64
93
|
command(name, description, options = {}) {
|
|
65
|
-
|
|
66
|
-
|
|
94
|
+
if (this._commands[name]) {
|
|
95
|
+
if (name === SingleCommand) {
|
|
96
|
+
throw new CommandExistsError("Single command already exists");
|
|
97
|
+
}
|
|
98
|
+
throw new CommandExistsError(`Command "${name === SingleCommand ? "[SingleCommand]" : name}" already exists`);
|
|
99
|
+
}
|
|
100
|
+
if (this.__isSingleCommand) {
|
|
101
|
+
throw new SingleCommandError("Single command mode enabled");
|
|
102
|
+
}
|
|
103
|
+
if (name === SingleCommand && this.__hasCommands) {
|
|
104
|
+
throw new CommonCommandExistsError("Common command exists");
|
|
105
|
+
}
|
|
106
|
+
const { alias, flags, parameters } = options;
|
|
107
|
+
this._commands[name] = { name, description, alias, flags, parameters };
|
|
67
108
|
return this;
|
|
68
109
|
}
|
|
69
|
-
on(name,
|
|
70
|
-
this.
|
|
110
|
+
on(name, handler) {
|
|
111
|
+
this.__commandEmitter.on(name, handler);
|
|
71
112
|
return this;
|
|
72
113
|
}
|
|
73
114
|
use(plugin) {
|
|
74
115
|
return plugin.setup(this);
|
|
75
116
|
}
|
|
76
|
-
|
|
77
|
-
this.
|
|
117
|
+
inspector(inspector) {
|
|
118
|
+
this._inspectors.push(inspector);
|
|
78
119
|
return this;
|
|
79
120
|
}
|
|
80
|
-
parse() {
|
|
81
|
-
const argv = process.argv.slice(2);
|
|
121
|
+
parse(argv = resolveArgv()) {
|
|
82
122
|
let parsed = minimist__default["default"](argv);
|
|
83
|
-
const name = parsed._[0];
|
|
84
|
-
const command = resolveCommand(this._commands, name
|
|
85
|
-
|
|
86
|
-
throw new Error(`No such command: ${name}`);
|
|
87
|
-
}
|
|
88
|
-
const commandName = command.name;
|
|
123
|
+
const name = String(parsed._[0]);
|
|
124
|
+
const command = this.__isSingleCommand ? this._commands[SingleCommand] : resolveCommand(this._commands, name);
|
|
125
|
+
const isCommandResolved = !!command;
|
|
89
126
|
parsed = minimist__default["default"](argv, {
|
|
90
|
-
alias: resolveFlagAlias(
|
|
127
|
+
alias: command ? resolveFlagAlias(command) : {},
|
|
128
|
+
default: command ? resolveFlagDefault(command) : {}
|
|
91
129
|
});
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
130
|
+
const { _: args, ...flags } = parsed;
|
|
131
|
+
const camelCaseFlags = Object.fromEntries(
|
|
132
|
+
Object.entries(flags).map(([key, value]) => [camelCase(key), value])
|
|
133
|
+
);
|
|
134
|
+
const parameters = this.__isSingleCommand || !isCommandResolved ? args : args.slice(1);
|
|
135
|
+
const inspectorContext = {
|
|
136
|
+
name: command == null ? void 0 : command.name,
|
|
137
|
+
resolved: isCommandResolved,
|
|
138
|
+
raw: parsed,
|
|
139
|
+
parameters,
|
|
140
|
+
flags: camelCaseFlags,
|
|
98
141
|
cli: this
|
|
99
142
|
};
|
|
100
|
-
const handlerContext =
|
|
143
|
+
const handlerContext = inspectorContext;
|
|
101
144
|
const emitHandler = () => {
|
|
102
|
-
|
|
145
|
+
if (!command) {
|
|
146
|
+
throw new NoSuchCommandsError(`No such command: ${name}`);
|
|
147
|
+
}
|
|
148
|
+
this.__commandEmitter.emit(command.name, handlerContext);
|
|
103
149
|
};
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
|
|
150
|
+
const inspectors = [...this._inspectors, emitHandler];
|
|
151
|
+
const inspector = compose(inspectors);
|
|
152
|
+
inspector(inspectorContext);
|
|
107
153
|
}
|
|
108
154
|
}
|
|
109
155
|
|
|
110
|
-
|
|
111
|
-
return p;
|
|
112
|
-
}
|
|
156
|
+
const definePlugin = (p) => p;
|
|
113
157
|
|
|
114
158
|
exports.Clerc = Clerc;
|
|
159
|
+
exports.CommandExistsError = CommandExistsError;
|
|
160
|
+
exports.CommonCommandExistsError = CommonCommandExistsError;
|
|
161
|
+
exports.NoSuchCommandsError = NoSuchCommandsError;
|
|
162
|
+
exports.SingleCommand = SingleCommand;
|
|
163
|
+
exports.SingleCommandError = SingleCommandError;
|
|
164
|
+
exports.camelCase = camelCase;
|
|
115
165
|
exports.compose = compose;
|
|
116
166
|
exports.definePlugin = definePlugin;
|
|
167
|
+
exports.kebabCase = kebabCase;
|
|
168
|
+
exports.resolveArgv = resolveArgv;
|
|
117
169
|
exports.resolveCommand = resolveCommand;
|
|
118
170
|
exports.resolveFlagAlias = resolveFlagAlias;
|
|
171
|
+
exports.resolveFlagDefault = resolveFlagDefault;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
interface Plugin<U, T extends Clerc = Clerc> {
|
|
1
|
+
interface Plugin<T extends Clerc = Clerc, U extends Clerc = Clerc> {
|
|
4
2
|
setup: (cli: T) => U;
|
|
5
3
|
}
|
|
6
|
-
declare
|
|
4
|
+
declare const definePlugin: <T extends Clerc<{}>, U extends Clerc<{}>>(p: Plugin<T, U>) => Plugin<T, U>;
|
|
7
5
|
|
|
8
6
|
declare type Dict<T> = Record<string, T>;
|
|
9
7
|
declare type MustArray<T> = T extends any[] ? T : [T];
|
|
@@ -14,57 +12,211 @@ declare type GetLength<T extends any[]> = T extends {
|
|
|
14
12
|
declare type GetTail<T extends any[]> = T extends [infer _Head, ...infer Tail] ? Tail : never;
|
|
15
13
|
declare type EnhanceSingle<T, E extends Dict<any>> = T & E;
|
|
16
14
|
declare type Enhance<T, E extends Dict<any> | Dict<any>[]> = GetLength<MustArray<E>> extends 0 ? T : Enhance<EnhanceSingle<T, MustArray<E>[0]>, GetTail<MustArray<E>>>;
|
|
15
|
+
interface ParsedArgs {
|
|
16
|
+
[arg: string]: any;
|
|
17
|
+
"--"?: string[] | undefined;
|
|
18
|
+
_: string[];
|
|
19
|
+
}
|
|
17
20
|
interface FlagOptions {
|
|
18
|
-
alias?: MaybeArray<string>;
|
|
19
21
|
description: string;
|
|
22
|
+
alias?: MaybeArray<string>;
|
|
23
|
+
default?: PossibleInputKind;
|
|
24
|
+
required?: boolean;
|
|
20
25
|
}
|
|
21
26
|
interface Flag extends FlagOptions {
|
|
22
27
|
name: string;
|
|
23
28
|
}
|
|
29
|
+
interface ParameterOptions {
|
|
30
|
+
description: string;
|
|
31
|
+
required?: boolean;
|
|
32
|
+
}
|
|
33
|
+
interface Parameter extends ParameterOptions {
|
|
34
|
+
name: string;
|
|
35
|
+
}
|
|
24
36
|
interface CommandOptions {
|
|
25
37
|
alias?: MaybeArray<string>;
|
|
38
|
+
parameters?: Dict<ParameterOptions>;
|
|
26
39
|
flags?: Dict<FlagOptions>;
|
|
27
40
|
}
|
|
28
|
-
interface Command<N extends string = string, D extends string = string> extends CommandOptions {
|
|
41
|
+
interface Command<N extends string | SingleCommandType = string, D extends string = string> extends CommandOptions {
|
|
29
42
|
name: N;
|
|
30
43
|
description: D;
|
|
31
44
|
}
|
|
32
|
-
declare type CommandRecord = Dict<Command
|
|
45
|
+
declare type CommandRecord = Dict<Command> & {
|
|
46
|
+
[SingleCommand]?: Command;
|
|
47
|
+
};
|
|
33
48
|
declare type MakeEventMap<T extends CommandRecord> = {
|
|
34
|
-
[K in keyof T]: [
|
|
49
|
+
[K in keyof T]: [InspectorContext];
|
|
35
50
|
};
|
|
36
|
-
declare type
|
|
51
|
+
declare type PossibleInputKind = string | number | boolean | Dict<any>;
|
|
37
52
|
interface HandlerContext<C extends CommandRecord = CommandRecord, N extends keyof C = keyof C> {
|
|
38
|
-
name
|
|
39
|
-
|
|
53
|
+
name?: N;
|
|
54
|
+
resolved: boolean;
|
|
55
|
+
raw: ParsedArgs;
|
|
56
|
+
parameters: PossibleInputKind[];
|
|
57
|
+
flags: Dict<MaybeArray<PossibleInputKind> | undefined>;
|
|
40
58
|
cli: Clerc<C>;
|
|
41
59
|
}
|
|
42
60
|
declare type Handler = (ctx: HandlerContext) => void;
|
|
43
|
-
interface
|
|
61
|
+
interface InspectorContext<C extends CommandRecord = CommandRecord, N extends keyof C = keyof C> extends HandlerContext<C, N> {
|
|
44
62
|
}
|
|
45
|
-
declare type
|
|
63
|
+
declare type Inspector = (ctx: InspectorContext<any>, next: () => void) => void;
|
|
46
64
|
|
|
65
|
+
declare const SingleCommand: unique symbol;
|
|
66
|
+
declare type SingleCommandType = typeof SingleCommand;
|
|
47
67
|
declare class Clerc<C extends CommandRecord = {}> {
|
|
48
68
|
_name: string;
|
|
49
69
|
_description: string;
|
|
50
70
|
_version: string;
|
|
51
|
-
|
|
71
|
+
_inspectors: Inspector[];
|
|
52
72
|
_commands: C;
|
|
53
|
-
|
|
73
|
+
private __commandEmitter;
|
|
54
74
|
private constructor();
|
|
75
|
+
private get __isSingleCommand();
|
|
76
|
+
private get __hasCommands();
|
|
77
|
+
/**
|
|
78
|
+
* Create a new cli
|
|
79
|
+
* @returns
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* const cli = Clerc.create()
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
55
85
|
static create(): Clerc<{}>;
|
|
86
|
+
/**
|
|
87
|
+
* Set the name of the cli
|
|
88
|
+
* @param name
|
|
89
|
+
* @returns
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* Clerc.create()
|
|
93
|
+
* .name("test")
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
56
96
|
name(name: string): this;
|
|
97
|
+
/**
|
|
98
|
+
* Set the description of the cli
|
|
99
|
+
* @param description
|
|
100
|
+
* @returns
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* Clerc.create()
|
|
104
|
+
* .description("test cli")
|
|
105
|
+
*/
|
|
57
106
|
description(description: string): this;
|
|
107
|
+
/**
|
|
108
|
+
* Set the version of the cli
|
|
109
|
+
* @param version
|
|
110
|
+
* @returns
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* Clerc.create()
|
|
114
|
+
* .version("1.0.0")
|
|
115
|
+
*/
|
|
58
116
|
version(version: string): this;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Register a command
|
|
119
|
+
* @param name
|
|
120
|
+
* @param description
|
|
121
|
+
* @param options
|
|
122
|
+
* @returns
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* Clerc.create()
|
|
126
|
+
* .command("test", "test command", {
|
|
127
|
+
* alias: "t",
|
|
128
|
+
* flags: {
|
|
129
|
+
* foo: {
|
|
130
|
+
* alias: "f",
|
|
131
|
+
* description: "foo flag",
|
|
132
|
+
* }
|
|
133
|
+
* }
|
|
134
|
+
* })
|
|
135
|
+
* ```
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* Clerc.create()
|
|
139
|
+
* .command("", "single command", {
|
|
140
|
+
* flags: {
|
|
141
|
+
* foo: {
|
|
142
|
+
* alias: "f",
|
|
143
|
+
* description: "foo flag",
|
|
144
|
+
* }
|
|
145
|
+
* }
|
|
146
|
+
* })
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
command<N extends string | SingleCommandType, D extends string>(name: N, description: D, options?: CommandOptions): this & Clerc<C & Record<N, Command<N, D>>>;
|
|
150
|
+
/**
|
|
151
|
+
* Register a handler
|
|
152
|
+
* @param name
|
|
153
|
+
* @param handler
|
|
154
|
+
* @returns
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* Clerc.create()
|
|
158
|
+
* .command("test", "test command")
|
|
159
|
+
* .on("test", (ctx) => {
|
|
160
|
+
* console.log(ctx);
|
|
161
|
+
* })
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
on<K extends keyof C>(name: K, handler: Handler): this;
|
|
165
|
+
/**
|
|
166
|
+
* Use a plugin
|
|
167
|
+
* @param plugin
|
|
168
|
+
* @returns
|
|
169
|
+
* @example
|
|
170
|
+
* ```ts
|
|
171
|
+
* Clerc.create()
|
|
172
|
+
* .use(plugin)
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
use<T extends Clerc, U extends Clerc>(plugin: Plugin<T, U>): U;
|
|
176
|
+
/**
|
|
177
|
+
* Register a inspector
|
|
178
|
+
* @param inspector
|
|
179
|
+
* @returns
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* Clerc.create()
|
|
183
|
+
* .inspector((ctx, next) => {
|
|
184
|
+
* console.log(ctx);
|
|
185
|
+
* next();
|
|
186
|
+
* })
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
inspector(inspector: Inspector): this;
|
|
190
|
+
/**
|
|
191
|
+
* Parse the command line arguments
|
|
192
|
+
* @param args
|
|
193
|
+
* @returns
|
|
194
|
+
* @example
|
|
195
|
+
* ```ts
|
|
196
|
+
* Clerc.create()
|
|
197
|
+
* .parse(process.argv.slice(2)) // Optional
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
parse(argv?: string[]): void;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
declare class SingleCommandError extends Error {
|
|
204
|
+
}
|
|
205
|
+
declare class CommandExistsError extends Error {
|
|
206
|
+
}
|
|
207
|
+
declare class CommonCommandExistsError extends Error {
|
|
208
|
+
}
|
|
209
|
+
declare class NoSuchCommandsError extends Error {
|
|
64
210
|
}
|
|
65
211
|
|
|
66
|
-
declare
|
|
67
|
-
declare
|
|
68
|
-
declare
|
|
212
|
+
declare type CamelCase<T extends string> = T extends `${infer A}-${infer B}${infer C}` ? `${A}${Capitalize<B>}${CamelCase<C>}` : T;
|
|
213
|
+
declare const camelCase: <T extends string>(s: T) => CamelCase<T>;
|
|
214
|
+
declare type KebabCase<T extends string, A extends string = ""> = T extends `${infer F}${infer R}` ? KebabCase<R, `${A}${F extends Lowercase<F> ? "" : "-"}${Lowercase<F>}`> : A;
|
|
215
|
+
declare const kebabCase: <T extends string>(s: T) => KebabCase<T, "">;
|
|
216
|
+
declare const resolveFlagAlias: (_command: Command) => Dict<string[]>;
|
|
217
|
+
declare const resolveFlagDefault: (_command: Command) => Dict<PossibleInputKind | undefined>;
|
|
218
|
+
declare function resolveCommand(commands: CommandRecord, name: string | SingleCommandType): Command | undefined;
|
|
219
|
+
declare const resolveArgv: () => string[];
|
|
220
|
+
declare function compose(inspectors: Inspector[]): (ctx: InspectorContext) => void;
|
|
69
221
|
|
|
70
|
-
export { Clerc, Command, CommandOptions, CommandRecord, Dict, Enhance, Flag, FlagOptions, Handler, HandlerContext,
|
|
222
|
+
export { CamelCase, Clerc, Command, CommandExistsError, CommandOptions, CommandRecord, CommonCommandExistsError, Dict, Enhance, Flag, FlagOptions, Handler, HandlerContext, Inspector, InspectorContext, KebabCase, MakeEventMap, MaybeArray, NoSuchCommandsError, Parameter, ParameterOptions, Plugin, PossibleInputKind, SingleCommand, SingleCommandError, SingleCommandType, camelCase, compose, definePlugin, kebabCase, resolveArgv, resolveCommand, resolveFlagAlias, resolveFlagDefault };
|
package/dist/index.mjs
CHANGED
|
@@ -1,42 +1,71 @@
|
|
|
1
1
|
import { LiteEmit } from 'lite-emit';
|
|
2
2
|
import minimist from 'minimist';
|
|
3
|
+
import { isNode, isDeno } from 'is-platform';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
class SingleCommandError extends Error {
|
|
6
|
+
}
|
|
7
|
+
class CommandExistsError extends Error {
|
|
8
|
+
}
|
|
9
|
+
class CommonCommandExistsError extends Error {
|
|
10
|
+
}
|
|
11
|
+
class NoSuchCommandsError extends Error {
|
|
11
12
|
}
|
|
13
|
+
|
|
14
|
+
const mustArray = (a) => Array.isArray(a) ? a : [a];
|
|
15
|
+
const camelCase = (s) => s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
16
|
+
const kebabCase = (s) => s.replace(/([A-Z])/g, (_, c) => `-${c.toLowerCase()}`);
|
|
17
|
+
const resolveFlagAlias = (_command) => Object.entries((_command == null ? void 0 : _command.flags) || {}).reduce((acc, [name, command]) => {
|
|
18
|
+
if (command.alias) {
|
|
19
|
+
const item = mustArray(command.alias).map(kebabCase);
|
|
20
|
+
acc[kebabCase(name)] = item;
|
|
21
|
+
}
|
|
22
|
+
return acc;
|
|
23
|
+
}, {});
|
|
24
|
+
const resolveFlagDefault = (_command) => Object.entries((_command == null ? void 0 : _command.flags) || {}).reduce((acc, [name, command]) => {
|
|
25
|
+
const item = command.default;
|
|
26
|
+
if (item) {
|
|
27
|
+
acc[name] = item;
|
|
28
|
+
}
|
|
29
|
+
return acc;
|
|
30
|
+
}, {});
|
|
12
31
|
function resolveCommand(commands, name) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
32
|
+
if (name === SingleCommand) {
|
|
33
|
+
return commands[SingleCommand];
|
|
34
|
+
}
|
|
35
|
+
const possibleCommands = Object.values(commands).filter(
|
|
36
|
+
(c) => c.name === name || mustArray(c.alias || []).map(String).includes(name)
|
|
37
|
+
);
|
|
17
38
|
if (possibleCommands.length > 1) {
|
|
18
39
|
throw new Error(`Multiple commands found with name "${name}"`);
|
|
19
40
|
}
|
|
20
41
|
return possibleCommands[0];
|
|
21
42
|
}
|
|
22
|
-
|
|
23
|
-
|
|
43
|
+
const resolveArgv = () => isNode() ? process.argv.slice(2) : isDeno() ? Deno.args : [];
|
|
44
|
+
function compose(inspectors) {
|
|
45
|
+
return (ctx) => {
|
|
24
46
|
return dispatch(0);
|
|
25
47
|
function dispatch(i) {
|
|
26
|
-
const
|
|
27
|
-
return
|
|
48
|
+
const inspector = inspectors[i];
|
|
49
|
+
return inspector(ctx, dispatch.bind(null, i + 1));
|
|
28
50
|
}
|
|
29
51
|
};
|
|
30
52
|
}
|
|
31
53
|
|
|
54
|
+
const SingleCommand = Symbol("SingleCommand");
|
|
32
55
|
class Clerc {
|
|
33
56
|
constructor() {
|
|
34
57
|
this._name = "";
|
|
35
58
|
this._description = "";
|
|
36
59
|
this._version = "";
|
|
37
|
-
this.
|
|
60
|
+
this._inspectors = [];
|
|
38
61
|
this._commands = {};
|
|
39
|
-
this.
|
|
62
|
+
this.__commandEmitter = new LiteEmit();
|
|
63
|
+
}
|
|
64
|
+
get __isSingleCommand() {
|
|
65
|
+
return this._commands[SingleCommand] !== void 0;
|
|
66
|
+
}
|
|
67
|
+
get __hasCommands() {
|
|
68
|
+
return Object.keys(this._commands).length > 0;
|
|
40
69
|
}
|
|
41
70
|
static create() {
|
|
42
71
|
return new Clerc();
|
|
@@ -54,53 +83,68 @@ class Clerc {
|
|
|
54
83
|
return this;
|
|
55
84
|
}
|
|
56
85
|
command(name, description, options = {}) {
|
|
57
|
-
|
|
58
|
-
|
|
86
|
+
if (this._commands[name]) {
|
|
87
|
+
if (name === SingleCommand) {
|
|
88
|
+
throw new CommandExistsError("Single command already exists");
|
|
89
|
+
}
|
|
90
|
+
throw new CommandExistsError(`Command "${name === SingleCommand ? "[SingleCommand]" : name}" already exists`);
|
|
91
|
+
}
|
|
92
|
+
if (this.__isSingleCommand) {
|
|
93
|
+
throw new SingleCommandError("Single command mode enabled");
|
|
94
|
+
}
|
|
95
|
+
if (name === SingleCommand && this.__hasCommands) {
|
|
96
|
+
throw new CommonCommandExistsError("Common command exists");
|
|
97
|
+
}
|
|
98
|
+
const { alias, flags, parameters } = options;
|
|
99
|
+
this._commands[name] = { name, description, alias, flags, parameters };
|
|
59
100
|
return this;
|
|
60
101
|
}
|
|
61
|
-
on(name,
|
|
62
|
-
this.
|
|
102
|
+
on(name, handler) {
|
|
103
|
+
this.__commandEmitter.on(name, handler);
|
|
63
104
|
return this;
|
|
64
105
|
}
|
|
65
106
|
use(plugin) {
|
|
66
107
|
return plugin.setup(this);
|
|
67
108
|
}
|
|
68
|
-
|
|
69
|
-
this.
|
|
109
|
+
inspector(inspector) {
|
|
110
|
+
this._inspectors.push(inspector);
|
|
70
111
|
return this;
|
|
71
112
|
}
|
|
72
|
-
parse() {
|
|
73
|
-
const argv = process.argv.slice(2);
|
|
113
|
+
parse(argv = resolveArgv()) {
|
|
74
114
|
let parsed = minimist(argv);
|
|
75
|
-
const name = parsed._[0];
|
|
76
|
-
const command = resolveCommand(this._commands, name
|
|
77
|
-
|
|
78
|
-
throw new Error(`No such command: ${name}`);
|
|
79
|
-
}
|
|
80
|
-
const commandName = command.name;
|
|
115
|
+
const name = String(parsed._[0]);
|
|
116
|
+
const command = this.__isSingleCommand ? this._commands[SingleCommand] : resolveCommand(this._commands, name);
|
|
117
|
+
const isCommandResolved = !!command;
|
|
81
118
|
parsed = minimist(argv, {
|
|
82
|
-
alias: resolveFlagAlias(
|
|
119
|
+
alias: command ? resolveFlagAlias(command) : {},
|
|
120
|
+
default: command ? resolveFlagDefault(command) : {}
|
|
83
121
|
});
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
122
|
+
const { _: args, ...flags } = parsed;
|
|
123
|
+
const camelCaseFlags = Object.fromEntries(
|
|
124
|
+
Object.entries(flags).map(([key, value]) => [camelCase(key), value])
|
|
125
|
+
);
|
|
126
|
+
const parameters = this.__isSingleCommand || !isCommandResolved ? args : args.slice(1);
|
|
127
|
+
const inspectorContext = {
|
|
128
|
+
name: command == null ? void 0 : command.name,
|
|
129
|
+
resolved: isCommandResolved,
|
|
130
|
+
raw: parsed,
|
|
131
|
+
parameters,
|
|
132
|
+
flags: camelCaseFlags,
|
|
90
133
|
cli: this
|
|
91
134
|
};
|
|
92
|
-
const handlerContext =
|
|
135
|
+
const handlerContext = inspectorContext;
|
|
93
136
|
const emitHandler = () => {
|
|
94
|
-
|
|
137
|
+
if (!command) {
|
|
138
|
+
throw new NoSuchCommandsError(`No such command: ${name}`);
|
|
139
|
+
}
|
|
140
|
+
this.__commandEmitter.emit(command.name, handlerContext);
|
|
95
141
|
};
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
|
|
142
|
+
const inspectors = [...this._inspectors, emitHandler];
|
|
143
|
+
const inspector = compose(inspectors);
|
|
144
|
+
inspector(inspectorContext);
|
|
99
145
|
}
|
|
100
146
|
}
|
|
101
147
|
|
|
102
|
-
|
|
103
|
-
return p;
|
|
104
|
-
}
|
|
148
|
+
const definePlugin = (p) => p;
|
|
105
149
|
|
|
106
|
-
export { Clerc, compose, definePlugin, resolveCommand, resolveFlagAlias };
|
|
150
|
+
export { Clerc, CommandExistsError, CommonCommandExistsError, NoSuchCommandsError, SingleCommand, SingleCommandError, camelCase, compose, definePlugin, kebabCase, resolveArgv, resolveCommand, resolveFlagAlias, resolveFlagDefault };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clerc",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.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,6 +39,7 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
+
"is-platform": "^0.2.0",
|
|
42
43
|
"lite-emit": "^1.4.0",
|
|
43
44
|
"minimist": "^1.2.7"
|
|
44
45
|
},
|