@wooksjs/event-cli 0.2.23 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/index.cjs +316 -25
- package/dist/index.d.ts +188 -9
- package/dist/index.mjs +312 -23
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ As a part of `wooks` event processing framework, `@wooksjs/event-cli` implements
|
|
|
13
13
|
|
|
14
14
|
- access flags (- or --)
|
|
15
15
|
|
|
16
|
-
##
|
|
16
|
+
## Installation
|
|
17
17
|
|
|
18
18
|
`npm install wooks @wooksjs/event-cli`
|
|
19
19
|
|
|
@@ -21,13 +21,13 @@ As a part of `wooks` event processing framework, `@wooksjs/event-cli` implements
|
|
|
21
21
|
|
|
22
22
|
```js
|
|
23
23
|
import { useRouteParams } from 'wooks'
|
|
24
|
-
import { createCliApp,
|
|
24
|
+
import { createCliApp, useCliOptions } from '@wooksjs/event-cli'
|
|
25
25
|
|
|
26
26
|
const app = createCliApp()
|
|
27
27
|
|
|
28
28
|
app.cli('test', () => {
|
|
29
|
-
console.log('
|
|
30
|
-
return
|
|
29
|
+
console.log('options:')
|
|
30
|
+
return useCliOptions()
|
|
31
31
|
})
|
|
32
32
|
|
|
33
33
|
app.cli(':arg', () => {
|
|
@@ -43,4 +43,4 @@ app.run()
|
|
|
43
43
|
|
|
44
44
|
## Documentation
|
|
45
45
|
|
|
46
|
-
To check out docs, visit [wooksjs.org](https://wooksjs.org/).
|
|
46
|
+
To check out docs, visit [wooksjs.org](https://wooksjs.org/guide/cli/).
|
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var eventCore = require('@wooksjs/event-core');
|
|
4
4
|
var wooks = require('wooks');
|
|
5
|
+
var cliHelp = require('@prostojs/cli-help');
|
|
5
6
|
var minimist = require('minimist');
|
|
6
7
|
|
|
7
8
|
function createCliContext(data, options) {
|
|
@@ -10,6 +11,11 @@ function createCliContext(data, options) {
|
|
|
10
11
|
options,
|
|
11
12
|
});
|
|
12
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Wrapper on top of useEventContext that provides
|
|
16
|
+
* proper context types for CLI event
|
|
17
|
+
* @returns set of hooks { getCtx, restoreCtx, clearCtx, hookStore, getStore, setStore }
|
|
18
|
+
*/
|
|
13
19
|
function useCliContext() {
|
|
14
20
|
return eventCore.useEventContext('CLI');
|
|
15
21
|
}
|
|
@@ -48,22 +54,138 @@ class WooksCli extends wooks.WooksAdapterBase {
|
|
|
48
54
|
constructor(opts, wooks) {
|
|
49
55
|
super(wooks, opts === null || opts === void 0 ? void 0 : opts.logger);
|
|
50
56
|
this.opts = opts;
|
|
57
|
+
this.alreadyComputedAliases = false;
|
|
51
58
|
this.logger = (opts === null || opts === void 0 ? void 0 : opts.logger) || this.getLogger('wooks-cli');
|
|
59
|
+
this.cliHelp =
|
|
60
|
+
(opts === null || opts === void 0 ? void 0 : opts.cliHelp) instanceof cliHelp.CliHelpRenderer
|
|
61
|
+
? opts.cliHelp
|
|
62
|
+
: new cliHelp.CliHelpRenderer(opts === null || opts === void 0 ? void 0 : opts.cliHelp);
|
|
52
63
|
}
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
/**
|
|
65
|
+
* ### Register CLI Command
|
|
66
|
+
* Command path segments may be separated by / or space.
|
|
67
|
+
*
|
|
68
|
+
* For example the folowing path are interpreted the same:
|
|
69
|
+
* - "command test use:dev :name"
|
|
70
|
+
* - "command/test/use:dev/:name"
|
|
71
|
+
*
|
|
72
|
+
* Where name will become an argument
|
|
73
|
+
*
|
|
74
|
+
* ```js
|
|
75
|
+
* // example without options
|
|
76
|
+
* app.cli('command/:arg', () => 'arg = ' + useRouteParams().params.arg )
|
|
77
|
+
*
|
|
78
|
+
* // example with options
|
|
79
|
+
* app.cli('command/:arg', {
|
|
80
|
+
* description: 'Description of the command',
|
|
81
|
+
* options: [{ keys: ['project', 'p'], description: 'Description of the option', value: 'myProject' }],
|
|
82
|
+
* args: { arg: 'Description of the arg' },
|
|
83
|
+
* aliases: ['cmd'], // alias "cmd/:arg" will be registered
|
|
84
|
+
* examples: [{
|
|
85
|
+
* description: 'Example of usage with someProject',
|
|
86
|
+
* cmd: 'argValue -p=someProject',
|
|
87
|
+
* // will result in help display:
|
|
88
|
+
* // "# Example of usage with someProject\n" +
|
|
89
|
+
* // "$ myCli command argValue -p=someProject\n"
|
|
90
|
+
* }],
|
|
91
|
+
* handler: () => 'arg = ' + useRouteParams().params.arg
|
|
92
|
+
* })
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @param path command path
|
|
96
|
+
* @param _options handler or options
|
|
97
|
+
*
|
|
98
|
+
* @returns
|
|
99
|
+
*/
|
|
100
|
+
cli(path, _options) {
|
|
101
|
+
const options = typeof _options === 'function' ? { handler: _options } : _options;
|
|
102
|
+
const handler = typeof _options === 'function' ? _options : _options.handler;
|
|
103
|
+
const makePath = (s) => '/' + s.replace(/\s+/g, '/');
|
|
104
|
+
// register handler
|
|
105
|
+
const targetPath = makePath(path);
|
|
106
|
+
const routed = this.on('CLI', targetPath, handler);
|
|
107
|
+
if (options.onRegister) {
|
|
108
|
+
options.onRegister(targetPath, 0);
|
|
109
|
+
}
|
|
110
|
+
// register direct aliases
|
|
111
|
+
for (const alias of options.aliases || []) {
|
|
112
|
+
const vars = routed.getArgs().map((k) => ':' + k).join('/');
|
|
113
|
+
const targetPath = makePath(alias) + (vars ? '/' + vars : '');
|
|
114
|
+
this.on('CLI', targetPath, handler);
|
|
115
|
+
if (options.onRegister) {
|
|
116
|
+
options.onRegister(targetPath, 1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// register helpCli entry
|
|
120
|
+
const command = routed.getStaticPart().replace(/\//g, ' ').trim();
|
|
121
|
+
const args = Object.assign({}, (options.args || {}));
|
|
122
|
+
for (const arg of routed.getArgs()) {
|
|
123
|
+
if (!args[arg]) {
|
|
124
|
+
args[arg] = '';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
this.cliHelp.addEntry({
|
|
128
|
+
command,
|
|
129
|
+
aliases: options.aliases,
|
|
130
|
+
args,
|
|
131
|
+
description: options.description,
|
|
132
|
+
examples: options.examples,
|
|
133
|
+
options: options.options,
|
|
134
|
+
custom: { handler: options.handler, cb: options.onRegister },
|
|
135
|
+
});
|
|
136
|
+
return routed;
|
|
137
|
+
}
|
|
138
|
+
computeAliases() {
|
|
139
|
+
if (!this.alreadyComputedAliases) {
|
|
140
|
+
this.alreadyComputedAliases = true;
|
|
141
|
+
const aliases = this.cliHelp.getComputedAliases();
|
|
142
|
+
for (const [alias, entry] of Object.entries(aliases)) {
|
|
143
|
+
if (entry.custom) {
|
|
144
|
+
const vars = Object.keys(entry.args || {})
|
|
145
|
+
.map((k) => ':' + k)
|
|
146
|
+
.join('/');
|
|
147
|
+
const path = '/' +
|
|
148
|
+
alias.replace(/\s+/g, '/').replace(/:/g, '\\:') +
|
|
149
|
+
(vars ? '/' + vars : '');
|
|
150
|
+
this.on('CLI', path, entry.custom.handler);
|
|
151
|
+
if (entry.custom.cb) {
|
|
152
|
+
entry.custom.cb(path, 3);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
55
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* ## run
|
|
160
|
+
* ### Start command processing
|
|
161
|
+
* Triggers command processing
|
|
162
|
+
*
|
|
163
|
+
* By default takes `process.argv.slice(2)` as a command
|
|
164
|
+
*
|
|
165
|
+
* It's possible to replace the command by passing an argument
|
|
166
|
+
*
|
|
167
|
+
* @param _argv optionally overwrite `process.argv.slice(2)` with your `argv` array
|
|
168
|
+
*/
|
|
56
169
|
run(_argv) {
|
|
57
170
|
var _a, _b;
|
|
58
171
|
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
-
const argv = process.argv.slice(2)
|
|
172
|
+
const argv = _argv || process.argv.slice(2);
|
|
60
173
|
const firstFlagIndex = argv.findIndex((a) => a.startsWith('-')) + 1;
|
|
61
|
-
const pathParams =
|
|
174
|
+
const pathParams = firstFlagIndex
|
|
62
175
|
? argv.slice(0, firstFlagIndex - 1)
|
|
63
|
-
: argv
|
|
64
|
-
const path = '/' +
|
|
65
|
-
|
|
66
|
-
const
|
|
176
|
+
: argv;
|
|
177
|
+
const path = '/' +
|
|
178
|
+
pathParams.map((v) => encodeURI(v).replace(/\//g, '%2F')).join('/');
|
|
179
|
+
const { restoreCtx, clearCtx, store } = createCliContext({ argv, pathParams, cliHelp: this.cliHelp, command: path.replace(/\//g, ' ').trim() }, this.mergeEventOptions((_a = this.opts) === null || _a === void 0 ? void 0 : _a.eventOptions));
|
|
180
|
+
this.computeAliases();
|
|
181
|
+
const { handlers: foundHandlers, firstStatic } = this.wooks.lookup('CLI', path);
|
|
182
|
+
if (typeof firstStatic === 'string') {
|
|
183
|
+
// overwriting command with firstStatic to properly search for help
|
|
184
|
+
store('event').set('command', firstStatic.replace(/\//g, ' ').trim());
|
|
185
|
+
}
|
|
186
|
+
const handlers = foundHandlers ||
|
|
187
|
+
(((_b = this.opts) === null || _b === void 0 ? void 0 : _b.onNotFound) && [this.opts.onNotFound]) ||
|
|
188
|
+
null;
|
|
67
189
|
if (handlers) {
|
|
68
190
|
try {
|
|
69
191
|
for (const handler of handlers) {
|
|
@@ -108,16 +230,21 @@ class WooksCli extends wooks.WooksAdapterBase {
|
|
|
108
230
|
process.exit(1);
|
|
109
231
|
}
|
|
110
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Triggers `unknown command` processing and callbacks
|
|
235
|
+
* @param pathParams `string[]` containing command
|
|
236
|
+
*/
|
|
111
237
|
onUnknownCommand(pathParams) {
|
|
112
238
|
var _a;
|
|
239
|
+
const raiseError = () => {
|
|
240
|
+
this.error('[0m' + 'Unknown command: ' + pathParams.join(' '));
|
|
241
|
+
process.exit(1);
|
|
242
|
+
};
|
|
113
243
|
if ((_a = this.opts) === null || _a === void 0 ? void 0 : _a.onUnknownCommand) {
|
|
114
|
-
this.opts.onUnknownCommand(pathParams);
|
|
244
|
+
this.opts.onUnknownCommand(pathParams, raiseError);
|
|
115
245
|
}
|
|
116
246
|
else {
|
|
117
|
-
|
|
118
|
-
'Unknown command: ' +
|
|
119
|
-
pathParams.join(' '));
|
|
120
|
-
process.exit(1);
|
|
247
|
+
raiseError();
|
|
121
248
|
}
|
|
122
249
|
}
|
|
123
250
|
error(e) {
|
|
@@ -129,11 +256,158 @@ class WooksCli extends wooks.WooksAdapterBase {
|
|
|
129
256
|
}
|
|
130
257
|
}
|
|
131
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Factory for WooksCli App
|
|
261
|
+
* @param opts TWooksCliOptions
|
|
262
|
+
* @param wooks Wooks | WooksAdapterBase
|
|
263
|
+
* @returns WooksHttp
|
|
264
|
+
*/
|
|
132
265
|
function createCliApp(opts, wooks) {
|
|
133
266
|
return new WooksCli(opts, wooks);
|
|
134
267
|
}
|
|
135
268
|
|
|
136
|
-
|
|
269
|
+
/**
|
|
270
|
+
* ## useCliHelp
|
|
271
|
+
* ### Composable
|
|
272
|
+
* ```js
|
|
273
|
+
* // example of printing cli instructions
|
|
274
|
+
* const { print } = useCliHelp()
|
|
275
|
+
* // print with colors
|
|
276
|
+
* print(true)
|
|
277
|
+
* // print with no colors
|
|
278
|
+
* // print(false)
|
|
279
|
+
* ```
|
|
280
|
+
* @returns
|
|
281
|
+
*/
|
|
282
|
+
function useCliHelp() {
|
|
283
|
+
const event = useCliContext().store('event');
|
|
284
|
+
const getCliHelp = () => event.get('cliHelp');
|
|
285
|
+
const getEntry = () => { var _a; return (_a = getCliHelp().match(event.get('command'))) === null || _a === void 0 ? void 0 : _a.main; };
|
|
286
|
+
return {
|
|
287
|
+
getCliHelp,
|
|
288
|
+
getEntry,
|
|
289
|
+
render: (width, withColors) => getCliHelp().render(event.get('command'), width, withColors),
|
|
290
|
+
print: (withColors) => getCliHelp().print(event.get('command'), withColors),
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* ## useAutoHelp
|
|
295
|
+
* ### Composable
|
|
296
|
+
*
|
|
297
|
+
* Prints help if `--help` option provided.
|
|
298
|
+
*
|
|
299
|
+
* ```js
|
|
300
|
+
* // example of use: print help and exit
|
|
301
|
+
* app.cli('test', () => {
|
|
302
|
+
* useAutoHelp() && process.exit(0)
|
|
303
|
+
* return 'hit test command'
|
|
304
|
+
* })
|
|
305
|
+
*
|
|
306
|
+
* // add option -h to print help, no colors
|
|
307
|
+
* app.cli('test/nocolors', () => {
|
|
308
|
+
* useAutoHelp(['help', 'h'], false) && process.exit(0)
|
|
309
|
+
* return 'hit test nocolors command'
|
|
310
|
+
* })
|
|
311
|
+
* ```
|
|
312
|
+
* @param keys default `['help']` - list of options to trigger help render
|
|
313
|
+
* @param colors default `true`, prints with colors when true
|
|
314
|
+
* @returns true when --help was provided. Otherwise returns false
|
|
315
|
+
*/
|
|
316
|
+
function useAutoHelp(keys = ['help'], colors = true) {
|
|
317
|
+
for (const option of keys) {
|
|
318
|
+
if (useCliOption(option) === true) {
|
|
319
|
+
// try {
|
|
320
|
+
useCliHelp().print(colors);
|
|
321
|
+
return true;
|
|
322
|
+
// } catch (e) {
|
|
323
|
+
// throw new
|
|
324
|
+
// }
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* ##useCommandLookupHelp
|
|
330
|
+
* ### Composable
|
|
331
|
+
*
|
|
332
|
+
* Tries to find valid command based on provided command.
|
|
333
|
+
*
|
|
334
|
+
* If manages to find a valid command, throws an error
|
|
335
|
+
* suggesting a list of valid commands
|
|
336
|
+
*
|
|
337
|
+
* Best to use in `onUnknownCommand` callback:
|
|
338
|
+
*
|
|
339
|
+
* ```js
|
|
340
|
+
* const app = createCliApp({
|
|
341
|
+
* onUnknownCommand: (path, raiseError) => {
|
|
342
|
+
* // will throw an error suggesting a list
|
|
343
|
+
* // of valid commands if could find some
|
|
344
|
+
* useCommandLookupHelp()
|
|
345
|
+
* // fallback to a regular error handler
|
|
346
|
+
* raiseError()
|
|
347
|
+
* },
|
|
348
|
+
* })
|
|
349
|
+
* ```
|
|
350
|
+
*
|
|
351
|
+
* @param lookupDepth depth of search in backwards
|
|
352
|
+
* @example
|
|
353
|
+
*
|
|
354
|
+
* For provided command `run test:drive dir`
|
|
355
|
+
* - lookup1: `run test:drive dir` (deep = 0)
|
|
356
|
+
* - lookup2: `run test:drive` (deep = 1)
|
|
357
|
+
* - lookup3: `run test` (deep = 2)
|
|
358
|
+
* - lookup4: `run` (deep = 3)
|
|
359
|
+
* ...
|
|
360
|
+
*/
|
|
361
|
+
function useCommandLookupHelp(lookupDepth = 3) {
|
|
362
|
+
const parts = useCliContext()
|
|
363
|
+
.store('event')
|
|
364
|
+
.get('pathParams')
|
|
365
|
+
.map((p) => (p + ' ').split(':').map((s, i) => (i ? ':' + s : s)))
|
|
366
|
+
.flat();
|
|
367
|
+
const cliHelp = useCliHelp().getCliHelp();
|
|
368
|
+
const cmd = cliHelp.getCliName();
|
|
369
|
+
let data;
|
|
370
|
+
for (let i = 0; i < Math.min(parts.length, lookupDepth + 1); i++) {
|
|
371
|
+
const pathParams = parts
|
|
372
|
+
.slice(0, i ? -i : parts.length)
|
|
373
|
+
.join('')
|
|
374
|
+
.trim();
|
|
375
|
+
try {
|
|
376
|
+
data = cliHelp.match(pathParams);
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
catch (e) {
|
|
380
|
+
const variants = cliHelp.lookup(pathParams);
|
|
381
|
+
if (variants.length) {
|
|
382
|
+
throw new Error(`Wrong command, did you mean:\n${variants
|
|
383
|
+
.slice(0, 7)
|
|
384
|
+
.map((c) => ` $ ${cmd} ${c.main.command}`)
|
|
385
|
+
.join('\n')}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (data) {
|
|
390
|
+
const { main, children } = data;
|
|
391
|
+
if (main.args && Object.keys(main.args).length) {
|
|
392
|
+
throw new Error(`Arguments expected: ${Object.keys(main.args)
|
|
393
|
+
.map((l) => `<${l}>`)
|
|
394
|
+
.join(', ')}`);
|
|
395
|
+
}
|
|
396
|
+
else if (children && children.length) {
|
|
397
|
+
throw new Error(`Wrong command, did you mean:\n${children
|
|
398
|
+
.slice(0, 7)
|
|
399
|
+
.map((c) => ` $ ${cmd} ${c.command}`)
|
|
400
|
+
.join('\n')}`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Get CLI Options
|
|
407
|
+
*
|
|
408
|
+
* @returns an object with CLI options
|
|
409
|
+
*/
|
|
410
|
+
function useCliOptions() {
|
|
137
411
|
const { store } = useCliContext();
|
|
138
412
|
const flags = store('flags');
|
|
139
413
|
if (!flags.value) {
|
|
@@ -141,21 +415,38 @@ function useFlags() {
|
|
|
141
415
|
}
|
|
142
416
|
return flags.value;
|
|
143
417
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
418
|
+
/**
|
|
419
|
+
* Getter for Cli Option value
|
|
420
|
+
*
|
|
421
|
+
* @param name name of the option
|
|
422
|
+
* @returns value of a CLI option
|
|
423
|
+
*/
|
|
424
|
+
function useCliOption(name) {
|
|
425
|
+
var _a;
|
|
426
|
+
try {
|
|
427
|
+
const options = ((_a = useCliHelp().getEntry()) === null || _a === void 0 ? void 0 : _a.options) || [];
|
|
428
|
+
const opt = options.find(o => o.keys.includes(name));
|
|
429
|
+
if (opt) {
|
|
430
|
+
for (const key of opt.keys) {
|
|
431
|
+
if (useCliOptions()[key]) {
|
|
432
|
+
return useCliOptions()[key];
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
catch (e) {
|
|
438
|
+
//
|
|
439
|
+
}
|
|
440
|
+
return useCliOptions()[name];
|
|
152
441
|
}
|
|
153
442
|
|
|
154
443
|
exports.WooksCli = WooksCli;
|
|
155
444
|
exports.cliShortcuts = cliShortcuts;
|
|
156
445
|
exports.createCliApp = createCliApp;
|
|
157
446
|
exports.createCliContext = createCliContext;
|
|
447
|
+
exports.useAutoHelp = useAutoHelp;
|
|
158
448
|
exports.useCliContext = useCliContext;
|
|
159
|
-
exports.
|
|
160
|
-
exports.
|
|
161
|
-
exports.
|
|
449
|
+
exports.useCliHelp = useCliHelp;
|
|
450
|
+
exports.useCliOption = useCliOption;
|
|
451
|
+
exports.useCliOptions = useCliOptions;
|
|
452
|
+
exports.useCommandLookupHelp = useCommandLookupHelp;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { CliHelpRenderer } from '@prostojs/cli-help';
|
|
2
|
+
import { TCliEntry } from '@prostojs/cli-help';
|
|
3
|
+
import { TCliHelpOptions } from '@prostojs/cli-help';
|
|
1
4
|
import { TConsoleBase } from '@prostojs/logger';
|
|
2
5
|
import { TEmpty } from '@wooksjs/event-core';
|
|
3
6
|
import { TEventOptions } from '@wooksjs/event-core';
|
|
4
7
|
import { TGenericContextStore } from '@wooksjs/event-core';
|
|
5
8
|
import { TProstoRouterPathHandle } from '@prostojs/router';
|
|
6
|
-
import { TWooksHandler } from 'wooks';
|
|
9
|
+
import { TWooksHandler } from '@wooksjs/wooks';
|
|
10
|
+
import { TWooksHandler as TWooksHandler_2 } from 'wooks';
|
|
7
11
|
import { Wooks } from 'wooks';
|
|
8
12
|
import { WooksAdapterBase } from 'wooks';
|
|
9
13
|
|
|
@@ -11,6 +15,12 @@ export declare const cliShortcuts: {
|
|
|
11
15
|
cli: string;
|
|
12
16
|
};
|
|
13
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Factory for WooksCli App
|
|
20
|
+
* @param opts TWooksCliOptions
|
|
21
|
+
* @param wooks Wooks | WooksAdapterBase
|
|
22
|
+
* @returns WooksHttp
|
|
23
|
+
*/
|
|
14
24
|
export declare function createCliApp(opts?: TWooksCliOptions, wooks?: Wooks | WooksAdapterBase): WooksCli;
|
|
15
25
|
|
|
16
26
|
export declare function createCliContext(data: Omit<TCliEventData, 'type'>, options: TEventOptions): {
|
|
@@ -44,17 +54,68 @@ export declare interface TCliContextStore {
|
|
|
44
54
|
export declare interface TCliEventData {
|
|
45
55
|
argv: string[];
|
|
46
56
|
pathParams: string[];
|
|
57
|
+
command: string;
|
|
47
58
|
type: 'CLI';
|
|
59
|
+
cliHelp: TCliHelpRenderer;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export declare type TCliHelpCustom = {
|
|
63
|
+
handler: TWooksHandler<any>;
|
|
64
|
+
/**
|
|
65
|
+
* ### Callback for registered path
|
|
66
|
+
*
|
|
67
|
+
* @param path registered path
|
|
68
|
+
* @param aliasType 0 - direct command, 1 - direct alias, 2 - computed alias
|
|
69
|
+
*/
|
|
70
|
+
cb?: (path: string, aliasType: number) => void;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export declare type TCliHelpRenderer = CliHelpRenderer<TCliHelpCustom>;
|
|
74
|
+
|
|
75
|
+
export declare interface TWooksCliEntry<T> extends Omit<TCliEntry<TWooksHandler_2<T>>, 'custom' | 'command'> {
|
|
76
|
+
onRegister?: TCliHelpCustom['cb'];
|
|
77
|
+
handler: TWooksHandler_2<T>;
|
|
48
78
|
}
|
|
49
79
|
|
|
50
80
|
export declare interface TWooksCliOptions {
|
|
51
81
|
onError?(e: Error): void;
|
|
52
|
-
onNotFound?:
|
|
53
|
-
onUnknownCommand?: (
|
|
82
|
+
onNotFound?: TWooksHandler_2<unknown>;
|
|
83
|
+
onUnknownCommand?: (params: string[], raiseError: () => void) => unknown;
|
|
54
84
|
logger?: TConsoleBase;
|
|
55
85
|
eventOptions?: TEventOptions;
|
|
86
|
+
cliHelp?: TCliHelpRenderer | TCliHelpOptions;
|
|
56
87
|
}
|
|
57
88
|
|
|
89
|
+
/**
|
|
90
|
+
* ## useAutoHelp
|
|
91
|
+
* ### Composable
|
|
92
|
+
*
|
|
93
|
+
* Prints help if `--help` option provided.
|
|
94
|
+
*
|
|
95
|
+
* ```js
|
|
96
|
+
* // example of use: print help and exit
|
|
97
|
+
* app.cli('test', () => {
|
|
98
|
+
* useAutoHelp() && process.exit(0)
|
|
99
|
+
* return 'hit test command'
|
|
100
|
+
* })
|
|
101
|
+
*
|
|
102
|
+
* // add option -h to print help, no colors
|
|
103
|
+
* app.cli('test/nocolors', () => {
|
|
104
|
+
* useAutoHelp(['help', 'h'], false) && process.exit(0)
|
|
105
|
+
* return 'hit test nocolors command'
|
|
106
|
+
* })
|
|
107
|
+
* ```
|
|
108
|
+
* @param keys default `['help']` - list of options to trigger help render
|
|
109
|
+
* @param colors default `true`, prints with colors when true
|
|
110
|
+
* @returns true when --help was provided. Otherwise returns false
|
|
111
|
+
*/
|
|
112
|
+
export declare function useAutoHelp(keys?: string[], colors?: boolean): true | undefined;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Wrapper on top of useEventContext that provides
|
|
116
|
+
* proper context types for CLI event
|
|
117
|
+
* @returns set of hooks { getCtx, restoreCtx, clearCtx, hookStore, getStore, setStore }
|
|
118
|
+
*/
|
|
58
119
|
export declare function useCliContext<T extends TEmpty>(): {
|
|
59
120
|
getCtx: () => TCliContextStore & T & TGenericContextStore<TCliEventData>;
|
|
60
121
|
restoreCtx: () => TGenericContextStore<TEmpty>;
|
|
@@ -77,23 +138,141 @@ export declare function useCliContext<T extends TEmpty>(): {
|
|
|
77
138
|
setStore: <K_2 extends "flags" | keyof TGenericContextStore<TCliEventData> | keyof T>(key: K_2, v: (TCliContextStore & T & TGenericContextStore<TCliEventData>)[K_2]) => void;
|
|
78
139
|
};
|
|
79
140
|
|
|
80
|
-
|
|
141
|
+
/**
|
|
142
|
+
* ## useCliHelp
|
|
143
|
+
* ### Composable
|
|
144
|
+
* ```js
|
|
145
|
+
* // example of printing cli instructions
|
|
146
|
+
* const { print } = useCliHelp()
|
|
147
|
+
* // print with colors
|
|
148
|
+
* print(true)
|
|
149
|
+
* // print with no colors
|
|
150
|
+
* // print(false)
|
|
151
|
+
* ```
|
|
152
|
+
* @returns
|
|
153
|
+
*/
|
|
154
|
+
export declare function useCliHelp(): {
|
|
155
|
+
getCliHelp: () => TCliHelpRenderer;
|
|
156
|
+
getEntry: () => TCliEntry<TCliHelpCustom>;
|
|
157
|
+
render: (width?: number, withColors?: boolean) => string[];
|
|
158
|
+
print: (withColors?: boolean) => void;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Getter for Cli Option value
|
|
163
|
+
*
|
|
164
|
+
* @param name name of the option
|
|
165
|
+
* @returns value of a CLI option
|
|
166
|
+
*/
|
|
167
|
+
export declare function useCliOption(name: string): string | boolean;
|
|
81
168
|
|
|
82
|
-
|
|
169
|
+
/**
|
|
170
|
+
* Get CLI Options
|
|
171
|
+
*
|
|
172
|
+
* @returns an object with CLI options
|
|
173
|
+
*/
|
|
174
|
+
export declare function useCliOptions(): {
|
|
83
175
|
[name: string]: string | boolean;
|
|
84
176
|
};
|
|
85
177
|
|
|
86
|
-
|
|
178
|
+
/**
|
|
179
|
+
* ##useCommandLookupHelp
|
|
180
|
+
* ### Composable
|
|
181
|
+
*
|
|
182
|
+
* Tries to find valid command based on provided command.
|
|
183
|
+
*
|
|
184
|
+
* If manages to find a valid command, throws an error
|
|
185
|
+
* suggesting a list of valid commands
|
|
186
|
+
*
|
|
187
|
+
* Best to use in `onUnknownCommand` callback:
|
|
188
|
+
*
|
|
189
|
+
* ```js
|
|
190
|
+
* const app = createCliApp({
|
|
191
|
+
* onUnknownCommand: (path, raiseError) => {
|
|
192
|
+
* // will throw an error suggesting a list
|
|
193
|
+
* // of valid commands if could find some
|
|
194
|
+
* useCommandLookupHelp()
|
|
195
|
+
* // fallback to a regular error handler
|
|
196
|
+
* raiseError()
|
|
197
|
+
* },
|
|
198
|
+
* })
|
|
199
|
+
* ```
|
|
200
|
+
*
|
|
201
|
+
* @param lookupDepth depth of search in backwards
|
|
202
|
+
* @example
|
|
203
|
+
*
|
|
204
|
+
* For provided command `run test:drive dir`
|
|
205
|
+
* - lookup1: `run test:drive dir` (deep = 0)
|
|
206
|
+
* - lookup2: `run test:drive` (deep = 1)
|
|
207
|
+
* - lookup3: `run test` (deep = 2)
|
|
208
|
+
* - lookup4: `run` (deep = 3)
|
|
209
|
+
* ...
|
|
210
|
+
*/
|
|
211
|
+
export declare function useCommandLookupHelp(lookupDepth?: number): void;
|
|
87
212
|
|
|
88
213
|
export declare class WooksCli extends WooksAdapterBase {
|
|
89
214
|
protected opts?: TWooksCliOptions | undefined;
|
|
90
215
|
protected logger: TConsoleBase;
|
|
216
|
+
protected cliHelp: TCliHelpRenderer;
|
|
91
217
|
constructor(opts?: TWooksCliOptions | undefined, wooks?: Wooks | WooksAdapterBase);
|
|
92
|
-
|
|
218
|
+
/**
|
|
219
|
+
* ### Register CLI Command
|
|
220
|
+
* Command path segments may be separated by / or space.
|
|
221
|
+
*
|
|
222
|
+
* For example the folowing path are interpreted the same:
|
|
223
|
+
* - "command test use:dev :name"
|
|
224
|
+
* - "command/test/use:dev/:name"
|
|
225
|
+
*
|
|
226
|
+
* Where name will become an argument
|
|
227
|
+
*
|
|
228
|
+
* ```js
|
|
229
|
+
* // example without options
|
|
230
|
+
* app.cli('command/:arg', () => 'arg = ' + useRouteParams().params.arg )
|
|
231
|
+
*
|
|
232
|
+
* // example with options
|
|
233
|
+
* app.cli('command/:arg', {
|
|
234
|
+
* description: 'Description of the command',
|
|
235
|
+
* options: [{ keys: ['project', 'p'], description: 'Description of the option', value: 'myProject' }],
|
|
236
|
+
* args: { arg: 'Description of the arg' },
|
|
237
|
+
* aliases: ['cmd'], // alias "cmd/:arg" will be registered
|
|
238
|
+
* examples: [{
|
|
239
|
+
* description: 'Example of usage with someProject',
|
|
240
|
+
* cmd: 'argValue -p=someProject',
|
|
241
|
+
* // will result in help display:
|
|
242
|
+
* // "# Example of usage with someProject\n" +
|
|
243
|
+
* // "$ myCli command argValue -p=someProject\n"
|
|
244
|
+
* }],
|
|
245
|
+
* handler: () => 'arg = ' + useRouteParams().params.arg
|
|
246
|
+
* })
|
|
247
|
+
* ```
|
|
248
|
+
*
|
|
249
|
+
* @param path command path
|
|
250
|
+
* @param _options handler or options
|
|
251
|
+
*
|
|
252
|
+
* @returns
|
|
253
|
+
*/
|
|
254
|
+
cli<ResType = unknown, ParamsType = Record<string, string | string[]>>(path: string, _options: TWooksCliEntry<ResType> | TWooksHandler_2<ResType>): TProstoRouterPathHandle<ParamsType>;
|
|
255
|
+
protected alreadyComputedAliases: boolean;
|
|
256
|
+
protected computeAliases(): void;
|
|
257
|
+
/**
|
|
258
|
+
* ## run
|
|
259
|
+
* ### Start command processing
|
|
260
|
+
* Triggers command processing
|
|
261
|
+
*
|
|
262
|
+
* By default takes `process.argv.slice(2)` as a command
|
|
263
|
+
*
|
|
264
|
+
* It's possible to replace the command by passing an argument
|
|
265
|
+
*
|
|
266
|
+
* @param _argv optionally overwrite `process.argv.slice(2)` with your `argv` array
|
|
267
|
+
*/
|
|
93
268
|
run(_argv?: string[]): Promise<void>;
|
|
94
|
-
onError(e: Error): void;
|
|
269
|
+
protected onError(e: Error): void;
|
|
270
|
+
/**
|
|
271
|
+
* Triggers `unknown command` processing and callbacks
|
|
272
|
+
* @param pathParams `string[]` containing command
|
|
273
|
+
*/
|
|
95
274
|
onUnknownCommand(pathParams: string[]): void;
|
|
96
|
-
error(e: string | Error): void;
|
|
275
|
+
protected error(e: string | Error): void;
|
|
97
276
|
}
|
|
98
277
|
|
|
99
278
|
export { }
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createEventContext, useEventContext } from '@wooksjs/event-core';
|
|
2
2
|
import { WooksAdapterBase } from 'wooks';
|
|
3
|
+
import { CliHelpRenderer } from '@prostojs/cli-help';
|
|
3
4
|
import minimist from 'minimist';
|
|
4
5
|
|
|
5
6
|
function createCliContext(data, options) {
|
|
@@ -8,6 +9,11 @@ function createCliContext(data, options) {
|
|
|
8
9
|
options,
|
|
9
10
|
});
|
|
10
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Wrapper on top of useEventContext that provides
|
|
14
|
+
* proper context types for CLI event
|
|
15
|
+
* @returns set of hooks { getCtx, restoreCtx, clearCtx, hookStore, getStore, setStore }
|
|
16
|
+
*/
|
|
11
17
|
function useCliContext() {
|
|
12
18
|
return useEventContext('CLI');
|
|
13
19
|
}
|
|
@@ -46,22 +52,138 @@ class WooksCli extends WooksAdapterBase {
|
|
|
46
52
|
constructor(opts, wooks) {
|
|
47
53
|
super(wooks, opts === null || opts === void 0 ? void 0 : opts.logger);
|
|
48
54
|
this.opts = opts;
|
|
55
|
+
this.alreadyComputedAliases = false;
|
|
49
56
|
this.logger = (opts === null || opts === void 0 ? void 0 : opts.logger) || this.getLogger('wooks-cli');
|
|
57
|
+
this.cliHelp =
|
|
58
|
+
(opts === null || opts === void 0 ? void 0 : opts.cliHelp) instanceof CliHelpRenderer
|
|
59
|
+
? opts.cliHelp
|
|
60
|
+
: new CliHelpRenderer(opts === null || opts === void 0 ? void 0 : opts.cliHelp);
|
|
50
61
|
}
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
/**
|
|
63
|
+
* ### Register CLI Command
|
|
64
|
+
* Command path segments may be separated by / or space.
|
|
65
|
+
*
|
|
66
|
+
* For example the folowing path are interpreted the same:
|
|
67
|
+
* - "command test use:dev :name"
|
|
68
|
+
* - "command/test/use:dev/:name"
|
|
69
|
+
*
|
|
70
|
+
* Where name will become an argument
|
|
71
|
+
*
|
|
72
|
+
* ```js
|
|
73
|
+
* // example without options
|
|
74
|
+
* app.cli('command/:arg', () => 'arg = ' + useRouteParams().params.arg )
|
|
75
|
+
*
|
|
76
|
+
* // example with options
|
|
77
|
+
* app.cli('command/:arg', {
|
|
78
|
+
* description: 'Description of the command',
|
|
79
|
+
* options: [{ keys: ['project', 'p'], description: 'Description of the option', value: 'myProject' }],
|
|
80
|
+
* args: { arg: 'Description of the arg' },
|
|
81
|
+
* aliases: ['cmd'], // alias "cmd/:arg" will be registered
|
|
82
|
+
* examples: [{
|
|
83
|
+
* description: 'Example of usage with someProject',
|
|
84
|
+
* cmd: 'argValue -p=someProject',
|
|
85
|
+
* // will result in help display:
|
|
86
|
+
* // "# Example of usage with someProject\n" +
|
|
87
|
+
* // "$ myCli command argValue -p=someProject\n"
|
|
88
|
+
* }],
|
|
89
|
+
* handler: () => 'arg = ' + useRouteParams().params.arg
|
|
90
|
+
* })
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @param path command path
|
|
94
|
+
* @param _options handler or options
|
|
95
|
+
*
|
|
96
|
+
* @returns
|
|
97
|
+
*/
|
|
98
|
+
cli(path, _options) {
|
|
99
|
+
const options = typeof _options === 'function' ? { handler: _options } : _options;
|
|
100
|
+
const handler = typeof _options === 'function' ? _options : _options.handler;
|
|
101
|
+
const makePath = (s) => '/' + s.replace(/\s+/g, '/');
|
|
102
|
+
// register handler
|
|
103
|
+
const targetPath = makePath(path);
|
|
104
|
+
const routed = this.on('CLI', targetPath, handler);
|
|
105
|
+
if (options.onRegister) {
|
|
106
|
+
options.onRegister(targetPath, 0);
|
|
107
|
+
}
|
|
108
|
+
// register direct aliases
|
|
109
|
+
for (const alias of options.aliases || []) {
|
|
110
|
+
const vars = routed.getArgs().map((k) => ':' + k).join('/');
|
|
111
|
+
const targetPath = makePath(alias) + (vars ? '/' + vars : '');
|
|
112
|
+
this.on('CLI', targetPath, handler);
|
|
113
|
+
if (options.onRegister) {
|
|
114
|
+
options.onRegister(targetPath, 1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// register helpCli entry
|
|
118
|
+
const command = routed.getStaticPart().replace(/\//g, ' ').trim();
|
|
119
|
+
const args = Object.assign({}, (options.args || {}));
|
|
120
|
+
for (const arg of routed.getArgs()) {
|
|
121
|
+
if (!args[arg]) {
|
|
122
|
+
args[arg] = '';
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
this.cliHelp.addEntry({
|
|
126
|
+
command,
|
|
127
|
+
aliases: options.aliases,
|
|
128
|
+
args,
|
|
129
|
+
description: options.description,
|
|
130
|
+
examples: options.examples,
|
|
131
|
+
options: options.options,
|
|
132
|
+
custom: { handler: options.handler, cb: options.onRegister },
|
|
133
|
+
});
|
|
134
|
+
return routed;
|
|
135
|
+
}
|
|
136
|
+
computeAliases() {
|
|
137
|
+
if (!this.alreadyComputedAliases) {
|
|
138
|
+
this.alreadyComputedAliases = true;
|
|
139
|
+
const aliases = this.cliHelp.getComputedAliases();
|
|
140
|
+
for (const [alias, entry] of Object.entries(aliases)) {
|
|
141
|
+
if (entry.custom) {
|
|
142
|
+
const vars = Object.keys(entry.args || {})
|
|
143
|
+
.map((k) => ':' + k)
|
|
144
|
+
.join('/');
|
|
145
|
+
const path = '/' +
|
|
146
|
+
alias.replace(/\s+/g, '/').replace(/:/g, '\\:') +
|
|
147
|
+
(vars ? '/' + vars : '');
|
|
148
|
+
this.on('CLI', path, entry.custom.handler);
|
|
149
|
+
if (entry.custom.cb) {
|
|
150
|
+
entry.custom.cb(path, 3);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
53
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* ## run
|
|
158
|
+
* ### Start command processing
|
|
159
|
+
* Triggers command processing
|
|
160
|
+
*
|
|
161
|
+
* By default takes `process.argv.slice(2)` as a command
|
|
162
|
+
*
|
|
163
|
+
* It's possible to replace the command by passing an argument
|
|
164
|
+
*
|
|
165
|
+
* @param _argv optionally overwrite `process.argv.slice(2)` with your `argv` array
|
|
166
|
+
*/
|
|
54
167
|
run(_argv) {
|
|
55
168
|
var _a, _b;
|
|
56
169
|
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
-
const argv = process.argv.slice(2)
|
|
170
|
+
const argv = _argv || process.argv.slice(2);
|
|
58
171
|
const firstFlagIndex = argv.findIndex((a) => a.startsWith('-')) + 1;
|
|
59
|
-
const pathParams =
|
|
172
|
+
const pathParams = firstFlagIndex
|
|
60
173
|
? argv.slice(0, firstFlagIndex - 1)
|
|
61
|
-
: argv
|
|
62
|
-
const path = '/' +
|
|
63
|
-
|
|
64
|
-
const
|
|
174
|
+
: argv;
|
|
175
|
+
const path = '/' +
|
|
176
|
+
pathParams.map((v) => encodeURI(v).replace(/\//g, '%2F')).join('/');
|
|
177
|
+
const { restoreCtx, clearCtx, store } = createCliContext({ argv, pathParams, cliHelp: this.cliHelp, command: path.replace(/\//g, ' ').trim() }, this.mergeEventOptions((_a = this.opts) === null || _a === void 0 ? void 0 : _a.eventOptions));
|
|
178
|
+
this.computeAliases();
|
|
179
|
+
const { handlers: foundHandlers, firstStatic } = this.wooks.lookup('CLI', path);
|
|
180
|
+
if (typeof firstStatic === 'string') {
|
|
181
|
+
// overwriting command with firstStatic to properly search for help
|
|
182
|
+
store('event').set('command', firstStatic.replace(/\//g, ' ').trim());
|
|
183
|
+
}
|
|
184
|
+
const handlers = foundHandlers ||
|
|
185
|
+
(((_b = this.opts) === null || _b === void 0 ? void 0 : _b.onNotFound) && [this.opts.onNotFound]) ||
|
|
186
|
+
null;
|
|
65
187
|
if (handlers) {
|
|
66
188
|
try {
|
|
67
189
|
for (const handler of handlers) {
|
|
@@ -106,16 +228,21 @@ class WooksCli extends WooksAdapterBase {
|
|
|
106
228
|
process.exit(1);
|
|
107
229
|
}
|
|
108
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Triggers `unknown command` processing and callbacks
|
|
233
|
+
* @param pathParams `string[]` containing command
|
|
234
|
+
*/
|
|
109
235
|
onUnknownCommand(pathParams) {
|
|
110
236
|
var _a;
|
|
237
|
+
const raiseError = () => {
|
|
238
|
+
this.error('[0m' + 'Unknown command: ' + pathParams.join(' '));
|
|
239
|
+
process.exit(1);
|
|
240
|
+
};
|
|
111
241
|
if ((_a = this.opts) === null || _a === void 0 ? void 0 : _a.onUnknownCommand) {
|
|
112
|
-
this.opts.onUnknownCommand(pathParams);
|
|
242
|
+
this.opts.onUnknownCommand(pathParams, raiseError);
|
|
113
243
|
}
|
|
114
244
|
else {
|
|
115
|
-
|
|
116
|
-
'Unknown command: ' +
|
|
117
|
-
pathParams.join(' '));
|
|
118
|
-
process.exit(1);
|
|
245
|
+
raiseError();
|
|
119
246
|
}
|
|
120
247
|
}
|
|
121
248
|
error(e) {
|
|
@@ -127,11 +254,158 @@ class WooksCli extends WooksAdapterBase {
|
|
|
127
254
|
}
|
|
128
255
|
}
|
|
129
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Factory for WooksCli App
|
|
259
|
+
* @param opts TWooksCliOptions
|
|
260
|
+
* @param wooks Wooks | WooksAdapterBase
|
|
261
|
+
* @returns WooksHttp
|
|
262
|
+
*/
|
|
130
263
|
function createCliApp(opts, wooks) {
|
|
131
264
|
return new WooksCli(opts, wooks);
|
|
132
265
|
}
|
|
133
266
|
|
|
134
|
-
|
|
267
|
+
/**
|
|
268
|
+
* ## useCliHelp
|
|
269
|
+
* ### Composable
|
|
270
|
+
* ```js
|
|
271
|
+
* // example of printing cli instructions
|
|
272
|
+
* const { print } = useCliHelp()
|
|
273
|
+
* // print with colors
|
|
274
|
+
* print(true)
|
|
275
|
+
* // print with no colors
|
|
276
|
+
* // print(false)
|
|
277
|
+
* ```
|
|
278
|
+
* @returns
|
|
279
|
+
*/
|
|
280
|
+
function useCliHelp() {
|
|
281
|
+
const event = useCliContext().store('event');
|
|
282
|
+
const getCliHelp = () => event.get('cliHelp');
|
|
283
|
+
const getEntry = () => { var _a; return (_a = getCliHelp().match(event.get('command'))) === null || _a === void 0 ? void 0 : _a.main; };
|
|
284
|
+
return {
|
|
285
|
+
getCliHelp,
|
|
286
|
+
getEntry,
|
|
287
|
+
render: (width, withColors) => getCliHelp().render(event.get('command'), width, withColors),
|
|
288
|
+
print: (withColors) => getCliHelp().print(event.get('command'), withColors),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* ## useAutoHelp
|
|
293
|
+
* ### Composable
|
|
294
|
+
*
|
|
295
|
+
* Prints help if `--help` option provided.
|
|
296
|
+
*
|
|
297
|
+
* ```js
|
|
298
|
+
* // example of use: print help and exit
|
|
299
|
+
* app.cli('test', () => {
|
|
300
|
+
* useAutoHelp() && process.exit(0)
|
|
301
|
+
* return 'hit test command'
|
|
302
|
+
* })
|
|
303
|
+
*
|
|
304
|
+
* // add option -h to print help, no colors
|
|
305
|
+
* app.cli('test/nocolors', () => {
|
|
306
|
+
* useAutoHelp(['help', 'h'], false) && process.exit(0)
|
|
307
|
+
* return 'hit test nocolors command'
|
|
308
|
+
* })
|
|
309
|
+
* ```
|
|
310
|
+
* @param keys default `['help']` - list of options to trigger help render
|
|
311
|
+
* @param colors default `true`, prints with colors when true
|
|
312
|
+
* @returns true when --help was provided. Otherwise returns false
|
|
313
|
+
*/
|
|
314
|
+
function useAutoHelp(keys = ['help'], colors = true) {
|
|
315
|
+
for (const option of keys) {
|
|
316
|
+
if (useCliOption(option) === true) {
|
|
317
|
+
// try {
|
|
318
|
+
useCliHelp().print(colors);
|
|
319
|
+
return true;
|
|
320
|
+
// } catch (e) {
|
|
321
|
+
// throw new
|
|
322
|
+
// }
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* ##useCommandLookupHelp
|
|
328
|
+
* ### Composable
|
|
329
|
+
*
|
|
330
|
+
* Tries to find valid command based on provided command.
|
|
331
|
+
*
|
|
332
|
+
* If manages to find a valid command, throws an error
|
|
333
|
+
* suggesting a list of valid commands
|
|
334
|
+
*
|
|
335
|
+
* Best to use in `onUnknownCommand` callback:
|
|
336
|
+
*
|
|
337
|
+
* ```js
|
|
338
|
+
* const app = createCliApp({
|
|
339
|
+
* onUnknownCommand: (path, raiseError) => {
|
|
340
|
+
* // will throw an error suggesting a list
|
|
341
|
+
* // of valid commands if could find some
|
|
342
|
+
* useCommandLookupHelp()
|
|
343
|
+
* // fallback to a regular error handler
|
|
344
|
+
* raiseError()
|
|
345
|
+
* },
|
|
346
|
+
* })
|
|
347
|
+
* ```
|
|
348
|
+
*
|
|
349
|
+
* @param lookupDepth depth of search in backwards
|
|
350
|
+
* @example
|
|
351
|
+
*
|
|
352
|
+
* For provided command `run test:drive dir`
|
|
353
|
+
* - lookup1: `run test:drive dir` (deep = 0)
|
|
354
|
+
* - lookup2: `run test:drive` (deep = 1)
|
|
355
|
+
* - lookup3: `run test` (deep = 2)
|
|
356
|
+
* - lookup4: `run` (deep = 3)
|
|
357
|
+
* ...
|
|
358
|
+
*/
|
|
359
|
+
function useCommandLookupHelp(lookupDepth = 3) {
|
|
360
|
+
const parts = useCliContext()
|
|
361
|
+
.store('event')
|
|
362
|
+
.get('pathParams')
|
|
363
|
+
.map((p) => (p + ' ').split(':').map((s, i) => (i ? ':' + s : s)))
|
|
364
|
+
.flat();
|
|
365
|
+
const cliHelp = useCliHelp().getCliHelp();
|
|
366
|
+
const cmd = cliHelp.getCliName();
|
|
367
|
+
let data;
|
|
368
|
+
for (let i = 0; i < Math.min(parts.length, lookupDepth + 1); i++) {
|
|
369
|
+
const pathParams = parts
|
|
370
|
+
.slice(0, i ? -i : parts.length)
|
|
371
|
+
.join('')
|
|
372
|
+
.trim();
|
|
373
|
+
try {
|
|
374
|
+
data = cliHelp.match(pathParams);
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
catch (e) {
|
|
378
|
+
const variants = cliHelp.lookup(pathParams);
|
|
379
|
+
if (variants.length) {
|
|
380
|
+
throw new Error(`Wrong command, did you mean:\n${variants
|
|
381
|
+
.slice(0, 7)
|
|
382
|
+
.map((c) => ` $ ${cmd} ${c.main.command}`)
|
|
383
|
+
.join('\n')}`);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (data) {
|
|
388
|
+
const { main, children } = data;
|
|
389
|
+
if (main.args && Object.keys(main.args).length) {
|
|
390
|
+
throw new Error(`Arguments expected: ${Object.keys(main.args)
|
|
391
|
+
.map((l) => `<${l}>`)
|
|
392
|
+
.join(', ')}`);
|
|
393
|
+
}
|
|
394
|
+
else if (children && children.length) {
|
|
395
|
+
throw new Error(`Wrong command, did you mean:\n${children
|
|
396
|
+
.slice(0, 7)
|
|
397
|
+
.map((c) => ` $ ${cmd} ${c.command}`)
|
|
398
|
+
.join('\n')}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Get CLI Options
|
|
405
|
+
*
|
|
406
|
+
* @returns an object with CLI options
|
|
407
|
+
*/
|
|
408
|
+
function useCliOptions() {
|
|
135
409
|
const { store } = useCliContext();
|
|
136
410
|
const flags = store('flags');
|
|
137
411
|
if (!flags.value) {
|
|
@@ -139,14 +413,29 @@ function useFlags() {
|
|
|
139
413
|
}
|
|
140
414
|
return flags.value;
|
|
141
415
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
416
|
+
/**
|
|
417
|
+
* Getter for Cli Option value
|
|
418
|
+
*
|
|
419
|
+
* @param name name of the option
|
|
420
|
+
* @returns value of a CLI option
|
|
421
|
+
*/
|
|
422
|
+
function useCliOption(name) {
|
|
423
|
+
var _a;
|
|
424
|
+
try {
|
|
425
|
+
const options = ((_a = useCliHelp().getEntry()) === null || _a === void 0 ? void 0 : _a.options) || [];
|
|
426
|
+
const opt = options.find(o => o.keys.includes(name));
|
|
427
|
+
if (opt) {
|
|
428
|
+
for (const key of opt.keys) {
|
|
429
|
+
if (useCliOptions()[key]) {
|
|
430
|
+
return useCliOptions()[key];
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
catch (e) {
|
|
436
|
+
//
|
|
437
|
+
}
|
|
438
|
+
return useCliOptions()[name];
|
|
150
439
|
}
|
|
151
440
|
|
|
152
|
-
export { WooksCli, cliShortcuts, createCliApp, createCliContext, useCliContext,
|
|
441
|
+
export { WooksCli, cliShortcuts, createCliApp, createCliContext, useAutoHelp, useCliContext, useCliHelp, useCliOption, useCliOptions, useCommandLookupHelp };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wooksjs/event-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "@wooksjs/event-cli",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -31,11 +31,12 @@
|
|
|
31
31
|
"url": "https://github.com/wooksjs/wooksjs/issues"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"wooks": "0.
|
|
35
|
-
"@wooksjs/event-core": "0.
|
|
34
|
+
"wooks": "0.3.1",
|
|
35
|
+
"@wooksjs/event-core": "0.3.1"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"minimist": "^1.2.6",
|
|
39
|
+
"@prostojs/cli-help": "^0.0.10",
|
|
39
40
|
"@prostojs/logger": "^0.3.6"
|
|
40
41
|
},
|
|
41
42
|
"homepage": "https://github.com/wooksjs/wooksjs/tree/main/packages/event-cli#readme"
|