@wooksjs/event-cli 0.4.9 → 0.4.11

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.
Files changed (3) hide show
  1. package/dist/index.cjs +398 -425
  2. package/dist/index.mjs +398 -425
  3. package/package.json +6 -3
package/dist/index.mjs CHANGED
@@ -3,438 +3,411 @@ import { WooksAdapterBase } from 'wooks';
3
3
  import { CliHelpRenderer } from '@prostojs/cli-help';
4
4
  import minimist from 'minimist';
5
5
 
6
- function createCliContext(data, options) {
7
- return createEventContext({
8
- event: Object.assign(Object.assign({}, data), { type: 'CLI' }),
9
- options,
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
- */
17
- function useCliContext() {
18
- return useEventContext('CLI');
6
+ function createCliContext(data, options) {
7
+ return createEventContext({
8
+ event: {
9
+ ...data,
10
+ type: 'CLI',
11
+ },
12
+ options,
13
+ });
19
14
  }
20
-
21
- /******************************************************************************
22
- Copyright (c) Microsoft Corporation.
23
-
24
- Permission to use, copy, modify, and/or distribute this software for any
25
- purpose with or without fee is hereby granted.
26
-
27
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
28
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
29
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
30
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
31
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
32
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
33
- PERFORMANCE OF THIS SOFTWARE.
34
- ***************************************************************************** */
35
-
36
- function __awaiter(thisArg, _arguments, P, generator) {
37
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
- return new (P || (P = Promise))(function (resolve, reject) {
39
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
- step((generator = generator.apply(thisArg, _arguments || [])).next());
43
- });
15
+ /**
16
+ * Wrapper on top of useEventContext that provides
17
+ * proper context types for CLI event
18
+ * @returns set of hooks { getCtx, restoreCtx, clearCtx, hookStore, getStore, setStore }
19
+ */
20
+ function useCliContext() {
21
+ return useEventContext('CLI');
44
22
  }
45
23
 
46
- const cliShortcuts = {
47
- cli: 'CLI',
48
- };
49
- class WooksCli extends WooksAdapterBase {
50
- constructor(opts, wooks) {
51
- super(wooks, opts === null || opts === void 0 ? void 0 : opts.logger, opts === null || opts === void 0 ? void 0 : opts.router);
52
- this.opts = opts;
53
- this.alreadyComputedAliases = false;
54
- this.logger = (opts === null || opts === void 0 ? void 0 : opts.logger) || this.getLogger('wooks-cli');
55
- this.cliHelp =
56
- (opts === null || opts === void 0 ? void 0 : opts.cliHelp) instanceof CliHelpRenderer
57
- ? opts.cliHelp
58
- : new CliHelpRenderer(opts === null || opts === void 0 ? void 0 : opts.cliHelp);
59
- }
60
- /**
61
- * ### Register CLI Command
62
- * Command path segments may be separated by / or space.
63
- *
64
- * For example the folowing path are interpreted the same:
65
- * - "command test use:dev :name"
66
- * - "command/test/use:dev/:name"
67
- *
68
- * Where name will become an argument
69
- *
70
- * ```js
71
- * // example without options
72
- * app.cli('command/:arg', () => 'arg = ' + useRouteParams().params.arg )
73
- *
74
- * // example with options
75
- * app.cli('command/:arg', {
76
- * description: 'Description of the command',
77
- * options: [{ keys: ['project', 'p'], description: 'Description of the option', value: 'myProject' }],
78
- * args: { arg: 'Description of the arg' },
79
- * aliases: ['cmd'], // alias "cmd/:arg" will be registered
80
- * examples: [{
81
- * description: 'Example of usage with someProject',
82
- * cmd: 'argValue -p=someProject',
83
- * // will result in help display:
84
- * // "# Example of usage with someProject\n" +
85
- * // "$ myCli command argValue -p=someProject\n"
86
- * }],
87
- * handler: () => 'arg = ' + useRouteParams().params.arg
88
- * })
89
- * ```
90
- *
91
- * @param path command path
92
- * @param _options handler or options
93
- *
94
- * @returns
95
- */
96
- cli(path, _options) {
97
- var _a;
98
- const options = typeof _options === 'function' ? { handler: _options } : _options;
99
- const handler = typeof _options === 'function' ? _options : _options.handler;
100
- const makePath = (s) => '/' + s.replace(/\s+/g, '/');
101
- // register handler
102
- const targetPath = makePath(path);
103
- const routed = this.on('CLI', targetPath, handler);
104
- if (options.onRegister) {
105
- options.onRegister(targetPath, 0, routed);
106
- }
107
- // register direct aliases
108
- for (const alias of options.aliases || []) {
109
- const vars = routed.getArgs().map((k) => ':' + k).join('/');
110
- const targetPath = makePath(alias) + (vars ? '/' + vars : '');
111
- this.on('CLI', targetPath, handler);
112
- if (options.onRegister) {
113
- options.onRegister(targetPath, 1, routed);
114
- }
115
- }
116
- // register helpCli entry
117
- const command = routed.getStaticPart().replace(/\//g, ' ').trim();
118
- const args = Object.assign({}, (options.args || {}));
119
- for (const arg of routed.getArgs()) {
120
- if (!args[arg]) {
121
- args[arg] = '';
122
- }
123
- }
124
- this.cliHelp.addEntry({
125
- command,
126
- aliases: (_a = options.aliases) === null || _a === void 0 ? void 0 : _a.map(alias => alias.replace(/\\:/g, ':')),
127
- args,
128
- description: options.description,
129
- examples: options.examples,
130
- options: options.options,
131
- custom: { handler: options.handler, cb: options.onRegister },
132
- });
133
- return routed;
134
- }
135
- computeAliases() {
136
- if (!this.alreadyComputedAliases) {
137
- this.alreadyComputedAliases = true;
138
- const aliases = this.cliHelp.getComputedAliases();
139
- for (const [alias, entry] of Object.entries(aliases)) {
140
- if (entry.custom) {
141
- const vars = Object.keys(entry.args || {})
142
- .map((k) => ':' + k)
143
- .join('/');
144
- const path = '/' +
145
- alias.replace(/\s+/g, '/').replace(/:/g, '\\:') +
146
- (vars ? '/' + vars : '');
147
- this.on('CLI', path, entry.custom.handler);
148
- if (entry.custom.cb) {
149
- entry.custom.cb(path, 3);
150
- }
151
- }
152
- }
153
- }
154
- }
155
- /**
156
- * ## run
157
- * ### Start command processing
158
- * Triggers command processing
159
- *
160
- * By default takes `process.argv.slice(2)` as a command
161
- *
162
- * It's possible to replace the command by passing an argument
163
- *
164
- * @param _argv optionally overwrite `process.argv.slice(2)` with your `argv` array
165
- */
166
- run(_argv, _opts) {
167
- var _a, _b;
168
- return __awaiter(this, void 0, void 0, function* () {
169
- const argv = _argv || process.argv.slice(2);
170
- const parsedFlags = minimist(argv, _opts);
171
- const pathParams = parsedFlags._;
172
- const path = '/' +
173
- pathParams.map((v) => encodeURI(v).replace(/\//g, '%2F')).join('/');
174
- const { restoreCtx, clearCtx, store } = createCliContext({ opts: _opts, argv, pathParams, cliHelp: this.cliHelp, command: path.replace(/\//g, ' ').trim() }, this.mergeEventOptions((_a = this.opts) === null || _a === void 0 ? void 0 : _a.eventOptions));
175
- store('flags').value = parsedFlags;
176
- this.computeAliases();
177
- const { handlers: foundHandlers, firstStatic } = this.wooks.lookup('CLI', path);
178
- if (typeof firstStatic === 'string') {
179
- // overwriting command with firstStatic to properly search for help
180
- store('event').set('command', firstStatic.replace(/\//g, ' ').trim());
181
- }
182
- const handlers = foundHandlers ||
183
- (((_b = this.opts) === null || _b === void 0 ? void 0 : _b.onNotFound) && [this.opts.onNotFound]) ||
184
- null;
185
- if (handlers) {
186
- try {
187
- for (const handler of handlers) {
188
- restoreCtx();
189
- const response = yield handler();
190
- if (typeof response === 'string') {
191
- console.log(response);
192
- }
193
- else if (Array.isArray(response)) {
194
- response.forEach((r) => console.log(typeof r === 'string'
195
- ? r
196
- : JSON.stringify(r, null, ' ')));
197
- }
198
- else if (response instanceof Error) {
199
- this.onError(response);
200
- }
201
- else if (response) {
202
- if (response) {
203
- console.log(JSON.stringify(response, null, ' '));
204
- }
205
- }
206
- }
207
- }
208
- catch (e) {
209
- this.onError(e);
210
- }
211
- clearCtx();
212
- }
213
- else {
214
- this.onUnknownCommand(pathParams);
215
- clearCtx();
216
- }
217
- });
218
- }
219
- onError(e) {
220
- var _a;
221
- if ((_a = this.opts) === null || _a === void 0 ? void 0 : _a.onError) {
222
- this.opts.onError(e);
223
- }
224
- else {
225
- this.error(e.message);
226
- process.exit(1);
227
- }
228
- }
229
- /**
230
- * Triggers `unknown command` processing and callbacks
231
- * @param pathParams `string[]` containing command
232
- */
233
- onUnknownCommand(pathParams) {
234
- var _a;
235
- const raiseError = () => {
236
- this.error('' + 'Unknown command: ' + pathParams.join(' '));
237
- process.exit(1);
238
- };
239
- if ((_a = this.opts) === null || _a === void 0 ? void 0 : _a.onUnknownCommand) {
240
- this.opts.onUnknownCommand(pathParams, raiseError);
241
- }
242
- else {
243
- raiseError();
244
- }
245
- }
246
- error(e) {
247
- if (typeof e === 'string') {
248
- console.error('' + 'ERROR: ' + '' + e);
249
- }
250
- else {
251
- console.error('' + 'ERROR: ' + '' + e.message);
252
- }
253
- }
254
- }
255
- /**
256
- * Factory for WooksCli App
257
- * @param opts TWooksCliOptions
258
- * @param wooks Wooks | WooksAdapterBase
259
- * @returns WooksCli
260
- */
261
- function createCliApp(opts, wooks) {
262
- return new WooksCli(opts, wooks);
24
+ const cliShortcuts = {
25
+ cli: 'CLI',
26
+ };
27
+ class WooksCli extends WooksAdapterBase {
28
+ constructor(opts, wooks) {
29
+ super(wooks, opts?.logger, opts?.router);
30
+ this.opts = opts;
31
+ this.alreadyComputedAliases = false;
32
+ this.logger = opts?.logger || this.getLogger('wooks-cli');
33
+ this.cliHelp =
34
+ opts?.cliHelp instanceof CliHelpRenderer
35
+ ? opts.cliHelp
36
+ : new CliHelpRenderer(opts?.cliHelp);
37
+ }
38
+ /**
39
+ * ### Register CLI Command
40
+ * Command path segments may be separated by / or space.
41
+ *
42
+ * For example the folowing path are interpreted the same:
43
+ * - "command test use:dev :name"
44
+ * - "command/test/use:dev/:name"
45
+ *
46
+ * Where name will become an argument
47
+ *
48
+ * ```js
49
+ * // example without options
50
+ * app.cli('command/:arg', () => 'arg = ' + useRouteParams().params.arg )
51
+ *
52
+ * // example with options
53
+ * app.cli('command/:arg', {
54
+ * description: 'Description of the command',
55
+ * options: [{ keys: ['project', 'p'], description: 'Description of the option', value: 'myProject' }],
56
+ * args: { arg: 'Description of the arg' },
57
+ * aliases: ['cmd'], // alias "cmd/:arg" will be registered
58
+ * examples: [{
59
+ * description: 'Example of usage with someProject',
60
+ * cmd: 'argValue -p=someProject',
61
+ * // will result in help display:
62
+ * // "# Example of usage with someProject\n" +
63
+ * // "$ myCli command argValue -p=someProject\n"
64
+ * }],
65
+ * handler: () => 'arg = ' + useRouteParams().params.arg
66
+ * })
67
+ * ```
68
+ *
69
+ * @param path command path
70
+ * @param _options handler or options
71
+ *
72
+ * @returns
73
+ */
74
+ cli(path, _options) {
75
+ const options = typeof _options === 'function' ? { handler: _options } : _options;
76
+ const handler = typeof _options === 'function' ? _options : _options.handler;
77
+ const makePath = (s) => '/' + s.replace(/\s+/g, '/');
78
+ // register handler
79
+ const targetPath = makePath(path);
80
+ const routed = this.on('CLI', targetPath, handler);
81
+ if (options.onRegister) {
82
+ options.onRegister(targetPath, 0, routed);
83
+ }
84
+ // register direct aliases
85
+ for (const alias of options.aliases || []) {
86
+ const vars = routed.getArgs().map((k) => ':' + k).join('/');
87
+ const targetPath = makePath(alias) + (vars ? '/' + vars : '');
88
+ this.on('CLI', targetPath, handler);
89
+ if (options.onRegister) {
90
+ options.onRegister(targetPath, 1, routed);
91
+ }
92
+ }
93
+ // register helpCli entry
94
+ const command = routed.getStaticPart().replace(/\//g, ' ').trim();
95
+ const args = {
96
+ ...(options.args || {}),
97
+ };
98
+ for (const arg of routed.getArgs()) {
99
+ if (!args[arg]) {
100
+ args[arg] = '';
101
+ }
102
+ }
103
+ this.cliHelp.addEntry({
104
+ command,
105
+ aliases: options.aliases?.map(alias => alias.replace(/\\:/g, ':')), // unescape ":" character
106
+ args,
107
+ description: options.description,
108
+ examples: options.examples,
109
+ options: options.options,
110
+ custom: { handler: options.handler, cb: options.onRegister },
111
+ });
112
+ return routed;
113
+ }
114
+ computeAliases() {
115
+ if (!this.alreadyComputedAliases) {
116
+ this.alreadyComputedAliases = true;
117
+ const aliases = this.cliHelp.getComputedAliases();
118
+ for (const [alias, entry] of Object.entries(aliases)) {
119
+ if (entry.custom) {
120
+ const vars = Object.keys(entry.args || {})
121
+ .map((k) => ':' + k)
122
+ .join('/');
123
+ const path = '/' +
124
+ alias.replace(/\s+/g, '/').replace(/:/g, '\\:') +
125
+ (vars ? '/' + vars : '');
126
+ this.on('CLI', path, entry.custom.handler);
127
+ if (entry.custom.cb) {
128
+ entry.custom.cb(path, 3);
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }
134
+ /**
135
+ * ## run
136
+ * ### Start command processing
137
+ * Triggers command processing
138
+ *
139
+ * By default takes `process.argv.slice(2)` as a command
140
+ *
141
+ * It's possible to replace the command by passing an argument
142
+ *
143
+ * @param _argv optionally overwrite `process.argv.slice(2)` with your `argv` array
144
+ */
145
+ async run(_argv, _opts) {
146
+ const argv = _argv || process.argv.slice(2);
147
+ const parsedFlags = minimist(argv, _opts);
148
+ const pathParams = parsedFlags._;
149
+ const path = '/' +
150
+ pathParams.map((v) => encodeURI(v).replace(/\//g, '%2F')).join('/');
151
+ const { restoreCtx, clearCtx, store } = createCliContext({ opts: _opts, argv, pathParams, cliHelp: this.cliHelp, command: path.replace(/\//g, ' ').trim() }, this.mergeEventOptions(this.opts?.eventOptions));
152
+ store('flags').value = parsedFlags;
153
+ this.computeAliases();
154
+ const { handlers: foundHandlers, firstStatic } = this.wooks.lookup('CLI', path);
155
+ if (typeof firstStatic === 'string') {
156
+ // overwriting command with firstStatic to properly search for help
157
+ store('event').set('command', firstStatic.replace(/\//g, ' ').trim());
158
+ }
159
+ const handlers = foundHandlers ||
160
+ (this.opts?.onNotFound && [this.opts.onNotFound]) ||
161
+ null;
162
+ if (handlers) {
163
+ try {
164
+ for (const handler of handlers) {
165
+ restoreCtx();
166
+ const response = await handler();
167
+ if (typeof response === 'string') {
168
+ console.log(response);
169
+ }
170
+ else if (Array.isArray(response)) {
171
+ response.forEach((r) => console.log(typeof r === 'string'
172
+ ? r
173
+ : JSON.stringify(r, null, ' ')));
174
+ }
175
+ else if (response instanceof Error) {
176
+ this.onError(response);
177
+ }
178
+ else if (response) {
179
+ if (response) {
180
+ console.log(JSON.stringify(response, null, ' '));
181
+ }
182
+ }
183
+ }
184
+ }
185
+ catch (e) {
186
+ this.onError(e);
187
+ }
188
+ clearCtx();
189
+ }
190
+ else {
191
+ this.onUnknownCommand(pathParams);
192
+ clearCtx();
193
+ }
194
+ }
195
+ onError(e) {
196
+ if (this.opts?.onError) {
197
+ this.opts.onError(e);
198
+ }
199
+ else {
200
+ this.error(e.message);
201
+ process.exit(1);
202
+ }
203
+ }
204
+ /**
205
+ * Triggers `unknown command` processing and callbacks
206
+ * @param pathParams `string[]` containing command
207
+ */
208
+ onUnknownCommand(pathParams) {
209
+ const raiseError = () => {
210
+ this.error('' + 'Unknown command: ' + pathParams.join(' '));
211
+ process.exit(1);
212
+ };
213
+ if (this.opts?.onUnknownCommand) {
214
+ this.opts.onUnknownCommand(pathParams, raiseError);
215
+ }
216
+ else {
217
+ raiseError();
218
+ }
219
+ }
220
+ error(e) {
221
+ if (typeof e === 'string') {
222
+ console.error('' + 'ERROR: ' + '' + e);
223
+ }
224
+ else {
225
+ console.error('' + 'ERROR: ' + '' + e.message);
226
+ }
227
+ }
228
+ }
229
+ /**
230
+ * Factory for WooksCli App
231
+ * @param opts TWooksCliOptions
232
+ * @param wooks Wooks | WooksAdapterBase
233
+ * @returns WooksCli
234
+ */
235
+ function createCliApp(opts, wooks) {
236
+ return new WooksCli(opts, wooks);
263
237
  }
264
238
 
265
- /**
266
- * ## useCliHelp
267
- * ### Composable
268
- * ```js
269
- * // example of printing cli instructions
270
- * const { print } = useCliHelp()
271
- * // print with colors
272
- * print(true)
273
- * // print with no colors
274
- * // print(false)
275
- * ```
276
- * @returns
277
- */
278
- function useCliHelp() {
279
- const event = useCliContext().store('event');
280
- const getCliHelp = () => event.get('cliHelp');
281
- const getEntry = () => { var _a; return (_a = getCliHelp().match(event.get('command'))) === null || _a === void 0 ? void 0 : _a.main; };
282
- return {
283
- getCliHelp,
284
- getEntry,
285
- render: (width, withColors) => getCliHelp().render(event.get('command'), width, withColors),
286
- print: (withColors) => getCliHelp().print(event.get('command'), withColors),
287
- };
288
- }
289
- /**
290
- * ## useAutoHelp
291
- * ### Composable
292
- *
293
- * Prints help if `--help` option provided.
294
- *
295
- * ```js
296
- * // example of use: print help and exit
297
- * app.cli('test', () => {
298
- * useAutoHelp() && process.exit(0)
299
- * return 'hit test command'
300
- * })
301
- *
302
- * // add option -h to print help, no colors
303
- * app.cli('test/nocolors', () => {
304
- * useAutoHelp(['help', 'h'], false) && process.exit(0)
305
- * return 'hit test nocolors command'
306
- * })
307
- * ```
308
- * @param keys default `['help']` - list of options to trigger help render
309
- * @param colors default `true`, prints with colors when true
310
- * @returns true when --help was provided. Otherwise returns false
311
- */
312
- function useAutoHelp(keys = ['help'], colors = true) {
313
- for (const option of keys) {
314
- if (useCliOption(option) === true) {
315
- // try {
316
- useCliHelp().print(colors);
317
- return true;
318
- // } catch (e) {
319
- // throw new
320
- // }
321
- }
322
- }
323
- }
324
- /**
325
- * ##useCommandLookupHelp
326
- * ### Composable
327
- *
328
- * Tries to find valid command based on provided command.
329
- *
330
- * If manages to find a valid command, throws an error
331
- * suggesting a list of valid commands
332
- *
333
- * Best to use in `onUnknownCommand` callback:
334
- *
335
- * ```js
336
- * const app = createCliApp({
337
- * onUnknownCommand: (path, raiseError) => {
338
- * // will throw an error suggesting a list
339
- * // of valid commands if could find some
340
- * useCommandLookupHelp()
341
- * // fallback to a regular error handler
342
- * raiseError()
343
- * },
344
- * })
345
- * ```
346
- *
347
- * @param lookupDepth depth of search in backwards
348
- * @example
349
- *
350
- * For provided command `run test:drive dir`
351
- * - lookup1: `run test:drive dir` (deep = 0)
352
- * - lookup2: `run test:drive` (deep = 1)
353
- * - lookup3: `run test` (deep = 2)
354
- * - lookup4: `run` (deep = 3)
355
- * ...
356
- */
357
- function useCommandLookupHelp(lookupDepth = 3) {
358
- const parts = useCliContext()
359
- .store('event')
360
- .get('pathParams')
361
- .map((p) => (p + ' ').split(':').map((s, i) => (i ? ':' + s : s)))
362
- .flat();
363
- const cliHelp = useCliHelp().getCliHelp();
364
- const cmd = cliHelp.getCliName();
365
- let data;
366
- for (let i = 0; i < Math.min(parts.length, lookupDepth + 1); i++) {
367
- const pathParams = parts
368
- .slice(0, i ? -i : parts.length)
369
- .join('')
370
- .trim();
371
- try {
372
- data = cliHelp.match(pathParams);
373
- break;
374
- }
375
- catch (e) {
376
- const variants = cliHelp.lookup(pathParams);
377
- if (variants.length) {
378
- throw new Error(`Wrong command, did you mean:\n${variants
379
- .slice(0, 7)
380
- .map((c) => ` $ ${cmd} ${c.main.command}`)
381
- .join('\n')}`);
382
- }
383
- }
384
- }
385
- if (data) {
386
- const { main, children } = data;
387
- if (main.args && Object.keys(main.args).length) {
388
- throw new Error(`Arguments expected: ${Object.keys(main.args)
389
- .map((l) => `<${l}>`)
390
- .join(', ')}`);
391
- }
392
- else if (children && children.length) {
393
- throw new Error(`Wrong command, did you mean:\n${children
394
- .slice(0, 7)
395
- .map((c) => ` $ ${cmd} ${c.command}`)
396
- .join('\n')}`);
397
- }
398
- }
239
+ /**
240
+ * ## useCliHelp
241
+ * ### Composable
242
+ * ```js
243
+ * // example of printing cli instructions
244
+ * const { print } = useCliHelp()
245
+ * // print with colors
246
+ * print(true)
247
+ * // print with no colors
248
+ * // print(false)
249
+ * ```
250
+ * @returns
251
+ */
252
+ function useCliHelp() {
253
+ const event = useCliContext().store('event');
254
+ const getCliHelp = () => event.get('cliHelp');
255
+ const getEntry = () => getCliHelp().match(event.get('command'))?.main;
256
+ return {
257
+ getCliHelp,
258
+ getEntry,
259
+ render: (width, withColors) => getCliHelp().render(event.get('command'), width, withColors),
260
+ print: (withColors) => getCliHelp().print(event.get('command'), withColors),
261
+ };
262
+ }
263
+ /**
264
+ * ## useAutoHelp
265
+ * ### Composable
266
+ *
267
+ * Prints help if `--help` option provided.
268
+ *
269
+ * ```js
270
+ * // example of use: print help and exit
271
+ * app.cli('test', () => {
272
+ * useAutoHelp() && process.exit(0)
273
+ * return 'hit test command'
274
+ * })
275
+ *
276
+ * // add option -h to print help, no colors
277
+ * app.cli('test/nocolors', () => {
278
+ * useAutoHelp(['help', 'h'], false) && process.exit(0)
279
+ * return 'hit test nocolors command'
280
+ * })
281
+ * ```
282
+ * @param keys default `['help']` - list of options to trigger help render
283
+ * @param colors default `true`, prints with colors when true
284
+ * @returns true when --help was provided. Otherwise returns false
285
+ */
286
+ function useAutoHelp(keys = ['help'], colors = true) {
287
+ for (const option of keys) {
288
+ if (useCliOption(option) === true) {
289
+ // try {
290
+ useCliHelp().print(colors);
291
+ return true;
292
+ // } catch (e) {
293
+ // throw new
294
+ // }
295
+ }
296
+ }
297
+ }
298
+ /**
299
+ * ##useCommandLookupHelp
300
+ * ### Composable
301
+ *
302
+ * Tries to find valid command based on provided command.
303
+ *
304
+ * If manages to find a valid command, throws an error
305
+ * suggesting a list of valid commands
306
+ *
307
+ * Best to use in `onUnknownCommand` callback:
308
+ *
309
+ * ```js
310
+ * const app = createCliApp({
311
+ * onUnknownCommand: (path, raiseError) => {
312
+ * // will throw an error suggesting a list
313
+ * // of valid commands if could find some
314
+ * useCommandLookupHelp()
315
+ * // fallback to a regular error handler
316
+ * raiseError()
317
+ * },
318
+ * })
319
+ * ```
320
+ *
321
+ * @param lookupDepth depth of search in backwards
322
+ * @example
323
+ *
324
+ * For provided command `run test:drive dir`
325
+ * - lookup1: `run test:drive dir` (deep = 0)
326
+ * - lookup2: `run test:drive` (deep = 1)
327
+ * - lookup3: `run test` (deep = 2)
328
+ * - lookup4: `run` (deep = 3)
329
+ * ...
330
+ */
331
+ function useCommandLookupHelp(lookupDepth = 3) {
332
+ const parts = useCliContext()
333
+ .store('event')
334
+ .get('pathParams')
335
+ .map((p) => (p + ' ').split(':').map((s, i) => (i ? ':' + s : s)))
336
+ .flat();
337
+ const cliHelp = useCliHelp().getCliHelp();
338
+ const cmd = cliHelp.getCliName();
339
+ let data;
340
+ for (let i = 0; i < Math.min(parts.length, lookupDepth + 1); i++) {
341
+ const pathParams = parts
342
+ .slice(0, i ? -i : parts.length)
343
+ .join('')
344
+ .trim();
345
+ try {
346
+ data = cliHelp.match(pathParams);
347
+ break;
348
+ }
349
+ catch (e) {
350
+ const variants = cliHelp.lookup(pathParams);
351
+ if (variants.length) {
352
+ throw new Error(`Wrong command, did you mean:\n${variants
353
+ .slice(0, 7)
354
+ .map((c) => ` $ ${cmd} ${c.main.command}`)
355
+ .join('\n')}`);
356
+ }
357
+ }
358
+ }
359
+ if (data) {
360
+ const { main, children } = data;
361
+ if (main.args && Object.keys(main.args).length) {
362
+ throw new Error(`Arguments expected: ${Object.keys(main.args)
363
+ .map((l) => `<${l}>`)
364
+ .join(', ')}`);
365
+ }
366
+ else if (children && children.length) {
367
+ throw new Error(`Wrong command, did you mean:\n${children
368
+ .slice(0, 7)
369
+ .map((c) => ` $ ${cmd} ${c.command}`)
370
+ .join('\n')}`);
371
+ }
372
+ }
399
373
  }
400
374
 
401
- /**
402
- * Get CLI Options
403
- *
404
- * @returns an object with CLI options
405
- */
406
- function useCliOptions() {
407
- const { store } = useCliContext();
408
- const flags = store('flags');
409
- if (!flags.value) {
410
- const event = store('event');
411
- flags.value = minimist(event.value.argv, event.get('opts'));
412
- }
413
- return flags.value;
414
- }
415
- /**
416
- * Getter for Cli Option value
417
- *
418
- * @param name name of the option
419
- * @returns value of a CLI option
420
- */
421
- function useCliOption(name) {
422
- var _a;
423
- try {
424
- const options = ((_a = useCliHelp().getEntry()) === null || _a === void 0 ? void 0 : _a.options) || [];
425
- const opt = options.find(o => o.keys.includes(name));
426
- if (opt) {
427
- for (const key of opt.keys) {
428
- if (useCliOptions()[key]) {
429
- return useCliOptions()[key];
430
- }
431
- }
432
- }
433
- }
434
- catch (e) {
435
- //
436
- }
437
- return useCliOptions()[name];
375
+ /**
376
+ * Get CLI Options
377
+ *
378
+ * @returns an object with CLI options
379
+ */
380
+ function useCliOptions() {
381
+ const { store } = useCliContext();
382
+ const flags = store('flags');
383
+ if (!flags.value) {
384
+ const event = store('event');
385
+ flags.value = minimist(event.value.argv, event.get('opts'));
386
+ }
387
+ return flags.value;
388
+ }
389
+ /**
390
+ * Getter for Cli Option value
391
+ *
392
+ * @param name name of the option
393
+ * @returns value of a CLI option
394
+ */
395
+ function useCliOption(name) {
396
+ try {
397
+ const options = useCliHelp().getEntry()?.options || [];
398
+ const opt = options.find(o => o.keys.includes(name));
399
+ if (opt) {
400
+ for (const key of opt.keys) {
401
+ if (useCliOptions()[key]) {
402
+ return useCliOptions()[key];
403
+ }
404
+ }
405
+ }
406
+ }
407
+ catch (e) {
408
+ //
409
+ }
410
+ return useCliOptions()[name];
438
411
  }
439
412
 
440
413
  export { WooksCli, cliShortcuts, createCliApp, createCliContext, useAutoHelp, useCliContext, useCliHelp, useCliOption, useCliOptions, useCommandLookupHelp };