Comparing version 1.4.4 to 1.4.5
992
dist/cli.js
@@ -7,18 +7,18 @@ #!/usr/bin/env node | ||
function _interopNamespace(e) { | ||
if (e && e.__esModule) { return e; } else { | ||
var n = {}; | ||
if (e) { | ||
Object.keys(e).forEach(function (k) { | ||
var d = Object.getOwnPropertyDescriptor(e, k); | ||
Object.defineProperty(n, k, d.get ? d : { | ||
enumerable: true, | ||
get: function () { | ||
return e[k]; | ||
} | ||
}); | ||
}); | ||
} | ||
n['default'] = e; | ||
return n; | ||
if (e && e.__esModule) { return e; } else { | ||
var n = {}; | ||
if (e) { | ||
Object.keys(e).forEach(function (k) { | ||
var d = Object.getOwnPropertyDescriptor(e, k); | ||
Object.defineProperty(n, k, d.get ? d : { | ||
enumerable: true, | ||
get: function () { | ||
return e[k]; | ||
} | ||
}); | ||
}); | ||
} | ||
n['default'] = e; | ||
return n; | ||
} | ||
} | ||
@@ -151,613 +151,483 @@ | ||
const removeBrackets = (v) => v.replace(/[<[].+/, '').trim(); | ||
const removeBrackets = (v) => v.replace(/[<[].+/, "").trim(); | ||
const findAllBrackets = (v) => { | ||
const ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g; | ||
const SQUARE_BRACKET_RE_GLOBAL = /\[([^\]]+)\]/g; | ||
const res = []; | ||
const parse = (match) => { | ||
let variadic = false; | ||
let value = match[1]; | ||
if (value.startsWith('...')) { | ||
value = value.slice(3); | ||
variadic = true; | ||
} | ||
return { | ||
required: match[0].startsWith('<'), | ||
value, | ||
variadic | ||
}; | ||
const ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g; | ||
const SQUARE_BRACKET_RE_GLOBAL = /\[([^\]]+)\]/g; | ||
const res = []; | ||
const parse = (match) => { | ||
let variadic = false; | ||
let value = match[1]; | ||
if (value.startsWith("...")) { | ||
value = value.slice(3); | ||
variadic = true; | ||
} | ||
return { | ||
required: match[0].startsWith("<"), | ||
value, | ||
variadic | ||
}; | ||
let angledMatch; | ||
while ((angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v))) { | ||
res.push(parse(angledMatch)); | ||
} | ||
let squareMatch; | ||
while ((squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v))) { | ||
res.push(parse(squareMatch)); | ||
} | ||
return res; | ||
}; | ||
let angledMatch; | ||
while (angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v)) { | ||
res.push(parse(angledMatch)); | ||
} | ||
let squareMatch; | ||
while (squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v)) { | ||
res.push(parse(squareMatch)); | ||
} | ||
return res; | ||
}; | ||
const getMriOptions = (options) => { | ||
const result = { alias: {}, boolean: [] }; | ||
for (const [index, option] of options.entries()) { | ||
// We do not set default values in mri options | ||
// Since its type (typeof) will be used to cast parsed arguments. | ||
// Which mean `--foo foo` will be parsed as `{foo: true}` if we have `{default:{foo: true}}` | ||
// Set alias | ||
if (option.names.length > 1) { | ||
result.alias[option.names[0]] = option.names.slice(1); | ||
const result = { | ||
alias: {}, | ||
boolean: [] | ||
}; | ||
for (const [index, option] of options.entries()) { | ||
if (option.names.length > 1) { | ||
result.alias[option.names[0]] = option.names.slice(1); | ||
} | ||
if (option.isBoolean) { | ||
if (option.negated) { | ||
const hasStringTypeOption = options.some((o, i) => { | ||
return i !== index && o.names.some((name) => option.names.includes(name)) && typeof o.required === "boolean"; | ||
}); | ||
if (!hasStringTypeOption) { | ||
result.boolean.push(option.names[0]); | ||
} | ||
// Set boolean | ||
if (option.isBoolean) { | ||
if (option.negated) { | ||
// For negated option | ||
// We only set it to `boolean` type when there's no string-type option with the same name | ||
const hasStringTypeOption = options.some((o, i) => { | ||
return (i !== index && | ||
o.names.some(name => option.names.includes(name)) && | ||
typeof o.required === 'boolean'); | ||
}); | ||
if (!hasStringTypeOption) { | ||
result.boolean.push(option.names[0]); | ||
} | ||
} | ||
else { | ||
result.boolean.push(option.names[0]); | ||
} | ||
} | ||
} else { | ||
result.boolean.push(option.names[0]); | ||
} | ||
} | ||
return result; | ||
} | ||
return result; | ||
}; | ||
const findLongest = (arr) => { | ||
return arr.sort((a, b) => { | ||
return a.length > b.length ? -1 : 1; | ||
})[0]; | ||
return arr.sort((a, b) => { | ||
return a.length > b.length ? -1 : 1; | ||
})[0]; | ||
}; | ||
const padRight = (str, length) => { | ||
return str.length >= length ? str : `${str}${' '.repeat(length - str.length)}`; | ||
return str.length >= length ? str : `${str}${" ".repeat(length - str.length)}`; | ||
}; | ||
const camelcase = (input) => { | ||
return input.replace(/([a-z])-([a-z])/g, (_, p1, p2) => { | ||
return p1 + p2.toUpperCase(); | ||
}); | ||
return input.replace(/([a-z])-([a-z])/g, (_, p1, p2) => { | ||
return p1 + p2.toUpperCase(); | ||
}); | ||
}; | ||
const setDotProp = (obj, keys, val) => { | ||
let i = 0; | ||
let length = keys.length; | ||
let t = obj; | ||
let x; | ||
for (; i < length; ++i) { | ||
x = t[keys[i]]; | ||
t = t[keys[i]] = | ||
i === length - 1 | ||
? val | ||
: x != null | ||
? x | ||
: !!~keys[i + 1].indexOf('.') || !(+keys[i + 1] > -1) | ||
? {} | ||
: []; | ||
} | ||
let i = 0; | ||
let length = keys.length; | ||
let t = obj; | ||
let x; | ||
for (; i < length; ++i) { | ||
x = t[keys[i]]; | ||
t = t[keys[i]] = i === length - 1 ? val : x != null ? x : !!~keys[i + 1].indexOf(".") || !(+keys[i + 1] > -1) ? {} : []; | ||
} | ||
}; | ||
const setByType = (obj, transforms) => { | ||
for (const key of Object.keys(transforms)) { | ||
const transform = transforms[key]; | ||
if (transform.shouldTransform) { | ||
obj[key] = Array.prototype.concat.call([], obj[key]); | ||
if (typeof transform.transformFunction === 'function') { | ||
obj[key] = obj[key].map(transform.transformFunction); | ||
} | ||
} | ||
for (const key of Object.keys(transforms)) { | ||
const transform = transforms[key]; | ||
if (transform.shouldTransform) { | ||
obj[key] = Array.prototype.concat.call([], obj[key]); | ||
if (typeof transform.transformFunction === "function") { | ||
obj[key] = obj[key].map(transform.transformFunction); | ||
} | ||
} | ||
} | ||
}; | ||
const getFileName = (input) => { | ||
const m = /([^\\\/]+)$/.exec(input); | ||
return m ? m[1] : ''; | ||
const m = /([^\\\/]+)$/.exec(input); | ||
return m ? m[1] : ""; | ||
}; | ||
const camelcaseOptionName = (name) => { | ||
// Camelcase the option name | ||
// Don't camelcase anything after the dot `.` | ||
return name | ||
.split('.') | ||
.map((v, i) => { | ||
return i === 0 ? camelcase(v) : v; | ||
}) | ||
.join('.'); | ||
return name.split(".").map((v, i) => { | ||
return i === 0 ? camelcase(v) : v; | ||
}).join("."); | ||
}; | ||
class CACError extends Error { | ||
constructor(message) { | ||
super(message); | ||
this.name = this.constructor.name; | ||
if (typeof Error.captureStackTrace === 'function') { | ||
Error.captureStackTrace(this, this.constructor); | ||
} | ||
else { | ||
this.stack = new Error(message).stack; | ||
} | ||
constructor(message) { | ||
super(message); | ||
this.name = this.constructor.name; | ||
if (typeof Error.captureStackTrace === "function") { | ||
Error.captureStackTrace(this, this.constructor); | ||
} else { | ||
this.stack = new Error(message).stack; | ||
} | ||
} | ||
} | ||
class Option { | ||
constructor(rawName, description, config) { | ||
this.rawName = rawName; | ||
this.description = description; | ||
this.config = Object.assign({}, config); | ||
// You may use cli.option('--env.* [value]', 'desc') to denote a dot-nested option | ||
rawName = rawName.replace(/\.\*/g, ''); | ||
this.negated = false; | ||
this.names = removeBrackets(rawName) | ||
.split(',') | ||
.map((v) => { | ||
let name = v.trim().replace(/^-{1,2}/, ''); | ||
if (name.startsWith('no-')) { | ||
this.negated = true; | ||
name = name.replace(/^no-/, ''); | ||
} | ||
return camelcaseOptionName(name); | ||
}) | ||
.sort((a, b) => (a.length > b.length ? 1 : -1)); // Sort names | ||
// Use the longest name (last one) as actual option name | ||
this.name = this.names[this.names.length - 1]; | ||
if (this.negated) { | ||
this.config.default = true; | ||
} | ||
if (rawName.includes('<')) { | ||
this.required = true; | ||
} | ||
else if (rawName.includes('[')) { | ||
this.required = false; | ||
} | ||
else { | ||
// No arg needed, it's boolean flag | ||
this.isBoolean = true; | ||
} | ||
constructor(rawName, description, config) { | ||
this.rawName = rawName; | ||
this.description = description; | ||
this.config = Object.assign({}, config); | ||
rawName = rawName.replace(/\.\*/g, ""); | ||
this.negated = false; | ||
this.names = removeBrackets(rawName).split(",").map((v) => { | ||
let name = v.trim().replace(/^-{1,2}/, ""); | ||
if (name.startsWith("no-")) { | ||
this.negated = true; | ||
name = name.replace(/^no-/, ""); | ||
} | ||
return camelcaseOptionName(name); | ||
}).sort((a, b) => a.length > b.length ? 1 : -1); | ||
this.name = this.names[this.names.length - 1]; | ||
if (this.negated) { | ||
this.config.default = true; | ||
} | ||
if (rawName.includes("<")) { | ||
this.required = true; | ||
} else if (rawName.includes("[")) { | ||
this.required = false; | ||
} else { | ||
this.isBoolean = true; | ||
} | ||
} | ||
} | ||
const deno = typeof window !== 'undefined' && window.Deno; | ||
const denoScriptPath = deno && typeof window !== 'undefined' && window.location.pathname; | ||
// Adds deno executable and script path to processArgs as "compatibility" layer for node | ||
// See https://github.com/cacjs/cac/issues/69 | ||
const processArgs = deno | ||
? ['deno', denoScriptPath].concat(Deno.args) | ||
: process.argv; | ||
const platformInfo = deno | ||
? `${Deno.build.os}-${Deno.build.arch} deno-${Deno.version.deno}` | ||
: `${process.platform}-${process.arch} node-${process.version}`; | ||
const deno = typeof window !== "undefined" && window.Deno; | ||
const processArgs = deno ? ["deno", "cli"].concat(Deno.args) : process.argv; | ||
const platformInfo = deno ? `${Deno.build.os}-${Deno.build.arch} deno-${Deno.version.deno}` : `${process.platform}-${process.arch} node-${process.version}`; | ||
class Command { | ||
constructor(rawName, description, config = {}, cli) { | ||
this.rawName = rawName; | ||
this.description = description; | ||
this.config = config; | ||
this.cli = cli; | ||
this.options = []; | ||
this.aliasNames = []; | ||
this.name = removeBrackets(rawName); | ||
this.args = findAllBrackets(rawName); | ||
this.examples = []; | ||
constructor(rawName, description, config = {}, cli) { | ||
this.rawName = rawName; | ||
this.description = description; | ||
this.config = config; | ||
this.cli = cli; | ||
this.options = []; | ||
this.aliasNames = []; | ||
this.name = removeBrackets(rawName); | ||
this.args = findAllBrackets(rawName); | ||
this.examples = []; | ||
} | ||
usage(text) { | ||
this.usageText = text; | ||
return this; | ||
} | ||
allowUnknownOptions() { | ||
this.config.allowUnknownOptions = true; | ||
return this; | ||
} | ||
ignoreOptionDefaultValue() { | ||
this.config.ignoreOptionDefaultValue = true; | ||
return this; | ||
} | ||
version(version, customFlags = "-v, --version") { | ||
this.versionNumber = version; | ||
this.option(customFlags, "Display version number"); | ||
return this; | ||
} | ||
example(example) { | ||
this.examples.push(example); | ||
return this; | ||
} | ||
option(rawName, description, config) { | ||
const option = new Option(rawName, description, config); | ||
this.options.push(option); | ||
return this; | ||
} | ||
alias(name) { | ||
this.aliasNames.push(name); | ||
return this; | ||
} | ||
action(callback) { | ||
this.commandAction = callback; | ||
return this; | ||
} | ||
isMatched(name) { | ||
return this.name === name || this.aliasNames.includes(name); | ||
} | ||
get isDefaultCommand() { | ||
return this.name === "" || this.aliasNames.includes("!"); | ||
} | ||
get isGlobalCommand() { | ||
return this instanceof GlobalCommand; | ||
} | ||
hasOption(name) { | ||
name = name.split(".")[0]; | ||
return this.options.find((option) => { | ||
return option.names.includes(name); | ||
}); | ||
} | ||
outputHelp() { | ||
const {name, commands} = this.cli; | ||
const {versionNumber, options: globalOptions, helpCallback} = this.cli.globalCommand; | ||
const sections = [{ | ||
body: `${name}${versionNumber ? ` v${versionNumber}` : ""}` | ||
}]; | ||
sections.push({ | ||
title: "Usage", | ||
body: ` $ ${name} ${this.usageText || this.rawName}` | ||
}); | ||
const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0; | ||
if (showCommands) { | ||
const longestCommandName = findLongest(commands.map((command) => command.rawName)); | ||
sections.push({ | ||
title: "Commands", | ||
body: commands.map((command) => { | ||
return ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`; | ||
}).join("\n") | ||
}); | ||
sections.push({ | ||
title: `For more info, run any command with the \`--help\` flag`, | ||
body: commands.map((command) => ` $ ${name}${command.name === "" ? "" : ` ${command.name}`} --help`).join("\n") | ||
}); | ||
} | ||
usage(text) { | ||
this.usageText = text; | ||
return this; | ||
const options = this.isGlobalCommand ? globalOptions : [...this.options, ...globalOptions || []]; | ||
if (options.length > 0) { | ||
const longestOptionName = findLongest(options.map((option) => option.rawName)); | ||
sections.push({ | ||
title: "Options", | ||
body: options.map((option) => { | ||
return ` ${padRight(option.rawName, longestOptionName.length)} ${option.description} ${option.config.default === void 0 ? "" : `(default: ${option.config.default})`}`; | ||
}).join("\n") | ||
}); | ||
} | ||
allowUnknownOptions() { | ||
this.config.allowUnknownOptions = true; | ||
return this; | ||
if (this.examples.length > 0) { | ||
sections.push({ | ||
title: "Examples", | ||
body: this.examples.map((example) => { | ||
if (typeof example === "function") { | ||
return example(name); | ||
} | ||
return example; | ||
}).join("\n") | ||
}); | ||
} | ||
ignoreOptionDefaultValue() { | ||
this.config.ignoreOptionDefaultValue = true; | ||
return this; | ||
if (helpCallback) { | ||
helpCallback(sections); | ||
} | ||
version(version, customFlags = '-v, --version') { | ||
this.versionNumber = version; | ||
this.option(customFlags, 'Display version number'); | ||
return this; | ||
console.log(sections.map((section) => { | ||
return section.title ? `${section.title}: | ||
${section.body}` : section.body; | ||
}).join("\n\n")); | ||
} | ||
outputVersion() { | ||
const {name} = this.cli; | ||
const {versionNumber} = this.cli.globalCommand; | ||
if (versionNumber) { | ||
console.log(`${name}/${versionNumber} ${platformInfo}`); | ||
} | ||
example(example) { | ||
this.examples.push(example); | ||
return this; | ||
} | ||
checkRequiredArgs() { | ||
const minimalArgsCount = this.args.filter((arg) => arg.required).length; | ||
if (this.cli.args.length < minimalArgsCount) { | ||
throw new CACError(`missing required args for command \`${this.rawName}\``); | ||
} | ||
/** | ||
* Add a option for this command | ||
* @param rawName Raw option name(s) | ||
* @param description Option description | ||
* @param config Option config | ||
*/ | ||
option(rawName, description, config) { | ||
const option = new Option(rawName, description, config); | ||
this.options.push(option); | ||
return this; | ||
} | ||
alias(name) { | ||
this.aliasNames.push(name); | ||
return this; | ||
} | ||
action(callback) { | ||
this.commandAction = callback; | ||
return this; | ||
} | ||
/** | ||
* Check if a command name is matched by this command | ||
* @param name Command name | ||
*/ | ||
isMatched(name) { | ||
return this.name === name || this.aliasNames.includes(name); | ||
} | ||
get isDefaultCommand() { | ||
return this.name === '' || this.aliasNames.includes('!'); | ||
} | ||
get isGlobalCommand() { | ||
return this instanceof GlobalCommand; | ||
} | ||
/** | ||
* Check if an option is registered in this command | ||
* @param name Option name | ||
*/ | ||
hasOption(name) { | ||
name = name.split('.')[0]; | ||
return this.options.find(option => { | ||
return option.names.includes(name); | ||
}); | ||
} | ||
outputHelp() { | ||
const { name, commands } = this.cli; | ||
const { versionNumber, options: globalOptions, helpCallback } = this.cli.globalCommand; | ||
const sections = [ | ||
{ | ||
body: `${name}${versionNumber ? ` v${versionNumber}` : ''}` | ||
} | ||
]; | ||
sections.push({ | ||
title: 'Usage', | ||
body: ` $ ${name} ${this.usageText || this.rawName}` | ||
}); | ||
const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0; | ||
if (showCommands) { | ||
const longestCommandName = findLongest(commands.map(command => command.rawName)); | ||
sections.push({ | ||
title: 'Commands', | ||
body: commands | ||
.map(command => { | ||
return ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`; | ||
}) | ||
.join('\n') | ||
}); | ||
sections.push({ | ||
title: `For more info, run any command with the \`--help\` flag`, | ||
body: commands | ||
.map(command => ` $ ${name}${command.name === '' ? '' : ` ${command.name}`} --help`) | ||
.join('\n') | ||
}); | ||
} | ||
checkUnknownOptions() { | ||
const {options, globalCommand} = this.cli; | ||
if (!this.config.allowUnknownOptions) { | ||
for (const name of Object.keys(options)) { | ||
if (name !== "--" && !this.hasOption(name) && !globalCommand.hasOption(name)) { | ||
throw new CACError(`Unknown option \`${name.length > 1 ? `--${name}` : `-${name}`}\``); | ||
} | ||
const options = this.isGlobalCommand | ||
? globalOptions | ||
: [...this.options, ...(globalOptions || [])]; | ||
if (options.length > 0) { | ||
const longestOptionName = findLongest(options.map(option => option.rawName)); | ||
sections.push({ | ||
title: 'Options', | ||
body: options | ||
.map(option => { | ||
return ` ${padRight(option.rawName, longestOptionName.length)} ${option.description} ${option.config.default === undefined | ||
? '' | ||
: `(default: ${option.config.default})`}`; | ||
}) | ||
.join('\n') | ||
}); | ||
} | ||
if (this.examples.length > 0) { | ||
sections.push({ | ||
title: 'Examples', | ||
body: this.examples | ||
.map(example => { | ||
if (typeof example === 'function') { | ||
return example(name); | ||
} | ||
return example; | ||
}) | ||
.join('\n') | ||
}); | ||
} | ||
if (helpCallback) { | ||
helpCallback(sections); | ||
} | ||
console.log(sections | ||
.map(section => { | ||
return section.title | ||
? `${section.title}:\n${section.body}` | ||
: section.body; | ||
}) | ||
.join('\n\n')); | ||
} | ||
} | ||
outputVersion() { | ||
const { name } = this.cli; | ||
const { versionNumber } = this.cli.globalCommand; | ||
if (versionNumber) { | ||
console.log(`${name}/${versionNumber} ${platformInfo}`); | ||
} | ||
checkOptionValue() { | ||
const {options: parsedOptions, globalCommand} = this.cli; | ||
const options = [...globalCommand.options, ...this.options]; | ||
for (const option of options) { | ||
const value = parsedOptions[option.name.split(".")[0]]; | ||
if (option.required) { | ||
const hasNegated = options.some((o) => o.negated && o.names.includes(option.name)); | ||
if (value === true || value === false && !hasNegated) { | ||
throw new CACError(`option \`${option.rawName}\` value is missing`); | ||
} | ||
} | ||
} | ||
checkRequiredArgs() { | ||
const minimalArgsCount = this.args.filter(arg => arg.required).length; | ||
if (this.cli.args.length < minimalArgsCount) { | ||
throw new CACError(`missing required args for command \`${this.rawName}\``); | ||
} | ||
} | ||
/** | ||
* Check if the parsed options contain any unknown options | ||
* | ||
* Exit and output error when true | ||
*/ | ||
checkUnknownOptions() { | ||
const { options, globalCommand } = this.cli; | ||
if (!this.config.allowUnknownOptions) { | ||
for (const name of Object.keys(options)) { | ||
if (name !== '--' && | ||
!this.hasOption(name) && | ||
!globalCommand.hasOption(name)) { | ||
throw new CACError(`Unknown option \`${name.length > 1 ? `--${name}` : `-${name}`}\``); | ||
} | ||
} | ||
} | ||
} | ||
/** | ||
* Check if the required string-type options exist | ||
*/ | ||
checkOptionValue() { | ||
const { options: parsedOptions, globalCommand } = this.cli; | ||
const options = [...globalCommand.options, ...this.options]; | ||
for (const option of options) { | ||
const value = parsedOptions[option.name.split('.')[0]]; | ||
// Check required option value | ||
if (option.required) { | ||
const hasNegated = options.some(o => o.negated && o.names.includes(option.name)); | ||
if (value === true || (value === false && !hasNegated)) { | ||
throw new CACError(`option \`${option.rawName}\` value is missing`); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
class GlobalCommand extends Command { | ||
constructor(cli) { | ||
super('@@global@@', '', {}, cli); | ||
} | ||
constructor(cli) { | ||
super("@@global@@", "", {}, cli); | ||
} | ||
} | ||
let __assign = Object.assign; | ||
class CAC extends events.EventEmitter { | ||
/** | ||
* @param name The program name to display in help and version message | ||
*/ | ||
constructor(name = '') { | ||
super(); | ||
this.name = name; | ||
this.commands = []; | ||
this.globalCommand = new GlobalCommand(this); | ||
this.globalCommand.usage('<command> [options]'); | ||
constructor(name = "") { | ||
super(); | ||
this.name = name; | ||
this.commands = []; | ||
this.globalCommand = new GlobalCommand(this); | ||
this.globalCommand.usage("<command> [options]"); | ||
} | ||
usage(text) { | ||
this.globalCommand.usage(text); | ||
return this; | ||
} | ||
command(rawName, description, config) { | ||
const command = new Command(rawName, description || "", config, this); | ||
command.globalCommand = this.globalCommand; | ||
this.commands.push(command); | ||
return command; | ||
} | ||
option(rawName, description, config) { | ||
this.globalCommand.option(rawName, description, config); | ||
return this; | ||
} | ||
help(callback) { | ||
this.globalCommand.option("-h, --help", "Display this message"); | ||
this.globalCommand.helpCallback = callback; | ||
this.showHelpOnExit = true; | ||
return this; | ||
} | ||
version(version, customFlags = "-v, --version") { | ||
this.globalCommand.version(version, customFlags); | ||
this.showVersionOnExit = true; | ||
return this; | ||
} | ||
example(example) { | ||
this.globalCommand.example(example); | ||
return this; | ||
} | ||
outputHelp() { | ||
if (this.matchedCommand) { | ||
this.matchedCommand.outputHelp(); | ||
} else { | ||
this.globalCommand.outputHelp(); | ||
} | ||
/** | ||
* Add a global usage text. | ||
* | ||
* This is not used by sub-commands. | ||
*/ | ||
usage(text) { | ||
this.globalCommand.usage(text); | ||
return this; | ||
} | ||
outputVersion() { | ||
this.globalCommand.outputVersion(); | ||
} | ||
setParsedInfo({args, options}, matchedCommand, matchedCommandName) { | ||
this.args = args; | ||
this.options = options; | ||
if (matchedCommand) { | ||
this.matchedCommand = matchedCommand; | ||
} | ||
/** | ||
* Add a sub-command | ||
*/ | ||
command(rawName, description, config) { | ||
const command = new Command(rawName, description || '', config, this); | ||
command.globalCommand = this.globalCommand; | ||
this.commands.push(command); | ||
return command; | ||
if (matchedCommandName) { | ||
this.matchedCommandName = matchedCommandName; | ||
} | ||
/** | ||
* Add a global CLI option. | ||
* | ||
* Which is also applied to sub-commands. | ||
*/ | ||
option(rawName, description, config) { | ||
this.globalCommand.option(rawName, description, config); | ||
return this; | ||
return this; | ||
} | ||
parse(argv = processArgs, {run = true} = {}) { | ||
this.rawArgs = argv; | ||
if (!this.name) { | ||
this.name = argv[1] ? getFileName(argv[1]) : "cli"; | ||
} | ||
/** | ||
* Show help message when `-h, --help` flags appear. | ||
* | ||
*/ | ||
help(callback) { | ||
this.globalCommand.option('-h, --help', 'Display this message'); | ||
this.globalCommand.helpCallback = callback; | ||
this.showHelpOnExit = true; | ||
return this; | ||
let shouldParse = true; | ||
for (const command of this.commands) { | ||
const parsed = this.mri(argv.slice(2), command); | ||
const commandName = parsed.args[0]; | ||
if (command.isMatched(commandName)) { | ||
shouldParse = false; | ||
const parsedInfo = __assign(__assign({}, parsed), { | ||
args: parsed.args.slice(1) | ||
}); | ||
this.setParsedInfo(parsedInfo, command, commandName); | ||
this.emit(`command:${commandName}`, command); | ||
} | ||
} | ||
/** | ||
* Show version number when `-v, --version` flags appear. | ||
* | ||
*/ | ||
version(version, customFlags = '-v, --version') { | ||
this.globalCommand.version(version, customFlags); | ||
this.showVersionOnExit = true; | ||
return this; | ||
if (shouldParse) { | ||
for (const command of this.commands) { | ||
if (command.name === "") { | ||
shouldParse = false; | ||
const parsed = this.mri(argv.slice(2), command); | ||
this.setParsedInfo(parsed, command); | ||
this.emit(`command:!`, command); | ||
} | ||
} | ||
} | ||
/** | ||
* Add a global example. | ||
* | ||
* This example added here will not be used by sub-commands. | ||
*/ | ||
example(example) { | ||
this.globalCommand.example(example); | ||
return this; | ||
if (shouldParse) { | ||
const parsed = this.mri(argv.slice(2)); | ||
this.setParsedInfo(parsed); | ||
} | ||
/** | ||
* Output the corresponding help message | ||
* When a sub-command is matched, output the help message for the command | ||
* Otherwise output the global one. | ||
* | ||
*/ | ||
outputHelp() { | ||
if (this.matchedCommand) { | ||
this.matchedCommand.outputHelp(); | ||
} | ||
else { | ||
this.globalCommand.outputHelp(); | ||
} | ||
if (this.options.help && this.showHelpOnExit) { | ||
this.outputHelp(); | ||
run = false; | ||
} | ||
/** | ||
* Output the version number. | ||
* | ||
*/ | ||
outputVersion() { | ||
this.globalCommand.outputVersion(); | ||
if (this.options.version && this.showVersionOnExit) { | ||
this.outputVersion(); | ||
run = false; | ||
} | ||
setParsedInfo({ args, options }, matchedCommand, matchedCommandName) { | ||
this.args = args; | ||
this.options = options; | ||
if (matchedCommand) { | ||
this.matchedCommand = matchedCommand; | ||
} | ||
if (matchedCommandName) { | ||
this.matchedCommandName = matchedCommandName; | ||
} | ||
return this; | ||
const parsedArgv = { | ||
args: this.args, | ||
options: this.options | ||
}; | ||
if (run) { | ||
this.runMatchedCommand(); | ||
} | ||
/** | ||
* Parse argv | ||
*/ | ||
parse(argv = processArgs, { | ||
/** Whether to run the action for matched command */ | ||
run = true } = {}) { | ||
this.rawArgs = argv; | ||
if (!this.name) { | ||
this.name = argv[1] ? getFileName(argv[1]) : 'cli'; | ||
} | ||
let shouldParse = true; | ||
// Search sub-commands | ||
for (const command of this.commands) { | ||
const parsed = this.mri(argv.slice(2), command); | ||
const commandName = parsed.args[0]; | ||
if (command.isMatched(commandName)) { | ||
shouldParse = false; | ||
const parsedInfo = Object.assign({}, parsed, { args: parsed.args.slice(1) }); | ||
this.setParsedInfo(parsedInfo, command, commandName); | ||
this.emit(`command:${commandName}`, command); | ||
} | ||
} | ||
if (shouldParse) { | ||
// Search the default command | ||
for (const command of this.commands) { | ||
if (command.name === '') { | ||
shouldParse = false; | ||
const parsed = this.mri(argv.slice(2), command); | ||
this.setParsedInfo(parsed, command); | ||
this.emit(`command:!`, command); | ||
} | ||
} | ||
} | ||
if (shouldParse) { | ||
const parsed = this.mri(argv.slice(2)); | ||
this.setParsedInfo(parsed); | ||
} | ||
if (this.options.help && this.showHelpOnExit) { | ||
this.outputHelp(); | ||
run = false; | ||
} | ||
if (this.options.version && this.showVersionOnExit) { | ||
this.outputVersion(); | ||
run = false; | ||
} | ||
const parsedArgv = { args: this.args, options: this.options }; | ||
if (run) { | ||
this.runMatchedCommand(); | ||
} | ||
if (!this.matchedCommand && this.args[0]) { | ||
this.emit('command:*'); | ||
} | ||
return parsedArgv; | ||
if (!this.matchedCommand && this.args[0]) { | ||
this.emit("command:*"); | ||
} | ||
mri(argv, | ||
/** Matched command */ command) { | ||
// All added options | ||
const cliOptions = [ | ||
...this.globalCommand.options, | ||
...(command ? command.options : []) | ||
]; | ||
const mriOptions = getMriOptions(cliOptions); | ||
// Extract everything after `--` since mri doesn't support it | ||
let argsAfterDoubleDashes = []; | ||
const doubleDashesIndex = argv.indexOf('--'); | ||
if (doubleDashesIndex > -1) { | ||
argsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1); | ||
argv = argv.slice(0, doubleDashesIndex); | ||
return parsedArgv; | ||
} | ||
mri(argv, command) { | ||
const cliOptions = [...this.globalCommand.options, ...command ? command.options : []]; | ||
const mriOptions = getMriOptions(cliOptions); | ||
let argsAfterDoubleDashes = []; | ||
const doubleDashesIndex = argv.indexOf("--"); | ||
if (doubleDashesIndex > -1) { | ||
argsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1); | ||
argv = argv.slice(0, doubleDashesIndex); | ||
} | ||
let parsed = lib(argv, mriOptions); | ||
parsed = Object.keys(parsed).reduce((res, name) => { | ||
return __assign(__assign({}, res), { | ||
[camelcaseOptionName(name)]: parsed[name] | ||
}); | ||
}, { | ||
_: [] | ||
}); | ||
const args = parsed._; | ||
delete parsed._; | ||
const options = { | ||
"--": argsAfterDoubleDashes | ||
}; | ||
const ignoreDefault = command && command.config.ignoreOptionDefaultValue ? command.config.ignoreOptionDefaultValue : this.globalCommand.config.ignoreOptionDefaultValue; | ||
let transforms = Object.create(null); | ||
for (const cliOption of cliOptions) { | ||
if (!ignoreDefault && cliOption.config.default !== void 0) { | ||
for (const name of cliOption.names) { | ||
options[name] = cliOption.config.default; | ||
} | ||
let parsed = lib(argv, mriOptions); | ||
parsed = Object.keys(parsed).reduce((res, name) => { | ||
return Object.assign({}, res, { [camelcaseOptionName(name)]: parsed[name] }); | ||
}, { _: [] }); | ||
const args = parsed._; | ||
delete parsed._; | ||
const options = { | ||
'--': argsAfterDoubleDashes | ||
}; | ||
// Set option default value | ||
const ignoreDefault = command && command.config.ignoreOptionDefaultValue | ||
? command.config.ignoreOptionDefaultValue | ||
: this.globalCommand.config.ignoreOptionDefaultValue; | ||
let transforms = Object.create(null); | ||
for (const cliOption of cliOptions) { | ||
if (!ignoreDefault && cliOption.config.default !== undefined) { | ||
for (const name of cliOption.names) { | ||
options[name] = cliOption.config.default; | ||
} | ||
} | ||
// If options type is defined | ||
if (Array.isArray(cliOption.config.type)) { | ||
if (transforms[cliOption.name] === undefined) { | ||
transforms[cliOption.name] = Object.create(null); | ||
transforms[cliOption.name]['shouldTransform'] = true; | ||
transforms[cliOption.name]['transformFunction'] = | ||
cliOption.config.type[0]; | ||
} | ||
} | ||
} | ||
if (Array.isArray(cliOption.config.type)) { | ||
if (transforms[cliOption.name] === void 0) { | ||
transforms[cliOption.name] = Object.create(null); | ||
transforms[cliOption.name]["shouldTransform"] = true; | ||
transforms[cliOption.name]["transformFunction"] = cliOption.config.type[0]; | ||
} | ||
// Set dot nested option values | ||
for (const key of Object.keys(parsed)) { | ||
const keys = key.split('.'); | ||
setDotProp(options, keys, parsed[key]); | ||
setByType(options, transforms); | ||
} | ||
return { | ||
args, | ||
options | ||
}; | ||
} | ||
} | ||
runMatchedCommand() { | ||
const { args, options, matchedCommand: command } = this; | ||
if (!command || !command.commandAction) | ||
return; | ||
command.checkUnknownOptions(); | ||
command.checkOptionValue(); | ||
command.checkRequiredArgs(); | ||
const actionArgs = []; | ||
command.args.forEach((arg, index) => { | ||
if (arg.variadic) { | ||
actionArgs.push(args.slice(index)); | ||
} | ||
else { | ||
actionArgs.push(args[index]); | ||
} | ||
}); | ||
actionArgs.push(options); | ||
return command.commandAction.apply(this, actionArgs); | ||
for (const key of Object.keys(parsed)) { | ||
const keys = key.split("."); | ||
setDotProp(options, keys, parsed[key]); | ||
setByType(options, transforms); | ||
} | ||
return { | ||
args, | ||
options | ||
}; | ||
} | ||
runMatchedCommand() { | ||
const {args, options, matchedCommand: command} = this; | ||
if (!command || !command.commandAction) | ||
return; | ||
command.checkUnknownOptions(); | ||
command.checkOptionValue(); | ||
command.checkRequiredArgs(); | ||
const actionArgs = []; | ||
command.args.forEach((arg, index) => { | ||
if (arg.variadic) { | ||
actionArgs.push(args.slice(index)); | ||
} else { | ||
actionArgs.push(args[index]); | ||
} | ||
}); | ||
actionArgs.push(options); | ||
return command.commandAction.apply(this, actionArgs); | ||
} | ||
} | ||
/** | ||
* @param name The program name to display in help and version message | ||
*/ | ||
const cac = (name = '') => new CAC(name); | ||
const cac = (name = "") => new CAC(name); | ||
{ | ||
module.exports = cac; | ||
module.exports.default = cac; | ||
module.exports.cac = cac; | ||
module.exports = cac; | ||
module.exports.default = cac; | ||
module.exports.cac = cac; | ||
} | ||
@@ -764,0 +634,0 @@ |
{ | ||
"name": "tsup", | ||
"version": "1.4.4", | ||
"version": "1.4.5", | ||
"main": "dist/index.js", | ||
@@ -27,6 +27,6 @@ "bin": "dist/cli.js", | ||
"@types/fs-extra": "^8.1.0", | ||
"@types/jest": "^25.2.1", | ||
"@types/node": "^13.9.2", | ||
"@types/resolve": "^1.17.0", | ||
"cac": "^6.5.8", | ||
"@types/jest": "^25.2.2", | ||
"@types/node": "^14.0.1", | ||
"@types/resolve": "^1.17.1", | ||
"cac": "^6.5.9", | ||
"colorette": "^1.1.0", | ||
@@ -39,8 +39,8 @@ "execa": "^4.0.1", | ||
"resolve": "^1.17.0", | ||
"rollup-plugin-dts": "^1.4.2", | ||
"rollup-plugin-dts": "^1.4.3", | ||
"rollup-plugin-hashbang": "^2.2.2", | ||
"ts-jest": "^25.5.1", | ||
"tsup": "^1.4.3", | ||
"tsup": "^1.4.4", | ||
"typescript": "^3.9.2" | ||
} | ||
} |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
384723
11302