初始化
This commit is contained in:
331
uni_modules/UniDevTools/node_modules/cac/deno/CAC.ts
generated
vendored
Normal file
331
uni_modules/UniDevTools/node_modules/cac/deno/CAC.ts
generated
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
import { EventEmitter } from "https://deno.land/std@0.80.0/node/events.ts";
|
||||
import mri from "https://cdn.skypack.dev/mri";
|
||||
import Command, { GlobalCommand, CommandConfig, HelpCallback, CommandExample } from "./Command.ts";
|
||||
import { OptionConfig } from "./Option.ts";
|
||||
import { getMriOptions, setDotProp, setByType, getFileName, camelcaseOptionName } from "./utils.ts";
|
||||
import { processArgs } from "./deno.ts";
|
||||
interface ParsedArgv {
|
||||
args: ReadonlyArray<string>;
|
||||
options: {
|
||||
[k: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
class CAC extends EventEmitter {
|
||||
/** The program name to display in help and version message */
|
||||
name: string;
|
||||
commands: Command[];
|
||||
globalCommand: GlobalCommand;
|
||||
matchedCommand?: Command;
|
||||
matchedCommandName?: string;
|
||||
/**
|
||||
* Raw CLI arguments
|
||||
*/
|
||||
|
||||
rawArgs: string[];
|
||||
/**
|
||||
* Parsed CLI arguments
|
||||
*/
|
||||
|
||||
args: ParsedArgv['args'];
|
||||
/**
|
||||
* Parsed CLI options, camelCased
|
||||
*/
|
||||
|
||||
options: ParsedArgv['options'];
|
||||
showHelpOnExit?: boolean;
|
||||
showVersionOnExit?: boolean;
|
||||
/**
|
||||
* @param name The program name to display in help and version message
|
||||
*/
|
||||
|
||||
constructor(name = '') {
|
||||
super();
|
||||
this.name = name;
|
||||
this.commands = [];
|
||||
this.rawArgs = [];
|
||||
this.args = [];
|
||||
this.options = {};
|
||||
this.globalCommand = new GlobalCommand(this);
|
||||
this.globalCommand.usage('<command> [options]');
|
||||
}
|
||||
/**
|
||||
* Add a global usage text.
|
||||
*
|
||||
* This is not used by sub-commands.
|
||||
*/
|
||||
|
||||
|
||||
usage(text: string) {
|
||||
this.globalCommand.usage(text);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Add a sub-command
|
||||
*/
|
||||
|
||||
|
||||
command(rawName: string, description?: string, config?: CommandConfig) {
|
||||
const command = new Command(rawName, description || '', config, this);
|
||||
command.globalCommand = this.globalCommand;
|
||||
this.commands.push(command);
|
||||
return command;
|
||||
}
|
||||
/**
|
||||
* Add a global CLI option.
|
||||
*
|
||||
* Which is also applied to sub-commands.
|
||||
*/
|
||||
|
||||
|
||||
option(rawName: string, description: string, config?: OptionConfig) {
|
||||
this.globalCommand.option(rawName, description, config);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Show help message when `-h, --help` flags appear.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
help(callback?: HelpCallback) {
|
||||
this.globalCommand.option('-h, --help', 'Display this message');
|
||||
this.globalCommand.helpCallback = callback;
|
||||
this.showHelpOnExit = true;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Show version number when `-v, --version` flags appear.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
version(version: string, customFlags = '-v, --version') {
|
||||
this.globalCommand.version(version, customFlags);
|
||||
this.showVersionOnExit = true;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Add a global example.
|
||||
*
|
||||
* This example added here will not be used by sub-commands.
|
||||
*/
|
||||
|
||||
|
||||
example(example: CommandExample) {
|
||||
this.globalCommand.example(example);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Output the version number.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
outputVersion() {
|
||||
this.globalCommand.outputVersion();
|
||||
}
|
||||
|
||||
private setParsedInfo({
|
||||
args,
|
||||
options
|
||||
}: ParsedArgv, matchedCommand?: Command, matchedCommandName?: string) {
|
||||
this.args = args;
|
||||
this.options = options;
|
||||
|
||||
if (matchedCommand) {
|
||||
this.matchedCommand = matchedCommand;
|
||||
}
|
||||
|
||||
if (matchedCommandName) {
|
||||
this.matchedCommandName = matchedCommandName;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
unsetMatchedCommand() {
|
||||
this.matchedCommand = undefined;
|
||||
this.matchedCommandName = undefined;
|
||||
}
|
||||
/**
|
||||
* Parse argv
|
||||
*/
|
||||
|
||||
|
||||
parse(argv = processArgs, {
|
||||
/** Whether to run the action for matched command */
|
||||
run = true
|
||||
} = {}): ParsedArgv {
|
||||
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 = { ...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;
|
||||
this.unsetMatchedCommand();
|
||||
}
|
||||
|
||||
if (this.options.version && this.showVersionOnExit && this.matchedCommandName == null) {
|
||||
this.outputVersion();
|
||||
run = false;
|
||||
this.unsetMatchedCommand();
|
||||
}
|
||||
|
||||
const parsedArgv = {
|
||||
args: this.args,
|
||||
options: this.options
|
||||
};
|
||||
|
||||
if (run) {
|
||||
this.runMatchedCommand();
|
||||
}
|
||||
|
||||
if (!this.matchedCommand && this.args[0]) {
|
||||
this.emit('command:*');
|
||||
}
|
||||
|
||||
return parsedArgv;
|
||||
}
|
||||
|
||||
private mri(argv: string[],
|
||||
/** Matched command */
|
||||
command?: Command): ParsedArgv {
|
||||
// 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: string[] = [];
|
||||
const doubleDashesIndex = argv.indexOf('--');
|
||||
|
||||
if (doubleDashesIndex > -1) {
|
||||
argsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1);
|
||||
argv = argv.slice(0, doubleDashesIndex);
|
||||
}
|
||||
|
||||
let parsed = mri(argv, mriOptions);
|
||||
parsed = Object.keys(parsed).reduce((res, name) => {
|
||||
return { ...res,
|
||||
[camelcaseOptionName(name)]: parsed[name]
|
||||
};
|
||||
}, {
|
||||
_: []
|
||||
});
|
||||
const args = parsed._;
|
||||
const options: {
|
||||
[k: string]: any;
|
||||
} = {
|
||||
'--': 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];
|
||||
}
|
||||
}
|
||||
} // Set option values (support dot-nested property name)
|
||||
|
||||
|
||||
for (const key of Object.keys(parsed)) {
|
||||
if (key !== '_') {
|
||||
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: any[] = [];
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CAC;
|
||||
269
uni_modules/UniDevTools/node_modules/cac/deno/Command.ts
generated
vendored
Normal file
269
uni_modules/UniDevTools/node_modules/cac/deno/Command.ts
generated
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
import CAC from "./CAC.ts";
|
||||
import Option, { OptionConfig } from "./Option.ts";
|
||||
import { removeBrackets, findAllBrackets, findLongest, padRight, CACError } from "./utils.ts";
|
||||
import { platformInfo } from "./deno.ts";
|
||||
interface CommandArg {
|
||||
required: boolean;
|
||||
value: string;
|
||||
variadic: boolean;
|
||||
}
|
||||
interface HelpSection {
|
||||
title?: string;
|
||||
body: string;
|
||||
}
|
||||
interface CommandConfig {
|
||||
allowUnknownOptions?: boolean;
|
||||
ignoreOptionDefaultValue?: boolean;
|
||||
}
|
||||
type HelpCallback = (sections: HelpSection[]) => void | HelpSection[];
|
||||
type CommandExample = ((bin: string) => string) | string;
|
||||
|
||||
class Command {
|
||||
options: Option[];
|
||||
aliasNames: string[];
|
||||
/* Parsed command name */
|
||||
|
||||
name: string;
|
||||
args: CommandArg[];
|
||||
commandAction?: (...args: any[]) => any;
|
||||
usageText?: string;
|
||||
versionNumber?: string;
|
||||
examples: CommandExample[];
|
||||
helpCallback?: HelpCallback;
|
||||
globalCommand?: GlobalCommand;
|
||||
|
||||
constructor(public rawName: string, public description: string, public config: CommandConfig = {}, public cli: CAC) {
|
||||
this.options = [];
|
||||
this.aliasNames = [];
|
||||
this.name = removeBrackets(rawName);
|
||||
this.args = findAllBrackets(rawName);
|
||||
this.examples = [];
|
||||
}
|
||||
|
||||
usage(text: string) {
|
||||
this.usageText = text;
|
||||
return this;
|
||||
}
|
||||
|
||||
allowUnknownOptions() {
|
||||
this.config.allowUnknownOptions = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
ignoreOptionDefaultValue() {
|
||||
this.config.ignoreOptionDefaultValue = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
version(version: string, customFlags = '-v, --version') {
|
||||
this.versionNumber = version;
|
||||
this.option(customFlags, 'Display version number');
|
||||
return this;
|
||||
}
|
||||
|
||||
example(example: CommandExample) {
|
||||
this.examples.push(example);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Add a option for this command
|
||||
* @param rawName Raw option name(s)
|
||||
* @param description Option description
|
||||
* @param config Option config
|
||||
*/
|
||||
|
||||
|
||||
option(rawName: string, description: string, config?: OptionConfig) {
|
||||
const option = new Option(rawName, description, config);
|
||||
this.options.push(option);
|
||||
return this;
|
||||
}
|
||||
|
||||
alias(name: string) {
|
||||
this.aliasNames.push(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
action(callback: (...args: any[]) => any) {
|
||||
this.commandAction = callback;
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Check if a command name is matched by this command
|
||||
* @param name Command name
|
||||
*/
|
||||
|
||||
|
||||
isMatched(name: string) {
|
||||
return this.name === name || this.aliasNames.includes(name);
|
||||
}
|
||||
|
||||
get isDefaultCommand() {
|
||||
return this.name === '' || this.aliasNames.includes('!');
|
||||
}
|
||||
|
||||
get isGlobalCommand(): boolean {
|
||||
return this instanceof GlobalCommand;
|
||||
}
|
||||
/**
|
||||
* Check if an option is registered in this command
|
||||
* @param name Option name
|
||||
*/
|
||||
|
||||
|
||||
hasOption(name: string) {
|
||||
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;
|
||||
let sections: HelpSection[] = [{
|
||||
body: `${name}${versionNumber ? `/${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')
|
||||
});
|
||||
}
|
||||
|
||||
let options = this.isGlobalCommand ? globalOptions : [...this.options, ...(globalOptions || [])];
|
||||
|
||||
if (!this.isGlobalCommand && !this.isDefaultCommand) {
|
||||
options = options.filter(option => option.name !== 'version');
|
||||
}
|
||||
|
||||
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) {
|
||||
sections = helpCallback(sections) || 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}`);
|
||||
}
|
||||
}
|
||||
|
||||
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: CAC) {
|
||||
super('@@global@@', '', {}, cli);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export type { HelpCallback, CommandExample, CommandConfig };
|
||||
export { GlobalCommand };
|
||||
export default Command;
|
||||
52
uni_modules/UniDevTools/node_modules/cac/deno/Option.ts
generated
vendored
Normal file
52
uni_modules/UniDevTools/node_modules/cac/deno/Option.ts
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
import { removeBrackets, camelcaseOptionName } from "./utils.ts";
|
||||
interface OptionConfig {
|
||||
default?: any;
|
||||
type?: any[];
|
||||
}
|
||||
export default class Option {
|
||||
/** Option name */
|
||||
name: string;
|
||||
/** Option name and aliases */
|
||||
|
||||
names: string[];
|
||||
isBoolean?: boolean; // `required` will be a boolean for options with brackets
|
||||
|
||||
required?: boolean;
|
||||
config: OptionConfig;
|
||||
negated: boolean;
|
||||
|
||||
constructor(public rawName: string, public description: string, config?: OptionConfig) {
|
||||
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: string) => {
|
||||
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 == null) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
export type { OptionConfig };
|
||||
4
uni_modules/UniDevTools/node_modules/cac/deno/deno.ts
generated
vendored
Normal file
4
uni_modules/UniDevTools/node_modules/cac/deno/deno.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
// Ignore the TypeScript errors
|
||||
// Since this file will only be used in Deno runtime
|
||||
export const processArgs = ['deno', 'cli'].concat(Deno.args);
|
||||
export const platformInfo = `${Deno.build.os}-${Deno.build.arch} deno-${Deno.version.deno}`;
|
||||
10
uni_modules/UniDevTools/node_modules/cac/deno/index.ts
generated
vendored
Normal file
10
uni_modules/UniDevTools/node_modules/cac/deno/index.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import CAC from "./CAC.ts";
|
||||
import Command from "./Command.ts";
|
||||
/**
|
||||
* @param name The program name to display in help and version message
|
||||
*/
|
||||
|
||||
const cac = (name = '') => new CAC(name);
|
||||
|
||||
export default cac;
|
||||
export { cac, CAC, Command };
|
||||
145
uni_modules/UniDevTools/node_modules/cac/deno/utils.ts
generated
vendored
Normal file
145
uni_modules/UniDevTools/node_modules/cac/deno/utils.ts
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
import Option from "./Option.ts";
|
||||
export const removeBrackets = (v: string) => v.replace(/[<[].+/, '').trim();
|
||||
export const findAllBrackets = (v: string) => {
|
||||
const ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g;
|
||||
const SQUARE_BRACKET_RE_GLOBAL = /\[([^\]]+)\]/g;
|
||||
const res = [];
|
||||
|
||||
const parse = (match: string[]) => {
|
||||
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;
|
||||
};
|
||||
interface MriOptions {
|
||||
alias: {
|
||||
[k: string]: string[];
|
||||
};
|
||||
boolean: string[];
|
||||
}
|
||||
export const getMriOptions = (options: Option[]) => {
|
||||
const result: MriOptions = {
|
||||
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);
|
||||
} // 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
export const findLongest = (arr: string[]) => {
|
||||
return arr.sort((a, b) => {
|
||||
return a.length > b.length ? -1 : 1;
|
||||
})[0];
|
||||
};
|
||||
export const padRight = (str: string, length: number) => {
|
||||
return str.length >= length ? str : `${str}${' '.repeat(length - str.length)}`;
|
||||
};
|
||||
export const camelcase = (input: string) => {
|
||||
return input.replace(/([a-z])-([a-z])/g, (_, p1, p2) => {
|
||||
return p1 + p2.toUpperCase();
|
||||
});
|
||||
};
|
||||
export const setDotProp = (obj: {
|
||||
[k: string]: any;
|
||||
}, keys: string[], val: any) => {
|
||||
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) ? {} : [];
|
||||
}
|
||||
};
|
||||
export const setByType = (obj: {
|
||||
[k: string]: any;
|
||||
}, transforms: {
|
||||
[k: string]: any;
|
||||
}) => {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
export const getFileName = (input: string) => {
|
||||
const m = /([^\\\/]+)$/.exec(input);
|
||||
return m ? m[1] : '';
|
||||
};
|
||||
export const camelcaseOptionName = (name: string) => {
|
||||
// Camelcase the option name
|
||||
// Don't camelcase anything after the dot `.`
|
||||
return name.split('.').map((v, i) => {
|
||||
return i === 0 ? camelcase(v) : v;
|
||||
}).join('.');
|
||||
};
|
||||
export class CACError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
|
||||
if (typeof Error.captureStackTrace === 'function') {
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
} else {
|
||||
this.stack = new Error(message).stack;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user