juisy 2.0.0-beta.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/README.md +211 -0
- package/bin/cli/cli.js +23 -0
- package/bin/cli/cmds/changelog.js +41 -0
- package/bin/cli/cmds/docs/generate-api.js +22 -0
- package/bin/cli/cmds/docs/generate-cli.js +11 -0
- package/bin/cli/cmds/docs/generate-readme.js +11 -0
- package/bin/cli/cmds/docs/index.js +22 -0
- package/bin/cli/cmds/docs/lint.js +42 -0
- package/bin/cli/cmds/eject.js +28 -0
- package/bin/cli/cmds/git-hooks/index.js +20 -0
- package/bin/cli/cmds/git-hooks/reset.js +48 -0
- package/bin/cli/cmds/git-hooks/sync.js +19 -0
- package/bin/cli/cmds/index.js +15 -0
- package/bin/cli/cmds/print-globals.js +28 -0
- package/bin/cli/cmds/release.js +231 -0
- package/bin/cli/cmds/squeeze.js +269 -0
- package/bin/cli/cmds/test.js +33 -0
- package/bin/cli/index.js +9 -0
- package/bin/cli/lib/docs/generate-api-doc.js +78 -0
- package/bin/cli/lib/version/update-version.js +52 -0
- package/bin/scripts/commit-msg.js +32 -0
- package/bin/scripts/pre-commit.js +24 -0
- package/dist/DataExporter.d.ts +67 -0
- package/dist/cli/CLIFactory.d.ts +19 -0
- package/dist/cli/Command.d.ts +44 -0
- package/dist/cli/InterfaceUtils.d.ts +53 -0
- package/dist/cli/OutputUtils.d.ts +123 -0
- package/dist/cli/command-visitors/command-handler-injections.d.ts +10 -0
- package/dist/cli/command-visitors/get-command-meta.d.ts +10 -0
- package/dist/cli/command-visitors/index.d.ts +9 -0
- package/dist/cli/command-visitors/private-command.d.ts +16 -0
- package/dist/cli/create-engine.d.ts +7 -0
- package/dist/cli/extract-usage.d.ts +72 -0
- package/dist/cli/index.d.ts +20 -0
- package/dist/cli/index.js +559 -0
- package/dist/cli/types.d.ts +112 -0
- package/dist/cli/utils.d.ts +19 -0
- package/dist/eject.d.ts +22 -0
- package/dist/get-package-info.d.ts +6 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +244 -0
- package/dist/project-globals.d.ts +63 -0
- package/dist/templater/Templater.d.ts +23 -0
- package/dist/templater/index.d.ts +6 -0
- package/dist/templater/index.js +330 -0
- package/dist/templater/markdown-templater/ReadmeTemplater.d.ts +154 -0
- package/dist/templater/markdown-templater/index.d.ts +25 -0
- package/dist/templater/types.d.ts +10 -0
- package/dist/utils/misc.d.ts +21 -0
- package/package.json +179 -0
- package/src/index.js +507 -0
- package/template/CHANGELOG.md +0 -0
- package/template/bin/cli/cli.js +27 -0
- package/template/bin/cli/cmds/changelog.js +71 -0
- package/template/bin/cli/cmds/docs.js +30 -0
- package/template/bin/cli/cmds/docs_cmds/generate-api.js +75 -0
- package/template/bin/cli/cmds/docs_cmds/generate-readme.js +51 -0
- package/template/bin/cli/cmds/git-hooks.js +30 -0
- package/template/bin/cli/cmds/git_hooks_cmds/reset.js +76 -0
- package/template/bin/cli/cmds/git_hooks_cmds/sync.js +44 -0
- package/template/bin/cli/cmds/release.js +219 -0
- package/template/bin/cli/index.js +7 -0
- package/template/bin/cli/lib/docs/generate-api-doc.js +33 -0
- package/template/bin/cli/lib/release/generate-release-note.js +3 -0
- package/template/bin/cli/lib/version/update-version.js +51 -0
- package/template/bin/scripts/commit-msg.js +42 -0
- package/template/bin/scripts/pre-commit.js +32 -0
- package/template/docs/api/docs.config.js +10 -0
- package/template/docs/readme/config.js +22 -0
- package/template/docs/readme/readme.js +70 -0
- package/template/docs/readme/template.md +53 -0
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* juisy v1.4.0
|
|
3
|
+
* Copyright © 2022-Present Hervé Perchec
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { hideBin } from 'yargs/helpers';
|
|
7
|
+
import execa from 'execa';
|
|
8
|
+
import _prompts from 'prompts';
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import indent from 'indent-string';
|
|
11
|
+
import _stripAnsi from 'strip-ansi';
|
|
12
|
+
import Yargs from 'yargs/yargs';
|
|
13
|
+
import deepmerge from 'deepmerge';
|
|
14
|
+
|
|
15
|
+
class Command {
|
|
16
|
+
/**
|
|
17
|
+
* Creates a Command instance from object (CommandModule)
|
|
18
|
+
* @param {CommandModule} commandObject - The command definition object
|
|
19
|
+
*/
|
|
20
|
+
constructor(commandObject) {
|
|
21
|
+
this.command = commandObject.command;
|
|
22
|
+
this.aliases = commandObject.aliases;
|
|
23
|
+
this.describe = commandObject.describe;
|
|
24
|
+
this.deprecated = commandObject.deprecated;
|
|
25
|
+
this.meta = commandObject.meta;
|
|
26
|
+
this.builder = commandObject.builder || ((cli) => cli);
|
|
27
|
+
this.handler = commandObject.handler;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The command
|
|
31
|
+
*/
|
|
32
|
+
command;
|
|
33
|
+
/**
|
|
34
|
+
* The aliases
|
|
35
|
+
*/
|
|
36
|
+
aliases;
|
|
37
|
+
/**
|
|
38
|
+
* Command description
|
|
39
|
+
*/
|
|
40
|
+
describe;
|
|
41
|
+
/**
|
|
42
|
+
* Is deprecated?
|
|
43
|
+
*/
|
|
44
|
+
deprecated;
|
|
45
|
+
/**
|
|
46
|
+
* Command meta
|
|
47
|
+
*/
|
|
48
|
+
meta;
|
|
49
|
+
/**
|
|
50
|
+
* Command builder
|
|
51
|
+
*/
|
|
52
|
+
builder;
|
|
53
|
+
/**
|
|
54
|
+
* Command handler
|
|
55
|
+
*/
|
|
56
|
+
handler;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const loading = {
|
|
60
|
+
// Duration of each character displaying (in ms)
|
|
61
|
+
velocity: 250,
|
|
62
|
+
// Reference to call setInterval and clearInterval
|
|
63
|
+
intervalRef: null,
|
|
64
|
+
// Display loading to STDOUT
|
|
65
|
+
display: function(message) {
|
|
66
|
+
const P = ["\\", "|", "/", "-"];
|
|
67
|
+
const S = [" ", ". ", ".. ", "..."];
|
|
68
|
+
let x = 0;
|
|
69
|
+
let y = 0;
|
|
70
|
+
const velocity = this.velocity;
|
|
71
|
+
this.intervalRef = setInterval(function() {
|
|
72
|
+
process.stdout.write("\r" + P[x++] + " " + message + " : " + S[y++]);
|
|
73
|
+
x &= 3;
|
|
74
|
+
y &= 3;
|
|
75
|
+
}, velocity);
|
|
76
|
+
},
|
|
77
|
+
stop: function() {
|
|
78
|
+
clearInterval(this.intervalRef);
|
|
79
|
+
try {
|
|
80
|
+
process.stdout.clearLine(0);
|
|
81
|
+
process.stdout.cursorTo(0);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.log("Warn: process.stdout.clearLine (or cursorTo) function is non-TTY. Skipped...");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
class OutputUtils {
|
|
88
|
+
/**
|
|
89
|
+
* To automatically increment step index
|
|
90
|
+
* @ignore
|
|
91
|
+
*/
|
|
92
|
+
static stepsCache = {
|
|
93
|
+
index: 0
|
|
94
|
+
// 0 by default
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Use `chalk` package to style output in console/stdout
|
|
98
|
+
* @example
|
|
99
|
+
* const { $style } = OutputUtils
|
|
100
|
+
* console.log($style.green('Green text!')) // => '[32mGreen text![0m'
|
|
101
|
+
*/
|
|
102
|
+
static $style = chalk;
|
|
103
|
+
/**
|
|
104
|
+
* Format a message for console output
|
|
105
|
+
* @param msg - The message to format
|
|
106
|
+
* @param options - Format options
|
|
107
|
+
* @returns The formatted message
|
|
108
|
+
* @example
|
|
109
|
+
* formatOutputMessage('laundry\nshopping', { indentChar: '- ' })
|
|
110
|
+
* // => '- laundry\n- shopping'
|
|
111
|
+
*
|
|
112
|
+
* formatOutputMessage('foo\nbar', { indent: 2, indentChar: '❤' })
|
|
113
|
+
* // => '❤❤foo\n❤❤bar'
|
|
114
|
+
*/
|
|
115
|
+
static formatOutputMessage(msg, options = {}) {
|
|
116
|
+
let formatted = `${msg}`;
|
|
117
|
+
if (options.indentChar) {
|
|
118
|
+
if (options.indent === void 0) {
|
|
119
|
+
options.indent = 1;
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
options.indentChar = " ";
|
|
123
|
+
options.indent = options.indent || 0;
|
|
124
|
+
}
|
|
125
|
+
if (options.indent) {
|
|
126
|
+
formatted = indent(msg, options.indent, { indent: options.indentChar });
|
|
127
|
+
}
|
|
128
|
+
return formatted;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* @param msg - The message
|
|
132
|
+
* @param options - (Optional) Options object
|
|
133
|
+
* @param options.indent - How many repeat indent (see `indent-string` package)
|
|
134
|
+
* @param options.indentChar - Indent character(s). If `options.indent` not provided, will be repeated only 1 time
|
|
135
|
+
* @description
|
|
136
|
+
* Log message in console
|
|
137
|
+
* @example
|
|
138
|
+
* const { log } = OutputUtils
|
|
139
|
+
* log() // => blank line
|
|
140
|
+
* log('Hello world! =)') // => 'Hello world! =)'
|
|
141
|
+
* log('To do:', { indent: 2 }) // => ' To do:'
|
|
142
|
+
*/
|
|
143
|
+
static log(msg, options = {}) {
|
|
144
|
+
const loggerInstance = options.loggerInstance || console;
|
|
145
|
+
if (msg) {
|
|
146
|
+
loggerInstance.log(OutputUtils.formatOutputMessage(msg, options));
|
|
147
|
+
} else {
|
|
148
|
+
loggerInstance.log();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Display warning message
|
|
153
|
+
* @param msg - The message to display
|
|
154
|
+
* @example
|
|
155
|
+
* const { warn } = OutputUtils
|
|
156
|
+
* warn('No configuration file') // => '[33m⚠ Warning: No configuration file[0m'
|
|
157
|
+
*/
|
|
158
|
+
static warn(msg) {
|
|
159
|
+
OutputUtils.log(OutputUtils.$style.yellow(`⚠ Warning: ${msg}`));
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* @param msg - The message to display
|
|
163
|
+
* @param {Error} [err] - If provided, throw the error
|
|
164
|
+
* @description
|
|
165
|
+
* Display error message. Throws `err` if provided.
|
|
166
|
+
* @example
|
|
167
|
+
* const { error } = require('@hperchec/juisy').utils
|
|
168
|
+
* error('No configuration file') // => '[31m⨉ ERROR: No configuration file[0m'
|
|
169
|
+
* error('No configuration file', error) // => Log and throws error
|
|
170
|
+
*/
|
|
171
|
+
static error(msg, err = void 0) {
|
|
172
|
+
OutputUtils.log(OutputUtils.$style.red(`⨉ ERROR: ${msg}`));
|
|
173
|
+
if (err !== void 0) {
|
|
174
|
+
OutputUtils.log();
|
|
175
|
+
throw err;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Log step title
|
|
180
|
+
* @param msg - The message to display
|
|
181
|
+
* @param options - Options object
|
|
182
|
+
* @param options.index - Custom index. If `null`, no index prepended to string
|
|
183
|
+
* @example
|
|
184
|
+
* step('Important step') // => '● 1 - Important step'
|
|
185
|
+
* step('Very important step') // => '● 2 - Very important step'
|
|
186
|
+
*/
|
|
187
|
+
static step(msg, options = {}) {
|
|
188
|
+
OutputUtils.stepsCache.index++;
|
|
189
|
+
if (options.index === void 0) {
|
|
190
|
+
options.index = OutputUtils.stepsCache.index;
|
|
191
|
+
}
|
|
192
|
+
OutputUtils.log(`${options.index !== null ? options.index + " - " : ""}${msg}`, { indentChar: "● " });
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Log substep title
|
|
196
|
+
* @param msg - The message to display
|
|
197
|
+
* @param options - Options object
|
|
198
|
+
* @param options.last - Defines if it is the last substep
|
|
199
|
+
* @example
|
|
200
|
+
* const { substep } = require('@hperchec/juisy').utils
|
|
201
|
+
* substep('Awesome substep') // => '├ Awesome substep'
|
|
202
|
+
* substep('Last substep', { last: true }) // => '└ Last substep'
|
|
203
|
+
*/
|
|
204
|
+
static substep(msg, options = {}) {
|
|
205
|
+
OutputUtils.log(msg, { indentChar: options.last ? "└ " : "├ " });
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* @param {string} message - Message to display
|
|
209
|
+
* @param {Function} fct - The function to execute
|
|
210
|
+
* @returns {Promise<void>}
|
|
211
|
+
* @description
|
|
212
|
+
* Wait function: display loading during 'fct' execution
|
|
213
|
+
* @example
|
|
214
|
+
* const { wait } = require('@hperchec/juisy').utils
|
|
215
|
+
* await wait('Waiting', async () => {
|
|
216
|
+
* // Do async logic
|
|
217
|
+
* })
|
|
218
|
+
*/
|
|
219
|
+
static async wait(message, fct) {
|
|
220
|
+
loading.display(message);
|
|
221
|
+
await fct();
|
|
222
|
+
loading.stop();
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* See `strip-ansi` package documentation
|
|
226
|
+
* @see https://www.npmjs.com/package/strip-ansi
|
|
227
|
+
*/
|
|
228
|
+
static stripAnsi = _stripAnsi;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const { log, $style } = OutputUtils;
|
|
232
|
+
class InterfaceUtils {
|
|
233
|
+
/**
|
|
234
|
+
* Get root directory path
|
|
235
|
+
* @example
|
|
236
|
+
* import { CLIUtils: { rootDir } } from '@hperchec/juisy'
|
|
237
|
+
* console.log(rootDir) // => 'path/to/your/root/dir'
|
|
238
|
+
*/
|
|
239
|
+
static rootDir = process.cwd();
|
|
240
|
+
/**
|
|
241
|
+
* @param {string} bin - Command
|
|
242
|
+
* @param {string[]} args - Same as execa second arg
|
|
243
|
+
* @param {object} [opts] - Options
|
|
244
|
+
* @returns {Promise<object>} The `execa` Promise
|
|
245
|
+
* @description
|
|
246
|
+
* Run command (child_process). See also `execa` package documentation
|
|
247
|
+
* @example
|
|
248
|
+
* const { run } = require('@hperchec/juisy').utils
|
|
249
|
+
* await run('npm', [ 'run', 'test' ], { stdio: 'inherit' })
|
|
250
|
+
*/
|
|
251
|
+
static run(bin, args, opts = {}) {
|
|
252
|
+
return execa(bin, args, { stdio: "inherit", cwd: InterfaceUtils.rootDir, ...opts });
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* @alias utils.abort
|
|
256
|
+
* @param {number} [code] - Code for process.exit() (default: 0)
|
|
257
|
+
* @returns {void}
|
|
258
|
+
* @description
|
|
259
|
+
* Exit process
|
|
260
|
+
* @example
|
|
261
|
+
* const { abort } = require('@hperchec/juisy').utils
|
|
262
|
+
* abort() // => exit process with code 0
|
|
263
|
+
* abort(1) // => error code
|
|
264
|
+
*/
|
|
265
|
+
static abort(code = 0) {
|
|
266
|
+
log($style.yellow("Aborted..."));
|
|
267
|
+
process.exit(code);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* @alias utils.confirm
|
|
271
|
+
* @param {prompts.PromptObject} question - A prompt question object (see https://gitlab.com/hperchec/juisy/-/blob/main/documentation/utils.md#utilspromptsargs-object)
|
|
272
|
+
* @returns {Promise<boolean>} - True if confirmed
|
|
273
|
+
* @description
|
|
274
|
+
* Demand confirmation with prompts native util. If not confirmed, it will automatically abort the script.
|
|
275
|
+
* @example
|
|
276
|
+
* confirm({ message: 'Confirm to continue' }) // Deny it will abort the script
|
|
277
|
+
*/
|
|
278
|
+
static async confirm(question) {
|
|
279
|
+
if (!question) {
|
|
280
|
+
question = {
|
|
281
|
+
type: "confirm",
|
|
282
|
+
name: "yes"
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
const { yes } = await InterfaceUtils.prompts([
|
|
286
|
+
{
|
|
287
|
+
message: "Confirm?",
|
|
288
|
+
initial: true,
|
|
289
|
+
...question,
|
|
290
|
+
type: "confirm",
|
|
291
|
+
name: "yes"
|
|
292
|
+
}
|
|
293
|
+
]);
|
|
294
|
+
if (!yes) {
|
|
295
|
+
InterfaceUtils.abort();
|
|
296
|
+
} else {
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* See `prompts` package documentation
|
|
302
|
+
* @example
|
|
303
|
+
* const { prompts } = InterfaceUtils
|
|
304
|
+
* // See prompts documentation
|
|
305
|
+
* @see https://www.npmjs.com/package/prompts
|
|
306
|
+
*/
|
|
307
|
+
static prompts = _prompts;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function wrapCommandBuilder(target, builder) {
|
|
311
|
+
const _target = target || ((cli) => cli);
|
|
312
|
+
return (cli) => {
|
|
313
|
+
return _target(builder(cli));
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function wrapCommandhandler(target, handler) {
|
|
317
|
+
return function(args) {
|
|
318
|
+
handler.call(this, args);
|
|
319
|
+
return target.call(this, args);
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const visitor$2 = function(commandObject, cli) {
|
|
324
|
+
commandObject.handler = wrapCommandhandler(commandObject.handler, function(args) {
|
|
325
|
+
Object.defineProperty(this, "engine", {
|
|
326
|
+
get() {
|
|
327
|
+
return cli;
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
Object.defineProperty(this, "log", {
|
|
331
|
+
get() {
|
|
332
|
+
return (msg, options2 = {}) => {
|
|
333
|
+
OutputUtils.log(msg, {
|
|
334
|
+
...options2,
|
|
335
|
+
loggerInstance: cli.getInternalMethods().getLoggerInstance()
|
|
336
|
+
});
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
return commandObject;
|
|
342
|
+
};
|
|
343
|
+
const options$2 = {};
|
|
344
|
+
|
|
345
|
+
const commandHandlerInjections = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
|
|
346
|
+
__proto__: null,
|
|
347
|
+
options: options$2,
|
|
348
|
+
visitor: visitor$2
|
|
349
|
+
}, Symbol.toStringTag, { value: 'Module' }));
|
|
350
|
+
|
|
351
|
+
const visitor$1 = function(commandObject, cli) {
|
|
352
|
+
if (commandObject.meta) {
|
|
353
|
+
const commandMeta = commandObject.meta;
|
|
354
|
+
commandObject.builder = wrapCommandBuilder(commandObject.builder, function(_cli) {
|
|
355
|
+
_cli._meta = deepmerge(_cli._meta, commandMeta);
|
|
356
|
+
return _cli;
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
return commandObject;
|
|
360
|
+
};
|
|
361
|
+
const options$1 = {};
|
|
362
|
+
|
|
363
|
+
const getCommandMeta = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
|
|
364
|
+
__proto__: null,
|
|
365
|
+
options: options$1,
|
|
366
|
+
visitor: visitor$1
|
|
367
|
+
}, Symbol.toStringTag, { value: 'Module' }));
|
|
368
|
+
|
|
369
|
+
const visitor = function(commandObject, engine, options2) {
|
|
370
|
+
const { metaProp, envKey } = options2;
|
|
371
|
+
if (commandObject.meta?.[metaProp]) {
|
|
372
|
+
if (process.env[envKey] === "private") {
|
|
373
|
+
commandObject.builder = wrapCommandBuilder(commandObject.builder, function(cli) {
|
|
374
|
+
cli._isPrivate = true;
|
|
375
|
+
return cli;
|
|
376
|
+
});
|
|
377
|
+
} else {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return commandObject;
|
|
382
|
+
};
|
|
383
|
+
const options = {
|
|
384
|
+
metaProp: "private",
|
|
385
|
+
envKey: "CLI_ENV"
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
const privateCommand = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
|
|
389
|
+
__proto__: null,
|
|
390
|
+
options,
|
|
391
|
+
visitor
|
|
392
|
+
}, Symbol.toStringTag, { value: 'Module' }));
|
|
393
|
+
|
|
394
|
+
const commandVisitors = {
|
|
395
|
+
commandHandlerInjections,
|
|
396
|
+
getCommandMeta,
|
|
397
|
+
privateCommand
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
function createEngine(yargs) {
|
|
401
|
+
const xargs = yargs;
|
|
402
|
+
xargs._isPrivate = false;
|
|
403
|
+
xargs._globalCommandVisitors = {};
|
|
404
|
+
xargs._globalCommandVisitorsEnabled = /* @__PURE__ */ new Set([]);
|
|
405
|
+
xargs._meta = {
|
|
406
|
+
private: false
|
|
407
|
+
};
|
|
408
|
+
const originalCommandMethod = xargs.command;
|
|
409
|
+
xargs.originalCommand = originalCommandMethod;
|
|
410
|
+
xargs.command = command;
|
|
411
|
+
xargs.globalCommandVisitor = globalCommandVisitor;
|
|
412
|
+
xargs.globalCommandVisitorOptions = globalCommandVisitorOptions;
|
|
413
|
+
xargs.hasGlobalCommandVisitor = hasGlobalCommandVisitor;
|
|
414
|
+
xargs.disableGlobalCommandVisitors = disableGlobalCommandVisitors;
|
|
415
|
+
xargs.enableGlobalCommandVisitors = enableGlobalCommandVisitors;
|
|
416
|
+
xargs.isPrivate = isPrivate;
|
|
417
|
+
xargs.getMeta = getMeta;
|
|
418
|
+
return xargs.globalCommandVisitor("command-handler-injections-visitor", commandVisitors.commandHandlerInjections.visitor, commandVisitors.commandHandlerInjections.options).globalCommandVisitor("get-meta-command-visitor", commandVisitors.getCommandMeta.visitor, commandVisitors.getCommandMeta.options).globalCommandVisitor("private-command-visitor", commandVisitors.privateCommand.visitor, commandVisitors.privateCommand.options).strict().help();
|
|
419
|
+
}
|
|
420
|
+
function command(...args) {
|
|
421
|
+
const self = this;
|
|
422
|
+
if (args.length === 1) {
|
|
423
|
+
const visit = (cmdModule) => {
|
|
424
|
+
const cmdObj = {
|
|
425
|
+
...cmdModule
|
|
426
|
+
};
|
|
427
|
+
let failOnFalsyReturn;
|
|
428
|
+
for (const name of self._globalCommandVisitorsEnabled) {
|
|
429
|
+
const globalVisitor = self._globalCommandVisitors[name];
|
|
430
|
+
if (!globalVisitor(cmdObj, self, globalVisitor.options)) {
|
|
431
|
+
failOnFalsyReturn = true;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return failOnFalsyReturn ? false : cmdObj;
|
|
435
|
+
};
|
|
436
|
+
if (args[0] instanceof Array) {
|
|
437
|
+
const cmdsArray = [];
|
|
438
|
+
for (const commandModule of args[0]) {
|
|
439
|
+
const visited = visit(commandModule);
|
|
440
|
+
if (visited)
|
|
441
|
+
cmdsArray.push(visited);
|
|
442
|
+
}
|
|
443
|
+
return self.originalCommand(cmdsArray);
|
|
444
|
+
} else {
|
|
445
|
+
const visited = visit(args[0]);
|
|
446
|
+
return visited ? self.originalCommand(visited) : self;
|
|
447
|
+
}
|
|
448
|
+
} else {
|
|
449
|
+
return self.originalCommand(...args);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
function globalCommandVisitor(name, visitor, defaultOptions = {}) {
|
|
453
|
+
this._globalCommandVisitors[name] = visitor;
|
|
454
|
+
return this.enableGlobalCommandVisitors([name]).globalCommandVisitorOptions(name, defaultOptions);
|
|
455
|
+
}
|
|
456
|
+
function globalCommandVisitorOptions(name, options) {
|
|
457
|
+
this._globalCommandVisitors[name].options = {
|
|
458
|
+
...this._globalCommandVisitors[name].options,
|
|
459
|
+
...options
|
|
460
|
+
};
|
|
461
|
+
return this;
|
|
462
|
+
}
|
|
463
|
+
function hasGlobalCommandVisitor(name) {
|
|
464
|
+
return Object.keys(this._globalCommandVisitors).includes(name);
|
|
465
|
+
}
|
|
466
|
+
function disableGlobalCommandVisitors(visitors = []) {
|
|
467
|
+
for (const name of visitors) {
|
|
468
|
+
if (this.hasGlobalCommandVisitor(name)) {
|
|
469
|
+
this._globalCommandVisitorsEnabled.delete(name);
|
|
470
|
+
} else {
|
|
471
|
+
throw new Error('Global command visitor: "' + name + '" not defined.');
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return this;
|
|
475
|
+
}
|
|
476
|
+
function enableGlobalCommandVisitors(visitors = []) {
|
|
477
|
+
for (const name of visitors) {
|
|
478
|
+
if (this.hasGlobalCommandVisitor(name)) {
|
|
479
|
+
this._globalCommandVisitorsEnabled.add(name);
|
|
480
|
+
} else {
|
|
481
|
+
throw new Error('Global command visitor: "' + name + '" not defined.');
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return this;
|
|
485
|
+
}
|
|
486
|
+
function isPrivate() {
|
|
487
|
+
return this._isPrivate;
|
|
488
|
+
}
|
|
489
|
+
function getMeta() {
|
|
490
|
+
return this._meta;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function CLIFactory(builder) {
|
|
494
|
+
const cli = function(argv) {
|
|
495
|
+
const engine = createEngine(Yargs(argv));
|
|
496
|
+
return builder(engine);
|
|
497
|
+
};
|
|
498
|
+
return cli;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
async function extractUsage(factory, recursive = false, args = [""], locale = "en") {
|
|
502
|
+
const innerYargs = factory([""]);
|
|
503
|
+
innerYargs.locale(locale);
|
|
504
|
+
const doclet = {
|
|
505
|
+
command: void 0,
|
|
506
|
+
args: void 0,
|
|
507
|
+
aliases: void 0,
|
|
508
|
+
deprecated: false,
|
|
509
|
+
extractedUsage: void 0,
|
|
510
|
+
rawUsage: void 0,
|
|
511
|
+
children: recursive ? {} : void 0
|
|
512
|
+
};
|
|
513
|
+
const parseCallback = function(err, argv, output) {
|
|
514
|
+
if (err)
|
|
515
|
+
throw err;
|
|
516
|
+
const self = this;
|
|
517
|
+
doclet.args = argv._;
|
|
518
|
+
doclet.command = argv._[argv._.length - 1];
|
|
519
|
+
doclet.rawUsage = output;
|
|
520
|
+
const extractedUsage = doclet.extractedUsage = {};
|
|
521
|
+
extractedUsage.demandedCommands = self.getDemandedCommands();
|
|
522
|
+
extractedUsage.demandedOptions = self.getDemandedOptions();
|
|
523
|
+
extractedUsage.deprecatedOptions = self.getDeprecatedOptions();
|
|
524
|
+
extractedUsage.groups = self.getGroups();
|
|
525
|
+
extractedUsage.options = self.getOptions();
|
|
526
|
+
const internalMethods = self.getInternalMethods();
|
|
527
|
+
const usageInstance = internalMethods.getUsageInstance();
|
|
528
|
+
extractedUsage.usages = usageInstance.getUsage();
|
|
529
|
+
const commandInstance = internalMethods.getCommandInstance();
|
|
530
|
+
doclet.aliases = commandInstance.aliasMap;
|
|
531
|
+
const childCommandsFromHandlers = commandInstance.handlers;
|
|
532
|
+
const childCommandsFromUsage = usageInstance.getCommands();
|
|
533
|
+
extractedUsage.commands = Object.keys(childCommandsFromHandlers).reduce((accumulator, handlerKey) => {
|
|
534
|
+
const [cmd, description, isDefault, aliases, deprecated] = childCommandsFromUsage.find((command) => {
|
|
535
|
+
return command[0] === childCommandsFromHandlers[handlerKey].original;
|
|
536
|
+
});
|
|
537
|
+
accumulator[handlerKey] = { cmd, description, isDefault, aliases, deprecated };
|
|
538
|
+
return accumulator;
|
|
539
|
+
}, {});
|
|
540
|
+
};
|
|
541
|
+
await innerYargs.parseAsync(args, { help: true }, parseCallback);
|
|
542
|
+
if (recursive) {
|
|
543
|
+
for (const childCommand in doclet.extractedUsage.commands) {
|
|
544
|
+
doclet.children[childCommand] = await extractUsage(factory, true, [...args.filter((a) => a !== ""), childCommand], locale);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return doclet;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
globalThis.CLI = {
|
|
551
|
+
helpers: {
|
|
552
|
+
hideBin
|
|
553
|
+
},
|
|
554
|
+
Command,
|
|
555
|
+
InterfaceUtils,
|
|
556
|
+
OutputUtils
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
export { CLIFactory, Command, InterfaceUtils, OutputUtils, extractUsage };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Argv, CommandModule as YargsCommandModule, CommandBuilder, MiddlewareFunction } from 'yargs';
|
|
2
|
+
/**
|
|
3
|
+
* An object whose all properties have the same type.
|
|
4
|
+
*/
|
|
5
|
+
type Dictionary<T = any> = {
|
|
6
|
+
[key: string]: T;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* An array whose first element is not undefined.
|
|
10
|
+
*/
|
|
11
|
+
type NotEmptyArray<T = any> = [T, ...T[]];
|
|
12
|
+
/** Shims for private yargs types */
|
|
13
|
+
interface Positional {
|
|
14
|
+
cmd: NotEmptyArray<string>;
|
|
15
|
+
variadic: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface YargsCommandHandler {
|
|
18
|
+
builder: CommandBuilder;
|
|
19
|
+
demanded: Positional[];
|
|
20
|
+
deprecated?: boolean;
|
|
21
|
+
description?: string | false;
|
|
22
|
+
handler: CommandModule['handler'];
|
|
23
|
+
middlewares: MiddlewareFunction[];
|
|
24
|
+
optional: Positional[];
|
|
25
|
+
original: string;
|
|
26
|
+
}
|
|
27
|
+
/** ---------------------------- */
|
|
28
|
+
/**
|
|
29
|
+
* Our custon extended Yargs type
|
|
30
|
+
*/
|
|
31
|
+
export interface CLIEngine extends Argv {
|
|
32
|
+
_isPrivate: boolean;
|
|
33
|
+
_globalCommandVisitors: Record<string, CommandVisitor>;
|
|
34
|
+
_globalCommandVisitorsEnabled: Set<string>;
|
|
35
|
+
_meta: Record<string, any> & {
|
|
36
|
+
private: boolean;
|
|
37
|
+
};
|
|
38
|
+
originalCommand: Argv['command'];
|
|
39
|
+
globalCommandVisitor: (name: string, visitor: CommandVisitor, defaultOptions: any) => this;
|
|
40
|
+
globalCommandVisitorOptions: (name: string, options: Record<any, any>) => this;
|
|
41
|
+
hasGlobalCommandVisitor: (name: string) => boolean;
|
|
42
|
+
disableGlobalCommandVisitors: (visitors: string[]) => this;
|
|
43
|
+
enableGlobalCommandVisitors: (visitors: string[]) => this;
|
|
44
|
+
isPrivate: () => this['_isPrivate'];
|
|
45
|
+
getMeta: () => this['_meta'];
|
|
46
|
+
getDemandedCommands: () => Dictionary<{
|
|
47
|
+
min: number;
|
|
48
|
+
max: number;
|
|
49
|
+
minMsg?: string | null;
|
|
50
|
+
maxMsg?: string | null;
|
|
51
|
+
}>;
|
|
52
|
+
getDemandedOptions: () => Dictionary<string | undefined>;
|
|
53
|
+
getDeprecatedOptions: () => Dictionary<string | boolean | undefined>;
|
|
54
|
+
getGroups: () => Dictionary<string[]>;
|
|
55
|
+
getOptions: () => Record<string, any>;
|
|
56
|
+
getInternalMethods: () => {
|
|
57
|
+
getCommandInstance(): any;
|
|
58
|
+
getContext(): any;
|
|
59
|
+
getHasOutput(): boolean;
|
|
60
|
+
getLoggerInstance(): any;
|
|
61
|
+
getParseContext(): any;
|
|
62
|
+
getParserConfiguration(): any;
|
|
63
|
+
getUsageConfiguration(): any;
|
|
64
|
+
getUsageInstance(): any;
|
|
65
|
+
getValidationInstance(): any;
|
|
66
|
+
hasParseCallback(): any;
|
|
67
|
+
isGlobalContext(): any;
|
|
68
|
+
postProcess(argv: any | Promise<any>, populateDoubleDash: boolean, calledFromCommand: boolean, runGlobalMiddleware: boolean): any;
|
|
69
|
+
reset(aliases?: any): any;
|
|
70
|
+
runValidation(aliases: Dictionary<string[]>, positionalMap: Dictionary<string[]>, parseErrors: Error | null, isDefaultCommand?: boolean): (argv: any) => void;
|
|
71
|
+
runYargsParserAndExecuteCommands(args: string | string[] | null, shortCircuit?: boolean | null, calledFromCommand?: boolean, commandIndex?: number, helpOnly?: boolean): any | Promise<any>;
|
|
72
|
+
setHasOutput(): void;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export type CommandModule = {
|
|
76
|
+
/** array of strings (or a single string) representing aliases of `exports.command`, positional args defined in an alias are ignored */
|
|
77
|
+
aliases: YargsCommandModule['aliases'];
|
|
78
|
+
/** string (or array of strings) that executes this command when given on the command line, first string may contain positional args */
|
|
79
|
+
command: YargsCommandModule['command'];
|
|
80
|
+
/** boolean (or string) to show deprecation notice */
|
|
81
|
+
deprecated: YargsCommandModule['deprecated'];
|
|
82
|
+
/** string used as the description for the command in help text, use `false` for a hidden command */
|
|
83
|
+
describe: YargsCommandModule['describe'];
|
|
84
|
+
/** a function which will be passed the parsed argv. */
|
|
85
|
+
handler: (this: YargsCommandHandler & {
|
|
86
|
+
engine?: CLIEngine;
|
|
87
|
+
log?: (msg?: string, options?: any) => void;
|
|
88
|
+
}, argv: Parameters<YargsCommandModule['handler']>[0]) => ReturnType<YargsCommandModule['handler']>;
|
|
89
|
+
/** object declaring the options the command accepts, or a function accepting and returning a yargs instance */
|
|
90
|
+
builder: (cli: CLIEngine) => CLIEngine | PromiseLike<CLIEngine>;
|
|
91
|
+
meta: Record<string, any>;
|
|
92
|
+
};
|
|
93
|
+
export type CLIBuilder = (cli: CLIEngine) => CLIEngine;
|
|
94
|
+
/**
|
|
95
|
+
* Custom global command visitor callback.
|
|
96
|
+
*/
|
|
97
|
+
export type CommandVisitor = {
|
|
98
|
+
options?: Record<any, any>;
|
|
99
|
+
} & ((
|
|
100
|
+
/**
|
|
101
|
+
* The exported command object
|
|
102
|
+
*/
|
|
103
|
+
commandObject: CommandModule,
|
|
104
|
+
/**
|
|
105
|
+
* The current CLI instance
|
|
106
|
+
*/
|
|
107
|
+
engine: CLIEngine,
|
|
108
|
+
/**
|
|
109
|
+
* The default options to set
|
|
110
|
+
*/
|
|
111
|
+
options: any) => false | CommandModule);
|
|
112
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CommandModule, CLIEngine } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* @ignore
|
|
4
|
+
* @param target - The target builder
|
|
5
|
+
* @param builder - The wrap
|
|
6
|
+
* @description
|
|
7
|
+
* Wrap command builder (target) with builder passed as second parameter
|
|
8
|
+
* that will be called before target. Target can be undefined
|
|
9
|
+
*/
|
|
10
|
+
export declare function wrapCommandBuilder(target: CommandModule['builder'], builder: (cli: CLIEngine) => CLIEngine): (cli: CLIEngine) => CLIEngine | PromiseLike<CLIEngine>;
|
|
11
|
+
/**
|
|
12
|
+
* @ignore
|
|
13
|
+
* @param target - The target handler
|
|
14
|
+
* @param handler - The wrap
|
|
15
|
+
* @description
|
|
16
|
+
* Wrap command handler (target) with handler passed as second parameter
|
|
17
|
+
* that will be called before target. Target can be undefined
|
|
18
|
+
*/
|
|
19
|
+
export declare function wrapCommandhandler(target: CommandModule['handler'], handler: CommandModule['handler']): CommandModule["handler"];
|