appbir
Version:
常用脚手架库 -【app-lib-cli】
7,924 lines • 240 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("app-lib-nobuild"), require("child_process"), require("events"), require("fs"), require("os"), require("path"), require("process"), require("readline"));
else if(typeof define === 'function' && define.amd)
define(["app-lib-nobuild", "child_process", "events", "fs", "os", "path", "process", "readline"], factory);
else {
var a = typeof exports === 'object' ? factory(require("app-lib-nobuild"), require("child_process"), require("events"), require("fs"), require("os"), require("path"), require("process"), require("readline")) : factory(root["app-lib-nobuild"], root["child_process"], root["events"], root["fs"], root["os"], root["path"], root["process"], root["readline"]);
for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
}
})(this, (__WEBPACK_EXTERNAL_MODULE__305__, __WEBPACK_EXTERNAL_MODULE__198__, __WEBPACK_EXTERNAL_MODULE__735__, __WEBPACK_EXTERNAL_MODULE__89__, __WEBPACK_EXTERNAL_MODULE__44__, __WEBPACK_EXTERNAL_MODULE__56__, __WEBPACK_EXTERNAL_MODULE__910__, __WEBPACK_EXTERNAL_MODULE__908__) => {
return /******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ 491:
/***/ ((module, exports, __webpack_require__) => {
const { Argument } = __webpack_require__(811);
const { Command } = __webpack_require__(527);
const { CommanderError, InvalidArgumentError } = __webpack_require__(831);
const { Help } = __webpack_require__(437);
const { Option } = __webpack_require__(311);
// @ts-check
/**
* Expose the root command.
*/
exports = module.exports = new Command();
exports.program = exports; // More explicit access to global command.
// Implicit export of createArgument, createCommand, and createOption.
/**
* Expose classes
*/
exports.Argument = Argument;
exports.Command = Command;
exports.CommanderError = CommanderError;
exports.Help = Help;
exports.InvalidArgumentError = InvalidArgumentError;
exports.InvalidOptionArgumentError = InvalidArgumentError; // Deprecated
exports.Option = Option;
/***/ }),
/***/ 811:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
const { InvalidArgumentError } = __webpack_require__(831);
// @ts-check
class Argument {
/**
* Initialize a new command argument with the given name and description.
* The default is that the argument is required, and you can explicitly
* indicate this with <> around the name. Put [] around the name for an optional argument.
*
* @param {string} name
* @param {string} [description]
*/
constructor(name, description) {
this.description = description || '';
this.variadic = false;
this.parseArg = undefined;
this.defaultValue = undefined;
this.defaultValueDescription = undefined;
this.argChoices = undefined;
switch (name[0]) {
case '<': // e.g. <required>
this.required = true;
this._name = name.slice(1, -1);
break;
case '[': // e.g. [optional]
this.required = false;
this._name = name.slice(1, -1);
break;
default:
this.required = true;
this._name = name;
break;
}
if (this._name.length > 3 && this._name.slice(-3) === '...') {
this.variadic = true;
this._name = this._name.slice(0, -3);
}
}
/**
* Return argument name.
*
* @return {string}
*/
name() {
return this._name;
}
/**
* @api private
*/
_concatValue(value, previous) {
if (previous === this.defaultValue || !Array.isArray(previous)) {
return [value];
}
return previous.concat(value);
}
/**
* Set the default value, and optionally supply the description to be displayed in the help.
*
* @param {any} value
* @param {string} [description]
* @return {Argument}
*/
default(value, description) {
this.defaultValue = value;
this.defaultValueDescription = description;
return this;
}
/**
* Set the custom handler for processing CLI command arguments into argument values.
*
* @param {Function} [fn]
* @return {Argument}
*/
argParser(fn) {
this.parseArg = fn;
return this;
}
/**
* Only allow argument value to be one of choices.
*
* @param {string[]} values
* @return {Argument}
*/
choices(values) {
this.argChoices = values.slice();
this.parseArg = (arg, previous) => {
if (!this.argChoices.includes(arg)) {
throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(', ')}.`);
}
if (this.variadic) {
return this._concatValue(arg, previous);
}
return arg;
};
return this;
}
/**
* Make argument required.
*/
argRequired() {
this.required = true;
return this;
}
/**
* Make argument optional.
*/
argOptional() {
this.required = false;
return this;
}
}
/**
* Takes an argument and returns its human readable equivalent for help usage.
*
* @param {Argument} arg
* @return {string}
* @api private
*/
function humanReadableArgName(arg) {
const nameOutput = arg.name() + (arg.variadic === true ? '...' : '');
return arg.required
? '<' + nameOutput + '>'
: '[' + nameOutput + ']';
}
exports.Argument = Argument;
exports.humanReadableArgName = humanReadableArgName;
/***/ }),
/***/ 527:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
const EventEmitter = (__webpack_require__(735).EventEmitter);
const childProcess = __webpack_require__(198);
const path = __webpack_require__(56);
const fs = __webpack_require__(89);
const process = __webpack_require__(910);
const { Argument, humanReadableArgName } = __webpack_require__(811);
const { CommanderError } = __webpack_require__(831);
const { Help } = __webpack_require__(437);
const { Option, splitOptionFlags, DualOptions } = __webpack_require__(311);
const { suggestSimilar } = __webpack_require__(426);
// @ts-check
class Command extends EventEmitter {
/**
* Initialize a new `Command`.
*
* @param {string} [name]
*/
constructor(name) {
super();
/** @type {Command[]} */
this.commands = [];
/** @type {Option[]} */
this.options = [];
this.parent = null;
this._allowUnknownOption = false;
this._allowExcessArguments = true;
/** @type {Argument[]} */
this._args = [];
/** @type {string[]} */
this.args = []; // cli args with options removed
this.rawArgs = [];
this.processedArgs = []; // like .args but after custom processing and collecting variadic
this._scriptPath = null;
this._name = name || '';
this._optionValues = {};
this._optionValueSources = {}; // default, env, cli etc
this._storeOptionsAsProperties = false;
this._actionHandler = null;
this._executableHandler = false;
this._executableFile = null; // custom name for executable
this._executableDir = null; // custom search directory for subcommands
this._defaultCommandName = null;
this._exitCallback = null;
this._aliases = [];
this._combineFlagAndOptionalValue = true;
this._description = '';
this._summary = '';
this._argsDescription = undefined; // legacy
this._enablePositionalOptions = false;
this._passThroughOptions = false;
this._lifeCycleHooks = {}; // a hash of arrays
/** @type {boolean | string} */
this._showHelpAfterError = false;
this._showSuggestionAfterError = true;
// see .configureOutput() for docs
this._outputConfiguration = {
writeOut: (str) => process.stdout.write(str),
writeErr: (str) => process.stderr.write(str),
getOutHelpWidth: () => process.stdout.isTTY ? process.stdout.columns : undefined,
getErrHelpWidth: () => process.stderr.isTTY ? process.stderr.columns : undefined,
outputError: (str, write) => write(str)
};
this._hidden = false;
this._hasHelpOption = true;
this._helpFlags = '-h, --help';
this._helpDescription = 'display help for command';
this._helpShortFlag = '-h';
this._helpLongFlag = '--help';
this._addImplicitHelpCommand = undefined; // Deliberately undefined, not decided whether true or false
this._helpCommandName = 'help';
this._helpCommandnameAndArgs = 'help [command]';
this._helpCommandDescription = 'display help for command';
this._helpConfiguration = {};
}
/**
* Copy settings that are useful to have in common across root command and subcommands.
*
* (Used internally when adding a command using `.command()` so subcommands inherit parent settings.)
*
* @param {Command} sourceCommand
* @return {Command} `this` command for chaining
*/
copyInheritedSettings(sourceCommand) {
this._outputConfiguration = sourceCommand._outputConfiguration;
this._hasHelpOption = sourceCommand._hasHelpOption;
this._helpFlags = sourceCommand._helpFlags;
this._helpDescription = sourceCommand._helpDescription;
this._helpShortFlag = sourceCommand._helpShortFlag;
this._helpLongFlag = sourceCommand._helpLongFlag;
this._helpCommandName = sourceCommand._helpCommandName;
this._helpCommandnameAndArgs = sourceCommand._helpCommandnameAndArgs;
this._helpCommandDescription = sourceCommand._helpCommandDescription;
this._helpConfiguration = sourceCommand._helpConfiguration;
this._exitCallback = sourceCommand._exitCallback;
this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties;
this._combineFlagAndOptionalValue = sourceCommand._combineFlagAndOptionalValue;
this._allowExcessArguments = sourceCommand._allowExcessArguments;
this._enablePositionalOptions = sourceCommand._enablePositionalOptions;
this._showHelpAfterError = sourceCommand._showHelpAfterError;
this._showSuggestionAfterError = sourceCommand._showSuggestionAfterError;
return this;
}
/**
* Define a command.
*
* There are two styles of command: pay attention to where to put the description.
*
* @example
* // Command implemented using action handler (description is supplied separately to `.command`)
* program
* .command('clone <source> [destination]')
* .description('clone a repository into a newly created directory')
* .action((source, destination) => {
* console.log('clone command called');
* });
*
* // Command implemented using separate executable file (description is second parameter to `.command`)
* program
* .command('start <service>', 'start named service')
* .command('stop [service]', 'stop named service, or all if no name supplied');
*
* @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
* @param {Object|string} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
* @param {Object} [execOpts] - configuration options (for executable)
* @return {Command} returns new command for action handler, or `this` for executable command
*/
command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
let desc = actionOptsOrExecDesc;
let opts = execOpts;
if (typeof desc === 'object' && desc !== null) {
opts = desc;
desc = null;
}
opts = opts || {};
const [, name, args] = nameAndArgs.match(/([^ ]+) *(.*)/);
const cmd = this.createCommand(name);
if (desc) {
cmd.description(desc);
cmd._executableHandler = true;
}
if (opts.isDefault) this._defaultCommandName = cmd._name;
cmd._hidden = !!(opts.noHelp || opts.hidden); // noHelp is deprecated old name for hidden
cmd._executableFile = opts.executableFile || null; // Custom name for executable file, set missing to null to match constructor
if (args) cmd.arguments(args);
this.commands.push(cmd);
cmd.parent = this;
cmd.copyInheritedSettings(this);
if (desc) return this;
return cmd;
}
/**
* Factory routine to create a new unattached command.
*
* See .command() for creating an attached subcommand, which uses this routine to
* create the command. You can override createCommand to customise subcommands.
*
* @param {string} [name]
* @return {Command} new command
*/
createCommand(name) {
return new Command(name);
}
/**
* You can customise the help with a subclass of Help by overriding createHelp,
* or by overriding Help properties using configureHelp().
*
* @return {Help}
*/
createHelp() {
return Object.assign(new Help(), this.configureHelp());
}
/**
* You can customise the help by overriding Help properties using configureHelp(),
* or with a subclass of Help by overriding createHelp().
*
* @param {Object} [configuration] - configuration options
* @return {Command|Object} `this` command for chaining, or stored configuration
*/
configureHelp(configuration) {
if (configuration === undefined) return this._helpConfiguration;
this._helpConfiguration = configuration;
return this;
}
/**
* The default output goes to stdout and stderr. You can customise this for special
* applications. You can also customise the display of errors by overriding outputError.
*
* The configuration properties are all functions:
*
* // functions to change where being written, stdout and stderr
* writeOut(str)
* writeErr(str)
* // matching functions to specify width for wrapping help
* getOutHelpWidth()
* getErrHelpWidth()
* // functions based on what is being written out
* outputError(str, write) // used for displaying errors, and not used for displaying help
*
* @param {Object} [configuration] - configuration options
* @return {Command|Object} `this` command for chaining, or stored configuration
*/
configureOutput(configuration) {
if (configuration === undefined) return this._outputConfiguration;
Object.assign(this._outputConfiguration, configuration);
return this;
}
/**
* Display the help or a custom message after an error occurs.
*
* @param {boolean|string} [displayHelp]
* @return {Command} `this` command for chaining
*/
showHelpAfterError(displayHelp = true) {
if (typeof displayHelp !== 'string') displayHelp = !!displayHelp;
this._showHelpAfterError = displayHelp;
return this;
}
/**
* Display suggestion of similar commands for unknown commands, or options for unknown options.
*
* @param {boolean} [displaySuggestion]
* @return {Command} `this` command for chaining
*/
showSuggestionAfterError(displaySuggestion = true) {
this._showSuggestionAfterError = !!displaySuggestion;
return this;
}
/**
* Add a prepared subcommand.
*
* See .command() for creating an attached subcommand which inherits settings from its parent.
*
* @param {Command} cmd - new subcommand
* @param {Object} [opts] - configuration options
* @return {Command} `this` command for chaining
*/
addCommand(cmd, opts) {
if (!cmd._name) {
throw new Error(`Command passed to .addCommand() must have a name
- specify the name in Command constructor or using .name()`);
}
opts = opts || {};
if (opts.isDefault) this._defaultCommandName = cmd._name;
if (opts.noHelp || opts.hidden) cmd._hidden = true; // modifying passed command due to existing implementation
this.commands.push(cmd);
cmd.parent = this;
return this;
}
/**
* Factory routine to create a new unattached argument.
*
* See .argument() for creating an attached argument, which uses this routine to
* create the argument. You can override createArgument to return a custom argument.
*
* @param {string} name
* @param {string} [description]
* @return {Argument} new argument
*/
createArgument(name, description) {
return new Argument(name, description);
}
/**
* Define argument syntax for command.
*
* The default is that the argument is required, and you can explicitly
* indicate this with <> around the name. Put [] around the name for an optional argument.
*
* @example
* program.argument('<input-file>');
* program.argument('[output-file]');
*
* @param {string} name
* @param {string} [description]
* @param {Function|*} [fn] - custom argument processing function
* @param {*} [defaultValue]
* @return {Command} `this` command for chaining
*/
argument(name, description, fn, defaultValue) {
const argument = this.createArgument(name, description);
if (typeof fn === 'function') {
argument.default(defaultValue).argParser(fn);
} else {
argument.default(fn);
}
this.addArgument(argument);
return this;
}
/**
* Define argument syntax for command, adding multiple at once (without descriptions).
*
* See also .argument().
*
* @example
* program.arguments('<cmd> [env]');
*
* @param {string} names
* @return {Command} `this` command for chaining
*/
arguments(names) {
names.split(/ +/).forEach((detail) => {
this.argument(detail);
});
return this;
}
/**
* Define argument syntax for command, adding a prepared argument.
*
* @param {Argument} argument
* @return {Command} `this` command for chaining
*/
addArgument(argument) {
const previousArgument = this._args.slice(-1)[0];
if (previousArgument && previousArgument.variadic) {
throw new Error(`only the last argument can be variadic '${previousArgument.name()}'`);
}
if (argument.required && argument.defaultValue !== undefined && argument.parseArg === undefined) {
throw new Error(`a default value for a required argument is never used: '${argument.name()}'`);
}
this._args.push(argument);
return this;
}
/**
* Override default decision whether to add implicit help command.
*
* addHelpCommand() // force on
* addHelpCommand(false); // force off
* addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom details
*
* @return {Command} `this` command for chaining
*/
addHelpCommand(enableOrNameAndArgs, description) {
if (enableOrNameAndArgs === false) {
this._addImplicitHelpCommand = false;
} else {
this._addImplicitHelpCommand = true;
if (typeof enableOrNameAndArgs === 'string') {
this._helpCommandName = enableOrNameAndArgs.split(' ')[0];
this._helpCommandnameAndArgs = enableOrNameAndArgs;
}
this._helpCommandDescription = description || this._helpCommandDescription;
}
return this;
}
/**
* @return {boolean}
* @api private
*/
_hasImplicitHelpCommand() {
if (this._addImplicitHelpCommand === undefined) {
return this.commands.length && !this._actionHandler && !this._findCommand('help');
}
return this._addImplicitHelpCommand;
}
/**
* Add hook for life cycle event.
*
* @param {string} event
* @param {Function} listener
* @return {Command} `this` command for chaining
*/
hook(event, listener) {
const allowedValues = ['preSubcommand', 'preAction', 'postAction'];
if (!allowedValues.includes(event)) {
throw new Error(`Unexpected value for event passed to hook : '${event}'.
Expecting one of '${allowedValues.join("', '")}'`);
}
if (this._lifeCycleHooks[event]) {
this._lifeCycleHooks[event].push(listener);
} else {
this._lifeCycleHooks[event] = [listener];
}
return this;
}
/**
* Register callback to use as replacement for calling process.exit.
*
* @param {Function} [fn] optional callback which will be passed a CommanderError, defaults to throwing
* @return {Command} `this` command for chaining
*/
exitOverride(fn) {
if (fn) {
this._exitCallback = fn;
} else {
this._exitCallback = (err) => {
if (err.code !== 'commander.executeSubCommandAsync') {
throw err;
} else {
// Async callback from spawn events, not useful to throw.
}
};
}
return this;
}
/**
* Call process.exit, and _exitCallback if defined.
*
* @param {number} exitCode exit code for using with process.exit
* @param {string} code an id string representing the error
* @param {string} message human-readable description of the error
* @return never
* @api private
*/
_exit(exitCode, code, message) {
if (this._exitCallback) {
this._exitCallback(new CommanderError(exitCode, code, message));
// Expecting this line is not reached.
}
process.exit(exitCode);
}
/**
* Register callback `fn` for the command.
*
* @example
* program
* .command('serve')
* .description('start service')
* .action(function() {
* // do work here
* });
*
* @param {Function} fn
* @return {Command} `this` command for chaining
*/
action(fn) {
const listener = (args) => {
// The .action callback takes an extra parameter which is the command or options.
const expectedArgsCount = this._args.length;
const actionArgs = args.slice(0, expectedArgsCount);
if (this._storeOptionsAsProperties) {
actionArgs[expectedArgsCount] = this; // backwards compatible "options"
} else {
actionArgs[expectedArgsCount] = this.opts();
}
actionArgs.push(this);
return fn.apply(this, actionArgs);
};
this._actionHandler = listener;
return this;
}
/**
* Factory routine to create a new unattached option.
*
* See .option() for creating an attached option, which uses this routine to
* create the option. You can override createOption to return a custom option.
*
* @param {string} flags
* @param {string} [description]
* @return {Option} new option
*/
createOption(flags, description) {
return new Option(flags, description);
}
/**
* Add an option.
*
* @param {Option} option
* @return {Command} `this` command for chaining
*/
addOption(option) {
const oname = option.name();
const name = option.attributeName();
// store default value
if (option.negate) {
// --no-foo is special and defaults foo to true, unless a --foo option is already defined
const positiveLongFlag = option.long.replace(/^--no-/, '--');
if (!this._findOption(positiveLongFlag)) {
this.setOptionValueWithSource(name, option.defaultValue === undefined ? true : option.defaultValue, 'default');
}
} else if (option.defaultValue !== undefined) {
this.setOptionValueWithSource(name, option.defaultValue, 'default');
}
// register the option
this.options.push(option);
// handler for cli and env supplied values
const handleOptionValue = (val, invalidValueMessage, valueSource) => {
// val is null for optional option used without an optional-argument.
// val is undefined for boolean and negated option.
if (val == null && option.presetArg !== undefined) {
val = option.presetArg;
}
// custom processing
const oldValue = this.getOptionValue(name);
if (val !== null && option.parseArg) {
try {
val = option.parseArg(val, oldValue);
} catch (err) {
if (err.code === 'commander.invalidArgument') {
const message = `${invalidValueMessage} ${err.message}`;
this.error(message, { exitCode: err.exitCode, code: err.code });
}
throw err;
}
} else if (val !== null && option.variadic) {
val = option._concatValue(val, oldValue);
}
// Fill-in appropriate missing values. Long winded but easy to follow.
if (val == null) {
if (option.negate) {
val = false;
} else if (option.isBoolean() || option.optional) {
val = true;
} else {
val = ''; // not normal, parseArg might have failed or be a mock function for testing
}
}
this.setOptionValueWithSource(name, val, valueSource);
};
this.on('option:' + oname, (val) => {
const invalidValueMessage = `error: option '${option.flags}' argument '${val}' is invalid.`;
handleOptionValue(val, invalidValueMessage, 'cli');
});
if (option.envVar) {
this.on('optionEnv:' + oname, (val) => {
const invalidValueMessage = `error: option '${option.flags}' value '${val}' from env '${option.envVar}' is invalid.`;
handleOptionValue(val, invalidValueMessage, 'env');
});
}
return this;
}
/**
* Internal implementation shared by .option() and .requiredOption()
*
* @api private
*/
_optionEx(config, flags, description, fn, defaultValue) {
if (typeof flags === 'object' && flags instanceof Option) {
throw new Error('To add an Option object use addOption() instead of option() or requiredOption()');
}
const option = this.createOption(flags, description);
option.makeOptionMandatory(!!config.mandatory);
if (typeof fn === 'function') {
option.default(defaultValue).argParser(fn);
} else if (fn instanceof RegExp) {
// deprecated
const regex = fn;
fn = (val, def) => {
const m = regex.exec(val);
return m ? m[0] : def;
};
option.default(defaultValue).argParser(fn);
} else {
option.default(fn);
}
return this.addOption(option);
}
/**
* Define option with `flags`, `description` and optional
* coercion `fn`.
*
* The `flags` string contains the short and/or long flags,
* separated by comma, a pipe or space. The following are all valid
* all will output this way when `--help` is used.
*
* "-p, --pepper"
* "-p|--pepper"
* "-p --pepper"
*
* @example
* // simple boolean defaulting to undefined
* program.option('-p, --pepper', 'add pepper');
*
* program.pepper
* // => undefined
*
* --pepper
* program.pepper
* // => true
*
* // simple boolean defaulting to true (unless non-negated option is also defined)
* program.option('-C, --no-cheese', 'remove cheese');
*
* program.cheese
* // => true
*
* --no-cheese
* program.cheese
* // => false
*
* // required argument
* program.option('-C, --chdir <path>', 'change the working directory');
*
* --chdir /tmp
* program.chdir
* // => "/tmp"
*
* // optional argument
* program.option('-c, --cheese [type]', 'add cheese [marble]');
*
* @param {string} flags
* @param {string} [description]
* @param {Function|*} [fn] - custom option processing function or default value
* @param {*} [defaultValue]
* @return {Command} `this` command for chaining
*/
option(flags, description, fn, defaultValue) {
return this._optionEx({}, flags, description, fn, defaultValue);
}
/**
* Add a required option which must have a value after parsing. This usually means
* the option must be specified on the command line. (Otherwise the same as .option().)
*
* The `flags` string contains the short and/or long flags, separated by comma, a pipe or space.
*
* @param {string} flags
* @param {string} [description]
* @param {Function|*} [fn] - custom option processing function or default value
* @param {*} [defaultValue]
* @return {Command} `this` command for chaining
*/
requiredOption(flags, description, fn, defaultValue) {
return this._optionEx({ mandatory: true }, flags, description, fn, defaultValue);
}
/**
* Alter parsing of short flags with optional values.
*
* @example
* // for `.option('-f,--flag [value]'):
* program.combineFlagAndOptionalValue(true); // `-f80` is treated like `--flag=80`, this is the default behaviour
* program.combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`
*
* @param {Boolean} [combine=true] - if `true` or omitted, an optional value can be specified directly after the flag.
*/
combineFlagAndOptionalValue(combine = true) {
this._combineFlagAndOptionalValue = !!combine;
return this;
}
/**
* Allow unknown options on the command line.
*
* @param {Boolean} [allowUnknown=true] - if `true` or omitted, no error will be thrown
* for unknown options.
*/
allowUnknownOption(allowUnknown = true) {
this._allowUnknownOption = !!allowUnknown;
return this;
}
/**
* Allow excess command-arguments on the command line. Pass false to make excess arguments an error.
*
* @param {Boolean} [allowExcess=true] - if `true` or omitted, no error will be thrown
* for excess arguments.
*/
allowExcessArguments(allowExcess = true) {
this._allowExcessArguments = !!allowExcess;
return this;
}
/**
* Enable positional options. Positional means global options are specified before subcommands which lets
* subcommands reuse the same option names, and also enables subcommands to turn on passThroughOptions.
* The default behaviour is non-positional and global options may appear anywhere on the command line.
*
* @param {Boolean} [positional=true]
*/
enablePositionalOptions(positional = true) {
this._enablePositionalOptions = !!positional;
return this;
}
/**
* Pass through options that come after command-arguments rather than treat them as command-options,
* so actual command-options come before command-arguments. Turning this on for a subcommand requires
* positional options to have been enabled on the program (parent commands).
* The default behaviour is non-positional and options may appear before or after command-arguments.
*
* @param {Boolean} [passThrough=true]
* for unknown options.
*/
passThroughOptions(passThrough = true) {
this._passThroughOptions = !!passThrough;
if (!!this.parent && passThrough && !this.parent._enablePositionalOptions) {
throw new Error('passThroughOptions can not be used without turning on enablePositionalOptions for parent command(s)');
}
return this;
}
/**
* Whether to store option values as properties on command object,
* or store separately (specify false). In both cases the option values can be accessed using .opts().
*
* @param {boolean} [storeAsProperties=true]
* @return {Command} `this` command for chaining
*/
storeOptionsAsProperties(storeAsProperties = true) {
this._storeOptionsAsProperties = !!storeAsProperties;
if (this.options.length) {
throw new Error('call .storeOptionsAsProperties() before adding options');
}
return this;
}
/**
* Retrieve option value.
*
* @param {string} key
* @return {Object} value
*/
getOptionValue(key) {
if (this._storeOptionsAsProperties) {
return this[key];
}
return this._optionValues[key];
}
/**
* Store option value.
*
* @param {string} key
* @param {Object} value
* @return {Command} `this` command for chaining
*/
setOptionValue(key, value) {
return this.setOptionValueWithSource(key, value, undefined);
}
/**
* Store option value and where the value came from.
*
* @param {string} key
* @param {Object} value
* @param {string} source - expected values are default/config/env/cli/implied
* @return {Command} `this` command for chaining
*/
setOptionValueWithSource(key, value, source) {
if (this._storeOptionsAsProperties) {
this[key] = value;
} else {
this._optionValues[key] = value;
}
this._optionValueSources[key] = source;
return this;
}
/**
* Get source of option value.
* Expected values are default | config | env | cli | implied
*
* @param {string} key
* @return {string}
*/
getOptionValueSource(key) {
return this._optionValueSources[key];
}
/**
* Get source of option value. See also .optsWithGlobals().
* Expected values are default | config | env | cli | implied
*
* @param {string} key
* @return {string}
*/
getOptionValueSourceWithGlobals(key) {
// global overwrites local, like optsWithGlobals
let source;
getCommandAndParents(this).forEach((cmd) => {
if (cmd.getOptionValueSource(key) !== undefined) {
source = cmd.getOptionValueSource(key);
}
});
return source;
}
/**
* Get user arguments from implied or explicit arguments.
* Side-effects: set _scriptPath if args included script. Used for default program name, and subcommand searches.
*
* @api private
*/
_prepareUserArgs(argv, parseOptions) {
if (argv !== undefined && !Array.isArray(argv)) {
throw new Error('first parameter to parse must be array or undefined');
}
parseOptions = parseOptions || {};
// Default to using process.argv
if (argv === undefined) {
argv = process.argv;
// @ts-ignore: unknown property
if (process.versions && process.versions.electron) {
parseOptions.from = 'electron';
}
}
this.rawArgs = argv.slice();
// make it a little easier for callers by supporting various argv conventions
let userArgs;
switch (parseOptions.from) {
case undefined:
case 'node':
this._scriptPath = argv[1];
userArgs = argv.slice(2);
break;
case 'electron':
// @ts-ignore: unknown property
if (process.defaultApp) {
this._scriptPath = argv[1];
userArgs = argv.slice(2);
} else {
userArgs = argv.slice(1);
}
break;
case 'user':
userArgs = argv.slice(0);
break;
default:
throw new Error(`unexpected parse option { from: '${parseOptions.from}' }`);
}
// Find default name for program from arguments.
if (!this._name && this._scriptPath) this.nameFromFilename(this._scriptPath);
this._name = this._name || 'program';
return userArgs;
}
/**
* Parse `argv`, setting options and invoking commands when defined.
*
* The default expectation is that the arguments are from node and have the application as argv[0]
* and the script being run in argv[1], with user parameters after that.
*
* @example
* program.parse(process.argv);
* program.parse(); // implicitly use process.argv and auto-detect node vs electron conventions
* program.parse(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
*
* @param {string[]} [argv] - optional, defaults to process.argv
* @param {Object} [parseOptions] - optionally specify style of options with from: node/user/electron
* @param {string} [parseOptions.from] - where the args are from: 'node', 'user', 'electron'
* @return {Command} `this` command for chaining
*/
parse(argv, parseOptions) {
const userArgs = this._prepareUserArgs(argv, parseOptions);
this._parseCommand([], userArgs);
return this;
}
/**
* Parse `argv`, setting options and invoking commands when defined.
*
* Use parseAsync instead of parse if any of your action handlers are async. Returns a Promise.
*
* The default expectation is that the arguments are from node and have the application as argv[0]
* and the script being run in argv[1], with user parameters after that.
*
* @example
* await program.parseAsync(process.argv);
* await program.parseAsync(); // implicitly use process.argv and auto-detect node vs electron conventions
* await program.parseAsync(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
*
* @param {string[]} [argv]
* @param {Object} [parseOptions]
* @param {string} parseOptions.from - where the args are from: 'node', 'user', 'electron'
* @return {Promise}
*/
async parseAsync(argv, parseOptions) {
const userArgs = this._prepareUserArgs(argv, parseOptions);
await this._parseCommand([], userArgs);
return this;
}
/**
* Execute a sub-command executable.
*
* @api private
*/
_executeSubCommand(subcommand, args) {
args = args.slice();
let launchWithNode = false; // Use node for source targets so do not need to get permissions correct, and on Windows.
const sourceExt = ['.js', '.ts', '.tsx', '.mjs', '.cjs'];
function findFile(baseDir, baseName) {
// Look for specified file
const localBin = path.resolve(baseDir, baseName);
if (fs.existsSync(localBin)) return localBin;
// Stop looking if candidate already has an expected extension.
if (sourceExt.includes(path.extname(baseName))) return undefined;
// Try all the extensions.
const foundExt = sourceExt.find(ext => fs.existsSync(`${localBin}${ext}`));
if (foundExt) return `${localBin}${foundExt}`;
return undefined;
}
// Not checking for help first. Unlikely to have mandatory and executable, and can't robustly test for help flags in external command.
this._checkForMissingMandatoryOptions();
this._checkForConflictingOptions();
// executableFile and executableDir might be full path, or just a name
let executableFile = subcommand._executableFile || `${this._name}-${subcommand._name}`;
let executableDir = this._executableDir || '';
if (this._scriptPath) {
let resolvedScriptPath; // resolve possible symlink for installed npm binary
try {
resolvedScriptPath = fs.realpathSync(this._scriptPath);
} catch (err) {
resolvedScriptPath = this._scriptPath;
}
executableDir = path.resolve(path.dirname(resolvedScriptPath), executableDir);
}
// Look for a local file in preference to a command in PATH.
if (executableDir) {
let localFile = findFile(executableDir, executableFile);
// Legacy search using prefix of script name instead of command name
if (!localFile && !subcommand._executableFile && this._scriptPath) {
const legacyName = path.basename(this._scriptPath, path.extname(this._scriptPath));
if (legacyName !== this._name) {
localFile = findFile(executableDir, `${legacyName}-${subcommand._name}`);
}
}
executableFile = localFile || executableFile;
}
launchWithNode = sourceExt.includes(path.extname(executableFile));
let proc;
if (process.platform !== 'win32') {
if (launchWithNode) {
args.unshift(executableFile);
// add executable arguments to spawn
args = incrementNodeInspectorPort(process.execArgv).concat(args);
proc = childProcess.spawn(process.argv[0], args, { stdio: 'inherit' });
} else {
proc = childProcess.spawn(executableFile, args, { stdio: 'inherit' });
}
} else {
args.unshift(executableFile);
// add executable arguments to spawn
args = incrementNodeInspectorPort(process.execArgv).concat(args);
proc = childProcess.spawn(process.execPath, args, { stdio: 'inherit' });
}
if (!proc.killed) { // testing mainly to avoid leak warnings during unit tests with mocked spawn
const signals = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP'];
signals.forEach((signal) => {
// @ts-ignore
process.on(signal, () => {
if (proc.killed === false && proc.exitCode === null) {
proc.kill(signal);
}
});
});
}
// By default terminate process when spawned process terminates.
// Suppressing the exit if exitCallback defined is a bit messy and of limited use, but does allow process to stay running!
const exitCallback = this._exitCallback;
if (!exitCallback) {
proc.on('close', process.exit.bind(process));
} else {
proc.on('close', () => {
exitCallback(new CommanderError(process.exitCode || 0, 'commander.executeSubCommandAsync', '(close)'));
});
}
proc.on('error', (err) => {
// @ts-ignore
if (err.code === 'ENOENT') {
const executableDirMessage = executableDir
? `searched for local subcommand relative to directory '${executableDir}'`
: 'no directory for search for local subcommand, use .executableDir() to supply a custom directory';
const executableMissing = `'${executableFile}' does not exist
- if '${subcommand._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
- ${executableDirMessage}`;
throw new Error(executableMissing);
// @ts-ignore
} else if (err.code === 'EACCES') {
throw new Error(`'${executableFile}' not executable`);
}
if (!exitCallback) {
process.exit(1);
} else {
const wrappedError = new CommanderError(1, 'commander.executeSubCommandAsync', '(error)');
wrappedError.nestedError = err;
exitCallback(wrappedError);
}
});
// Store the reference to the child process
this.runningCommand = proc;
}
/**
* @api private
*/
_dispatchSubcommand(commandName, operands, unknown) {
const subCommand = this._findCommand(commandName);
if (!subCommand) this.help({ error: true });
let hookResult;
hookResult = this._chainOrCallSubCommandHook(hookResult, subCommand, 'preSubcommand');
hookResult = this._chainOrCall(hookResult, () => {
if (subCommand._executableHandler) {
this._executeSubCommand(subCommand, operands.concat(unknown));
} else {
return subCommand._parseCommand(operands, unknown);
}
});
return hookResult;
}
/**
* Check this.args against expected this._args.
*
* @api private
*/
_checkNumberOfArguments() {
// too few
this._args.forEach((arg, i) => {
if (arg.required && this.args[i] == null) {
this.missingArgument(arg.name());
}
});
// too many
if (this._args.length > 0 && this._args[this._args.length - 1].variadic) {
return;
}
if (this.args.length > this._args.length) {
this._excessArguments(this.args);
}
}
/**
* Process this.args using this._args and save as this.processedArgs!
*
* @api private
*/
_processArguments() {
const myParseArg = (argument, value, previous) => {
// Extra processing for nice error message on parsing failure.
let parsedValue = value;
if (value !== null && argument.parseArg) {
try {
parsedValue = argument.parseArg(value, previous);
} catch (err) {
if (err.code === 'commander.invalidArgument') {
const message = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'. ${err.message}`;
this.error(message, { exitCode: err.exitCode, code: err.code });
}
throw err;
}
}
return parsedValue;
};
this._checkNumberOfArguments();
const processedArgs = [];
this._args.forEach((declaredArg, index) => {
let value = declaredArg.defaultValue;
if (declaredArg.variadic) {
// Collect together remaining arguments for passing together as an array.
if (index < this.args.length) {
value = this.args.slice(index);
if (declaredArg.parseArg) {
value = value.reduce((processed, v) => {
return myParseArg(declaredArg, v, processed);
}, declaredArg.defaultValue);
}
} else if (value === undefined) {
value = [];
}
} else if (index < this.args.length) {
value = this.args[index];
if (declaredArg.parseArg) {
value = myParseArg(declaredArg, value, declaredArg.defaultValue);
}
}
processedArgs[index] = value;
});
this.processedArgs = processedArgs;
}
/**
* Once we have a promise we chain, but call synchronously until then.
*
* @param {Promise|undefined} promise
* @param {Function} fn
* @return {Promise|undefined}
* @api private
*/
_chainOrCall(promise, fn) {
// thenable
if (promise && promise.then && typeof promise.then === 'function') {
// already have a promise, chain callback
return promise.then(() => fn());
}
// callback might return a promise
return fn();
}
/**
*
* @param {Promise|undefined} promise
* @param {string} event
* @return {Promise|undefined}
* @api private
*/
_chainOrCallHooks(promise, event) {
let result = promise;
const hooks = [];
getCommandAndParents(this)
.reverse()
.filter(cmd => cmd._lifeCycleHooks[event] !== undefined)
.forEach(hookedCommand => {
hookedCommand._lifeCycleHooks[event].forEach((callback) => {
hooks.push({ hookedCommand, callback });
});
});
if (event === 'postAction') {
hooks.reverse();
}
hooks.forEach((hookDetail) => {
result = this._chainOrCall(result, () => {
return hookDetail.callback(hookDetail.hookedCommand, this);
});
});
return result;
}
/**
*
* @param {Promise|undefined} promise
* @param {Command} subCommand
* @param {string} event
* @return {Promise|undefined}
* @api private
*/
_chainOrCallSubCommandHook(promise, subCommand, event) {
let result = promise;
if (this._lifeCycleHooks[event] !== undefined) {
this._lifeCycleHooks[event].forEach((hook) => {
result = this._chainOrCall(result, () => {
return hook(this, subCommand);
});
});
}
return result;
}
/**
* Process arguments in context of this command.
* Returns action result, in case it is a promise.
*
* @api private
*/
_parseCommand(operands, unknown) {
const parsed = this.parseOptions(unknown);
this._parseOptionsEnv(); // after cli, so parseArg not called on both cli and env
this._parseOptionsImplied();
operands = operands.concat(parsed.operands);
unknown = parsed.unknown;
this.args = operands.concat(unknown);
if (operands && this._findCommand(operands[0])) {
return this._dispatchSubcommand(operands[0], operands.slice(1), unknown);
}
if (this._hasImplicitHelpCommand() && operands[0] === this._helpCommandName) {
if (operands.length === 1) {
this.help();
}
return this._dispatchSubcommand(operands[1], [], [this._helpLongFlag]);
}
if (this._defaultCommandName) {
outputHelpIfRequested(this, unknown); // Run the help for default command from parent rather than passing to default command
return this._dispatchSubcommand(this._defaultCommandName, operands, unknown);
}
if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
// probably missing subcommand and no handler, user needs help (and exit)
this.help({ error: true });
}
outputHelpIfRequested(this, parsed.unknown);
this._checkForMissingMandatoryOptions();
this._checkForConflictingOptions();
// We do not always call this check to avoid masking a "better" error, like unknown command.
const checkForUnknownOptions = () => {
if (parsed.unknown.length > 0) {
this.unknownOption(parsed.unknown[0]);
}
};
const commandEvent = `command:${this.name()}`;
if (this._actionHandler) {
checkForUnknownOptions();
this._processArguments();
let actionResult;
actionResult = this._chainOrCallHooks(actionResult, 'preAction');
actionResult = this._chainOrCall(actionResult, () => this._actionHandler(this.processedArgs));
if (this.parent) {
actionResult = this._chainOrCall(actionResult, () => {
this.parent.emit(commandEvent, operands, unknown); // legacy
});
}
actionResult = this._chainOrCallHooks(actionResult, 'postAction');
return actionResult;
}
if (this.parent && this.parent.listenerCount(commandEvent)) {
checkForUnknownOptions();
this._processArguments();
this.parent.emit(commandEvent, operands, unknown); // legacy
} else if (operands.length) {
if (this._findCommand('*')) { // legacy default command
return this._dispatchSubcommand('*', operands, unknown);
}
if (this.listenerCount('command:*')) {
// skip option check, emit event for possible misspelling suggestion
this.emit('command:*', operands, unknown);
} else if (this.commands.length) {
this.unknownCommand();
} else {
checkForUnknownOptions();
this._processArguments();
}
} else if (this.commands.length) {
checkForUnknownOptions();
// This command has subcommands and nothing hooked up at this level, so display help (and exit).
this.help({ error: true });
} else {
checkForUnknownOptions();
this._processArguments();
// fall through for caller to handle after calling .parse()
}
}
/**
* Find matching command.
*
* @api private
*/
_findCommand(name) {
if (!name) return undefined;
return this.commands.find(cmd => cmd._name === name || cmd._aliases.includes(name));
}
/**
* Return an option matching `arg` if any.
*
* @param {string} arg
* @return {Option}
* @api private
*/
_findOption(arg) {
return this.options.find(option => option.is(arg));
}
/**
* Display an error message if a mandatory option does not have a value.
* Called after checking for help flags in leaf subcommand.
*
* @api private
*/
_checkForMissingMandatoryOptions() {
// Walk up hierarchy so can call in subcommand after checking for displaying help.
for (let cmd = this; cmd; cmd = cmd.parent) {
cmd.options.forEach((anOption) => {
if (anOption.mandatory && (cmd.getOptionValue(anOption.attributeName()) === undefined)) {
cmd.missingMandatoryOptionValue(anOption);
}
});
}
}
/**
* Display an error message if conflicting options are used together in this.
*
* @api private
*/
_checkForConflictingLocalOptions() {
const definedNonDefaultOptions = this.options.filter(
(option) => {
const optionKey = option.attributeName();
if (this.getOptionValue(optionKey) === undefined) {
return false;
}
return this.getOptionValueSource(optionKey) !== 'default';
}
);
const optionsWithConflicting = definedNonDefaultOptions.filter(
(option) => option.conflictsWith.length > 0
);
optionsWithConflicting.forEach((option) => {
const conflictingAndDefined = definedNonDefaultOptions.find((defined) =>
option.conflictsWith.includes(defined.attributeName())
);
if (conflictingAndDefined) {
this._conflictingOption(option, conflictingAndDefined);
}
});
}
/**
* Display an error message if conflicting options are used together.
* Called after checking for help flags in leaf subcommand.
*
* @api private
*/
_checkForConflictingOptions() {
// Walk up hierarchy so can call in subcommand after checking for displaying help.
for (let cmd = this; cmd; cmd = cmd.parent) {
cmd._checkForConflictingLocalOptions();
}
}
/**
* Parse options from `argv` removing known options,
* and return argv split into operands and unknown arguments.
*
* Examples:
*
* argv => operands, unknown
* --known kkk op => [op], []
* op --known kkk => [op], []
* sub --unknown uuu op => [sub], [--unknown uuu op]
* sub -- --unknown uuu op => [sub --unknown uuu op], []
*
* @param {String[]} argv
* @return {{operands: String[], unknown: String[]}}
*/
parseOptions(argv) {
const operands = []; // operands, not options or values
const unknown = []; // first unknown option and remaining unknown args
let dest = operands;
const args = argv.slice();
function maybeOption(arg) {
return arg.length > 1 && arg[0] === '-';
}
// parse options
let activeVariadicOption = null;
while (args.length) {
const arg = args.shift();
// literal
if (arg === '--') {
if (dest === unknown) dest.push(arg);
dest.push(...args);
break;
}
if (activeVariadicOption && !maybeOption(arg)) {
this.emit(`option:${activeVariadicOption.name()}`, arg);
continue;
}
activeVariadicOption = null;
if (maybeOption(arg)) {
const option = this._findOption(arg);
// recognised option, call listener to assign value with possible custom processing
if (option) {
if (option.required) {
const value = args.shift();
if (value === undefined) this.optionMissingArgument(option);
this.emit(`option:${option.name()}`, value);
} else if (option.optional) {
let value = null;
// historical behaviour is optional value is following arg unless an option
if (args.length > 0 && !maybeOption(args[0])) {
value = args.shift();
}
this.emit(`option:${option.name()}`, value);
} else { // boolean flag
this.emit(`option:${option.name()}`);
}
activeVariadicOption = option.variadic ? option : null;
continue;
}
}
// Look for combo options following single dash, eat first one if known.
if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') {
const option = this._findOption(`-${arg[1]}`);
if (option) {
if (option.required || (option.optional && this._combineFlagAndOptionalValue)) {
// option with value following in same argument
this.emit(`option:${option.name()}`, arg.slice(2));
} else {
// boolean option, emit and put back remainder of arg for further processing
this.emit(`option:${option.name()}`);
args.unshift(`-${arg.slice(2)}`);
}
continue;
}
}
// Look for known long flag with value, like --foo=bar
if (/^--[^=]+=/.test(arg)) {
const index = arg.indexOf('=');
const option = this._findOption(arg.slice(0, index));
if (option && (option.required || option.optional)) {
this.emit(`option:${option.name()}`, arg.slice(index + 1));
continue;
}
}
// Not a recognised option by this command.
// Might be a command-argument, or subcommand option, or unknown option, or help command or option.
// An unknown option means further arguments also classified as unknown so can be reprocessed by subcommands.
if (maybeOption(arg)) {
dest = unknown;
}
// If using positionalOptions, stop processing our options at subcommand.
if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
if (this._findCommand(arg)) {
operands.push(arg);
if (args.length > 0) unknown.push(...args);
break;
} else if (arg === this._helpCommandName && this._hasImplicitHelpCommand()) {
operands.push(arg);
if (args.length > 0) operands.push(...args);
break;
} else if (this._defaultCommandName) {
unknown.push(arg);
if (args.length > 0) unknown.push(...args);
break;
}
}
// If using passThroughOptions, stop processing options at first command-argument.
if (this._passThroughOptions) {
dest.push(arg);
if (args.length > 0) dest.push(...args);
break;
}
// add arg
dest.push(arg);
}
return { operands, unknown };
}
/**
* Return an object containing local option values as key-value pairs.
*
* @return {Object}
*/
opts() {
if (this._storeOptionsAsProperties) {
// Preserve original behaviour so backwards compatible when still using properties
const result = {};
const len = this.options.length;
for (let i = 0; i < len; i++) {
const key = this.options[i].attributeName();
result[key] = key === this._versionOptionName ? this._version : this[key];
}
return result;
}
return this._optionValues;
}
/**
* Return an object containing merged local and global option values as key-value pairs.
*
* @return {Object}
*/
optsWithGlobals() {
// globals overwrite locals
return getCommandAndParents(this).reduce(
(combinedOptions, cmd) => Object.assign(combinedOptions, cmd.opts()),
{}
);
}
/**
* Display error message and exit (or call exitOverride).
*
* @param {string} message
* @param {Object} [errorOptions]
* @param {string} [errorOptions.code] - an id string representing the error
* @param {number} [errorOptions.exitCode] - used with process.exit
*/
error(message, errorOptions) {
// output handling
this._outputConfiguration.outputError(`${message}\n`, this._outputConfiguration.writeErr);
if (typeof this._showHelpAfterError === 'string') {
this._outputConfiguration.writeErr(`${this._showHelpAfterError}\n`);
} else if (this._showHelpAfterError) {
this._outputConfiguration.writeErr('\n');
this.outputHelp({ error: true });
}
// exit handling
const config = errorOptions || {};
const exitCode = config.exitCode || 1;
const code = config.code || 'commander.error';
this._exit(exitCode, code, message);
}
/**
* Apply any option related environment variables, if option does
* not have a value from cli or client code.
*
* @api private
*/
_parseOptionsEnv() {
this.options.forEach((option) => {
if (option.envVar && option.envVar in process.env) {
const optionKey = option.attributeName();
// Priority check. Do not overwrite cli or options from unknown source (client-code).
if (this.getOptionValue(optionKey) === undefined || ['default', 'config', 'env'].includes(this.getOptionValueSource(optionKey))) {
if (option.required || option.optional) { // option can take a value
// keep very simple, optional always takes value
this.emit(`optionEnv:${option.name()}`, process.env[option.envVar]);
} else { // boolean
// keep very simple, only care that envVar defined and not the value
this.emit(`optionEnv:${option.name()}`);
}
}
}
});
}
/**
* Apply any implied option values, if option is undefined or default value.
*
* @api private
*/
_parseOptionsImplied() {
const dualHelper = new DualOptions(this.options);
const hasCustomOptionValue = (optionKey) => {
return this.getOptionValue(optionKey) !== undefined && !['default', 'implied'].includes(this.getOptionValueSource(optionKey));
};
this.options
.filter(option => (option.implied !== undefined) &&
hasCustomOptionValue(option.attributeName()) &&
dualHelper.valueFromOption(this.getOptionValue(option.attributeName()), option))
.forEach((option) => {
Object.keys(option.implied)
.filter(impliedKey => !hasCustomOptionValue(impliedKey))
.forEach(impliedKey => {
this.setOptionValueWithSource(impliedKey, option.implied[impliedKey], 'implied');
});
});
}
/**
* Argument `name` is missing.
*
* @param {string} name
* @api private
*/
missingArgument(name) {
const message = `error: missing required argument '${name}'`;
this.error(message, { code: 'commander.missingArgument' });
}
/**
* `Option` is missing an argument.
*
* @param {Option} option
* @api private
*/
optionMissingArgument(option) {
const message = `error: option '${option.flags}' argument missing`;
this.error(message, { code: 'commander.optionMissingArgument' });
}
/**
* `Option` does not have a value, and is a mandatory option.
*
* @param {Option} option
* @api private
*/
missingMandatoryOptionValue(option) {
const message = `error: required option '${option.flags}' not specified`;
this.error(message, { code: 'commander.missingMandatoryOptionValue' });
}
/**
* `Option` conflicts with another option.
*
* @param {Option} option
* @param {Option} conflictingOption
* @api private
*/
_conflictingOption(option, conflictingOption) {
// The calling code does not know whether a negated option is the source of the
// value, so do some work to take an educated guess.
const findBestOptionFromValue = (option) => {
const optionKey = option.attributeName();
const optionValue = this.getOptionValue(optionKey);
const negativeOption = this.options.find(target => target.negate && optionKey === target.attributeName());
const positiveOption = this.options.find(target => !target.negate && optionKey === target.attributeName());
if (negativeOption && (
(negativeOption.presetArg === undefined && optionValue === false) ||
(negativeOption.presetArg !== undefined && optionValue === negativeOption.presetArg)
)) {
return negativeOption;
}
return positiveOption || option;
};
const getErrorMessage = (option) => {
const bestOption = findBestOptionFromValue(option);
const optionKey = bestOption.attributeName();
const source = this.getOptionValueSource(optionKey);
if (source === 'env') {
return `environment variable '${bestOption.envVar}'`;
}
return `option '${bestOption.flags}'`;
};
const message = `error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;
this.error(message, { code: 'commander.conflictingOption' });
}
/**
* Unknown option `flag`.
*
* @param {string} flag
* @api private
*/
unknownOption(flag) {
if (this._allowUnknownOption) return;
let suggestion = '';
if (flag.startsWith('--') && this._showSuggestionAfterError) {
// Looping to pick up the global options too
let candidateFlags = [];
let command = this;
do {
const moreFlags = command.createHelp().visibleOptions(command)
.filter(option => option.long)
.map(option => option.long);
candidateFlags = candidateFlags.concat(moreFlags);
command = command.parent;
} while (command && !command._enablePositionalOptions);
suggestion = suggestSimilar(flag, candidateFlags);
}
const message = `error: unknown option '${flag}'${suggestion}`;
this.error(message, { code: 'commander.unknownOption' });
}
/**
* Excess arguments, more than expected.
*
* @param {string[]} receivedArgs
* @api private
*/
_excessArguments(receivedArgs) {
if (this._allowExcessArguments) return;
const expected = this._args.length;
const s = (expected === 1) ? '' : 's';
const forSubcommand = this.parent ? ` for '${this.name()}'` : '';
const message = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${receivedArgs.length}.`;
this.error(message, { code: 'commander.excessArguments' });
}
/**
* Unknown command.
*
* @api private
*/
unknownCommand() {
const unknownName = this.args[0];
let suggestion = '';
if (this._showSuggestionAfterError) {
const candidateNames = [];
this.createHelp().visibleCommands(this).forEach((command) => {
candidateNames.push(command.name());
// just visible alias
if (command.alias()) candidateNames.push(command.alias());
});
suggestion = suggestSimilar(unknownName, candidateNames);
}
const message = `error: unknown command '${unknownName}'${suggestion}`;
this.error(message, { code: 'commander.unknownCommand' });
}
/**
* Set the program version to `str`.
*
* This method auto-registers the "-V, --version" flag
* which will print the version number when passed.
*
* You can optionally supply the flags and description to override the defaults.
*
* @param {string} str
* @param {string} [flags]
* @param {string} [description]
* @return {this | string} `this` command for chaining, or version string if no arguments
*/
version(str, flags, description) {
if (str === undefined) return this._version;
this._version = str;
flags = flags || '-V, --version';
description = description || 'output the version number';
const versionOption = this.createOption(flags, description);
this._versionOptionName = versionOption.attributeName();
this.options.push(versionOption);
this.on('option:' + versionOption.name(), () => {
this._outputConfiguration.writeOut(`${str}\n`);
this._exit(0, 'commander.version', str);
});
return this;
}
/**
* Set the description.
*
* @param {string} [str]
* @param {Object} [argsDescription]
* @return {string|Command}
*/
description(str, argsDescription) {
if (str === undefined && argsDescription === undefined) return this._description;
this._description = str;
if (argsDescription) {
this._argsDescription = argsDescription;
}
return this;
}
/**
* Set the summary. Used when listed as subcommand of parent.
*
* @param {string} [str]
* @return {string|Command}
*/
summary(str) {
if (str === undefined) return this._summary;
this._summary = str;
return this;
}
/**
* Set an alias for the command.
*
* You may call more than once to add multiple aliases. Only the first alias is shown in the auto-generated help.
*
* @param {string} [alias]
* @return {string|Command}
*/
alias(alias) {
if (alias === undefined) return this._aliases[0]; // just return first, for backwards compatibility
/** @type {Command} */
let command = this;
if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
// assume adding alias for last added executable subcommand, rather than this
command = this.commands[this.commands.length - 1];
}
if (alias === command._name) throw new Error('Command alias can\'t be the same as its name');
command._aliases.push(alias);
return this;
}
/**
* Set aliases for the command.
*
* Only the first alias is shown in the auto-generated help.
*
* @param {string[]} [aliases]
* @return {string[]|Command}
*/
aliases(aliases) {
// Getter for the array of aliases is the main reason for having aliases() in addition to alias().
if (aliases === undefined) return this._aliases;
aliases.forEach((alias) => this.alias(alias));
return this;
}
/**
* Set / get the command usage `str`.
*
* @param {string} [str]
* @return {String|Command}
*/
usage(str) {
if (str === undefined) {
if (this._usage) return this._usage;
const args = this._args.map((arg) => {
return humanReadableArgName(arg);
});
return [].concat(
(this.options.length || this._hasHelpOption ? '[options]' : []),
(this.commands.length ? '[command]' : []),
(this._args.length ? args : [])
).join(' ');
}
this._usage = str;
return this;
}
/**
* Get or set the name of the command.
*
* @param {string} [str]
* @return {string|Command}
*/
name(str) {
if (str === undefined) return this._name;
this._name = str;
return this;
}
/**
* Set the name of the command from script filename, such as process.argv[1],
* or require.main.filename, or __filename.
*
* (Used internally and public although not documented in README.)
*
* @example
* program.nameFromFilename(require.main.filename);
*
* @param {string} filename
* @return {Command}
*/
nameFromFilename(filename) {
this._name = path.basename(filename, path.extname(filename));
return this;
}
/**
* Get or set the directory for searching for executable subcommands of this command.
*
* @example
* program.executableDir(__dirname);
* // or
* program.executableDir('subcommands');
*
* @param {string} [path]
* @return {string|Command}
*/
executableDir(path) {
if (path === undefined) return this._executableDir;
this._executableDir = path;
return this;
}
/**
* Return program help documentation.
*
* @param {{ error: boolean }} [contextOptions] - pass {error:true} to wrap for stderr instead of stdout
* @return {string}
*/
helpInformation(contextOptions) {
const helper = this.createHelp();
if (helper.helpWidth === undefined) {
helper.helpWidth = (contextOptions && contextOptions.error) ? this._outputConfiguration.getErrHelpWidth() : this._outputConfiguration.getOutHelpWidth();
}
return helper.formatHelp(this, helper);
}
/**
* @api private
*/
_getHelpContext(contextOptions) {
contextOptions = contextOptions || {};
const context = { error: !!contextOptions.error };
let write;
if (context.error) {
write = (arg) => this._outputConfiguration.writeErr(arg);
} else {
write = (arg) => this._outputConfiguration.writeOut(arg);
}
context.write = contextOptions.write || write;
context.command = this;
return context;
}
/**
* Output help information for this command.
*
* Outputs built-in help, and custom text added using `.addHelpText()`.
*
* @param {{ error: boolean } | Function} [contextOptions] - pass {error:true} to write to stderr instead of stdout
*/
outputHelp(contextOptions) {
let deprecatedCallback;
if (typeof contextOptions === 'function') {
deprecatedCallback = contextOptions;
contextOptions = undefined;
}
const context = this._getHelpContext(contextOptions);
getCommandAndParents(this).reverse().forEach(command => command.emit('beforeAllHelp', context));
this.emit('beforeHelp', context);
let helpInformation = this.helpInformation(context);
if (deprecatedCallback) {
helpInformation = deprecatedCallback(helpInformation);
if (typeof helpInformation !== 'string' && !Buffer.isBuffer(helpInformation)) {
throw new Error('outputHelp callback must return a string or a Buffer');
}
}
context.write(helpInformation);
this.emit(this._helpLongFlag); // deprecated
this.emit('afterHelp', context);
getCommandAndParents(this).forEach(command => command.emit('afterAllHelp', context));
}
/**
* You can pass in flags and a description to override the help
* flags and help description for your command. Pass in false to
* disable the built-in help option.
*
* @param {string | boolean} [flags]
* @param {string} [description]
* @return {Command} `this` command for chaining
*/
helpOption(flags, description) {
if (typeof flags === 'boolean') {
this._hasHelpOption = flags;
return this;
}
this._helpFlags = flags || this._helpFlags;
this._helpDescription = description || this._helpDescription;
const helpFlags = splitOptionFlags(this._helpFlags);
this._helpShortFlag = helpFlags.shortFlag;
this._helpLongFlag = helpFlags.longFlag;
return this;
}
/**
* Output help information and exit.
*
* Outputs built-in help, and custom text added using `.addHelpText()`.
*
* @param {{ error: boolean }} [contextOptions] - pass {error:true} to write to stderr instead of stdout
*/
help(contextOptions) {
this.outputHelp(contextOptions);
let exitCode = process.exitCode || 0;
if (exitCode === 0 && contextOptions && typeof contextOptions !== 'function' && contextOptions.error) {
exitCode = 1;
}
// message: do not have all displayed text available so only passing placeholder.
this._exit(exitCode, 'commander.help', '(outputHelp)');
}
/**
* Add additional text to be displayed with the built-in help.
*
* Position is 'before' or 'after' to affect just this command,
* and 'beforeAll' or 'afterAll' to affect this command and all its subcommands.
*
* @param {string} position - before or after built-in help
* @param {string | Function} text - string to add, or a function returning a string
* @return {Command} `this` command for chaining
*/
addHelpText(position, text) {
const allowedValues = ['beforeAll', 'before', 'after', 'afterAll'];
if (!allowedValues.includes(position)) {
throw new Error(`Unexpected value for position to addHelpText.
Expecting one of '${allowedValues.join("', '")}'`);
}
const helpEvent = `${position}Help`;
this.on(helpEvent, (context) => {
let helpStr;
if (typeof text === 'function') {
helpStr = text({ error: context.error, command: context.command });
} else {
helpStr = text;
}
// Ignore falsy value when nothing to output.
if (helpStr) {
context.write(`${helpStr}\n`);
}
});
return this;
}
}
/**
* Output help information if help flags specified
*
* @param {Command} cmd - command to output help for
* @param {Array} args - array of options to search for help flags
* @api private
*/
function outputHelpIfRequested(cmd, args) {
const helpOption = cmd._hasHelpOption && args.find(arg => arg === cmd._helpLongFlag || arg === cmd._helpShortFlag);
if (helpOption) {
cmd.outputHelp();
// (Do not have all displayed text available so only passing placeholder.)
cmd._exit(0, 'commander.helpDisplayed', '(outputHelp)');
}
}
/**
* Scan arguments and increment port number for inspect calls (to avoid conflicts when spawning new command).
*
* @param {string[]} args - array of arguments from node.execArgv
* @returns {string[]}
* @api private
*/
function incrementNodeInspectorPort(args) {
// Testing for these options:
// --inspect[=[host:]port]
// --inspect-brk[=[host:]port]
// --inspect-port=[host:]port
return args.map((arg) => {
if (!arg.startsWith('--inspect')) {
return arg;
}
let debugOption;
let debugHost = '127.0.0.1';
let debugPort = '9229';
let match;
if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
// e.g. --inspect
debugOption = match[1];
} else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
debugOption = match[1];
if (/^\d+$/.test(match[3])) {
// e.g. --inspect=1234
debugPort = match[3];
} else {
// e.g. --inspect=localhost
debugHost = match[3];
}
} else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
// e.g. --inspect=localhost:1234
debugOption = match[1];
debugHost = match[3];
debugPort = match[4];
}
if (debugOption && debugPort !== '0') {
return `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
}
return arg;
});
}
/**
* @param {Command} startCommand
* @returns {Command[]}
* @api private
*/
function getCommandAndParents(startCommand) {
const result = [];
for (let command = startCommand; command; command = command.parent) {
result.push(command);
}
return result;
}
exports.Command = Command;
/***/ }),
/***/ 831:
/***/ ((__unused_webpack_module, exports) => {
// @ts-check
/**
* CommanderError class
* @class
*/
class CommanderError extends Error {
/**
* Constructs the CommanderError class
* @param {number} exitCode suggested exit code which could be used with process.exit
* @param {string} code an id string representing the error
* @param {string} message human-readable description of the error
* @constructor
*/
constructor(exitCode, code, message) {
super(message);
// properly capture stack trace in Node.js
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.code = code;
this.exitCode = exitCode;
this.nestedError = undefined;
}
}
/**
* InvalidArgumentError class
* @class
*/
class InvalidArgumentError extends CommanderError {
/**
* Constructs the InvalidArgumentError class
* @param {string} [message] explanation of why argument is invalid
* @constructor
*/
constructor(message) {
super(1, 'commander.invalidArgument', message);
// properly capture stack trace in Node.js
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
}
}
exports.CommanderError = CommanderError;
exports.InvalidArgumentError = InvalidArgumentError;
/***/ }),
/***/ 437:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
const { humanReadableArgName } = __webpack_require__(811);
/**
* TypeScript import types for JSDoc, used by Visual Studio Code IntelliSense and `npm run typescript-checkJS`
* https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#import-types
* @typedef { import("./argument.js").Argument } Argument
* @typedef { import("./command.js").Command } Command
* @typedef { import("./option.js").Option } Option
*/
// @ts-check
// Although this is a class, methods are static in style to allow override using subclass or just functions.
class Help {
constructor() {
this.helpWidth = undefined;
this.sortSubcommands = false;
this.sortOptions = false;
this.showGlobalOptions = false;
}
/**
* Get an array of the visible subcommands. Includes a placeholder for the implicit help command, if there is one.
*
* @param {Command} cmd
* @returns {Command[]}
*/
visibleCommands(cmd) {
const visibleCommands = cmd.commands.filter(cmd => !cmd._hidden);
if (cmd._hasImplicitHelpCommand()) {
// Create a command matching the implicit help command.
const [, helpName, helpArgs] = cmd._helpCommandnameAndArgs.match(/([^ ]+) *(.*)/);
const helpCommand = cmd.createCommand(helpName)
.helpOption(false);
helpCommand.description(cmd._helpCommandDescription);
if (helpArgs) helpCommand.arguments(helpArgs);
visibleCommands.push(helpCommand);
}
if (this.sortSubcommands) {
visibleCommands.sort((a, b) => {
// @ts-ignore: overloaded return type
return a.name().localeCompare(b.name());
});
}
return visibleCommands;
}
/**
* Compare options for sort.
*
* @param {Option} a
* @param {Option} b
* @returns number
*/
compareOptions(a, b) {
const getSortKey = (option) => {
// WYSIWYG for order displayed in help. Short used for comparison if present. No special handling for negated.
return option.short ? option.short.replace(/^-/, '') : option.long.replace(/^--/, '');
};
return getSortKey(a).localeCompare(getSortKey(b));
}
/**
* Get an array of the visible options. Includes a placeholder for the implicit help option, if there is one.
*
* @param {Command} cmd
* @returns {Option[]}
*/
visibleOptions(cmd) {
const visibleOptions = cmd.options.filter((option) => !option.hidden);
// Implicit help
const showShortHelpFlag = cmd._hasHelpOption && cmd._helpShortFlag && !cmd._findOption(cmd._helpShortFlag);
const showLongHelpFlag = cmd._hasHelpOption && !cmd._findOption(cmd._helpLongFlag);
if (showShortHelpFlag || showLongHelpFlag) {
let helpOption;
if (!showShortHelpFlag) {
helpOption = cmd.createOption(cmd._helpLongFlag, cmd._helpDescription);
} else if (!showLongHelpFlag) {
helpOption = cmd.createOption(cmd._helpShortFlag, cmd._helpDescription);
} else {
helpOption = cmd.createOption(cmd._helpFlags, cmd._helpDescription);
}
visibleOptions.push(helpOption);
}
if (this.sortOptions) {
visibleOptions.sort(this.compareOptions);
}
return visibleOptions;
}
/**
* Get an array of the visible global options. (Not including help.)
*
* @param {Command} cmd
* @returns {Option[]}
*/
visibleGlobalOptions(cmd) {
if (!this.showGlobalOptions) return [];
const globalOptions = [];
for (let parentCmd = cmd.parent; parentCmd; parentCmd = parentCmd.parent) {
const visibleOptions = parentCmd.options.filter((option) => !option.hidden);
globalOptions.push(...visibleOptions);
}
if (this.sortOptions) {
globalOptions.sort(this.compareOptions);
}
return globalOptions;
}
/**
* Get an array of the arguments if any have a description.
*
* @param {Command} cmd
* @returns {Argument[]}
*/
visibleArguments(cmd) {
// Side effect! Apply the legacy descriptions before the arguments are displayed.
if (cmd._argsDescription) {
cmd._args.forEach(argument => {
argument.description = argument.description || cmd._argsDescription[argument.name()] || '';
});
}
// If there are any arguments with a description then return all the arguments.
if (cmd._args.find(argument => argument.description)) {
return cmd._args;
}
return [];
}
/**
* Get the command term to show in the list of subcommands.
*
* @param {Command} cmd
* @returns {string}
*/
subcommandTerm(cmd) {
// Legacy. Ignores custom usage string, and nested commands.
const args = cmd._args.map(arg => humanReadableArgName(arg)).join(' ');
return cmd._name +
(cmd._aliases[0] ? '|' + cmd._aliases[0] : '') +
(cmd.options.length ? ' [options]' : '') + // simplistic check for non-help option
(args ? ' ' + args : '');
}
/**
* Get the option term to show in the list of options.
*
* @param {Option} option
* @returns {string}
*/
optionTerm(option) {
return option.flags;
}
/**
* Get the argument term to show in the list of arguments.
*
* @param {Argument} argument
* @returns {string}
*/
argumentTerm(argument) {
return argument.name();
}
/**
* Get the longest command term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestSubcommandTermLength(cmd, helper) {
return helper.visibleCommands(cmd).reduce((max, command) => {
return Math.max(max, helper.subcommandTerm(command).length);
}, 0);
}
/**
* Get the longest option term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestOptionTermLength(cmd, helper) {
return helper.visibleOptions(cmd).reduce((max, option) => {
return Math.max(max, helper.optionTerm(option).length);
}, 0);
}
/**
* Get the longest global option term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestGlobalOptionTermLength(cmd, helper) {
return helper.visibleGlobalOptions(cmd).reduce((max, option) => {
return Math.max(max, helper.optionTerm(option).length);
}, 0);
}
/**
* Get the longest argument term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestArgumentTermLength(cmd, helper) {
return helper.visibleArguments(cmd).reduce((max, argument) => {
return Math.max(max, helper.argumentTerm(argument).length);
}, 0);
}
/**
* Get the command usage to be displayed at the top of the built-in help.
*
* @param {Command} cmd
* @returns {string}
*/
commandUsage(cmd) {
// Usage
let cmdName = cmd._name;
if (cmd._aliases[0]) {
cmdName = cmdName + '|' + cmd._aliases[0];
}
let parentCmdNames = '';
for (let parentCmd = cmd.parent; parentCmd; parentCmd = parentCmd.parent) {
parentCmdNames = parentCmd.name() + ' ' + parentCmdNames;
}
return parentCmdNames + cmdName + ' ' + cmd.usage();
}
/**
* Get the description for the command.
*
* @param {Command} cmd
* @returns {string}
*/
commandDescription(cmd) {
// @ts-ignore: overloaded return type
return cmd.description();
}
/**
* Get the subcommand summary to show in the list of subcommands.
* (Fallback to description for backwards compatibility.)
*
* @param {Command} cmd
* @returns {string}
*/
subcommandDescription(cmd) {
// @ts-ignore: overloaded return type
return cmd.summary() || cmd.description();
}
/**
* Get the option description to show in the list of options.
*
* @param {Option} option
* @return {string}
*/
optionDescription(option) {
const extraInfo = [];
if (option.argChoices) {
extraInfo.push(
// use stringify to match the display of the default value
`choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(', ')}`);
}
if (option.defaultValue !== undefined) {
// default for boolean and negated more for programmer than end user,
// but show true/false for boolean option as may be for hand-rolled env or config processing.
const showDefault = option.required || option.optional ||
(option.isBoolean() && typeof option.defaultValue === 'boolean');
if (showDefault) {
extraInfo.push(`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`);
}
}
// preset for boolean and negated are more for programmer than end user
if (option.presetArg !== undefined && option.optional) {
extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`);
}
if (option.envVar !== undefined) {
extraInfo.push(`env: ${option.envVar}`);
}
if (extraInfo.length > 0) {
return `${option.description} (${extraInfo.join(', ')})`;
}
return option.description;
}
/**
* Get the argument description to show in the list of arguments.
*
* @param {Argument} argument
* @return {string}
*/
argumentDescription(argument) {
const extraInfo = [];
if (argument.argChoices) {
extraInfo.push(
// use stringify to match the display of the default value
`choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(', ')}`);
}
if (argument.defaultValue !== undefined) {
extraInfo.push(`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`);
}
if (extraInfo.length > 0) {
const extraDescripton = `(${extraInfo.join(', ')})`;
if (argument.description) {
return `${argument.description} ${extraDescripton}`;
}
return extraDescripton;
}
return argument.description;
}
/**
* Generate the built-in help text.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {string}
*/
formatHelp(cmd, helper) {
const termWidth = helper.padWidth(cmd, helper);
const helpWidth = helper.helpWidth || 80;
const itemIndentWidth = 2;
const itemSeparatorWidth = 2; // between term and description
function formatItem(term, description) {
if (description) {
const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
return helper.wrap(fullText, helpWidth - itemIndentWidth, termWidth + itemSeparatorWidth);
}
return term;
}
function formatList(textArray) {
return textArray.join('\n').replace(/^/gm, ' '.repeat(itemIndentWidth));
}
// Usage
let output = [`Usage: ${helper.commandUsage(cmd)}`, ''];
// Description
const commandDescription = helper.commandDescription(cmd);
if (commandDescription.length > 0) {
output = output.concat([helper.wrap(commandDescription, helpWidth, 0), '']);
}
// Arguments
const argumentList = helper.visibleArguments(cmd).map((argument) => {
return formatItem(helper.argumentTerm(argument), helper.argumentDescription(argument));
});
if (argumentList.length > 0) {
output = output.concat(['Arguments:', formatList(argumentList), '']);
}
// Options
const optionList = helper.visibleOptions(cmd).map((option) => {
return formatItem(helper.optionTerm(option), helper.optionDescription(option));
});
if (optionList.length > 0) {
output = output.concat(['Options:', formatList(optionList), '']);
}
if (this.showGlobalOptions) {
const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
return formatItem(helper.optionTerm(option), helper.optionDescription(option));
});
if (globalOptionList.length > 0) {
output = output.concat(['Global Options:', formatList(globalOptionList), '']);
}
}
// Commands
const commandList = helper.visibleCommands(cmd).map((cmd) => {
return formatItem(helper.subcommandTerm(cmd), helper.subcommandDescription(cmd));
});
if (commandList.length > 0) {
output = output.concat(['Commands:', formatList(commandList), '']);
}
return output.join('\n');
}
/**
* Calculate the pad width from the maximum term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
padWidth(cmd, helper) {
return Math.max(
helper.longestOptionTermLength(cmd, helper),
helper.longestGlobalOptionTermLength(cmd, helper),
helper.longestSubcommandTermLength(cmd, helper),
helper.longestArgumentTermLength(cmd, helper)
);
}
/**
* Wrap the given string to width characters per line, with lines after the first indented.
* Do not wrap if insufficient room for wrapping (minColumnWidth), or string is manually formatted.
*
* @param {string} str
* @param {number} width
* @param {number} indent
* @param {number} [minColumnWidth=40]
* @return {string}
*
*/
wrap(str, width, indent, minColumnWidth = 40) {
// Full \s characters, minus the linefeeds.
const indents = ' \\f\\t\\v\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff';
// Detect manually wrapped and indented strings by searching for line break followed by spaces.
const manualIndent = new RegExp(`[\\n][${indents}]+`);
if (str.match(manualIndent)) return str;
// Do not wrap if not enough room for a wrapped column of text (as could end up with a word per line).
const columnWidth = width - indent;
if (columnWidth < minColumnWidth) return str;
const leadingStr = str.slice(0, indent);
const columnText = str.slice(indent).replace('\r\n', '\n');
const indentString = ' '.repeat(indent);
const zeroWidthSpace = '\u200B';
const breaks = `\\s${zeroWidthSpace}`;
// Match line end (so empty lines don't collapse),
// or as much text as will fit in column, or excess text up to first break.
const regex = new RegExp(`\n|.{1,${columnWidth - 1}}([${breaks}]|$)|[^${breaks}]+?([${breaks}]|$)`, 'g');
const lines = columnText.match(regex) || [];
return leadingStr + lines.map((line, i) => {
if (line === '\n') return ''; // preserve empty lines
return ((i > 0) ? indentString : '') + line.trimEnd();
}).join('\n');
}
}
exports.Help = Help;
/***/ }),
/***/ 311:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
const { InvalidArgumentError } = __webpack_require__(831);
// @ts-check
class Option {
/**
* Initialize a new `Option` with the given `flags` and `description`.
*
* @param {string} flags
* @param {string} [description]
*/
constructor(flags, description) {
this.flags = flags;
this.description = description || '';
this.required = flags.includes('<'); // A value must be supplied when the option is specified.
this.optional = flags.includes('['); // A value is optional when the option is specified.
// variadic test ignores <value,...> et al which might be used to describe custom splitting of single argument
this.variadic = /\w\.\.\.[>\]]$/.test(flags); // The option can take multiple values.
this.mandatory = false; // The option must have a value after parsing, which usually means it must be specified on command line.
const optionFlags = splitOptionFlags(flags);
this.short = optionFlags.shortFlag;
this.long = optionFlags.longFlag;
this.negate = false;
if (this.long) {
this.negate = this.long.startsWith('--no-');
}
this.defaultValue = undefined;
this.defaultValueDescription = undefined;
this.presetArg = undefined;
this.envVar = undefined;
this.parseArg = undefined;
this.hidden = false;
this.argChoices = undefined;
this.conflictsWith = [];
this.implied = undefined;
}
/**
* Set the default value, and optionally supply the description to be displayed in the help.
*
* @param {any} value
* @param {string} [description]
* @return {Option}
*/
default(value, description) {
this.defaultValue = value;
this.defaultValueDescription = description;
return this;
}
/**
* Preset to use when option used without option-argument, especially optional but also boolean and negated.
* The custom processing (parseArg) is called.
*
* @example
* new Option('--color').default('GREYSCALE').preset('RGB');
* new Option('--donate [amount]').preset('20').argParser(parseFloat);
*
* @param {any} arg
* @return {Option}
*/
preset(arg) {
this.presetArg = arg;
return this;
}
/**
* Add option name(s) that conflict with this option.
* An error will be displayed if conflicting options are found during parsing.
*
* @example
* new Option('--rgb').conflicts('cmyk');
* new Option('--js').conflicts(['ts', 'jsx']);
*
* @param {string | string[]} names
* @return {Option}
*/
conflicts(names) {
this.conflictsWith = this.conflictsWith.concat(names);
return this;
}
/**
* Specify implied option values for when this option is set and the implied options are not.
*
* The custom processing (parseArg) is not called on the implied values.
*
* @example
* program
* .addOption(new Option('--log', 'write logging information to file'))
* .addOption(new Option('--trace', 'log extra details').implies({ log: 'trace.txt' }));
*
* @param {Object} impliedOptionValues
* @return {Option}
*/
implies(impliedOptionValues) {
this.implied = Object.assign(this.implied || {}, impliedOptionValues);
return this;
}
/**
* Set environment variable to check for option value.
*
* An environment variable is only used if when processed the current option value is
* undefined, or the source of the current value is 'default' or 'config' or 'env'.
*
* @param {string} name
* @return {Option}
*/
env(name) {
this.envVar = name;
return this;
}
/**
* Set the custom handler for processing CLI option arguments into option values.
*
* @param {Function} [fn]
* @return {Option}
*/
argParser(fn) {
this.parseArg = fn;
return this;
}
/**
* Whether the option is mandatory and must have a value after parsing.
*
* @param {boolean} [mandatory=true]
* @return {Option}
*/
makeOptionMandatory(mandatory = true) {
this.mandatory = !!mandatory;
return this;
}
/**
* Hide option in help.
*
* @param {boolean} [hide=true]
* @return {Option}
*/
hideHelp(hide = true) {
this.hidden = !!hide;
return this;
}
/**
* @api private
*/
_concatValue(value, previous) {
if (previous === this.defaultValue || !Array.isArray(previous)) {
return [value];
}
return previous.concat(value);
}
/**
* Only allow option value to be one of choices.
*
* @param {string[]} values
* @return {Option}
*/
choices(values) {
this.argChoices = values.slice();
this.parseArg = (arg, previous) => {
if (!this.argChoices.includes(arg)) {
throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(', ')}.`);
}
if (this.variadic) {
return this._concatValue(arg, previous);
}
return arg;
};
return this;
}
/**
* Return option name.
*
* @return {string}
*/
name() {
if (this.long) {
return this.long.replace(/^--/, '');
}
return this.short.replace(/^-/, '');
}
/**
* Return option name, in a camelcase format that can be used
* as a object attribute key.
*
* @return {string}
* @api private
*/
attributeName() {
return camelcase(this.name().replace(/^no-/, ''));
}
/**
* Check if `arg` matches the short or long flag.
*
* @param {string} arg
* @return {boolean}
* @api private
*/
is(arg) {
return this.short === arg || this.long === arg;
}
/**
* Return whether a boolean option.
*
* Options are one of boolean, negated, required argument, or optional argument.
*
* @return {boolean}
* @api private
*/
isBoolean() {
return !this.required && !this.optional && !this.negate;
}
}
/**
* This class is to make it easier to work with dual options, without changing the existing
* implementation. We support separate dual options for separate positive and negative options,
* like `--build` and `--no-build`, which share a single option value. This works nicely for some
* use cases, but is tricky for others where we want separate behaviours despite
* the single shared option value.
*/
class DualOptions {
/**
* @param {Option[]} options
*/
constructor(options) {
this.positiveOptions = new Map();
this.negativeOptions = new Map();
this.dualOptions = new Set();
options.forEach(option => {
if (option.negate) {
this.negativeOptions.set(option.attributeName(), option);
} else {
this.positiveOptions.set(option.attributeName(), option);
}
});
this.negativeOptions.forEach((value, key) => {
if (this.positiveOptions.has(key)) {
this.dualOptions.add(key);
}
});
}
/**
* Did the value come from the option, and not from possible matching dual option?
*
* @param {any} value
* @param {Option} option
* @returns {boolean}
*/
valueFromOption(value, option) {
const optionKey = option.attributeName();
if (!this.dualOptions.has(optionKey)) return true;
// Use the value to deduce if (probably) came from the option.
const preset = this.negativeOptions.get(optionKey).presetArg;
const negativeValue = (preset !== undefined) ? preset : false;
return option.negate === (negativeValue === value);
}
}
/**
* Convert string from kebab-case to camelCase.
*
* @param {string} str
* @return {string}
* @api private
*/
function camelcase(str) {
return str.split('-').reduce((str, word) => {
return str + word[0].toUpperCase() + word.slice(1);
});
}
/**
* Split the short and long flag out of something like '-m,--mixed <value>'
*
* @api private
*/
function splitOptionFlags(flags) {
let shortFlag;
let longFlag;
// Use original very loose parsing to maintain backwards compatibility for now,
// which allowed for example unintended `-sw, --short-word` [sic].
const flagParts = flags.split(/[ |,]+/);
if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1])) shortFlag = flagParts.shift();
longFlag = flagParts.shift();
// Add support for lone short flag without significantly changing parsing!
if (!shortFlag && /^-[^-]$/.test(longFlag)) {
shortFlag = longFlag;
longFlag = undefined;
}
return { shortFlag, longFlag };
}
exports.Option = Option;
exports.splitOptionFlags = splitOptionFlags;
exports.DualOptions = DualOptions;
/***/ }),
/***/ 426:
/***/ ((__unused_webpack_module, exports) => {
const maxDistance = 3;
function editDistance(a, b) {
// https://en.wikipedia.org/wiki/Damerau–Levenshtein_distance
// Calculating optimal string alignment distance, no substring is edited more than once.
// (Simple implementation.)
// Quick early exit, return worst case.
if (Math.abs(a.length - b.length) > maxDistance) return Math.max(a.length, b.length);
// distance between prefix substrings of a and b
const d = [];
// pure deletions turn a into empty string
for (let i = 0; i <= a.length; i++) {
d[i] = [i];
}
// pure insertions turn empty string into b
for (let j = 0; j <= b.length; j++) {
d[0][j] = j;
}
// fill matrix
for (let j = 1; j <= b.length; j++) {
for (let i = 1; i <= a.length; i++) {
let cost = 1;
if (a[i - 1] === b[j - 1]) {
cost = 0;
} else {
cost = 1;
}
d[i][j] = Math.min(
d[i - 1][j] + 1, // deletion
d[i][j - 1] + 1, // insertion
d[i - 1][j - 1] + cost // substitution
);
// transposition
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
}
}
}
return d[a.length][b.length];
}
/**
* Find close matches, restricted to same number of edits.
*
* @param {string} word
* @param {string[]} candidates
* @returns {string}
*/
function suggestSimilar(word, candidates) {
if (!candidates || candidates.length === 0) return '';
// remove possible duplicates
candidates = Array.from(new Set(candidates));
const searchingOptions = word.startsWith('--');
if (searchingOptions) {
word = word.slice(2);
candidates = candidates.map(candidate => candidate.slice(2));
}
let similar = [];
let bestDistance = maxDistance;
const minSimilarity = 0.4;
candidates.forEach((candidate) => {
if (candidate.length <= 1) return; // no one character guesses
const distance = editDistance(word, candidate);
const length = Math.max(word.length, candidate.length);
const similarity = (length - distance) / length;
if (similarity > minSimilarity) {
if (distance < bestDistance) {
// better edit distance, throw away previous worse matches
bestDistance = distance;
similar = [candidate];
} else if (distance === bestDistance) {
similar.push(candidate);
}
}
});
similar.sort((a, b) => a.localeCompare(b));
if (searchingOptions) {
similar = similar.map(candidate => `--${candidate}`);
}
if (similar.length > 1) {
return `\n(Did you mean one of ${similar.join(', ')}?)`;
}
if (similar.length === 1) {
return `\n(Did you mean ${similar[0]}?)`;
}
return '';
}
exports.suggestSimilar = suggestSimilar;
/***/ }),
/***/ 708:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
(function webpackUniversalModuleDefinition(root, factory) {
if(true)
module.exports = factory(__webpack_require__(198), __webpack_require__(56), __webpack_require__(89), __webpack_require__(810));
else { var i, a; }
})(this, (__WEBPACK_EXTERNAL_MODULE_child_process__, __WEBPACK_EXTERNAL_MODULE_path__, __WEBPACK_EXTERNAL_MODULE_fs__, __WEBPACK_EXTERNAL_MODULE_app_lib_log__) => {
return /******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./src/cross-spawn/index.js":
/*!**********************************!*\
!*** ./src/cross-spawn/index.js ***!
\**********************************/
/***/ ((module, __unused_webpack_exports, __nested_webpack_require_1098__) => {
"use strict";
const cp = __nested_webpack_require_1098__(/*! child_process */ "child_process");
const parse = __nested_webpack_require_1098__(/*! ./lib/parse */ "./src/cross-spawn/lib/parse.js");
const enoent = __nested_webpack_require_1098__(/*! ./lib/enoent */ "./src/cross-spawn/lib/enoent.js");
const {log} = __nested_webpack_require_1098__(/*! app-lib-log */ "app-lib-log");
function spawn(command, args, options) {
// Parse the arguments
const parsed = parse(command, args, options);
// Spawn the child process
const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
// Hook into child process "exit" event to emit an error if the command
// does not exists, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16
enoent.hookChildProcess(spawned, parsed);
return spawned;
}
function spawnSync(command, args, options) {
// Parse the arguments
const parsed = parse(command, args, options);
log.md('exe node:',parsed.command, parsed.args, {...parsed.options,windowsHide:true})
// Spawn the child process
const result = cp.spawnSync(parsed.command, parsed.args, {...parsed.options});
// Analyze if the command does not exist, see: https://github.com/IndigoUnited/node-cross-spawn/issues/16
result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
return result;
}
module.exports = spawn;
module.exports.spawn = spawn;
module.exports.sync = spawnSync;
module.exports._parse = parse;
module.exports._enoent = enoent;
/***/ }),
/***/ "./src/cross-spawn/lib/enoent.js":
/*!***************************************!*\
!*** ./src/cross-spawn/lib/enoent.js ***!
\***************************************/
/***/ ((module) => {
"use strict";
const isWin = process.platform === 'win32';
function notFoundError(original, syscall) {
return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), {
code: 'ENOENT',
errno: 'ENOENT',
syscall: `${syscall} ${original.command}`,
path: original.command,
spawnargs: original.args,
});
}
function hookChildProcess(cp, parsed) {
if (!isWin) {
return;
}
const originalEmit = cp.emit;
cp.emit = function (name, arg1) {
// If emitting "exit" event and exit code is 1, we need to check if
// the command exists and emit an "error" instead
// See https://github.com/IndigoUnited/node-cross-spawn/issues/16
if (name === 'exit') {
const err = verifyENOENT(arg1, parsed, 'spawn');
if (err) {
return originalEmit.call(cp, 'error', err);
}
}
return originalEmit.apply(cp, arguments); // eslint-disable-line prefer-rest-params
};
}
function verifyENOENT(status, parsed) {
if (isWin && status === 1 && !parsed.file) {
return notFoundError(parsed.original, 'spawn');
}
return null;
}
function verifyENOENTSync(status, parsed) {
if (isWin && status === 1 && !parsed.file) {
return notFoundError(parsed.original, 'spawnSync');
}
return null;
}
module.exports = {
hookChildProcess,
verifyENOENT,
verifyENOENTSync,
notFoundError,
};
/***/ }),
/***/ "./src/cross-spawn/lib/parse.js":
/*!**************************************!*\
!*** ./src/cross-spawn/lib/parse.js ***!
\**************************************/
/***/ ((module, __unused_webpack_exports, __nested_webpack_require_4632__) => {
"use strict";
const path = __nested_webpack_require_4632__(/*! path */ "path");
const resolveCommand = __nested_webpack_require_4632__(/*! ./util/resolveCommand */ "./src/cross-spawn/lib/util/resolveCommand.js");
const escape = __nested_webpack_require_4632__(/*! ./util/escape */ "./src/cross-spawn/lib/util/escape.js");
const readShebang = __nested_webpack_require_4632__(/*! ./util/readShebang */ "./src/cross-spawn/lib/util/readShebang.js");
const isWin = process.platform === 'win32';
const isExecutableRegExp = /\.(?:com|exe)$/i;
const isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
function detectShebang(parsed) {
parsed.file = resolveCommand(parsed);
const shebang = parsed.file && readShebang(parsed.file);
if (shebang) {
parsed.args.unshift(parsed.file);
parsed.command = shebang;
return resolveCommand(parsed);
}
return parsed.file;
}
function parseNonShell(parsed) {
if (!isWin) {
return parsed;
}
// Detect & add support for shebangs
const commandFile = detectShebang(parsed);
// We don't need a shell if the command filename is an executable
const needsShell = !isExecutableRegExp.test(commandFile);
// If a shell is required, use cmd.exe and take care of escaping everything correctly
// Note that `forceShell` is an hidden option used only in tests
if (parsed.options.forceShell || needsShell) {
// Need to double escape meta chars if the command is a cmd-shim located in `node_modules/.bin/`
// The cmd-shim simply calls execute the package bin file with NodeJS, proxying any argument
// Because the escape of metachars with ^ gets interpreted when the cmd.exe is first called,
// we need to double escape them
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
// Normalize posix paths into OS compatible paths (e.g.: foo/bar -> foo\bar)
// This is necessary otherwise it will always fail with ENOENT in those cases
parsed.command = path.normalize(parsed.command);
// Escape command & arguments
parsed.command = escape.command(parsed.command);
parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
const shellCommand = [parsed.command].concat(parsed.args).join(' ');
parsed.args = ['/d', '/s', '/c', `"${shellCommand}"`];
parsed.command = process.env.comspec || 'cmd.exe';
parsed.options.windowsVerbatimArguments = true; // Tell node's spawn that the arguments are already escaped
}
return parsed;
}
function parse(command, args, options) {
// Normalize arguments, similar to nodejs
if (args && !Array.isArray(args)) {
options = args;
args = null;
}
args = args ? args.slice(0) : []; // Clone array to avoid changing the original
// 添加windows默认不显示
// let defaultConfig = {windowsHide:true};
let defaultConfig = {};
options = Object.assign(defaultConfig, options); // Clone object to avoid changing the original
// Build our parsed object
const parsed = {
command,
args,
options,
file: undefined,
original: {
command,
args,
},
};
// Delegate further parsing to shell or non-shell
return options.shell ? parsed : parseNonShell(parsed);
}
module.exports = parse;
/***/ }),
/***/ "./src/cross-spawn/lib/util/escape.js":
/*!********************************************!*\
!*** ./src/cross-spawn/lib/util/escape.js ***!
\********************************************/
/***/ ((module) => {
"use strict";
// See http://www.robvanderwoude.com/escapechars.php
const metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g;
function escapeCommand(arg) {
// Escape meta chars
arg = arg.replace(metaCharsRegExp, '^$1');
return arg;
}
function escapeArgument(arg, doubleEscapeMetaChars) {
// Convert to string
arg = `${arg}`;
// Algorithm below is based on https://qntm.org/cmd
// Sequence of backslashes followed by a double quote:
// double up all the backslashes and escape the double quote
arg = arg.replace(/(\\*)"/g, '$1$1\\"');
// Sequence of backslashes followed by the end of the string
// (which will become a double quote later):
// double up all the backslashes
arg = arg.replace(/(\\*)$/, '$1$1');
// All other backslashes occur literally
// Quote the whole thing:
arg = `"${arg}"`;
// Escape meta chars
arg = arg.replace(metaCharsRegExp, '^$1');
// Double escape meta chars if necessary
if (doubleEscapeMetaChars) {
arg = arg.replace(metaCharsRegExp, '^$1');
}
return arg;
}
module.exports.command = escapeCommand;
module.exports.argument = escapeArgument;
/***/ }),
/***/ "./src/cross-spawn/lib/util/path-key/path-key.js":
/*!*******************************************************!*\
!*** ./src/cross-spawn/lib/util/path-key/path-key.js ***!
\*******************************************************/
/***/ ((module) => {
"use strict";
const pathKey = (options = {}) => {
const environment = options.env || process.env;
const platform = options.platform || process.platform;
if (platform !== 'win32') {
return 'PATH';
}
return Object.keys(environment).reverse().find(key => key.toUpperCase() === 'PATH') || 'Path';
};
module.exports = pathKey;
// TODO: Remove this for the next major release
module.exports["default"] = pathKey;
/***/ }),
/***/ "./src/cross-spawn/lib/util/readShebang.js":
/*!*************************************************!*\
!*** ./src/cross-spawn/lib/util/readShebang.js ***!
\*************************************************/
/***/ ((module, __unused_webpack_exports, __nested_webpack_require_10543__) => {
"use strict";
const fs = __nested_webpack_require_10543__(/*! fs */ "fs");
// const shebangCommand = require('shebang-command');
const shebangCommand = __nested_webpack_require_10543__(/*! ./shebang-command/shebang-command.js */ "./src/cross-spawn/lib/util/shebang-command/shebang-command.js");
function readShebang(command) {
// Read the first 150 bytes from the file
const size = 150;
const buffer = Buffer.alloc(size);
let fd;
try {
fd = fs.openSync(command, 'r');
fs.readSync(fd, buffer, 0, size, 0);
fs.closeSync(fd);
} catch (e) { /* Empty */ }
// Attempt to extract shebang (null is returned if not a shebang)
return shebangCommand(buffer.toString());
}
module.exports = readShebang;
/***/ }),
/***/ "./src/cross-spawn/lib/util/resolveCommand.js":
/*!****************************************************!*\
!*** ./src/cross-spawn/lib/util/resolveCommand.js ***!
\****************************************************/
/***/ ((module, __unused_webpack_exports, __nested_webpack_require_11602__) => {
"use strict";
const path = __nested_webpack_require_11602__(/*! path */ "path");
// const which = require('which');
const which = __nested_webpack_require_11602__(/*! ./which/which */ "./src/cross-spawn/lib/util/which/which.js");
const getPathKey = __nested_webpack_require_11602__(/*! ./path-key/path-key */ "./src/cross-spawn/lib/util/path-key/path-key.js");
function resolveCommandAttempt(parsed, withoutPathExt) {
const env = parsed.options.env || process.env;
const cwd = process.cwd();
const hasCustomCwd = parsed.options.cwd != null;
// Worker threads do not have process.chdir()
const shouldSwitchCwd = hasCustomCwd && process.chdir !== undefined && !process.chdir.disabled;
// If a custom `cwd` was specified, we need to change the process cwd
// because `which` will do stat calls but does not support a custom cwd
if (shouldSwitchCwd) {
try {
process.chdir(parsed.options.cwd);
} catch (err) {
/* Empty */
}
}
let resolved;
try {
resolved = which.sync(parsed.command, {
path: env[getPathKey({ env })],
pathExt: withoutPathExt ? path.delimiter : undefined,
});
} catch (e) {
/* Empty */
} finally {
if (shouldSwitchCwd) {
process.chdir(cwd);
}
}
// If we successfully resolved, ensure that an absolute path is returned
// Note that when a custom `cwd` was used, we need to resolve to an absolute path based on it
if (resolved) {
resolved = path.resolve(hasCustomCwd ? parsed.options.cwd : '', resolved);
}
return resolved;
}
function resolveCommand(parsed) {
return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true);
}
module.exports = resolveCommand;
/***/ }),
/***/ "./src/cross-spawn/lib/util/shebang-command/shebang-command.js":
/*!*********************************************************************!*\
!*** ./src/cross-spawn/lib/util/shebang-command/shebang-command.js ***!
\*********************************************************************/
/***/ ((module, __unused_webpack_exports, __nested_webpack_require_13798__) => {
"use strict";
// const shebangRegex = require('shebang-regex');
const shebangRegex = __nested_webpack_require_13798__(/*! ./shebang-regex/shebang-regex.js */ "./src/cross-spawn/lib/util/shebang-command/shebang-regex/shebang-regex.js");
module.exports = (string = '') => {
const match = string.match(shebangRegex);
if (!match) {
return null;
}
const [path, argument] = match[0].replace(/#! ?/, '').split(' ');
const binary = path.split('/').pop();
if (binary === 'env') {
return argument;
}
return argument ? `${binary} ${argument}` : binary;
};
/***/ }),
/***/ "./src/cross-spawn/lib/util/shebang-command/shebang-regex/shebang-regex.js":
/*!*********************************************************************************!*\
!*** ./src/cross-spawn/lib/util/shebang-command/shebang-regex/shebang-regex.js ***!
\*********************************************************************************/
/***/ ((module) => {
"use strict";
module.exports = /^#!(.*)/;
/***/ }),
/***/ "./src/cross-spawn/lib/util/which/isexe/isexe.js":
/*!*******************************************************!*\
!*** ./src/cross-spawn/lib/util/which/isexe/isexe.js ***!
\*******************************************************/
/***/ ((module, __unused_webpack_exports, __nested_webpack_require_15112__) => {
var fs = __nested_webpack_require_15112__(/*! fs */ "fs")
var core
if (process.platform === 'win32' || __nested_webpack_require_15112__.g.TESTING_WINDOWS) {
core = __nested_webpack_require_15112__(/*! ./windows.js */ "./src/cross-spawn/lib/util/which/isexe/windows.js")
} else {
core = __nested_webpack_require_15112__(/*! ./mode.js */ "./src/cross-spawn/lib/util/which/isexe/mode.js")
}
module.exports = isexe
isexe.sync = sync
function isexe (path, options, cb) {
if (typeof options === 'function') {
cb = options
options = {}
}
if (!cb) {
if (typeof Promise !== 'function') {
throw new TypeError('callback not provided')
}
return new Promise(function (resolve, reject) {
isexe(path, options || {}, function (er, is) {
if (er) {
reject(er)
} else {
resolve(is)
}
})
})
}
core(path, options || {}, function (er, is) {
// ignore EACCES because that just means we aren't allowed to run it
if (er) {
if (er.code === 'EACCES' || options && options.ignoreErrors) {
er = null
is = false
}
}
cb(er, is)
})
}
function sync (path, options) {
// my kingdom for a filtered catch
try {
return core.sync(path, options || {})
} catch (er) {
if (options && options.ignoreErrors || er.code === 'EACCES') {
return false
} else {
throw er
}
}
}
/***/ }),
/***/ "./src/cross-spawn/lib/util/which/isexe/mode.js":
/*!******************************************************!*\
!*** ./src/cross-spawn/lib/util/which/isexe/mode.js ***!
\******************************************************/
/***/ ((module, __unused_webpack_exports, __nested_webpack_require_16850__) => {
module.exports = isexe
isexe.sync = sync
var fs = __nested_webpack_require_16850__(/*! fs */ "fs")
function isexe (path, options, cb) {
fs.stat(path, function (er, stat) {
cb(er, er ? false : checkStat(stat, options))
})
}
function sync (path, options) {
return checkStat(fs.statSync(path), options)
}
function checkStat (stat, options) {
return stat.isFile() && checkMode(stat, options)
}
function checkMode (stat, options) {
var mod = stat.mode
var uid = stat.uid
var gid = stat.gid
var myUid = options.uid !== undefined ?
options.uid : process.getuid && process.getuid()
var myGid = options.gid !== undefined ?
options.gid : process.getgid && process.getgid()
var u = parseInt('100', 8)
var g = parseInt('010', 8)
var o = parseInt('001', 8)
var ug = u | g
var ret = (mod & o) ||
(mod & g) && gid === myGid ||
(mod & u) && uid === myUid ||
(mod & ug) && myUid === 0
return ret
}
/***/ }),
/***/ "./src/cross-spawn/lib/util/which/isexe/windows.js":
/*!*********************************************************!*\
!*** ./src/cross-spawn/lib/util/which/isexe/windows.js ***!
\*********************************************************/
/***/ ((module, __unused_webpack_exports, __nested_webpack_require_18151__) => {
module.exports = isexe
isexe.sync = sync
var fs = __nested_webpack_require_18151__(/*! fs */ "fs")
function checkPathExt (path, options) {
var pathext = options.pathExt !== undefined ?
options.pathExt : process.env.PATHEXT
if (!pathext) {
return true
}
pathext = pathext.split(';')
if (pathext.indexOf('') !== -1) {
return true
}
for (var i = 0; i < pathext.length; i++) {
var p = pathext[i].toLowerCase()
if (p && path.substr(-p.length).toLowerCase() === p) {
return true
}
}
return false
}
function checkStat (stat, path, options) {
if (!stat.isSymbolicLink() && !stat.isFile()) {
return false
}
return checkPathExt(path, options)
}
function isexe (path, options, cb) {
fs.stat(path, function (er, stat) {
cb(er, er ? false : checkStat(stat, path, options))
})
}
function sync (path, options) {
return checkStat(fs.statSync(path), path, options)
}
/***/ }),
/***/ "./src/cross-spawn/lib/util/which/which.js":
/*!*************************************************!*\
!*** ./src/cross-spawn/lib/util/which/which.js ***!
\*************************************************/
/***/ ((module, __unused_webpack_exports, __nested_webpack_require_19402__) => {
const isWindows = process.platform === 'win32' ||
process.env.OSTYPE === 'cygwin' ||
process.env.OSTYPE === 'msys'
const path = __nested_webpack_require_19402__(/*! path */ "path")
const COLON = isWindows ? ';' : ':'
// const isexe = require('isexe')
const isexe = __nested_webpack_require_19402__(/*! ./isexe/isexe */ "./src/cross-spawn/lib/util/which/isexe/isexe.js")
const getNotFoundError = (cmd) =>
Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' })
const getPathInfo = (cmd, opt) => {
const colon = opt.colon || COLON
// If it has a slash, then we don't bother searching the pathenv.
// just check the file itself, and that's it.
const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? ['']
: (
[
// windows always checks the cwd first
...(isWindows ? [process.cwd()] : []),
...(opt.path || process.env.PATH ||
/* istanbul ignore next: very unusual */ '').split(colon),
]
)
const pathExtExe = isWindows
? opt.pathExt || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM'
: ''
const pathExt = isWindows ? pathExtExe.split(colon) : ['']
if (isWindows) {
if (cmd.indexOf('.') !== -1 && pathExt[0] !== '')
pathExt.unshift('')
}
return {
pathEnv,
pathExt,
pathExtExe,
}
}
const which = (cmd, opt, cb) => {
if (typeof opt === 'function') {
cb = opt
opt = {}
}
if (!opt)
opt = {}
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt)
const found = []
const step = i => new Promise((resolve, reject) => {
if (i === pathEnv.length)
return opt.all && found.length ? resolve(found)
: reject(getNotFoundError(cmd))
const ppRaw = pathEnv[i]
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw
const pCmd = path.join(pathPart, cmd)
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd
: pCmd
resolve(subStep(p, i, 0))
})
const subStep = (p, i, ii) => new Promise((resolve, reject) => {
if (ii === pathExt.length)
return resolve(step(i + 1))
const ext = pathExt[ii]
isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
if (!er && is) {
if (opt.all)
found.push(p + ext)
else
return resolve(p + ext)
}
return resolve(subStep(p, i, ii + 1))
})
})
return cb ? step(0).then(res => cb(null, res), cb) : step(0)
}
const whichSync = (cmd, opt) => {
opt = opt || {}
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt)
const found = []
for (let i = 0; i < pathEnv.length; i ++) {
const ppRaw = pathEnv[i]
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw
const pCmd = path.join(pathPart, cmd)
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd
: pCmd
for (let j = 0; j < pathExt.length; j ++) {
const cur = p + pathExt[j]
try {
const is = isexe.sync(cur, { pathExt: pathExtExe })
if (is) {
if (opt.all)
found.push(cur)
else
return cur
}
} catch (ex) {}
}
}
if (opt.all && found.length)
return found
if (opt.nothrow)
return null
throw getNotFoundError(cmd)
}
module.exports = which
which.sync = whichSync
/***/ }),
/***/ "app-lib-log":
/*!******************************!*\
!*** external "app-lib-log" ***!
\******************************/
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE_app_lib_log__;
/***/ }),
/***/ "child_process":
/*!********************************!*\
!*** external "child_process" ***!
\********************************/
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE_child_process__;
/***/ }),
/***/ "fs":
/*!*********************!*\
!*** external "fs" ***!
\*********************/
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE_fs__;
/***/ }),
/***/ "path":
/*!***********************!*\
!*** external "path" ***!
\***********************/
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE_path__;
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __nested_webpack_require_23948__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __nested_webpack_require_23948__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/global */
/******/ (() => {
/******/ __nested_webpack_require_23948__.g = (function() {
/******/ if (typeof globalThis === 'object') return globalThis;
/******/ try {
/******/ return this || new Function('return this')();
/******/ } catch (e) {
/******/ if (typeof window === 'object') return window;
/******/ }
/******/ })();
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
var exports = __webpack_exports__;
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
// 支持同步 异步 bat/shell 脚本和命令
// 同步 spawn
// spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
// 异步 pawn.sync
// spawn.sync('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
// 异步执行多个bat文件
// spawn.sync('./demo01/ping.bat', [], { stdio: 'inherit' });
// spawn.sync('./demo01/echo.bat', [], { stdio: 'inherit' });
// 注意:
// 有的命令会晃动 eg: tree
// 一直晃动
// spawn.sync('tree.bat', [], { stdio: 'inherit',cwd:'./demo01' });
// cwd 有的命令 tree 会抖动
// spawn.sync('echo.bat', [], { stdio: 'inherit', cwd: './demo01/' });
// https://github.com/moxystudio/node-cross-spawn
// https://nodejs.org/docs/latest-v14.x/api/child_process.html#child_process_options_stdio
// const spawn = require('cross-spawn');
const spawn = __nested_webpack_require_23948__(/*! ./cross-spawn/index.js */ "./src/cross-spawn/index.js");
const {log} = __nested_webpack_require_23948__(/*! app-lib-log */ "app-lib-log");
const isDebug = ()=>{
const { DEBUG } = process?.env || {};
// 命令行参数优先 直接设置环境变量DEBUG 或者
let debug = process.argv.slice(2).includes('--debug') || DEBUG;
return debug;
}
/**
* ---
* ##### 数据类型判断
* @function
* @param {string} commondOrFile 可执行的文件路径或者文件
* @param {array} args 所有命令行参数
* @param {object} options 执行参数配置
* @param {boolean} [isAsync=true] 是否同步
* @returns {null} 无返回
*
* ##### Examples
* option下支持的参数
* * stidio 支持的 [pipe,overlapped,ignore,inherit]
* ```
* inherit // Child will use parent's stdios.
* stdio: ['pipe', 'pipe', process.stderr] // Spawn child sharing only stderr.
* ```
*/
const exec = (commondOrFile, args,opt, isAsync = true) => {
let fn = isAsync ? spawn.sync : spawn;
let options = opt || {};
if (!options.stdio) {
options.stdio = isDebug() ? 'inherit' : ['ignore','ignore','inherit'];
}
// 默认模式内部输出
// debug模式输出全部
// 否则值输出错误
log.md.apply(log, [fn.name, commondOrFile, JSON.stringify(args),opt, options, isAsync]);
return fn(commondOrFile, args, options)
}
exports.exec = exec;
})();
/******/ return __webpack_exports__;
/******/ })()
;
});
//# sourceMappingURL=index.js.map
/***/ }),
/***/ 798:
/***/ (function(module) {
(function webpackUniversalModuleDefinition(root, factory) {
if(true)
module.exports = factory();
else { var i, a; }
})(this, () => {
return /******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ // The require scope
/******/ var __nested_webpack_require_468__ = {};
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __nested_webpack_require_468__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__nested_webpack_require_468__.o(definition, key) && !__nested_webpack_require_468__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/global */
/******/ (() => {
/******/ __nested_webpack_require_468__.g = (function() {
/******/ if (typeof globalThis === 'object') return globalThis;
/******/ try {
/******/ return this || new Function('return this')();
/******/ } catch (e) {
/******/ if (typeof window === 'object') return window;
/******/ }
/******/ })();
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __nested_webpack_require_468__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __nested_webpack_require_468__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
__nested_webpack_require_468__.r(__webpack_exports__);
/* harmony export */ __nested_webpack_require_468__.d(__webpack_exports__, {
/* harmony export */ ENV: () => (/* binding */ ENV),
/* harmony export */ bindToGlobal: () => (/* binding */ bindToGlobal),
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
/* harmony export */ getEnv: () => (/* binding */ getEnv),
/* harmony export */ getGlobal: () => (/* binding */ getGlobal),
/* harmony export */ getbindData: () => (/* binding */ getbindData),
/* harmony export */ isBindToGlobal: () => (/* binding */ isBindToGlobal),
/* harmony export */ isBroswerEnv: () => (/* binding */ isBroswerEnv),
/* harmony export */ isNodeEnv: () => (/* binding */ isNodeEnv)
/* harmony export */ });
/**
* 支持的环境变量
* ```
* * NODE: 'node', // ndoejs 环境
* * BROWSER: 'browser', // 浏览器环境
* ```
*/
const ENV = {
NODE: 'node', // ndoejs 环境
BROWSER: 'browser', // 浏览器环境
}
/**
* 获取当前环境
*
* @function
* @returns {string} 当前环境常量
*/
const getEnv = () => {
let root = getGlobal();
return root.window == root ? ENV.BROWSER : ENV.NODE;
}
/**
* 判断是否为nodejs环境
*
* @function
* @returns {Boolean}
* * true 是nodejs环境
* * false 不是nodejs环境
*/
const isNodeEnv = () => getEnv() === ENV.NODE;
/**
* 判断是否为浏览器环境
*
* @function
* @returns {Boolean}
* * true 是浏览器环境
* * false 不是浏览器环境
*/
const isBroswerEnv = () => getEnv() === ENV.BROWSER;
/**
* 获取全局变量
*
*
* @returns {Object} - 获取的全局变量
* * window
* * global
* @description
* 获取当前运行环境的全局变量
* * 支持浏览器 window
* * 支持nodejs gloabl
* @function
*/
const getGlobal = () => {
let root;
if (typeof __nested_webpack_require_468__.g === 'object') {
root = __nested_webpack_require_468__.g;
} else if (typeof window === 'object') {
root = window;
}
return root;
}
/**
* 获取绑定数据
*
*
* @param {string} namespace 命名空间
* @returns {any} 已绑定的值
* @function
*/
const getbindData = (namespace) => {
let root = getGlobal();
if (!root) throw new Error('未找到当前环境的全局变量');
return root[namespace];
}
/**
* 绑定数据到全局
*
*
* @param {string} namespace 命名空间
* @param {any} bindData 绑定数据
* @param {boolean} [isForce=false] 是否强制绑定 - 存在当前值时,进行强制绑定
* @returns {any} 全局已绑定的值
* @function
*/
const bindToGlobal = (namespace, bindData, isForce) => {
let isBind = isBindToGlobal(namespace);
if (isBind && !isForce) return getbindData(namespace);
let root = getGlobal()
root[namespace] = bindData;
return bindData;
}
/**
* 是否也绑定到全局
*
*
* @param {string} namespace 命名空间
* @param {Object} [needbindData='undefined'] - 绑定对象
* @returns {boolean} 是否绑定
* * true 已绑定
* * false 未绑定
* @description
* 是否也绑定到全局
* * needbindData 绑定对象不为undefined时:
* * 比对值相等 或者 json 序列化后相等 则表示已绑定
* @function
*/
const isBindToGlobal = (namespace, needbindData) => {
if (!namespace) throw new Error('必须执行绑定名称');
let root = getGlobal();
/**
* @throws {DOMException}
*/
if (!root) throw new Error('未找到当前环境的全局变量');
let bindData = root[namespace];
// 全局对象上的属性为undifed 表示未绑定
if (void 0 === bindData) return false;
// 需要比对指定绑定的值 值直接相等或者json 序列化后相等 则表示1已绑定
if (void 0 != needbindData) {
return bindData === needbindData || JSON.stringify(bindData) === JSON.stringify(needbindData);
}
return true;
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (bindToGlobal);
/******/ return __webpack_exports__;
/******/ })()
;
});
//# sourceMappingURL=index.js.map
/***/ }),
/***/ 810:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
(function webpackUniversalModuleDefinition(root, factory) {
if(true)
module.exports = factory(__webpack_require__(798));
else { var i, a; }
})(this, (__WEBPACK_EXTERNAL_MODULE_app_lib_global__) => {
return /******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "app-lib-global":
/*!*********************************!*\
!*** external "app-lib-global" ***!
\*********************************/
/***/ ((module) => {
module.exports = __WEBPACK_EXTERNAL_MODULE_app_lib_global__;
/***/ }),
/***/ "./src/chalk/source/index.js":
/*!***********************************!*\
!*** ./src/chalk/source/index.js ***!
\***********************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __nested_webpack_require_1095__) => {
__nested_webpack_require_1095__.r(__webpack_exports__);
/* harmony export */ __nested_webpack_require_1095__.d(__webpack_exports__, {
/* harmony export */ Chalk: () => (/* binding */ Chalk),
/* harmony export */ backgroundColorNames: () => (/* reexport safe */ _ansi_styles__WEBPACK_IMPORTED_MODULE_0__.backgroundColorNames),
/* harmony export */ backgroundColors: () => (/* reexport safe */ _ansi_styles__WEBPACK_IMPORTED_MODULE_0__.backgroundColorNames),
/* harmony export */ chalkStderr: () => (/* binding */ chalkStderr),
/* harmony export */ colorNames: () => (/* reexport safe */ _ansi_styles__WEBPACK_IMPORTED_MODULE_0__.colorNames),
/* harmony export */ colors: () => (/* reexport safe */ _ansi_styles__WEBPACK_IMPORTED_MODULE_0__.colorNames),
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
/* harmony export */ foregroundColorNames: () => (/* reexport safe */ _ansi_styles__WEBPACK_IMPORTED_MODULE_0__.foregroundColorNames),
/* harmony export */ foregroundColors: () => (/* reexport safe */ _ansi_styles__WEBPACK_IMPORTED_MODULE_0__.foregroundColorNames),
/* harmony export */ modifierNames: () => (/* reexport safe */ _ansi_styles__WEBPACK_IMPORTED_MODULE_0__.modifierNames),
/* harmony export */ modifiers: () => (/* reexport safe */ _ansi_styles__WEBPACK_IMPORTED_MODULE_0__.modifierNames),
/* harmony export */ supportsColor: () => (/* binding */ stdoutColor),
/* harmony export */ supportsColorStderr: () => (/* binding */ stderrColor)
/* harmony export */ });
/* harmony import */ var _ansi_styles__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_1095__(/*! ./vendor/ansi-styles/index.js */ "./src/chalk/source/vendor/ansi-styles/index.js");
/* harmony import */ var _supports_color__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_1095__(/*! #supports-color */ "./src/chalk/source/vendor/supports-color/browser.js");
/* harmony import */ var _utilities_js__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_1095__(/*! ./utilities.js */ "./src/chalk/source/utilities.js");
const {stdout: stdoutColor, stderr: stderrColor} = _supports_color__WEBPACK_IMPORTED_MODULE_1__["default"];
const GENERATOR = Symbol('GENERATOR');
const STYLER = Symbol('STYLER');
const IS_EMPTY = Symbol('IS_EMPTY');
// `supportsColor.level` → `ansiStyles.color[name]` mapping
const levelMapping = [
'ansi',
'ansi',
'ansi256',
'ansi16m',
];
const styles = Object.create(null);
const applyOptions = (object, options = {}) => {
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
throw new Error('The `level` option should be an integer from 0 to 3');
}
// Detect level if not set manually
const colorLevel = stdoutColor ? stdoutColor.level : 0;
object.level = options.level === undefined ? colorLevel : options.level;
};
class Chalk {
constructor(options) {
// eslint-disable-next-line no-constructor-return
return chalkFactory(options);
}
}
const chalkFactory = options => {
const chalk = (...strings) => strings.join(' ');
applyOptions(chalk, options);
Object.setPrototypeOf(chalk, createChalk.prototype);
return chalk;
};
function createChalk(options) {
return chalkFactory(options);
}
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
for (const [styleName, style] of Object.entries(_ansi_styles__WEBPACK_IMPORTED_MODULE_0__["default"])) {
styles[styleName] = {
get() {
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
Object.defineProperty(this, styleName, {value: builder});
return builder;
},
};
}
styles.visible = {
get() {
const builder = createBuilder(this, this[STYLER], true);
Object.defineProperty(this, 'visible', {value: builder});
return builder;
},
};
const getModelAnsi = (model, level, type, ...arguments_) => {
if (model === 'rgb') {
if (level === 'ansi16m') {
return _ansi_styles__WEBPACK_IMPORTED_MODULE_0__["default"][type].ansi16m(...arguments_);
}
if (level === 'ansi256') {
return _ansi_styles__WEBPACK_IMPORTED_MODULE_0__["default"][type].ansi256(_ansi_styles__WEBPACK_IMPORTED_MODULE_0__["default"].rgbToAnsi256(...arguments_));
}
return _ansi_styles__WEBPACK_IMPORTED_MODULE_0__["default"][type].ansi(_ansi_styles__WEBPACK_IMPORTED_MODULE_0__["default"].rgbToAnsi(...arguments_));
}
if (model === 'hex') {
return getModelAnsi('rgb', level, type, ..._ansi_styles__WEBPACK_IMPORTED_MODULE_0__["default"].hexToRgb(...arguments_));
}
return _ansi_styles__WEBPACK_IMPORTED_MODULE_0__["default"][type][model](...arguments_);
};
const usedModels = ['rgb', 'hex', 'ansi256'];
for (const model of usedModels) {
styles[model] = {
get() {
const {level} = this;
return function (...arguments_) {
const styler = createStyler(getModelAnsi(model, levelMapping[level], 'color', ...arguments_), _ansi_styles__WEBPACK_IMPORTED_MODULE_0__["default"].color.close, this[STYLER]);
return createBuilder(this, styler, this[IS_EMPTY]);
};
},
};
const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);
styles[bgModel] = {
get() {
const {level} = this;
return function (...arguments_) {
const styler = createStyler(getModelAnsi(model, levelMapping[level], 'bgColor', ...arguments_), _ansi_styles__WEBPACK_IMPORTED_MODULE_0__["default"].bgColor.close, this[STYLER]);
return createBuilder(this, styler, this[IS_EMPTY]);
};
},
};
}
const proto = Object.defineProperties(() => {}, {
...styles,
level: {
enumerable: true,
get() {
return this[GENERATOR].level;
},
set(level) {
this[GENERATOR].level = level;
},
},
});
const createStyler = (open, close, parent) => {
let openAll;
let closeAll;
if (parent === undefined) {
openAll = open;
closeAll = close;
} else {
openAll = parent.openAll + open;
closeAll = close + parent.closeAll;
}
return {
open,
close,
openAll,
closeAll,
parent,
};
};
const createBuilder = (self, _styler, _isEmpty) => {
// Single argument is hot path, implicit coercion is faster than anything
// eslint-disable-next-line no-implicit-coercion
const builder = (...arguments_) => applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' '));
// We alter the prototype because we must return a function, but there is
// no way to create a function with a different prototype
Object.setPrototypeOf(builder, proto);
builder[GENERATOR] = self;
builder[STYLER] = _styler;
builder[IS_EMPTY] = _isEmpty;
return builder;
};
const applyStyle = (self, string) => {
if (self.level <= 0 || !string) {
return self[IS_EMPTY] ? '' : string;
}
let styler = self[STYLER];
if (styler === undefined) {
return string;
}
const {openAll, closeAll} = styler;
if (string.includes('\u001B')) {
while (styler !== undefined) {
// Replace any instances already present with a re-opening code
// otherwise only the part of the string until said closing code
// will be colored, and the rest will simply be 'plain'.
string = (0,_utilities_js__WEBPACK_IMPORTED_MODULE_2__.stringReplaceAll)(string, styler.close, styler.open);
styler = styler.parent;
}
}
// We can move both next actions out of loop, because remaining actions in loop won't have
// any/visible effect on parts we add here. Close the styling before a linebreak and reopen
// after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92
const lfIndex = string.indexOf('\n');
if (lfIndex !== -1) {
string = (0,_utilities_js__WEBPACK_IMPORTED_MODULE_2__.stringEncaseCRLFWithFirstIndex)(string, closeAll, openAll, lfIndex);
}
return openAll + string + closeAll;
};
Object.defineProperties(createChalk.prototype, styles);
const chalk = createChalk();
const chalkStderr = createChalk({level: stderrColor ? stderrColor.level : 0});
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (chalk);
/***/ }),
/***/ "./src/chalk/source/utilities.js":
/*!***************************************!*\
!*** ./src/chalk/source/utilities.js ***!
\***************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __nested_webpack_require_9470__) => {
__nested_webpack_require_9470__.r(__webpack_exports__);
/* harmony export */ __nested_webpack_require_9470__.d(__webpack_exports__, {
/* harmony export */ stringEncaseCRLFWithFirstIndex: () => (/* binding */ stringEncaseCRLFWithFirstIndex),
/* harmony export */ stringReplaceAll: () => (/* binding */ stringReplaceAll)
/* harmony export */ });
// TODO: When targeting Node.js 16, use `String.prototype.replaceAll`.
function stringReplaceAll(string, substring, replacer) {
let index = string.indexOf(substring);
if (index === -1) {
return string;
}
const substringLength = substring.length;
let endIndex = 0;
let returnValue = '';
do {
returnValue += string.slice(endIndex, index) + substring + replacer;
endIndex = index + substringLength;
index = string.indexOf(substring, endIndex);
} while (index !== -1);
returnValue += string.slice(endIndex);
return returnValue;
}
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
let endIndex = 0;
let returnValue = '';
do {
const gotCR = string[index - 1] === '\r';
returnValue += string.slice(endIndex, (gotCR ? index - 1 : index)) + prefix + (gotCR ? '\r\n' : '\n') + postfix;
endIndex = index + 1;
index = string.indexOf('\n', endIndex);
} while (index !== -1);
returnValue += string.slice(endIndex);
return returnValue;
}
/***/ }),
/***/ "./src/chalk/source/vendor/ansi-styles/index.js":
/*!******************************************************!*\
!*** ./src/chalk/source/vendor/ansi-styles/index.js ***!
\******************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __nested_webpack_require_11151__) => {
__nested_webpack_require_11151__.r(__webpack_exports__);
/* harmony export */ __nested_webpack_require_11151__.d(__webpack_exports__, {
/* harmony export */ backgroundColorNames: () => (/* binding */ backgroundColorNames),
/* harmony export */ colorNames: () => (/* binding */ colorNames),
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
/* harmony export */ foregroundColorNames: () => (/* binding */ foregroundColorNames),
/* harmony export */ modifierNames: () => (/* binding */ modifierNames)
/* harmony export */ });
const ANSI_BACKGROUND_OFFSET = 10;
const wrapAnsi16 = (offset = 0) => code => `\u001B[${code + offset}m`;
const wrapAnsi256 = (offset = 0) => code => `\u001B[${38 + offset};5;${code}m`;
const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`;
const styles = {
modifier: {
reset: [0, 0],
// 21 isn't widely supported and 22 does the same thing
bold: [1, 22],
dim: [2, 22],
italic: [3, 23],
underline: [4, 24],
overline: [53, 55],
inverse: [7, 27],
hidden: [8, 28],
strikethrough: [9, 29],
},
color: {
black: [30, 39],
red: [31, 39],
green: [32, 39],
yellow: [33, 39],
blue: [34, 39],
magenta: [35, 39],
cyan: [36, 39],
white: [37, 39],
// Bright color
blackBright: [90, 39],
gray: [90, 39], // Alias of `blackBright`
grey: [90, 39], // Alias of `blackBright`
redBright: [91, 39],
greenBright: [92, 39],
yellowBright: [93, 39],
blueBright: [94, 39],
magentaBright: [95, 39],
cyanBright: [96, 39],
whiteBright: [97, 39],
},
bgColor: {
bgBlack: [40, 49],
bgRed: [41, 49],
bgGreen: [42, 49],
bgYellow: [43, 49],
bgBlue: [44, 49],
bgMagenta: [45, 49],
bgCyan: [46, 49],
bgWhite: [47, 49],
// Bright color
bgBlackBright: [100, 49],
bgGray: [100, 49], // Alias of `bgBlackBright`
bgGrey: [100, 49], // Alias of `bgBlackBright`
bgRedBright: [101, 49],
bgGreenBright: [102, 49],
bgYellowBright: [103, 49],
bgBlueBright: [104, 49],
bgMagentaBright: [105, 49],
bgCyanBright: [106, 49],
bgWhiteBright: [107, 49],
},
};
const modifierNames = Object.keys(styles.modifier);
const foregroundColorNames = Object.keys(styles.color);
const backgroundColorNames = Object.keys(styles.bgColor);
const colorNames = [...foregroundColorNames, ...backgroundColorNames];
function assembleStyles() {
const codes = new Map();
for (const [groupName, group] of Object.entries(styles)) {
for (const [styleName, style] of Object.entries(group)) {
styles[styleName] = {
open: `\u001B[${style[0]}m`,
close: `\u001B[${style[1]}m`,
};
group[styleName] = styles[styleName];
codes.set(style[0], style[1]);
}
Object.defineProperty(styles, groupName, {
value: group,
enumerable: false,
});
}
Object.defineProperty(styles, 'codes', {
value: codes,
enumerable: false,
});
styles.color.close = '\u001B[39m';
styles.bgColor.close = '\u001B[49m';
styles.color.ansi = wrapAnsi16();
styles.color.ansi256 = wrapAnsi256();
styles.color.ansi16m = wrapAnsi16m();
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
// From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js
Object.defineProperties(styles, {
rgbToAnsi256: {
value(red, green, blue) {
// We use the extended greyscale palette here, with the exception of
// black and white. normal palette only has 4 greyscale shades.
if (red === green && green === blue) {
if (red < 8) {
return 16;
}
if (red > 248) {
return 231;
}
return Math.round(((red - 8) / 247) * 24) + 232;
}
return 16
+ (36 * Math.round(red / 255 * 5))
+ (6 * Math.round(green / 255 * 5))
+ Math.round(blue / 255 * 5);
},
enumerable: false,
},
hexToRgb: {
value(hex) {
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
if (!matches) {
return [0, 0, 0];
}
let [colorString] = matches;
if (colorString.length === 3) {
colorString = [...colorString].map(character => character + character).join('');
}
const integer = Number.parseInt(colorString, 16);
return [
/* eslint-disable no-bitwise */
(integer >> 16) & 0xFF,
(integer >> 8) & 0xFF,
integer & 0xFF,
/* eslint-enable no-bitwise */
];
},
enumerable: false,
},
hexToAnsi256: {
value: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
enumerable: false,
},
ansi256ToAnsi: {
value(code) {
if (code < 8) {
return 30 + code;
}
if (code < 16) {
return 90 + (code - 8);
}
let red;
let green;
let blue;
if (code >= 232) {
red = (((code - 232) * 10) + 8) / 255;
green = red;
blue = red;
} else {
code -= 16;
const remainder = code % 36;
red = Math.floor(code / 36) / 5;
green = Math.floor(remainder / 6) / 5;
blue = (remainder % 6) / 5;
}
const value = Math.max(red, green, blue) * 2;
if (value === 0) {
return 30;
}
// eslint-disable-next-line no-bitwise
let result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red));
if (value === 2) {
result += 60;
}
return result;
},
enumerable: false,
},
rgbToAnsi: {
value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
enumerable: false,
},
hexToAnsi: {
value: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
enumerable: false,
},
});
return styles;
}
const ansiStyles = assembleStyles();
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ansiStyles);
/***/ }),
/***/ "./src/chalk/source/vendor/supports-color/browser.js":
/*!***********************************************************!*\
!*** ./src/chalk/source/vendor/supports-color/browser.js ***!
\***********************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __nested_webpack_require_17540__) => {
__nested_webpack_require_17540__.r(__webpack_exports__);
/* harmony export */ __nested_webpack_require_17540__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* eslint-env browser */
let isBlinkBasedBrowser = false;
if (typeof navigator != 'undefined') {
isBlinkBasedBrowser = navigator && navigator.userAgentData
? navigator.userAgentData.brands.some(({ brand }) => brand === 'Chromium')
: /\b(Chrome|Chromium)\//.test(navigator.userAgent);
}
const colorSupport = isBlinkBasedBrowser ? {
level: 1,
hasBasic: true,
has256: false,
has16m: false,
} : false;
const supportsColor = {
stdout: colorSupport,
stderr: colorSupport,
};
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (supportsColor);
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __nested_webpack_require_18593__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __nested_webpack_require_18593__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __nested_webpack_require_18593__.n = (module) => {
/******/ var getter = module && module.__esModule ?
/******/ () => (module['default']) :
/******/ () => (module);
/******/ __nested_webpack_require_18593__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __nested_webpack_require_18593__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__nested_webpack_require_18593__.o(definition, key) && !__nested_webpack_require_18593__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __nested_webpack_require_18593__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __nested_webpack_require_18593__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
__nested_webpack_require_18593__.r(__webpack_exports__);
/* harmony export */ __nested_webpack_require_18593__.d(__webpack_exports__, {
/* harmony export */ ALL_FUNCTIONS: () => (/* binding */ ALL_FUNCTIONS),
/* harmony export */ LEVEL: () => (/* binding */ LEVEL),
/* harmony export */ Logger: () => (/* binding */ Logger),
/* harmony export */ TYPE: () => (/* binding */ TYPE),
/* harmony export */ create: () => (/* binding */ create),
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
/* harmony export */ log: () => (/* binding */ log)
/* harmony export */ });
/* harmony import */ var _chalk_source_index__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_18593__(/*! ./chalk/source/index */ "./src/chalk/source/index.js");
/* harmony import */ var app_lib_global__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_18593__(/*! app-lib-global */ "app-lib-global");
/* harmony import */ var app_lib_global__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__nested_webpack_require_18593__.n(app_lib_global__WEBPACK_IMPORTED_MODULE_1__);
/***************************************************************************************************
*
* * 注意
* 1. 由于类的注释 在jsdoc-to-md 的组件中不能显示,故将类内部的方法独立出来
* 2. 由于箭头函数没有this指向到类 同时为了能在实例上显示具体的执行方法,便于简写能一目了然 故使用函数式声明
*
* * 参考地址
* * https://jsdoc.app/ 官方文档
* * https://github.com/jsdoc/jsdoc github
*
* @ignore
***************************************************************************************************/
/**
*
* * 测试全局方法
* @constant ALL_FUNCTIONS
* @description
* * 日志级别相关方法
*
* |级别|堆栈|调试|日志|信息|成功|表格|时间|警告|错误|
* |-|-|-|-|-|-|-|-|-|-|
* |方法名|trace|debug|log|info|success|table|time|warn/warnNoTrace|error/errorNoTrace|
* |简写|t|d|l|i|s|T|tt|w/wn|e/wn|
* |模块化|mTrace|mDebug|mLog|mInfo|mSuccess|mTable|mTime|mWarn/mWarnNoTrace|mError/mErrorNoTrace|
* |简写|mt|md|ml|mi|ms|mT|mtt|mw/mwn|me/mwn|
*
* * 彩色转换与其他方法
* > 参考详细文档
*
*/
const ALL_FUNCTIONS = [];
/**
* @ignore
* 是否浏览器模式
*/
const isBroswer = (0,app_lib_global__WEBPACK_IMPORTED_MODULE_1__.isBroswerEnv)();
/**
* @ignore
* 环境变量
*/
const env = (0,app_lib_global__WEBPACK_IMPORTED_MODULE_1__.getEnv)();
/**
* @ignore
* 终端彩色打印
*/
const chalk = new _chalk_source_index__WEBPACK_IMPORTED_MODULE_0__.Chalk({ level: 2 });
/**
* 支持的打印类型
* @constant
* @name TYPE
* @description
* 日志类型
*
* |级别|堆栈|调试|日志|信息|成功|表格|时间|警告|错误|
* |-|-|-|-|-|-|-|-|-|-|
* |常量名称|TRACE|DEBUG|LOG|INFO|SUCCESS|TABLE|TIME|WARN|ERROR|
* |常量值|trace|debug|log|info|success|table|time|warn|error|
*/
const TYPE = {
TRACE: 'trace',
DEBUG: 'debug',
INFO: 'info',
LOG: 'log',
SUCCESS: 'success',
TABLE: 'table',
TIME: 'time',
WARN: 'warn',
ERROR: 'error',
};
/**
* 日志级别
* @constant
* @name LEVEL
* @description
* 日志级别
* * 通过setOption({level:number})进行打印高于该值(number)的日志
* * 调整该顺序值进行灵活打印
* * 或者只打印某几项日志
*
* |级别|堆栈|调试|日志|信息|成功|表格|时间|警告|错误|
* |-|-|-|-|-|-|-|-|-|-|
* |常量名|trace|debug|log|info|success|table|time|warn|error|
* |常量值|10|20|30|31|32|33|40|60|70|
*/
const LEVEL = {
trace: 10, // 跟踪 堆栈
debug: 20, // 调试
info: 30, // 信息
log: 31,// 元素的log
success: 32,// 成功--便于开发高亮标识
table: 33,
time: 40, // 时间--带时间戳
warn: 60, // 告警
error: 70 // 错误
};
// 多彩的配置
const colorful = {
node: {
maxCharLength: 9, // 显示级别的最大字符长度 9 即success+两个空格
textAlgin: 'right', // 支持left/right和center
space: "", // 级别标识后的间隔距离
module: { // 模块标识背景和颜色
background: '#0a0afb',
color: '#ffffff',
},
trace: {
background: '#4a4848',
color: '#ffffff'
},
debug: {
background: '#4a4848',
color: '#ffffff',
index: ' ', // 标识前缩进
},
info: {
background: '#08df08',
color: '#ffffff',
index: ' ', // 标识前缩进
},
success: {
background: '#0808ef',
color: '#ffffff',
index: ' ', // 标识前缩进
},
warn: {
background: '#ffff08',
color: '#ff0000',
},
error: {
background: '#f50303',
color: '#ffffff',
},
time: {
background: '#47b2b2',
color: '#ffffff',
index: ' ', // 标识前缩进
}
},
browser: {
maxCharLength: 9, // 显示级别的最大字符长度 9 即success+两个空格
textAlgin: 'right', // 支持left/right和center
// 缩进- 由于chrome浏览器对不同级别的日志打印有的带堆栈和三角 故对不带堆栈的进行缩进 保持对齐
index: "background: transparent;margin-left:4px;",
// 空间隔 多个标签之间得到间隔
space: "background: transparent;",
// 每种log的标签样式 便于开发中快速copy样式代码
trace: "background: linear-gradient(90deg, #b7b2b2,#8080804d, #b7b2b2); color:white; font-weight:bold; border-radius: 1px; ",
debug: "background:linear-gradient(70deg, #b7b2b2, #8080804d, #b7b2b2); color:white; font-weight:bold; border-radius: 1px;",
info: "background: linear-gradient(70deg, #00800085, #57d4c1,#57d4c1, #00800085); color:white; font-weight:bold;border-radius: 1px;",
success: "background: linear-gradient(70deg, #172bdca1, #0000ff36, #172bdca1); color:white; font-weight:bold;border-radius: 1px;",
time: "background: linear-gradient(70deg, #00bfffcf,#00bfff4f,#00bfffcf); color:white; font-weight:bold;border-radius: 1px;",
warn: "background: linear-gradient(90deg, #eab60e, #eab60e6e, #eab60e); color:yellow; font-weight:bold; border-radius: 1px;",
error: "background: linear-gradient(90deg, #ff00006b, #ff000033,#ff000033, #ff00006b); color:red; font-weight:bold; border-radius: 1px;",
// 日期标签
dateTime: "background: none; border: 1px #ad10da4d solid; color:#ad10dacf; font-weight:bold; border-radius: 1px;",
// 模块标签
module: "background: linear-gradient(70deg, #0a0afb, #44448a); color:white; font-weight:bold; border-radius: 1px;padding:0 5px"
}
};
/**
* 日志配置
* @constant
* @name option
* @description
* 默认配置
* * setOption - 进行设置
* * getOption - 获取当前的配置
*
* |参数名|参数类型|参数默认值|参数描述|备注|
* |-|-|-|-|-|
* |bindGlobalName|string|log|全局的名称|直接在windows或者nodejs环境中直接使用log即可|
* |level|number/array|20|打印日志级别|低于该级别的类型忽略输出/或者打印指定级别['warn',error]的日志|
* |moduleName|string|''|模块名称|模块打印的名称|mxx打印时直接输入自定义名称即可|
* |isModule|boolean|false|是否开启模块标识打印|关闭模块打印表示|
* |isColorful|boolean|true|是否开启彩色打印|
* |colorful|object|参考彩色配置|不同终端、不同级别颜色配置|
* |LEVEL|object|参考LEVEL|配置打印级别值|灵活调整日志级别顺序|
* |dateFormatter|string/function|'YYYY-MM-DD HH:mm:ss'|日期打印格式化输出|
* |onLogger|function|null|日志输出记录|用于日志的收集管理|
*/
const defaultOption = {
bindGlobalName: 'log',
level: 0,
moduleName: '',
isModule: false,
isColorful: true,
colorful: colorful[env],
LEVEL,
dateFormatter: 'YYYY-MM-DD HH:mm:ss',
onLogger: null,
};
const PLACE_HOLDER = '%c';
const MODULE_PLACE_HOLDER = '%s';
/**
* 默认日期格式化
* @ignore
*/
const formatDate = (date, fmt) => {
var o = {
"M+": date.getMonth() + 1, //月份
"D+": date.getDate(), //日
"H+": date.getHours(), //小时
"m+": date.getMinutes(), //分
"s+": date.getSeconds() //秒
};
if (/(Y+)/.test(fmt)) { //根据y的长度来截取年
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
}
return fmt;
}
/**********************************************************************************
*
* 便于MARKDOWN中显示 API 采用prototype形式
*
**********************************************************************************
*/
/**
* 设置配置
* * 设置后即刻生效
* * 后续日志打印按照该设置进行
* @function
* @param {object} option 参考默认option配置
* @returns {objcet} 新的参数配置option
*
*/
const setOption = function (option) {
this.option = { ...this.option, ...option };
return this.option;
}
/**
* 获取配置
* @function
* @returns {object} 参考默认option
*/
const getOption = function () {
return this.option;
}
/**
* 根据命令行终端参数动态设置日志级别
* * --debug
* * process.env.DEBUG
* 仅在nodejs中生效
* debug模式 默认级别为0 否则为21
* @name auotLevel/auotLogLevel
* @function
* @returns {object} log 日志实例
*/
const auotLogLevel = function () {
const { DEBUG } = process?.env || {};
// 命令行参数优先 直接设置环境变量DEBUG 或者
let debug = process.argv.slice(2).includes('--debug') || DEBUG;
this.setOption({ level: debug && debug != 'undefined' ? 0 : 21 });
}
/**********************************************************************************
* 直接设置颜色输出形式 [只适合nodejs]
**********************************************************************************
*/
/**
*
* 输出执行缩进 显示块长度 文件颜色 和背景色的 文本
* 1. option参数
* * indent 缩进
* * width 块的长度
* * algin 对齐
* * color 颜色
* * background 背景颜色
* @name tb/transTextColorBlock
* @function
* @param {string} text
* @param {object} opitons
* @returns {string} 彩色文案
*
*/
function transTextColorBlock(text, opitons) {
let { indent, width, algin, color, background } = opitons
return log.fill(indent || 0) + log.tx(log.autoFillText(text, width, algin), color, background);
}
/**
* 转换文本颜色
* @name tx/transTextColor
* @function
* @param {string} text 文本内容
* @param {string} color 文字颜色 hex 格式
* @param {string} background 背景颜色 hex 格式
* @returns {string} 彩色文案
*/
function transTextColor(text, color, background) {
let cTextFn = chalk.hex(color || '#ffffff');
if (background) {
cTextFn = cTextFn.bgHex(background);
}
return cTextFn(text)
}
/**
* 转换文本颜色并且打印
* * 不受级别控制
* @function
* @name txl/transTextColorAndLog
* @param {string} text 文本内容
* @param {string} color 文字颜色 hex 格式
* @param {string} background 背景颜色 hex 格式
* @returns {string} 彩色文本内容
**/
function transTextColorAndLog(text, color, background) {
let res = this.tx(text, color, background)
console.log(res)
return res;
}
/**
* 转换指定级别文本颜色
* * 不受级别控制
* @name tl/transLevelTextColor
* @function
* @param {string} [level=TYPE.INFO] 日志界别 参考log.TYPE
* @param {string} text 打印的文本内容
* @param {boolean} isBackground 是否包含背景
* @returns {string} 彩色文本内容
*/
function transLevelTextColor(level = TYPE.INFO, text = '', isBackground = true) {
let { background, color } = colorful.node[level] || colorful.node[TYPE.INFO];
// 打印文本
let cTextFn = chalk.hex(color || background || '#ffffff');
if (isBackground && background) {
cTextFn = cTextFn.bgHex(background);
}
return cTextFn(text)
}
/**
* 转换指定级别文本颜色
* * 不受级别控制
* @name tll/transLevelTextColorAndLog
* @function
* @param {string} [level=TYPE.INFO] 日志界别 参考log.TYPE
* @param {string} text 打印的文本内容
* @param {boolean} isBackground 是否包含背景
* @returns {string} 彩色文本内容
*/
function transLevelTextColorAndLog(level = TYPE.INFO, text = '', isBackground = false) {
console.log.apply(null, this.tl(level, text, isBackground));
}
/**
* 打印指定的脚本
* * 带级别字段和内容
*
* @name tlh/transLevelHeaderAndLog
* @function
* @param {string} level 级别
* @param {string} text 文本内容
* @param {string} chalkOption 颜色配置参数 { bg, color } 形式
* @returns {string} 转换后的字符内容
*/
function transLevelHeaderAndLog(level, text, chalkOption) {
const type = typeof chalkOption;
if (!['object', 'undefined'].includes(type)) {
return this.error(`transLevelTextColorAndLog(level,text,chalkOption)方法参数chalkOption传递错误, 请传递{ bg, color }对象形式`)
}
let args = level ? this._getTerminalColorfulArguments(level) : [];
args = args.length ? [args.join('')] : args;
// 如果不传递背景值 则按照配置的级别答应字体颜色 无背景颜色
let { background } = colorful.node[level];
let { bg, color } = chalkOption || { color: background || '#ffffff' };
// 打印文本
let cTextFn = chalk.hex(color || background || '#ffffff');
if (bg) {
cTextFn = cTextFn.bgHex(bg);
}
args.push(cTextFn(' ' + text + ' '))
return args.join('');
}
/**********************************************************************************
* 按照级别形式
**********************************************************************************
*/
/**
* trace 调试打印
* @name t/trace
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function trace(...args) {
return this.exe(TYPE.TRACE, args);
}
/**
* debug 调试打印
* @name d/debug
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function debug(...arg) {
return this.exe(TYPE.DEBUG, [...arguments]);
}
/**
* info 信息打印
* @name i/info
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function info(...arg) {
return this.exe(TYPE.INFO, [...arguments]);
}
/**
* log 日志打印
* @name l/log
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function logFn(...arg) {
return this.exe(TYPE.LOG, [...arguments]);
}
/**
* success 成功打印
* @name s/success
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function success(...arg) {
return this.exe(TYPE.SUCCESS, [...arguments]);
}
/**
* time 时间打印
* @name tt/time
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function time(...arg) {
return this.exe(TYPE.TIME, [...arguments]);
}
/**
* table 表格打印
* @name T/table
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function table(...arg) {
return this.exe(TYPE.TABLE, [...arguments]);
}
/**
* warn 警告打印
* @name w/warn
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function warn(...arg) {
return this.exe(TYPE.WARN, [...arguments]);
}
/**
* debug 调试打印
* * 不带堆栈
* @name wn/warnNoTrace
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function warnNoTrace(...arg) {
return this.exe(TYPE.WARN, [...arguments], { noTrace: true });
}
/**
* error 错误打印
*
* @name e/error
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function error(...arg) {
return this.exe(TYPE.ERROR, [...arguments]);
}
/**
* error 调试打印
* * 不带堆栈
* @name en/errorNoTrace
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function errorNoTrace(...arg) {
return this.exe(TYPE.ERROR, [...arguments], { noTrace: true });
}
/**********************************************************************************
* 模块按照级别输出形式
**********************************************************************************
*/
/**
* mTrace 堆栈打印(模块化)
*
* @name mt/mTrace
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function mTrace(...arg) {
return this._mExecute(TYPE.TRACE, [...arguments]);
}
/**
* mDebug 调试打印(模块化)
*
* @name md/mDebug
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function mDebug(...arg) {
return this._mExecute(TYPE.DEBUG, [...arguments]);
}
/**
* mInfo 信息打印(模块化)
*
* @name mi/mInfo
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function mInfo(...arg) {
return this._mExecute(TYPE.INFO, [...arguments]);
}
/**
* mLog 日志打印(模块化)
* * 原生的控制台打印
* @name ml/mLog
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function mLog(...arg) {
return this._mExecute(TYPE.LOG, [...arguments]);
}
/**
* mSuccess 成功打印(模块化)
*
* @name ms/mSuccess
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function mSuccess(...arg) {
return this._mExecute(TYPE.SUCCESS, [...arguments]);
}
/**
* mTime 调试打印(模块化)
*
* @name mtt/mTime
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function mTime(...arg) {
return this._mExecute(TYPE.TIME, [...arguments]);
}
/**
* mTable 表格打印(模块化)
*
* @name mT/mTable
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function mTable(...arg) {
return this._mExecute(TYPE.TABLE, [...arguments]);
}
/**
* mWarn 告警打印(模块化)
*
* @name mw/mWarn
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function mWarn(...arg) {
return this._mExecute(TYPE.WARN, [...arguments]);
}
/**
* mWarnNoTrace 调试打印(模块化)
* * 不带堆栈
* @name mwn/mWarnNoTrace
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function mWarnNoTrace(...arg) {
return this._mExecute(TYPE.WARN, [...arguments], { noTrace: true });
}
/**
* mError 调试打印(模块化)
* @name me/mError
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function mError(...arg) {
return this._mExecute(TYPE.ERROR, [...arguments]);
}
/**
* mErrorNoTrace 调试打印(模块化)
* * 不带堆栈
* @name men/mErrorNoTrace
* @function
* @param {any} args 打印的内容
* @returns {null}
*/
function mErrorNoTrace(...arg) {
return this._mExecute(TYPE.ERROR, [...arguments], { noTrace: true });
}
/**
* autoFillText 动态补全文本
* * 常用于打印类似各种级别的日志 配置配合tl使用
* @param {string} text 文本内容
* @param {number} length 长度 默认级别打印的长度设置保持一致 超出长度按照超出的部分显示
* @param {string} aligin 对齐 支持center,left 和 默认 right
* @returns 整合的字段
*/
function autoFillText(text, length, aligin = 'right') {
let defaultLength = this.option.colorful.maxCharLength;
return this._autoFillLength(length || defaultLength, text, aligin);
}
/**
* * 填充文本(一般是空白)
*
* @param {number} length 填充的次数
* @param {string} content 填充的内容
* @returns string 填充后的内容
*/
function fill(length, content) {
return this._fill(length, content);
}
const instanceSupportFunctions = {
// 默认操作
setOption, getOption, auotLogLevel, auotLevel: auotLogLevel,
// 文本操作
autoFillText, fill, transTextColorBlock, tb: transTextColorBlock,
// 基础操作
trace, debug, info, log: logFn, success, time, table, warn, warnNoTrace, error, errorNoTrace,
// 简化操作
t: trace, d: debug, i: info, l: logFn, s: success, tt: time, T: table, w: warn, wn: warnNoTrace, e: error, en: errorNoTrace,
// 模块化
mTrace, mDebug, mInfo, mLog, mSuccess, mTime, mTable, mWarn, mWarnNoTrace, mError, mErrorNoTrace,
// 简化模块化输出
mt: mTrace, md: mDebug, mi: mInfo, ml: mLog, ms: mSuccess, mtt: mTime, mT: mTable, mw: mWarn, mwn: mWarnNoTrace, me: mError, men: mErrorNoTrace,
// // 带颜色的操作
transTextColor, transTextColorAndLog, transLevelTextColor, transLevelTextColorAndLog, transLevelHeaderAndLog,
tx: transTextColor, txl: transTextColorAndLog, tl: transLevelTextColor, tll: transLevelTextColorAndLog, tlh: transLevelHeaderAndLog,
};
/**
* 动态设置prototype上的方式
* @ignore
* @param {object} instanceSupportFunctions 支持的方法 非箭头函数
*/
const initMethonds = (instance) => {
for (let key in instanceSupportFunctions) {
instance[key] = instanceSupportFunctions[key]
}
}
/**
* 日志类
* 创建日志
*/
class Logger {
/**
* Create a Logger
* @param {object} option 参考默认option
*/
constructor(option) {
this.option = { ...defaultOption, ...option };
initMethonds(this);
}
// 是否缩进
_isIndex(level) {
return ![TYPE.TRACE, TYPE.WARN, TYPE.ERROR].includes(level);
}
// 获取空格间隔
_getSpace(num) {
let space = '';
for (let i = 0; i < num; i++) {
space += ' ';
}
return space;
}
// 获取对齐的字段
_getAlgin(level, algin, maxCharLength) {
let length = maxCharLength - level.length;
let pre = 0;
let suf = 1;
if (algin === 'center') {
// 除不尽时 前者取消值 后面间隔取大值
pre = Math.floor(length / 2); // 向下取整
suf = Math.ceil(length / 2); // 向上取整
} else { // 靠右对齐
pre = length - 1;
}
return PLACE_HOLDER + this._getSpace(pre) + level.toLowerCase() + this._getSpace(suf);
}
// 获取多色的参数显示
_getBroswerColorfulArguments(level) {
let { isColorful, colorful, moduleName, dateFormatter } = this.option;
let { textAlgin, maxCharLength, index, space, module, dateTime } = colorful;
if (!isColorful) return [];
let template = '';
let arg = [];
// 是否缩进
if (this._isIndex(level)) {
template += PLACE_HOLDER + ' ';
arg.push(index);
}
// 不同级别不同间隔和不同的样式
template += this._getAlgin(level, textAlgin, maxCharLength);
arg.push(colorful[level.toLowerCase()]);
// 添加模块标识
if (moduleName) {
template += PLACE_HOLDER + ' ' + PLACE_HOLDER + MODULE_PLACE_HOLDER;
arg = arg.concat([space, module, moduleName]);
}
// 添加time 时间戳标识
if (level === TYPE.TIME) {
template += PLACE_HOLDER + ' ' + PLACE_HOLDER + MODULE_PLACE_HOLDER;
let dateTimeString = (typeof dateFormatter === 'string') ? formatDate(new Date(), dateFormatter) : dateFormatter(new Date())
arg = arg.concat([space, dateTime, dateTimeString]);
}
return [template].concat(arg);
}
_fill(length, fillString = ' ') {
let res = [];
for (let i = 0; i < length; i++) {
res.push(fillString)
}
return res.join('');
}
// 居中时获取前后补充的长度
_getPosition(needFillLength) {
// 需要补充的长度
let avg = needFillLength / 2;
return [Math.ceil(avg), Math.floor(avg)]
}
// 动态配置长度
_autoFillLength(length, str, textAlgin = "right") {
// 尾部默认一个空格显示漂亮一下
str = str + ' ';
let less = length - str.length;
// 居中补充
if (textAlgin === 'center') {
let [preLength, endLength] = this._getPosition(less);
return this._fill(preLength) + str + this._fill(endLength);
}
if (less <= 0) return str;
return textAlgin == 'right' ? this._fill(less) + str : str + this._fill(less);
}
_getTerminalColorfulArguments(level, options = {}) {
let { isColorful, colorful, moduleName, dateFormatter } = this.option;
if (!isColorful) return [];
let { textAlgin, maxCharLength, space, module } = colorful;
let { background, color, index } = colorful[level] || colorful['trace'];
let arg = [];
// 是否缩进
if (options.noTrace || index) {
arg.push(options.noTrace ? colorful.debug.index : index);
}
// 不同级别不同间隔和不同的样式
let template = this._autoFillLength(maxCharLength, level.toLowerCase(), textAlgin);
arg.push(chalk.bgHex(background).hex(color)(template))
// 类型标识与后面文案的间距
arg.push(space);
// 添加模块标识
if (moduleName) {
arg.push(chalk.bgHex(module.background).hex(module.color)(' ' + moduleName + ' '));
}
// 添加time 时间戳标识
if (level === TYPE.TIME) {
let dateTimeString = (typeof dateFormatter === 'string') ? formatDate(new Date(), dateFormatter) : dateFormatter(new Date())
arg = arg.concat([dateTimeString]);
}
return arg;
}
// 根据配置和不同环境 不同的输出 TODO 扩展其他情况
_output(type, innerArg, outerArg, options = {}) {
let { onLogger, level } = this.option;
// 配置的打印级别小于当前打印的级别
if (typeof level === 'number') {
// if (level > LEVEL[type]) return;
if (level > this.option.LEVEL[type]) return;
// 支持动态设置日志级别
} else if (Array.isArray(level)) {
if (!level.includes(type)) {
return false;
}
};
// 外部输出
onLogger && onLogger(type, outerArg);
// 内部打印
if (console) {
// node js 下 兼容 error 与warm 打印堆栈
let foramtType = (!isBroswer && [TYPE.WARN, TYPE.ERROR].includes(type)) && !options.noTrace ? TYPE.TRACE : type;
// 兼容浏览器下能打印debug
foramtType = (isBroswer && [TYPE.DEBUG].includes(type)) ? TYPE.INFO : foramtType;
let fn = console[foramtType.toLowerCase()] || console[TYPE.INFO];
// 兼容表格直接输出
if (foramtType.toLowerCase() === TYPE.TABLE) {
console.table.apply(null, outerArg);
} else if (foramtType.toLowerCase() === TYPE.TIME) {
console.log.apply(null, innerArg.concat(outerArg))
} else if (foramtType.toLowerCase() === TYPE.LOG) {
console.log.apply(null, outerArg)
} else {
fn.apply(null, innerArg.concat(outerArg));
}
}
}
exe(level, userArg, options) {
let arg = isBroswer ? this._getBroswerColorfulArguments(level) : this._getTerminalColorfulArguments(level, options);
this._output(level, arg, userArg, options);
return null;
}
_mExecute(level, userArg, options = {}) {
this.option.moduleName = userArg[0];
let fn = level.toLowerCase() + (options.noTrace ? 'NoTrace' : '');
this[fn] && this[fn].apply(this, userArg.slice(1, userArg.length));
this.option.moduleName = '';
}
}
// autoAppendClassFn(fns);
/**
* 创建日志实例
*
* @function
* @description
* 1. 第一次引入 默认创建实例
* 2. 后续导入 直接返回第一次创建的实例
*
* @param {Object} option 详细参数参考option
* @returns {object} logInstance 日志实例
*/
const create = function (option) {
let namespace = option.bindGlobalName;
if (!(0,app_lib_global__WEBPACK_IMPORTED_MODULE_1__.isBindToGlobal)(namespace)) {
return (0,app_lib_global__WEBPACK_IMPORTED_MODULE_1__.bindToGlobal)(namespace, new Logger(option || {}))
}
return (0,app_lib_global__WEBPACK_IMPORTED_MODULE_1__.getbindData)(namespace);
}
/**
* 默认自动创建实例
*
* @constant
* @description
* * 默认会挂载全局 直接通过log来使用
*
*/
const log = create(defaultOption);
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (log);
})();
/******/ return __webpack_exports__;
/******/ })()
;
});
//# sourceMappingURL=index.js.map
/***/ }),
/***/ 882:
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
(function webpackUniversalModuleDefinition(root, factory) {
if(true)
module.exports = factory(__webpack_require__(708), __webpack_require__(810), __webpack_require__(305), __webpack_require__(89), __webpack_require__(44), __webpack_require__(56), __webpack_require__(908));
else { var i, a; }
})(this, (__WEBPACK_EXTERNAL_MODULE__86__, __WEBPACK_EXTERNAL_MODULE__668__, __WEBPACK_EXTERNAL_MODULE__305__, __WEBPACK_EXTERNAL_MODULE__89__, __WEBPACK_EXTERNAL_MODULE__44__, __WEBPACK_EXTERNAL_MODULE__56__, __WEBPACK_EXTERNAL_MODULE__908__) => {
return /******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ 138:
/***/ ((module, __unused_webpack_exports, __nested_webpack_require_1254__) => {
const path = __nested_webpack_require_1254__(56);
const fs = __nested_webpack_require_1254__(89);
const { log } = __nested_webpack_require_1254__(668);
const { exec } = __nested_webpack_require_1254__(86);
const node_readline = __nested_webpack_require_1254__(908);
const { appRequire } = __nested_webpack_require_1254__(305);
// 避免被weppack打包 采用该变量的形式使用
/**
* nodejs内置所有模块
* * 常用于webpack编译umd排除使用
*/
const NODE_INNER_MODULES = Object.keys(process.binding('natives')).filter(module => !/^internal\//.test(module)).sort();
/**
* 同步判断磁盘文件是否存在
*
* @param {string} path 相对路径
* @returns {boolean} 是否存在 true 存在 false 不存在
* @function
*/
const isExistFile = fs.existsSync;
/**
* 相对路径获取的据对路径
*
* @param {string} pathName 相对路径地址
* @returns {string} 据对路径地址
* @function
*/
const resolve = path.resolve;
/**
* 判断当前命令是否未全局安装
*
* * 向上两层判断是否存在node.exe
*
* @returns {boolean} 是否为全局安装
* @function
*/
const isGlobalInstall = () => {
let path = getRootPath();
return isExistDir(resolve(path, '../../node.exe'));
}
/**
* 是否存在bind
*
* @param {string} relativePath 相对路径
* @param {string} name 组件名称
* @returns {boolean} 是否存在bin
* @function
*/
const isExistBin = (relativePath, name) => {
let binPath = resolve(relativePath, `./node_modules/.bin/${name}`)
return isExistFile(binPath) ? binPath : null;
}
/**
* 获取nodejs的bin执行位置
*
* @param {string} compnentName 组件名称
* @returns {string} 组件的路径
*
* * tips
*
* 1. 开发模式直接获取当前目录的下的指定配置路径
* 2. 局部查找
* 3. 全局组件内部
* 4. 全局外部
*
* @function
*
*/
const getBin = (compnentName) => {
// 运行路径
let mainPath = getMainPath();
let runMain = isExistBin(mainPath, compnentName);
log.md('getBin:', compnentName, runMain)
if (runMain) {
return runMain;
}
return compnentName;
}
/**
*
* 是否为app 定义的开发模式
*
* @returns {boolean} 是否为开发模式
*
* * tips
* 1. cross-env 中不支持中划线 eg:APP-MODLE
* 2. MODE 或在 M 值为 DEV 或者DEVELOP, develop,dev
* 3. 主要用于该工程的开发模式
*
* @function
*/
const isDev = () => ["DEVELOP", 'DEV', 'develop', 'dev'].includes(process.env.MODE || process.env['M']);
/**
* 获取模版位置
*
* @returns {string} 模版位置
* @function
*/
const getTemplate = () => {
let template = './src/template.html';
if (!isExistFile(template)) {
log.mi(`use default tempalte config! diy in [${template}]`)
template = resolve(getRootPath(), '../../', './src/template', './init.index.default.template.html')
}
return template;
}
/**
* 读文件【异步】
*
*
* @param {string|Buffer|URL|integer} path 文件路径
* @param {object} options ndoejs的配置
* @returns {promise} data <string> | <Buffer> 读取的文件内容
*
* * tips
* 1. string|Buffer|URL|integer filename or file descriptor
* 2. https://nodejs.org/docs/latest-v13.x/api/fs.html#fs_fs_readfile_path_options_callback
* @function
*/
const readFile = (path, options = {}) => new Promise((res, reject) => {
const defualtOption = { encoding: 'utf8' };
if (options === true || options.cwd) {
path = resolve(path);
options = {}
options.cwd && delete options.cwd;
}
fs.readFile(path, { ...defualtOption, ...options }, function (err, data) {
if (err) return reject(err);
res(data);
})
});
/**
* 读文件【同步】
*
*
* @param {string|Buffer|URL|integer} path 文件路径
* @param {object} options ndoejs的配置
* @returns {string} 文件内容
*
* * tips
* 1. string|Buffer|URL|integer filename or file descriptor
* 2. https://nodejs.org/docs/latest-v13.x/api/fs.html#fs_fs_readfile_path_options_callback
* @function
*/
const readFileSync = (path, options = {}) => {
const defualtOption = { encoding: 'utf8' };
return fs.readFileSync(path, { ...defualtOption, options })
}
/**
* 写文件【异步】
*
*
* @param {string|Buffer|URL|integer} path 文件路径
* @param {object} options ndoejs的配置
* @returns {promise} data <string> | <Buffer> 读取的文件内容
*
* * tips
* 1. string|Buffer|URL|integer filename or file descriptor
* 2. https://nodejs.org/docs/latest-v13.x/api/fs.html#fs_fs_readfile_path_options_callback
* @function
*/
const writeFile = (path, data, options = {}) => new Promise((resolve, reject) => {
if (options === true || options.cwd) {
path = resolve(path);
options = {}
options.cwd && delete options.cwd;
}
const defualtOption = { encoding: 'utf8', flag: 'w+' };
fs.writeFile(path, data, {
...defualtOption,
...options
}, function (err) {
if (err) return reject(err);
resolve(data);
})
});
/**
* 写文件【同步】
*
*
* @param {string|Buffer|URL|integer} path 文件路径
* @param {object} options ndoejs的配置
* @returns {string} 文件内容
*
* * tips
* 1. string|Buffer|URL|integer filename or file descriptor
* 2. https://nodejs.org/docs/latest-v13.x/api/fs.html#fs_fs_readfile_path_options_callback
* @function
*/
const writeFileSync= (path, data, options = {}) => {
const defualtOption = { encoding: 'utf8' };
return fs.writeFileSync(path, data, { ...defualtOption, options })
}
/**
* 写文件【同步】 不存在文件夹则创建
*
* @param {string|Buffer|URL|integer} path 文件路径
* @param {object} options ndoejs的配置
* @returns {string} 文件内容
* @function
*/
const writeFileSyncAndCreate= (filePath, data, options = {}) => {
let root = path.parse(filePath).dir;
if (!isExistDir(root)) {
mkdir(root);
}
writeFileSync(filePath, data, options = {})
}
/**
* 是否为文件夹
*
* @param {string} path 文件夹路径
* @returns {boolean} 是否为文件夹
* @function
*/
const isExistDir = (path) => {
let existPath = fs.existsSync(path);
if (existPath) {
return fs.statSync(path).isDirectory();
}
return false;
}
/**
* 获取指定路径的父级目录包含的文件夹名
*
* @param {string} path 当前的路径
* @param {string} dirName 文件夹名称
* @param {number} layer 当前目录到找到目录目录的层级
* @returns {object} 找的父级的路径
*
* * example
* ```
* {
* path : null 标识不存在 否则标识存在的路径
* layer: number 查到的层级
* }
* ```
* @function
**/
const getParentDir = (path, dirName, layer = 0, paths = []) => {
let justPath = resolve(path, dirName);
let parentPath = resolve(path, '../', dirName);
if (justPath === parentPath) {
// 查到最后 则推出循环
return null;
}
if (isExistDir(justPath)) {
return { path: justPath, layer, paths };
} else {
paths.push(path.split('\\').pop())
return getParentDir(resolve(path, '../'), dirName, layer + 1, paths);
}
}
/**
* 复制文件
* * 不存在目录则创建 但是一定是两边都包含文件
* 否则会报错 operation not permitted, copyfile xxx
*
* @param {string} src 源地址
* @param {string } dest 目标地址
* @param {string} isForce 文件存在是否强制覆盖 默认false
* @param {number} flags 复制标识
* @returns {promise}
* @function
*/
const copyFile = (src, dest, isForce, flags = 0) => new Promise((res, reject) => {
const dirPath = resolve(dest, '../');
const realCopy = () => {
fs.copyFileSync(src, dest);
res();
}
const copy = async () => {
if (!isForce) { // 不是强制复制
if (isExistFile(dest)) {// 存在文件 提示
log.mwn(`exist file [${dest}], recover it ?`);
let isCover = await readline(`yes/no`, 'yes');
if (['yes', 'y'].includes(isCover)) {
realCopy();
} else {
res();
}
} else {
realCopy();
}
}
}
if (!fs.existsSync(dirPath)) {
mkdir(dirPath);
copy();
} else {
copy();
}
});
/**
* 单文件强制复制文件
*
* 不存在目录则创建 但是一定是两边都包含文件
* 否则会报错 operation not permitted, copyfile xxx
*
* @param {string} src 源文件路径
* @param {string} dest 目标文件路径
* @function
*/
const copyFileSync = (src, dest) => {
const dirPath = resolve(dest, '../');
const realCopy = () => {
fs.copyFileSync(src, dest);
res()
}
if (!fs.existsSync(dirPath)) {
mkdir(dirPath);
realCopy();
} else {
realCopy();
}
}
/**
* 创建目录【同步】
*
* @param {string} path 路径
* @param {object} options 参数
* @returns {null} 无返回
*
* * tips
* 1. https://nodejs.org/docs/latest-v13.x/api/fs.html#fs_fs_mkdir_path_options_callback
* @function
*
*/
const mkdir = (path, options = { recursive: true }) => {
fs.mkdirSync(path, options);
}
/**
* 录取用户输入
* @param {string} tips 提示信息
* @param {string} [defaultValue=yes] 默认值
* @returns {promise} 读取结果
* @function
*/
const yesOrNo = async (message, defaultValue = "yes") => {
// log.mwn(message);
let isForce = await readline(`${message} [yes/no]`, defaultValue);
return ['yes', 'y'].includes(isForce);
}
/**
* 录取用户输入
*
* @param {string} tips 提示信息
* @param {boolean} isAlowEmpty 运行为空
* @returns {promise} 读取结果
* @function
*/
const readline = (tips = '', defaultValue = '', isAlowEmpty = false) => new Promise((resolve) => {
log.mi(tips + '');
const r = node_readline.createInterface({
input: process.stdin,
output: process.stdout
});
let defaultValueTips = defaultValue ? `(${defaultValue})` : '';
// 默认标签
let defaultFlag = log.fill(7) + log.tx(log.autoFillText('default'), '#FFFFFF', '#7506ef');
let def = log.tx(defaultValueTips, '#00ffdc');
let tipMsg = `${defaultFlag} ${def}`
let question = () => {
r.question(tipMsg, (answer) => {
if (!isAlowEmpty) {
let resultValue = answer || defaultValue;
if (resultValue) {
r.close();
resolve(resultValue);
} else {
log.mwn("can't empty! please input again")
question();
}
} else {
r.close();
resolve(answer || defaultValue);
}
})
}
question();
});
/**
* 文本中添加或者覆盖指定内容
*
* @param {object} options 参数
* @param {object} [options.content] 文本内容
* @param {object} [options.startflag] 开始标识
* @param {object} [options.endFalg] 结束标识
* @param {object} [options.appContent] 最佳或者替换的内容
* @param {object} [options.isRepalce] 是否为替换 默认是追加 false
* @param {object} [options.isStart] 不存在时 追加最前面 默认是后面
* @param {object} [options.isInnerStart] 追加文档时 追加在heade与oldcontent之间 默认在尾部
* @param {object} [options.space] 与标识符的间隔
* @param {object} [options.newHeader] 不存在时候 添加头部内容
* @returns {string} 新文本
* @function
*/
const updateContent = ({ content, startflag, endFalg, appContent, isRepalce, isStart, isInnerStart, space, newHeader }) => {
const SPACE = space || '\r\n';
let begin = content.indexOf(startflag);
let end = content.indexOf(endFalg);
if (begin === -1 || end === -1) { // 不存在的时候 前面
let newContent = [startflag, newHeader, appContent, endFalg].filter(v => v);
return isStart ? newContent.concat([content]).join(SPACE) : [content].concat(newContent).join(SPACE);
}
let _oldContent = content.substr(begin, end - begin);
let oldContent = _oldContent.replace(/\r\n$/, '').replace(/\r\n$/, '')
let newContent = [];
if (isRepalce) {
newContent = [startflag, newHeader, appContent].filter(v => v);
} else {
if (isInnerStart) {
if (newHeader) {
const newOldContent = oldContent.replace(startflag, '').replace(newHeader, '');
newContent = [startflag, newHeader, appContent, newOldContent];
} else {
newContent = [appContent, oldContent];
}
} else {
newContent = [oldContent, appContent]
}
}
newContent = newContent.join(SPACE) + SPACE;
return content.replace(_oldContent, newContent)
}
/**
* 获取安装类库的据对目录
*
* @param {string} relativePath 执行文件的相对目录 默认 ../../
* @returns {string} 主目录路径
* @function
*/
const getRootPath = (relativePath = './') => {
return resolve(getMainPath(), relativePath);
}
/**
* 当前安装 或者执行命令 的路径
*
* @param {string} relativePath 相对路径
* @returns {string} 新路径
*
* * tips
* 默认执行的bin文件 在工程目录的下两层
* 到当前组件的跟目录层
* 上一侧目录都为当前组件的目录
*
* @function
*/
const getMainPath = (relativePath = '../../') => {
// webpack-ignore-line
return resolve(appRequire.main.filename, relativePath)
}
/**
* 获取当前组件bin的路径
* @returns {string} bin路径
* @function
*/
const getBinPath = () => {
let path = getRootPath();
return isGlobalInstall() ? resolve(path, '../..') :
(isDev() ? resolve(path, './node_modules/.bin') : resolve(path, '../.bin'))
}
/**
* 读取目录【同步】
*
* @param {string} path 目录路径
* * @param {object} options 读取配置
* @returns {array} 文件目录
* @function
*/
const readdirSync = (path, options) => fs.readdirSync(path, options)
/**
* 嵌套删除子文件夹和文件
*
* @param {string} path 路径
* @function
*/
const delDir = (path) => {
let files = [];
if (fs.existsSync(path)) {
files = fs.readdirSync(path);
files.forEach((file, index) => {
let curPath = path + "/" + file;
if (fs.statSync(curPath).isDirectory()) {
delDir(curPath); //递归删除文件夹
} else {
fs.unlinkSync(curPath); //删除文件
}
});
fs.rmdirSync(path);
}
};
/**
* 删除文件【同步】
*
* @param {string} path 文件路径
* @function
*
*/
const delFile = (path) => {
return fs.unlinkSync(path);
}
/**
* 系统判断端口使用 // TODO 采用静态编译方式 处理静态文件
*
* @param {number} port 端口号
* @returns {boolean} 事都被占用
* @function
*/
const isSysUsePort = (port) => {
// 避免乱码
let path = resolve(getRootPath(), './init.justport.used.config.ps1');
// 不能通过node的本身判断 判断不出webpackserver的端口使用
let res = exec('powershell', [path, port], { stdio: 'pipe' });
let isExistPort = res.stdout.toString();
log.md('test port result:', isExistPort)
return !!isExistPort;
}
/**
* 获取到能够使用的端口
* * 动态自增的方式 直到可用的端口
* @param {number} port
* @returns {number} 可用的端口
* @function
*/
const getCanUsePort = async (port) => {
let usePort = 1 * port;
let isUse = await isSysUsePort(usePort);
if (isUse) {
return await getCanUsePort(usePort + 1)
}
return usePort;
}
/**
* 复制文件 【异步】
*
* @param {string} from 相对发布组件的目录
* @param {string} to 相对生成的目录
* @param {boolean} defaultIsSucess 不存在文件的时候是否默认为成功 默认为成功
* @function
*/
const copyProjectFile = async (from, to, defaultIsSucess = 0) => {
let resourcePath = resolve(getRootPath(), from);
let toPath = resolve(to);
if (!isExistFile(resourcePath)) {
log.mwn(`not exist [${resourcePath}]`)
return defaultIsSucess;
}
await copyFile(resourcePath, toPath);
log.md(`finish copy [${resourcePath}] to ${toPath}`);
return 0;
}
/**
* 复制文件 【同步】
*
* @param {string} from 相对发布组件的目录
* @param {string} to 相对生成的目录
* @param {boolean} defaultIsSucess 不存在文件的时候是否默认为成功 默认为成功
* @function
*/
const copyProjectFileSync = (from, to, defaultIsSucess = 0) => {
let resourcePath = resolve(getRootPath(), from);
let toPath = resolve(to);
if (!isExistFile(resourcePath)) {
log.mwn(`not exist [${resourcePath}]`)
return defaultIsSucess;
}
copyFileSync(resourcePath, toPath);
log.md(`finish copy [${resourcePath}] to ${toPath}`);
return 0;
}
const _copyFile = (source, target) => {
fs.copyFileSync(source, target);
}
/**
* 嵌套复制文件夹 【同步】
*
* @param {string} source 源路径
* @param {string} target 目标路径
* @function
*/
const copyFolder = (source, target) => {
if (!fs.existsSync(target)) {
fs.mkdirSync(target);
}
const files = fs.readdirSync(source);
files.forEach((file) => {
const currentSource = path.join(source, file);
const currentTarget = path.join(target, file);
if (fs.lstatSync(currentSource).isDirectory()) {
copyFolder(currentSource, currentTarget);
} else {
_copyFile(currentSource, currentTarget);
}
});
}
/**
* 获取本机IP
*
* * windows验证 其他环境还未验证
*
* @returns {string} ip地址
*
* * tips
* 1. 目前值返回IPv4 后续可以扩展IPv6
*
* @function
*/
function getLocalIP() {
const os = __nested_webpack_require_1254__(44);
const osType = os.type(); //系统类型
const netInfo = os.networkInterfaces(); //网络信息
let ip = '';
if (osType === 'Windows_NT') {
for (let dev in netInfo) {
//win7的网络信息中显示为本地连接,win10显示为以太网
if (dev === '本地连接' || dev === '以太网') {
for (let j = 0; j < netInfo[dev].length; j++) {
if (netInfo[dev][j].family === 'IPv4') {
ip = netInfo[dev][j].address;
break;
}
}
}
}
} else if (osType === 'Linux') {
ip = netInfo.eth0[0].address;
} else if (osType === 'Darwin') {
// mac操作系统
// ip = netInfo.eth0[0].address;
} else {
// 其他操作系统
}
return ip;
}
/**
* 特殊路径
*
* 获取当前代码的路径 __dirname 据对文件的路径
* 在使用动态加载文件后 resolve会指向动态加载的位置 则需要使用__dirname来获取相对位置
*
*/
module.exports = {
copyFile, // 带提示的赋值 异步
copyFileSync, // 不带输入提示的辅助 同步
copyProjectFile, // 复制nodes发布目录到工程目录
copyFolder, // 复制文件夹
copyProjectFileSync, // 嵌套复制文件
delDir, // 删除目录
delFile, // 删除文件
getBin, // 获取所有组件的执行位置
getBinPath, // 获取当前组件的bin执行位置 - 全局 开发 和 内部安装
getCanUsePort, // 可用的端口
getLocalIP, // 获取本机IP
getMainPath, // 获取执行命令 入口位置
getParentDir, // 获取指定路径的父级目录包含的文件夹名
getRootPath, // 获取类库的根目录 动态加载后需要使用 __dirname 获取据对文件的路径
getTemplate,
isDev, // 是否为开发模式
isExistBin, // 是否存在bin
isExistDir, // 目录是否存在
isExistFile, // 文件是否存在
isGlobalInstall, // 是否全局安装
isSysUsePort, // 端口是否被占用
mkdir, // 创建目录
NODE_INNER_MODULES,
readFile, // 读文件数据
readFileSync, // 同步度文件数据
readdirSync, // 读取目录下的所有文件
readline, // 读用户输出
resolve, // 路径处理
updateContent, // 更新文件内容
writeFile, // 文件中写数据
writeFileSync, // 同步文件写数据
writeFileSyncAndCreate, // 同步文件写数据不存在目录则创建
yesOrNo, // 提示yes和no
}
/***/ }),
/***/ 86:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__86__;
/***/ }),
/***/ 668:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__668__;
/***/ }),
/***/ 305:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__305__;
/***/ }),
/***/ 89:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__89__;
/***/ }),
/***/ 44:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__44__;
/***/ }),
/***/ 56:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__56__;
/***/ }),
/***/ 908:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__908__;
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __nested_webpack_require_20996__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __nested_webpack_require_20996__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module is referenced by other modules so it can't be inlined
/******/ var __webpack_exports__ = __nested_webpack_require_20996__(138);
/******/
/******/ return __webpack_exports__;
/******/ })()
;
});
//# sourceMappingURL=index.js.map
/***/ }),
/***/ 561:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ 138:
/***/ ((module, __unused_webpack_exports, __nested_webpack_require_131__) => {
const path = __nested_webpack_require_131__(423);
const { readFileSync, isExistFile,resolve, isExistDir, writeFileSyncAndCreate, readdirSync,getRootPath } = __nested_webpack_require_131__(32);
const { log } = __nested_webpack_require_131__(115);
const BUILD_PATH = "./src/trans-static";
const FILE_PATH = "./static/"; // 默认文件写入位置
const BASE_PATH = "./static/store.json"; // 默认文件存储位置
/**
* 将文件转换为JSON进行存储
*
* @param {array} filePaths 多个文件转换了路径
* @param {string} [storagePath='./static/store.json'] 存储的文件路径名称 一般为json 便捷处理
* @returns {array} 返回文件读取的JSON内容
*
* * example
* ```
* filesToJson([path.resolve(__dirname,`./b.ps1`),path.resolve(__dirname,`./a.ps1`)]
* ```
* @function
*/
const filesToJson = (filePaths = [], storagePath = BASE_PATH) => {
let storageDatas = filePaths.map(filePath => {
if (!isExistFile(filePath)) {
log.men("不存在文件文件", path.resolve(filePath));
return null;
} else {
let data = readFileSync(filePath);
return { name: filePath.split('\\').pop(), content: data };
}
}).filter(v => !!v)
// 写入文件
storageDatas.length && writeFileSyncAndCreate(storagePath, JSON.stringify(storageDatas, null, 2));
return storageDatas;
}
/**
* 存储文件转换为文件
* @param {string} [storagePath='./static/store.json'] 存储文件位置
* @param {string} [basePath ='./static/'] 每个文件存储路径
* @returns {array} 所有存储的文件路径
*/
const pathToFile = (storagePath = BASE_PATH, basePath = FILE_PATH) => {
if (!isExistFile(storagePath)) {
return log.men("不存在文件文件", storagePath);
}
return jsonToFile(JSON.parse(readFileSync(storagePath)), basePath);
}
/**
* 存储文件转换为文件
* @param {array} [fileDatas='[]'] 存储数据
* @param {string} [basePath ='./static/'] 每个文件存储路径
* @param {boolean} [isForce=false] 是否强制写入 默认false
* @returns {array} 所有存储的文件路径
* @function
*/
const jsonToFile = (fileDatas = [], basePath = FILE_PATH, isForce = false) =>
fileDatas.map(({ name, content }) => {
// let filePath = path.resolve(basePath || '', name);
let filePath = getRootPath(path.join(basePath || '', name));
// console.log(getRootPath(),filePath,resolve(filePath));
// 非强制时候 不是每次都会写入 避免频繁的磁盘抄作 只有第一次会写入
// 后续可以考虑按照版本来进行判断是否要清理缓存 避免静态文件未更新的情况 目前不需要
if (!isForce && isExistFile(filePath)) {
// log.md("文件已经存在,不再进行覆写",filePath)
return filePath;
}
writeFileSyncAndCreate(filePath, content)
return filePath
})
/**
* 构建文件夹
* * 注意 所有文件路径是平级 不支持嵌套
* @param {string} buildDirPath=src/trans-static 构建的文件夹路径
* @param {string} [storagePath=./static/store.json] 存储路径
*/
const buildDirFiles = (buildDirPath = BUILD_PATH, storagePath = BASE_PATH) => {
// 扫描
if (!isExistDir(buildDirPath)) {
return log.md("不存在静态文件目录", buildDirPath);
}
// 只用文件 文件夹不在范围 也不支持嵌套
let filePaths = readdirSync(buildDirPath).filter(v => !isExistDir(path.resolve(buildDirPath, v)))
.map(v=>path.resolve(buildDirPath,v));
return filesToJson(filePaths, storagePath)
}
module.exports = {
filesToJson, // 作为工具使用
pathToFile, // 存储路径转换为文件
jsonToFile, // 常用
buildDirFiles, // 编译目录
}
/***/ }),
/***/ 115:
/***/ ((module) => {
"use strict";
module.exports = __webpack_require__(810);
/***/ }),
/***/ 32:
/***/ ((module) => {
"use strict";
module.exports = __webpack_require__(882);
/***/ }),
/***/ 423:
/***/ ((module) => {
"use strict";
module.exports = __webpack_require__(56);
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __nested_webpack_require_3952__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __nested_webpack_require_3952__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module is referenced by other modules so it can't be inlined
/******/ var __webpack_exports__ = __nested_webpack_require_3952__(138);
/******/ var __webpack_export_target__ = exports;
/******/ for(var i in __webpack_exports__) __webpack_export_target__[i] = __webpack_exports__[i];
/******/ if(__webpack_exports__.__esModule) Object.defineProperty(__webpack_export_target__, "__esModule", { value: true });
/******/
/******/ })()
;
//# sourceMappingURL=index.js.map
/***/ }),
/***/ 17:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const { log } = __webpack_require__(810);
/**
* 错误的定义
*
*/
const ERROR_CODE = {
ERROR: -1, // 终止程序 往往有 message
WARN: 1, // 警告 不终止程序
SUCESS: 0,
};
let CODES = [];
for (let key in ERROR_CODE) {
CODES.push(ERROR_CODE[key]);
}
const LOG_FN = {
[ERROR_CODE.ERROR]: "e",
[ERROR_CODE.WARN]: "w",
[ERROR_CODE.SUCESS]: "s",
};
/**
* msg 打印的内容
*/
class AppError {
/**
*
* @param {*} msg 打印的日志内容 可以是数组
* @param {*} code 打印日志的错误格式
* @param {*} cfg 配置
*/
constructor(msg, code = ERROR_CODE.WARN, cfg = {}) {
if (!CODES.includes(code)) {
throw log.me(
`create AppError code [${code}] is no't in ERROR_CODE [${CODES}] `
);
}
let message = Array.isArray(msg) ? msg : msg == void 0 ? [] : [msg];
let config = {
trace: false, // 默认打印堆栈
module: true, // 默认模块化打印
data: undefined, // 接受的数据
print: true,
...cfg,
};
this.options = { message, code, config };
config.print && this.print();
}
// 后续扩展功能
print(option = {}) {
let { message, code, config } = { ...this.options, ...option };
let { trace, module } = config;
if (message && message.length) {
let fnName = [module && "m", LOG_FN[code], trace ? "" : "n"].join("");
let fn = log[fnName];
if (fn) {
fn.apply(log, message);
} else {
throw log.me(`log no exist ${fnName} function`);
}
}
}
isError() {
return this.options.code === ERROR_CODE.ERROR;
}
noError() {
return this.options.code === ERROR_CODE.SUCESS;
}
}
module.exports = {
AppError,
ERROR_CODE: ERROR_CODE,
};
/***/ }),
/***/ 585:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const {LANGUAGE} = __webpack_require__(598)
// 常用常数配置
const ARGUMENTS = {
// 支持语言
language:(opt)=> [
'[language]',
`[${LANGUAGE.join('/')}] default(${LANGUAGE[0]})`,
(language) => {
if (!LANGUAGE.includes(language)) {
log.en('error', `command-argument value '${language}' is invalid for argument 'language' , please choice right language in [${LANGUAGE.join(',')}]`)
throw new opt.commander.InvalidArgumentError();
}
return language
}
,
LANGUAGE[0]
]
}
module.exports = {
ARGUMENTS
}
/***/ }),
/***/ 598:
/***/ ((module) => {
// 支持的包格式 目标类型
const TARGET = ['server', 'doc', 'build', 'process'];
// 支持的语言类型 static静态资源
const LANGUAGE = ['es', 'node','bin','react', 'vue','static'];
// 支持的编译类型
const LIBRARY_TARGET_OBJ = {
// umd的编译模式 使用与node 与 brower
umd: { key: 'umd' },
commonjs: { key: 'commonjs' },
window: { key: 'window' },
// es module 暂时为支持
// module: { key: 'module' },
// amd: { key: 'amd' },
// system: { key: 'system' },
}
// 数组形式
let LIBRARY_TARGET = (() => {
let res = [];
for (prop in LIBRARY_TARGET_OBJ) {
res.push(LIBRARY_TARGET_OBJ[prop].key)
}
return res;
})()
module.exports = {
TARGET,
LANGUAGE,
LIBRARY_TARGET_OBJ,
LIBRARY_TARGET
}
/***/ }),
/***/ 919:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const { TARGET, LIBRARY_TARGET } = __webpack_require__(598);
// 常用的OPTIONS
const OPTIONS = {
// 支持目标文档
target: ({ Option }) => new Option('-t, --target [string]', 'server target module').choices(TARGET),
// debug: new Option('-d, --debug', 'is show debug log').default(false, 'toggle show debug log'),
debug: ({ Option }) => new Option('-d, --debug', 'show debug log'),
// 默认的输出类型
libraryTarget: ({ Option }) => new Option('-t, --libraryTarget [string]', 'output libraryTarget').choices(LIBRARY_TARGET).default(LIBRARY_TARGET[0], 'default is umd'),
// message 用户输入信息
message: ({ Option }) => new Option('-msg, --message [string]', 'git submit or change log message'),
}
module.exports = OPTIONS;
/***/ }),
/***/ 783:
/***/ ((module) => {
const int = (error, val) => {
let value = 1 * val;
if (isNaN(value)) {
throw new error()
}
return value;
};
const port = int;
module.exports = {
int,
port,
}
/***/ }),
/***/ 174:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const { log } = __webpack_require__(810);
const { ERROR_CODE, AppError } = __webpack_require__(17);
const { getRootPath, resolve } = __webpack_require__(882);
const { autoRequire } = __webpack_require__(305);
const prase = __webpack_require__(783);
// 解析统一测脚本参数
const praseOpt = (opt) => {
let { options } = opt;
// 倒数第二个为配置参数
let option = options.slice(options.length - 2, options.length - 1)[0];
// 入参为前面内容
let arg = options.slice(0, options.length - 2);
return { arg, option };
}
/**
* 执行 参数传递 同事执行对应的start函数
* @param {*} args
* @param {...any} options
*/
const action = async (args, ...options) => {
let { commond, start, ...arg } = args;
let outOption = options.slice(0, options.length - 1);
const commondName = typeof options[0] === 'string' ? options[0] : '';
log.md(`${commond} ${commondName}::BEGAIN`, { ...arg, options: outOption })
// 构建
let error = await start({ commond, ...arg, options });
// 校验
if (error === void 0) {
return new AppError(`[./plugins/${commond}.commong.js] function need return `, ERROR_CODE.ERROR)
}
// 数字返回 则表示直接是ERROR_CODE的异常
if (typeof error != 'object') {
error = new AppError('', error, { print: false });
}
if (error.noError()) {
log.md(`${commond} ${options[0]}::SUCCESS`)
} else {
log.md(`execute [${commond} ${commondName}] result is not 0, confirm is execute success`, `exexute file is [./plugins/${commond}.commong.js]`)
if (error.isError()) {
log.men(`execute [${commond} ${commondName}] result is error!`)
} else {
log.mwn(`execute [${commond} ${commondName}] is not complete!`)
}
}
// TODO 后续很如处理
// 1. 错误统一处理 深入了解commonder和nodesjs child_process 中的数据回传 eg:process.stdout.write("xxxx")
// 将异常传递到父进程
return error;
}
// commander option 参数转换为 exec 执行的参数
const optionsToArray = (options = {}, except = []) => {
let res = [];
for (key in options) {
if (!except.includes(key)) {
res.push(`--${key}`);
res.push(options[key]);
}
}
return res;
}
// 对象绑定执行的参数
const bindArg = (obj, arg) => {
let newObj = {};
for (key in obj) {
newObj[key] = obj[key].bind(null, arg)
}
return newObj;
}
// 动态获取环境变量
const transEnv = (option, fileds = []) => {
let res = [];
for (let key in option) {
if (fileds.includes(key)) {
res.push(`${camelToConst(key)}=${option[key]}`);
}
}
return res;
}
/**
* ---
* ##### 驼峰转下划线
*
* @param {string} camelStr 驼峰字符串
* @returns {string} 下划线字符串
* @function
*/
const camelToUnderline = camelStr => camelStr.replace(/([A-Z])/g, "_$1").toLowerCase();
/**
* ---
* ##### 驼峰转常量格式
*
* @function
* @param {string} camelStr 驼峰字符串
* @returns {string} 常量字符串
*
*/
const camelToConst = str => camelToUnderline(str).toUpperCase();
/**
* // TODO 去掉
* 获取配置文件路径
* @param {object} param0
* @returns string 路径
* 文件名称命名规范
* commond + name + append+ .config.js
* 路径 工程跟路径 + 配置相对位置+ 文件
*/
const getConfigPath = (args) => {
let { opt, append } = args;
let { commond, options } = opt;
let fileName = [commond, options[0]].concat(append || []).concat(['config.js']).join('.');
return resolve(getRootPath(), './static/config', fileName);
}
// 获取静态资源路径下的
const getStaticPath = (path = "") => resolve(getRootPath(), './static/', path)
// 动态加载发布目录 或者当前工程目录的文件
const autoRequireFile = (path, isRoot = true) => autoRequire(isRoot ? resolve(getRootPath(), path) : resolve(path))
// 动态 加载发布目录下的静态文件
const autoRequireStaticFile = (path) => autoRequireFile(getStaticPath(path));
module.exports = {
praseOpt,
action,
optionsToArray,
bindArg,
prase,
transEnv,
getConfigPath,// TODO 去掉
getStaticPath,
autoRequireFile,
autoRequireStaticFile
}
/***/ }),
/***/ 625:
/***/ ((module) => {
// 支持的包格式 目标类型
const TARGET = ['server', 'doc', 'build', 'process'];
// 支持的语言类型
const LANGUAGE = ['es','bin','node', 'react', 'vue'];
// 支持的编译类型
const LIBRARY_TARGET_OBJ = {
// umd的编译模式 使用与node 与 brower
umd: { key: 'umd' },
commonjs: { key: 'commonjs' },
window: { key: 'window' },
// es module 暂时为支持
// module: { key: 'module' },
// amd: { key: 'amd' },
// system: { key: 'system' },
}
// 数组形式
let LIBRARY_TARGET = (() => {
let res = [];
for (prop in LIBRARY_TARGET_OBJ) {
res.push(LIBRARY_TARGET_OBJ[prop].key)
}
return res;
})()
module.exports = {
TARGET,
LANGUAGE,
LIBRARY_TARGET_OBJ,
LIBRARY_TARGET
}
/***/ }),
/***/ 424:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
/**
* 动态读取插件 注册到系统
* 命名生效两个条件
* 1: 需要配置或者用plugin命令
* 2: 需要启用 该命名 默认安装是启用
*/
const STATIC_FILE_DATA = __webpack_require__(177);
// 获取支持的命令
// const getSupportCommonds = ({ utils: { autoRequireStaticFile } }) => autoRequireStaticFile('plugin/plugin.config.json')
// 热注册命令
const hotRegisterCommond = (commonds, opts) => {
let { program, commander, utils: { autoRequireStaticFile, action }, OPTIONS, noBuild: { appRequire } } = opts;
const resitCommond = [];
commonds.forEach(commond => {
if (commond?.enable) { // 启用的时候才注册
let fileName = commond.path;
let commondName = commond.name;
try {
// 本地的时候 直接加载本地静态文件 包模式 直接加载包
let pluginFn = commond?.type == "local" ?
autoRequireStaticFile(`plugin/${fileName}`)
: appRequire(fileName);
const plugin = pluginFn?.start(opts);
if (!plugin.init) return log.me('need init method export in ' + fileName)
if (!plugin.start) return log.me('need start method export in ' + fileName)
// 添加命令名称
let instance = program.command(commondName)
// 自定义部分
plugin.init(instance, opts);
// 默认追加--debug参数和--message参数 已经 调用执行方法
instance.addOption(OPTIONS.debug(commander))
.action(action.bind(null, {
start: plugin.start, // 执行方法
commond: commondName, // 命令名称
}));
instance.addOption(OPTIONS.message(commander));
resitCommond.push(commond)
} catch (e) {
log.me(`regiter ${commondName} commond error,please check [${fileName}] file`, e)
}
}
});
log.md(`already success register ${resitCommond.length} commonds`);
let registerCommods = resitCommond.map(c => (
{
commond: c.name,
'see commond help': `appbir ${c.name} --help`,
enable: c.enable,
type: c.type,
discription: c.discription
}));
if (process.argv.includes('--debug')) {
log.T(registerCommods)
}
return registerCommods;
}
/**
* 初始化插件命令
*/
const initPluginCommond = (opts) => {
let {STATIC: { jsonToFile },utils: {autoRequireStaticFile }}=opts;
// 静态资源自动生成
jsonToFile(STATIC_FILE_DATA);
let commonds = autoRequireStaticFile("plugin.config.json");
// 如果命令失效 或者删除了static/store 则需要打开命令执行后再次隐藏即可
// let commonds = [
// {"name":"plugin","enable":true,"type":"package","path":"app-lib-cli-plugin-plugin","discription":"插件管理命令// TODO 进行插件管理的开发 "},
// {"name":"git","enable":true,"type":"package","path":"app-lib-cli-plugin-git","discription":"GIT操作"},
// {"name":"build","enable":true,"type":"package","path":"app-lib-cli-plugin-build","discription":"构建编译"},
// {"name":"md","enable":true,"type":"package","path":"app-lib-cli-plugin-md","discription":"markdown编译"},
// {"name":"run","enable":true,"type":"package","path":"app-lib-cli-plugin-run","discription":"自定义命令"},
// {"name":"server","enable":true,"type":"package","path":"app-lib-cli-plugin-server","discription":"启动服务"},
// {"name":"init","enable":true,"type":"package","path":"app-lib-cli-plugin-init","discription":"初始工程"},
// {"name":"doc","enable":true,"type":"package","path":"app-lib-cli-plugin-doc","discription":"API文档"}
// ];
let registerCommond = hotRegisterCommond(commonds, opts);
return { commonds, registerCommond };
}
module.exports = { initCommond: initPluginCommond }
/***/ }),
/***/ 555:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const { log } = __webpack_require__(810);
const commander = __webpack_require__(491);
const nodeUtils = __webpack_require__(882);
const STATIC = __webpack_require__(561);
const { exec } = __webpack_require__(708);
const utils = __webpack_require__(174);
const noBuild = __webpack_require__(305);
const OPTIONS = __webpack_require__(919);
const { ARGUMENTS } = __webpack_require__(585);
const Error = __webpack_require__(17);
const CONSTANT = __webpack_require__(625)
module.exports = {
nodeUtils,
utils,
exec,
commander,
log,
noBuild,
OPTIONS, // 常用的option
ARGUMENTS, // 常用debugger
Error,
STATIC,//静态文件存储
CONSTANT,//常量
}
/***/ }),
/***/ 305:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__305__;
/***/ }),
/***/ 198:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__198__;
/***/ }),
/***/ 735:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__735__;
/***/ }),
/***/ 89:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__89__;
/***/ }),
/***/ 44:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__44__;
/***/ }),
/***/ 56:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__56__;
/***/ }),
/***/ 910:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__910__;
/***/ }),
/***/ 908:
/***/ ((module) => {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE__908__;
/***/ }),
/***/ 177:
/***/ ((module) => {
"use strict";
module.exports = JSON.parse('[{"name":"plugin.config.json","content":"[\\r\\n {\\"name\\":\\"plugin\\",\\"enable\\":true,\\"type\\":\\"package\\",\\"path\\":\\"app-lib-cli-plugin-plugin\\",\\"discription\\":\\"//TODO 插件管理\\"},\\r\\n {\\"name\\":\\"git\\",\\"enable\\":true,\\"type\\":\\"package\\",\\"path\\":\\"app-lib-cli-plugin-git\\",\\"discription\\":\\"GIT操作\\"},\\r\\n {\\"name\\":\\"build\\",\\"enable\\":true,\\"type\\":\\"package\\",\\"path\\":\\"app-lib-cli-plugin-build\\",\\"discription\\":\\"构建编译\\"},\\r\\n {\\"name\\":\\"md\\",\\"enable\\":true,\\"type\\":\\"package\\",\\"path\\":\\"app-lib-cli-plugin-md\\",\\"discription\\":\\"markdown编译\\"},\\r\\n {\\"name\\":\\"run\\",\\"enable\\":true,\\"type\\":\\"package\\",\\"path\\":\\"app-lib-cli-plugin-run\\",\\"discription\\":\\"自定义命令\\"},\\r\\n {\\"name\\":\\"server\\",\\"enable\\":true,\\"type\\":\\"package\\",\\"path\\":\\"app-lib-cli-plugin-server\\",\\"discription\\":\\"启动服务\\"},\\r\\n {\\"name\\":\\"init\\",\\"enable\\":true,\\"type\\":\\"package\\",\\"path\\":\\"app-lib-cli-plugin-init\\",\\"discription\\":\\"初始工程\\"},\\r\\n {\\"name\\":\\"doc\\",\\"enable\\":true,\\"type\\":\\"package\\",\\"path\\":\\"app-lib-cli-plugin-doc\\",\\"discription\\":\\"API文档\\"}\\r\\n]"}]');
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
/**
* * commonder 命令组件
* https://github.com/tj/commander.js/blob/master/Readme_zh-CN.md
*
*/
const { initCommond } = __webpack_require__(424);
const utils = __webpack_require__(555);
let { log, commander: { Command },
utils: { action, autoRequireFile } } = utils;
// log.mi("---------内置路径:", {
// getMainPath: inner.getMainPath(),
// getRootPath: inner.getRootPath(),
// getBinPath: inner.getBinPath(),
// getBin_appbir: inner.getBin('appbir'),
// getBin_npm: inner.getBin('npm'),
// getBin_node: inner.getBin('app-lib-node'),
// })
// log.mi("---------引用路径:", {
// getMainPath: nodes.getMainPath(),
// getRootPath: nodes.getRootPath(),
// getBinPath: nodes.getBinPath(),
// getBin_appbir: nodes.getBin('appbir'),
// getBin_npm: nodes.getBin('npm'),
// getBin_node: nodes.getBin('app-lib-node'),
// })
const program = new Command();
/**
* 初始化日志
*/
log.auotLevel();
/**
* 初始化命令
*/
let { registerCommond } = initCommond({ ...utils, program });
// 获取PKG.json的配置
const PKG = autoRequireFile('package.json');
// 打印显示内容
const display = async () => {
log.mi("usage [ appbir --help ] , show support commond >")
log.T(registerCommond);
return 0;
}
/**
* appbir 的总入口命令
* 所有的debugger 命令会被外出拦截 最好不要添加其他命令
*/
program
.version(`v${PKG.version}`, '-v,--version', 'the current version')
.description('appbir personal cli tool for speed work, you can connection email for appbir@163.com')
.action(action.bind(null, { start: display, commond: PKG.name }));
log.md("run.argv", JSON.stringify(process.argv.slice(2)))
/**
* 命令解析
*/
program.parse(process.argv);
})();
/******/ return __webpack_exports__;
/******/ })()
;
});
//# sourceMappingURL=cli-bundle.js.map