diff options
author | Dimitri Staessens <[email protected]> | 2019-10-06 21:37:45 +0200 |
---|---|---|
committer | Dimitri Staessens <[email protected]> | 2019-10-06 21:37:45 +0200 |
commit | 3c51c3be85bb0d1bdb87ea0d6632f1c256912f27 (patch) | |
tree | c7ccc8279b12c4f7bdbbb4270d617e48f51722e4 /node_modules/yargs/lib | |
parent | 412c104bebc507bea9c94fd53b5bdc4b64cbfe31 (diff) | |
download | website-3c51c3be85bb0d1bdb87ea0d6632f1c256912f27.tar.gz website-3c51c3be85bb0d1bdb87ea0d6632f1c256912f27.zip |
build: Add some required modules for node
Diffstat (limited to 'node_modules/yargs/lib')
-rw-r--r-- | node_modules/yargs/lib/apply-extends.js | 53 | ||||
-rw-r--r-- | node_modules/yargs/lib/argsert.js | 66 | ||||
-rw-r--r-- | node_modules/yargs/lib/command.js | 426 | ||||
-rw-r--r-- | node_modules/yargs/lib/completion.js | 105 | ||||
-rw-r--r-- | node_modules/yargs/lib/levenshtein.js | 47 | ||||
-rw-r--r-- | node_modules/yargs/lib/obj-filter.js | 11 | ||||
-rw-r--r-- | node_modules/yargs/lib/usage.js | 531 | ||||
-rw-r--r-- | node_modules/yargs/lib/validation.js | 341 | ||||
-rw-r--r-- | node_modules/yargs/lib/yerror.js | 11 |
9 files changed, 1591 insertions, 0 deletions
diff --git a/node_modules/yargs/lib/apply-extends.js b/node_modules/yargs/lib/apply-extends.js new file mode 100644 index 0000000..1436b65 --- /dev/null +++ b/node_modules/yargs/lib/apply-extends.js @@ -0,0 +1,53 @@ + +'use strict' +const fs = require('fs') +const path = require('path') +const YError = require('./yerror') + +let previouslyVisitedConfigs = [] + +function checkForCircularExtends (cfgPath) { + if (previouslyVisitedConfigs.indexOf(cfgPath) > -1) { + throw new YError(`Circular extended configurations: '${cfgPath}'.`) + } +} + +function getPathToDefaultConfig (cwd, pathToExtend) { + return path.resolve(cwd, pathToExtend) +} + +function applyExtends (config, cwd) { + let defaultConfig = {} + + if (config.hasOwnProperty('extends')) { + if (typeof config.extends !== 'string') return defaultConfig + const isPath = /\.json|\..*rc$/.test(config.extends) + let pathToDefault = null + if (!isPath) { + try { + pathToDefault = require.resolve(config.extends) + } catch (err) { + // most likely this simply isn't a module. + } + } else { + pathToDefault = getPathToDefaultConfig(cwd, config.extends) + } + // maybe the module uses key for some other reason, + // err on side of caution. + if (!pathToDefault && !isPath) return config + + checkForCircularExtends(pathToDefault) + + previouslyVisitedConfigs.push(pathToDefault) + + defaultConfig = isPath ? JSON.parse(fs.readFileSync(pathToDefault, 'utf8')) : require(config.extends) + delete config.extends + defaultConfig = applyExtends(defaultConfig, path.dirname(pathToDefault)) + } + + previouslyVisitedConfigs = [] + + return Object.assign({}, defaultConfig, config) +} + +module.exports = applyExtends diff --git a/node_modules/yargs/lib/argsert.js b/node_modules/yargs/lib/argsert.js new file mode 100644 index 0000000..ed1d598 --- /dev/null +++ b/node_modules/yargs/lib/argsert.js @@ -0,0 +1,66 @@ +'use strict' +const command = require('./command')() +const YError = require('./yerror') + +const positionName = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth'] + +module.exports = function argsert (expected, callerArguments, length) { + // TODO: should this eventually raise an exception. + try { + // preface the argument description with "cmd", so + // that we can run it through yargs' command parser. + let position = 0 + let parsed = {demanded: [], optional: []} + if (typeof expected === 'object') { + length = callerArguments + callerArguments = expected + } else { + parsed = command.parseCommand(`cmd ${expected}`) + } + const args = [].slice.call(callerArguments) + + while (args.length && args[args.length - 1] === undefined) args.pop() + length = length || args.length + + if (length < parsed.demanded.length) { + throw new YError(`Not enough arguments provided. Expected ${parsed.demanded.length} but received ${args.length}.`) + } + + const totalCommands = parsed.demanded.length + parsed.optional.length + if (length > totalCommands) { + throw new YError(`Too many arguments provided. Expected max ${totalCommands} but received ${length}.`) + } + + parsed.demanded.forEach((demanded) => { + const arg = args.shift() + const observedType = guessType(arg) + const matchingTypes = demanded.cmd.filter(type => type === observedType || type === '*') + if (matchingTypes.length === 0) argumentTypeError(observedType, demanded.cmd, position, false) + position += 1 + }) + + parsed.optional.forEach((optional) => { + if (args.length === 0) return + const arg = args.shift() + const observedType = guessType(arg) + const matchingTypes = optional.cmd.filter(type => type === observedType || type === '*') + if (matchingTypes.length === 0) argumentTypeError(observedType, optional.cmd, position, true) + position += 1 + }) + } catch (err) { + console.warn(err.stack) + } +} + +function guessType (arg) { + if (Array.isArray(arg)) { + return 'array' + } else if (arg === null) { + return 'null' + } + return typeof arg +} + +function argumentTypeError (observedType, allowedTypes, position, optional) { + throw new YError(`Invalid ${positionName[position] || 'manyith'} argument. Expected ${allowedTypes.join(' or ')} but received ${observedType}.`) +} diff --git a/node_modules/yargs/lib/command.js b/node_modules/yargs/lib/command.js new file mode 100644 index 0000000..65322db --- /dev/null +++ b/node_modules/yargs/lib/command.js @@ -0,0 +1,426 @@ +'use strict' + +const inspect = require('util').inspect +const path = require('path') +const Parser = require('yargs-parser') + +const DEFAULT_MARKER = /(^\*)|(^\$0)/ + +// handles parsing positional arguments, +// and populating argv with said positional +// arguments. +module.exports = function command (yargs, usage, validation) { + const self = {} + let handlers = {} + let aliasMap = {} + let defaultCommand + self.addHandler = function addHandler (cmd, description, builder, handler, middlewares) { + let aliases = [] + handler = handler || (() => {}) + middlewares = middlewares || [] + if (Array.isArray(cmd)) { + aliases = cmd.slice(1) + cmd = cmd[0] + } else if (typeof cmd === 'object') { + let command = (Array.isArray(cmd.command) || typeof cmd.command === 'string') ? cmd.command : moduleName(cmd) + if (cmd.aliases) command = [].concat(command).concat(cmd.aliases) + self.addHandler(command, extractDesc(cmd), cmd.builder, cmd.handler, cmd.middlewares) + return + } + + // allow a module to be provided instead of separate builder and handler + if (typeof builder === 'object' && builder.builder && typeof builder.handler === 'function') { + self.addHandler([cmd].concat(aliases), description, builder.builder, builder.handler, builder.middlewares) + return + } + + // parse positionals out of cmd string + const parsedCommand = self.parseCommand(cmd) + + // remove positional args from aliases only + aliases = aliases.map(alias => self.parseCommand(alias).cmd) + + // check for default and filter out '*'' + let isDefault = false + const parsedAliases = [parsedCommand.cmd].concat(aliases).filter((c) => { + if (DEFAULT_MARKER.test(c)) { + isDefault = true + return false + } + return true + }) + + // standardize on $0 for default command. + if (parsedAliases.length === 0 && isDefault) parsedAliases.push('$0') + + // shift cmd and aliases after filtering out '*' + if (isDefault) { + parsedCommand.cmd = parsedAliases[0] + aliases = parsedAliases.slice(1) + cmd = cmd.replace(DEFAULT_MARKER, parsedCommand.cmd) + } + + // populate aliasMap + aliases.forEach((alias) => { + aliasMap[alias] = parsedCommand.cmd + }) + + if (description !== false) { + usage.command(cmd, description, isDefault, aliases) + } + + handlers[parsedCommand.cmd] = { + original: cmd, + description: description, + handler, + builder: builder || {}, + middlewares: middlewares || [], + demanded: parsedCommand.demanded, + optional: parsedCommand.optional + } + + if (isDefault) defaultCommand = handlers[parsedCommand.cmd] + } + + self.addDirectory = function addDirectory (dir, context, req, callerFile, opts) { + opts = opts || {} + // disable recursion to support nested directories of subcommands + if (typeof opts.recurse !== 'boolean') opts.recurse = false + // exclude 'json', 'coffee' from require-directory defaults + if (!Array.isArray(opts.extensions)) opts.extensions = ['js'] + // allow consumer to define their own visitor function + const parentVisit = typeof opts.visit === 'function' ? opts.visit : o => o + // call addHandler via visitor function + opts.visit = function visit (obj, joined, filename) { + const visited = parentVisit(obj, joined, filename) + // allow consumer to skip modules with their own visitor + if (visited) { + // check for cyclic reference + // each command file path should only be seen once per execution + if (~context.files.indexOf(joined)) return visited + // keep track of visited files in context.files + context.files.push(joined) + self.addHandler(visited) + } + return visited + } + require('require-directory')({ require: req, filename: callerFile }, dir, opts) + } + + // lookup module object from require()d command and derive name + // if module was not require()d and no name given, throw error + function moduleName (obj) { + const mod = require('which-module')(obj) + if (!mod) throw new Error(`No command name given for module: ${inspect(obj)}`) + return commandFromFilename(mod.filename) + } + + // derive command name from filename + function commandFromFilename (filename) { + return path.basename(filename, path.extname(filename)) + } + + function extractDesc (obj) { + for (let keys = ['describe', 'description', 'desc'], i = 0, l = keys.length, test; i < l; i++) { + test = obj[keys[i]] + if (typeof test === 'string' || typeof test === 'boolean') return test + } + return false + } + + self.parseCommand = function parseCommand (cmd) { + const extraSpacesStrippedCommand = cmd.replace(/\s{2,}/g, ' ') + const splitCommand = extraSpacesStrippedCommand.split(/\s+(?![^[]*]|[^<]*>)/) + const bregex = /\.*[\][<>]/g + const parsedCommand = { + cmd: (splitCommand.shift()).replace(bregex, ''), + demanded: [], + optional: [] + } + splitCommand.forEach((cmd, i) => { + let variadic = false + cmd = cmd.replace(/\s/g, '') + if (/\.+[\]>]/.test(cmd) && i === splitCommand.length - 1) variadic = true + if (/^\[/.test(cmd)) { + parsedCommand.optional.push({ + cmd: cmd.replace(bregex, '').split('|'), + variadic + }) + } else { + parsedCommand.demanded.push({ + cmd: cmd.replace(bregex, '').split('|'), + variadic + }) + } + }) + return parsedCommand + } + + self.getCommands = () => Object.keys(handlers).concat(Object.keys(aliasMap)) + + self.getCommandHandlers = () => handlers + + self.hasDefaultCommand = () => !!defaultCommand + + self.runCommand = function runCommand (command, yargs, parsed, commandIndex) { + let aliases = parsed.aliases + const commandHandler = handlers[command] || handlers[aliasMap[command]] || defaultCommand + const currentContext = yargs.getContext() + let numFiles = currentContext.files.length + const parentCommands = currentContext.commands.slice() + + // what does yargs look like after the buidler is run? + let innerArgv = parsed.argv + let innerYargs = null + let positionalMap = {} + if (command) { + currentContext.commands.push(command) + currentContext.fullCommands.push(commandHandler.original) + } + if (typeof commandHandler.builder === 'function') { + // a function can be provided, which builds + // up a yargs chain and possibly returns it. + innerYargs = commandHandler.builder(yargs.reset(parsed.aliases)) + // if the builder function did not yet parse argv with reset yargs + // and did not explicitly set a usage() string, then apply the + // original command string as usage() for consistent behavior with + // options object below. + if (yargs.parsed === false) { + if (shouldUpdateUsage(yargs)) { + yargs.getUsageInstance().usage( + usageFromParentCommandsCommandHandler(parentCommands, commandHandler), + commandHandler.description + ) + } + innerArgv = innerYargs ? innerYargs._parseArgs(null, null, true, commandIndex) : yargs._parseArgs(null, null, true, commandIndex) + } else { + innerArgv = yargs.parsed.argv + } + + if (innerYargs && yargs.parsed === false) aliases = innerYargs.parsed.aliases + else aliases = yargs.parsed.aliases + } else if (typeof commandHandler.builder === 'object') { + // as a short hand, an object can instead be provided, specifying + // the options that a command takes. + innerYargs = yargs.reset(parsed.aliases) + if (shouldUpdateUsage(innerYargs)) { + innerYargs.getUsageInstance().usage( + usageFromParentCommandsCommandHandler(parentCommands, commandHandler), + commandHandler.description + ) + } + Object.keys(commandHandler.builder).forEach((key) => { + innerYargs.option(key, commandHandler.builder[key]) + }) + innerArgv = innerYargs._parseArgs(null, null, true, commandIndex) + aliases = innerYargs.parsed.aliases + } + + if (!yargs._hasOutput()) { + positionalMap = populatePositionals(commandHandler, innerArgv, currentContext, yargs) + } + + // we apply validation post-hoc, so that custom + // checks get passed populated positional arguments. + if (!yargs._hasOutput()) yargs._runValidation(innerArgv, aliases, positionalMap, yargs.parsed.error) + + if (commandHandler.handler && !yargs._hasOutput()) { + yargs._setHasOutput() + if (commandHandler.middlewares.length > 0) { + const middlewareArgs = commandHandler.middlewares.reduce(function (initialObj, middleware) { + return Object.assign(initialObj, middleware(innerArgv)) + }, {}) + Object.assign(innerArgv, middlewareArgs) + } + const handlerResult = commandHandler.handler(innerArgv) + if (handlerResult && typeof handlerResult.then === 'function') { + handlerResult.then( + null, + (error) => yargs.getUsageInstance().fail(null, error) + ) + } + } + + if (command) { + currentContext.commands.pop() + currentContext.fullCommands.pop() + } + numFiles = currentContext.files.length - numFiles + if (numFiles > 0) currentContext.files.splice(numFiles * -1, numFiles) + + return innerArgv + } + + function shouldUpdateUsage (yargs) { + return !yargs.getUsageInstance().getUsageDisabled() && + yargs.getUsageInstance().getUsage().length === 0 + } + + function usageFromParentCommandsCommandHandler (parentCommands, commandHandler) { + const c = DEFAULT_MARKER.test(commandHandler.original) ? commandHandler.original.replace(DEFAULT_MARKER, '').trim() : commandHandler.original + const pc = parentCommands.filter((c) => { return !DEFAULT_MARKER.test(c) }) + pc.push(c) + return `$0 ${pc.join(' ')}` + } + + self.runDefaultBuilderOn = function (yargs) { + if (shouldUpdateUsage(yargs)) { + // build the root-level command string from the default string. + const commandString = DEFAULT_MARKER.test(defaultCommand.original) + ? defaultCommand.original : defaultCommand.original.replace(/^[^[\]<>]*/, '$0 ') + yargs.getUsageInstance().usage( + commandString, + defaultCommand.description + ) + } + const builder = defaultCommand.builder + if (typeof builder === 'function') { + builder(yargs) + } else { + Object.keys(builder).forEach((key) => { + yargs.option(key, builder[key]) + }) + } + } + + // transcribe all positional arguments "command <foo> <bar> [apple]" + // onto argv. + function populatePositionals (commandHandler, argv, context, yargs) { + argv._ = argv._.slice(context.commands.length) // nuke the current commands + const demanded = commandHandler.demanded.slice(0) + const optional = commandHandler.optional.slice(0) + const positionalMap = {} + + validation.positionalCount(demanded.length, argv._.length) + + while (demanded.length) { + const demand = demanded.shift() + populatePositional(demand, argv, positionalMap) + } + + while (optional.length) { + const maybe = optional.shift() + populatePositional(maybe, argv, positionalMap) + } + + argv._ = context.commands.concat(argv._) + + postProcessPositionals(argv, positionalMap, self.cmdToParseOptions(commandHandler.original)) + + return positionalMap + } + + function populatePositional (positional, argv, positionalMap, parseOptions) { + const cmd = positional.cmd[0] + if (positional.variadic) { + positionalMap[cmd] = argv._.splice(0).map(String) + } else { + if (argv._.length) positionalMap[cmd] = [String(argv._.shift())] + } + } + + // we run yargs-parser against the positional arguments + // applying the same parsing logic used for flags. + function postProcessPositionals (argv, positionalMap, parseOptions) { + // combine the parsing hints we've inferred from the command + // string with explicitly configured parsing hints. + const options = Object.assign({}, yargs.getOptions()) + options.default = Object.assign(parseOptions.default, options.default) + options.alias = Object.assign(parseOptions.alias, options.alias) + options.array = options.array.concat(parseOptions.array) + + const unparsed = [] + Object.keys(positionalMap).forEach((key) => { + positionalMap[key].map((value) => { + unparsed.push(`--${key}`) + unparsed.push(value) + }) + }) + + // short-circuit parse. + if (!unparsed.length) return + + const parsed = Parser.detailed(unparsed, options) + + if (parsed.error) { + yargs.getUsageInstance().fail(parsed.error.message, parsed.error) + } else { + // only copy over positional keys (don't overwrite + // flag arguments that were already parsed). + const positionalKeys = Object.keys(positionalMap) + Object.keys(positionalMap).forEach((key) => { + [].push.apply(positionalKeys, parsed.aliases[key]) + }) + + Object.keys(parsed.argv).forEach((key) => { + if (positionalKeys.indexOf(key) !== -1) { + argv[key] = parsed.argv[key] + } + }) + } + } + + self.cmdToParseOptions = function (cmdString) { + const parseOptions = { + array: [], + default: {}, + alias: {}, + demand: {} + } + + const parsed = self.parseCommand(cmdString) + parsed.demanded.forEach((d) => { + const cmds = d.cmd.slice(0) + const cmd = cmds.shift() + if (d.variadic) { + parseOptions.array.push(cmd) + parseOptions.default[cmd] = [] + } + cmds.forEach((c) => { + parseOptions.alias[cmd] = c + }) + parseOptions.demand[cmd] = true + }) + + parsed.optional.forEach((o) => { + const cmds = o.cmd.slice(0) + const cmd = cmds.shift() + if (o.variadic) { + parseOptions.array.push(cmd) + parseOptions.default[cmd] = [] + } + cmds.forEach((c) => { + parseOptions.alias[cmd] = c + }) + }) + + return parseOptions + } + + self.reset = () => { + handlers = {} + aliasMap = {} + defaultCommand = undefined + return self + } + + // used by yargs.parse() to freeze + // the state of commands such that + // we can apply .parse() multiple times + // with the same yargs instance. + let frozen + self.freeze = () => { + frozen = {} + frozen.handlers = handlers + frozen.aliasMap = aliasMap + frozen.defaultCommand = defaultCommand + } + self.unfreeze = () => { + handlers = frozen.handlers + aliasMap = frozen.aliasMap + defaultCommand = frozen.defaultCommand + frozen = undefined + } + + return self +} diff --git a/node_modules/yargs/lib/completion.js b/node_modules/yargs/lib/completion.js new file mode 100644 index 0000000..ad6969a --- /dev/null +++ b/node_modules/yargs/lib/completion.js @@ -0,0 +1,105 @@ +'use strict' +const fs = require('fs') +const path = require('path') + +// add bash completions to your +// yargs-powered applications. +module.exports = function completion (yargs, usage, command) { + const self = { + completionKey: 'get-yargs-completions' + } + + // get a list of completion commands. + // 'args' is the array of strings from the line to be completed + self.getCompletion = function getCompletion (args, done) { + const completions = [] + const current = args.length ? args[args.length - 1] : '' + const argv = yargs.parse(args, true) + const aliases = yargs.parsed.aliases + + // a custom completion function can be provided + // to completion(). + if (completionFunction) { + if (completionFunction.length < 3) { + const result = completionFunction(current, argv) + + // promise based completion function. + if (typeof result.then === 'function') { + return result.then((list) => { + process.nextTick(() => { done(list) }) + }).catch((err) => { + process.nextTick(() => { throw err }) + }) + } + + // synchronous completion function. + return done(result) + } else { + // asynchronous completion function + return completionFunction(current, argv, (completions) => { + done(completions) + }) + } + } + + const handlers = command.getCommandHandlers() + for (let i = 0, ii = args.length; i < ii; ++i) { + if (handlers[args[i]] && handlers[args[i]].builder) { + const builder = handlers[args[i]].builder + if (typeof builder === 'function') { + const y = yargs.reset() + builder(y) + return y.argv + } + } + } + + if (!current.match(/^-/)) { + usage.getCommands().forEach((usageCommand) => { + const commandName = command.parseCommand(usageCommand[0]).cmd + if (args.indexOf(commandName) === -1) { + completions.push(commandName) + } + }) + } + + if (current.match(/^-/)) { + Object.keys(yargs.getOptions().key).forEach((key) => { + // If the key and its aliases aren't in 'args', add the key to 'completions' + const keyAndAliases = [key].concat(aliases[key] || []) + const notInArgs = keyAndAliases.every(val => args.indexOf(`--${val}`) === -1) + if (notInArgs) { + completions.push(`--${key}`) + } + }) + } + + done(completions) + } + + // generate the completion script to add to your .bashrc. + self.generateCompletionScript = function generateCompletionScript ($0, cmd) { + let script = fs.readFileSync( + path.resolve(__dirname, '../completion.sh.hbs'), + 'utf-8' + ) + const name = path.basename($0) + + // add ./to applications not yet installed as bin. + if ($0.match(/\.js$/)) $0 = `./${$0}` + + script = script.replace(/{{app_name}}/g, name) + script = script.replace(/{{completion_command}}/g, cmd) + return script.replace(/{{app_path}}/g, $0) + } + + // register a function to perform your own custom + // completions., this function can be either + // synchrnous or asynchronous. + let completionFunction = null + self.registerFunction = (fn) => { + completionFunction = fn + } + + return self +} diff --git a/node_modules/yargs/lib/levenshtein.js b/node_modules/yargs/lib/levenshtein.js new file mode 100644 index 0000000..f32b0c2 --- /dev/null +++ b/node_modules/yargs/lib/levenshtein.js @@ -0,0 +1,47 @@ +/* +Copyright (c) 2011 Andrei Mackenzie + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// levenshtein distance algorithm, pulled from Andrei Mackenzie's MIT licensed. +// gist, which can be found here: https://gist.github.com/andrei-m/982927 +'use strict' +// Compute the edit distance between the two given strings +module.exports = function levenshtein (a, b) { + if (a.length === 0) return b.length + if (b.length === 0) return a.length + + const matrix = [] + + // increment along the first column of each row + let i + for (i = 0; i <= b.length; i++) { + matrix[i] = [i] + } + + // increment each column in the first row + let j + for (j = 0; j <= a.length; j++) { + matrix[0][j] = j + } + + // Fill in the rest of the matrix + for (i = 1; i <= b.length; i++) { + for (j = 1; j <= a.length; j++) { + if (b.charAt(i - 1) === a.charAt(j - 1)) { + matrix[i][j] = matrix[i - 1][j - 1] + } else { + matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution + Math.min(matrix[i][j - 1] + 1, // insertion + matrix[i - 1][j] + 1)) // deletion + } + } + } + + return matrix[b.length][a.length] +} diff --git a/node_modules/yargs/lib/obj-filter.js b/node_modules/yargs/lib/obj-filter.js new file mode 100644 index 0000000..c344ac5 --- /dev/null +++ b/node_modules/yargs/lib/obj-filter.js @@ -0,0 +1,11 @@ +'use strict' +module.exports = function objFilter (original, filter) { + const obj = {} + filter = filter || ((k, v) => true) + Object.keys(original || {}).forEach((key) => { + if (filter(key, original[key])) { + obj[key] = original[key] + } + }) + return obj +} diff --git a/node_modules/yargs/lib/usage.js b/node_modules/yargs/lib/usage.js new file mode 100644 index 0000000..c323c1b --- /dev/null +++ b/node_modules/yargs/lib/usage.js @@ -0,0 +1,531 @@ +'use strict' +// this file handles outputting usage instructions, +// failures, etc. keeps logging in one place. +const stringWidth = require('string-width') +const objFilter = require('./obj-filter') +const path = require('path') +const setBlocking = require('set-blocking') +const YError = require('./yerror') + +module.exports = function usage (yargs, y18n) { + const __ = y18n.__ + const self = {} + + // methods for ouputting/building failure message. + const fails = [] + self.failFn = function failFn (f) { + fails.push(f) + } + + let failMessage = null + let showHelpOnFail = true + self.showHelpOnFail = function showHelpOnFailFn (enabled, message) { + if (typeof enabled === 'string') { + message = enabled + enabled = true + } else if (typeof enabled === 'undefined') { + enabled = true + } + failMessage = message + showHelpOnFail = enabled + return self + } + + let failureOutput = false + self.fail = function fail (msg, err) { + const logger = yargs._getLoggerInstance() + + if (fails.length) { + for (let i = fails.length - 1; i >= 0; --i) { + fails[i](msg, err, self) + } + } else { + if (yargs.getExitProcess()) setBlocking(true) + + // don't output failure message more than once + if (!failureOutput) { + failureOutput = true + if (showHelpOnFail) yargs.showHelp('error') + if (msg || err) logger.error(msg || err) + if (failMessage) { + if (msg || err) logger.error('') + logger.error(failMessage) + } + } + + err = err || new YError(msg) + if (yargs.getExitProcess()) { + return yargs.exit(1) + } else if (yargs._hasParseCallback()) { + return yargs.exit(1, err) + } else { + throw err + } + } + } + + // methods for ouputting/building help (usage) message. + let usages = [] + let usageDisabled = false + self.usage = (msg, description) => { + if (msg === null) { + usageDisabled = true + usages = [] + return + } + usageDisabled = false + usages.push([msg, description || '']) + return self + } + self.getUsage = () => { + return usages + } + self.getUsageDisabled = () => { + return usageDisabled + } + + self.getPositionalGroupName = () => { + return __('Positionals:') + } + + let examples = [] + self.example = (cmd, description) => { + examples.push([cmd, description || '']) + } + + let commands = [] + self.command = function command (cmd, description, isDefault, aliases) { + // the last default wins, so cancel out any previously set default + if (isDefault) { + commands = commands.map((cmdArray) => { + cmdArray[2] = false + return cmdArray + }) + } + commands.push([cmd, description || '', isDefault, aliases]) + } + self.getCommands = () => commands + + let descriptions = {} + self.describe = function describe (key, desc) { + if (typeof key === 'object') { + Object.keys(key).forEach((k) => { + self.describe(k, key[k]) + }) + } else { + descriptions[key] = desc + } + } + self.getDescriptions = () => descriptions + + let epilog + self.epilog = (msg) => { + epilog = msg + } + + let wrapSet = false + let wrap + self.wrap = (cols) => { + wrapSet = true + wrap = cols + } + + function getWrap () { + if (!wrapSet) { + wrap = windowWidth() + wrapSet = true + } + + return wrap + } + + const deferY18nLookupPrefix = '__yargsString__:' + self.deferY18nLookup = str => deferY18nLookupPrefix + str + + const defaultGroup = 'Options:' + self.help = function help () { + normalizeAliases() + + // handle old demanded API + const base$0 = path.basename(yargs.$0) + const demandedOptions = yargs.getDemandedOptions() + const demandedCommands = yargs.getDemandedCommands() + const groups = yargs.getGroups() + const options = yargs.getOptions() + + let keys = [] + keys = keys.concat(Object.keys(descriptions)) + keys = keys.concat(Object.keys(demandedOptions)) + keys = keys.concat(Object.keys(demandedCommands)) + keys = keys.concat(Object.keys(options.default)) + keys = keys.filter(key => { + if (options.hiddenOptions.indexOf(key) < 0) { + return true + } else if (yargs.parsed.argv[options.showHiddenOpt]) { + return true + } + }) + keys = Object.keys(keys.reduce((acc, key) => { + if (key !== '_') acc[key] = true + return acc + }, {})) + + const theWrap = getWrap() + const ui = require('cliui')({ + width: theWrap, + wrap: !!theWrap + }) + + // the usage string. + if (!usageDisabled) { + if (usages.length) { + // user-defined usage. + usages.forEach((usage) => { + ui.div(`${usage[0].replace(/\$0/g, base$0)}`) + if (usage[1]) { + ui.div({text: `${usage[1]}`, padding: [1, 0, 0, 0]}) + } + }) + ui.div() + } else if (commands.length) { + let u = null + // demonstrate how commands are used. + if (demandedCommands._) { + u = `${base$0} <${__('command')}>\n` + } else { + u = `${base$0} [${__('command')}]\n` + } + ui.div(`${u}`) + } + } + + // your application's commands, i.e., non-option + // arguments populated in '_'. + if (commands.length) { + ui.div(__('Commands:')) + + const context = yargs.getContext() + const parentCommands = context.commands.length ? `${context.commands.join(' ')} ` : '' + + commands.forEach((command) => { + const commandString = `${base$0} ${parentCommands}${command[0].replace(/^\$0 ?/, '')}` // drop $0 from default commands. + ui.span( + { + text: commandString, + padding: [0, 2, 0, 2], + width: maxWidth(commands, theWrap, `${base$0}${parentCommands}`) + 4 + }, + {text: command[1]} + ) + const hints = [] + if (command[2]) hints.push(`[${__('default:').slice(0, -1)}]`) // TODO hacking around i18n here + if (command[3] && command[3].length) { + hints.push(`[${__('aliases:')} ${command[3].join(', ')}]`) + } + if (hints.length) { + ui.div({text: hints.join(' '), padding: [0, 0, 0, 2], align: 'right'}) + } else { + ui.div() + } + }) + + ui.div() + } + + // perform some cleanup on the keys array, making it + // only include top-level keys not their aliases. + const aliasKeys = (Object.keys(options.alias) || []) + .concat(Object.keys(yargs.parsed.newAliases) || []) + + keys = keys.filter(key => !yargs.parsed.newAliases[key] && aliasKeys.every(alias => (options.alias[alias] || []).indexOf(key) === -1)) + + // populate 'Options:' group with any keys that have not + // explicitly had a group set. + if (!groups[defaultGroup]) groups[defaultGroup] = [] + addUngroupedKeys(keys, options.alias, groups) + + // display 'Options:' table along with any custom tables: + Object.keys(groups).forEach((groupName) => { + if (!groups[groupName].length) return + + ui.div(__(groupName)) + + // if we've grouped the key 'f', but 'f' aliases 'foobar', + // normalizedKeys should contain only 'foobar'. + const normalizedKeys = groups[groupName].map((key) => { + if (~aliasKeys.indexOf(key)) return key + for (let i = 0, aliasKey; (aliasKey = aliasKeys[i]) !== undefined; i++) { + if (~(options.alias[aliasKey] || []).indexOf(key)) return aliasKey + } + return key + }) + + // actually generate the switches string --foo, -f, --bar. + const switches = normalizedKeys.reduce((acc, key) => { + acc[key] = [ key ].concat(options.alias[key] || []) + .map(sw => { + // for the special positional group don't + // add '--' or '-' prefix. + if (groupName === self.getPositionalGroupName()) return sw + else return (sw.length > 1 ? '--' : '-') + sw + }) + .join(', ') + + return acc + }, {}) + + normalizedKeys.forEach((key) => { + const kswitch = switches[key] + let desc = descriptions[key] || '' + let type = null + + if (~desc.lastIndexOf(deferY18nLookupPrefix)) desc = __(desc.substring(deferY18nLookupPrefix.length)) + + if (~options.boolean.indexOf(key)) type = `[${__('boolean')}]` + if (~options.count.indexOf(key)) type = `[${__('count')}]` + if (~options.string.indexOf(key)) type = `[${__('string')}]` + if (~options.normalize.indexOf(key)) type = `[${__('string')}]` + if (~options.array.indexOf(key)) type = `[${__('array')}]` + if (~options.number.indexOf(key)) type = `[${__('number')}]` + + const extra = [ + type, + (key in demandedOptions) ? `[${__('required')}]` : null, + options.choices && options.choices[key] ? `[${__('choices:')} ${ + self.stringifiedValues(options.choices[key])}]` : null, + defaultString(options.default[key], options.defaultDescription[key]) + ].filter(Boolean).join(' ') + + ui.span( + {text: kswitch, padding: [0, 2, 0, 2], width: maxWidth(switches, theWrap) + 4}, + desc + ) + + if (extra) ui.div({text: extra, padding: [0, 0, 0, 2], align: 'right'}) + else ui.div() + }) + + ui.div() + }) + + // describe some common use-cases for your application. + if (examples.length) { + ui.div(__('Examples:')) + + examples.forEach((example) => { + example[0] = example[0].replace(/\$0/g, base$0) + }) + + examples.forEach((example) => { + if (example[1] === '') { + ui.div( + { + text: example[0], + padding: [0, 2, 0, 2] + } + ) + } else { + ui.div( + { + text: example[0], + padding: [0, 2, 0, 2], + width: maxWidth(examples, theWrap) + 4 + }, { + text: example[1] + } + ) + } + }) + + ui.div() + } + + // the usage string. + if (epilog) { + const e = epilog.replace(/\$0/g, base$0) + ui.div(`${e}\n`) + } + + return ui.toString() + } + + // return the maximum width of a string + // in the left-hand column of a table. + function maxWidth (table, theWrap, modifier) { + let width = 0 + + // table might be of the form [leftColumn], + // or {key: leftColumn} + if (!Array.isArray(table)) { + table = Object.keys(table).map(key => [table[key]]) + } + + table.forEach((v) => { + width = Math.max( + stringWidth(modifier ? `${modifier} ${v[0]}` : v[0]), + width + ) + }) + + // if we've enabled 'wrap' we should limit + // the max-width of the left-column. + if (theWrap) width = Math.min(width, parseInt(theWrap * 0.5, 10)) + + return width + } + + // make sure any options set for aliases, + // are copied to the keys being aliased. + function normalizeAliases () { + // handle old demanded API + const demandedOptions = yargs.getDemandedOptions() + const options = yargs.getOptions() + + ;(Object.keys(options.alias) || []).forEach((key) => { + options.alias[key].forEach((alias) => { + // copy descriptions. + if (descriptions[alias]) self.describe(key, descriptions[alias]) + // copy demanded. + if (alias in demandedOptions) yargs.demandOption(key, demandedOptions[alias]) + // type messages. + if (~options.boolean.indexOf(alias)) yargs.boolean(key) + if (~options.count.indexOf(alias)) yargs.count(key) + if (~options.string.indexOf(alias)) yargs.string(key) + if (~options.normalize.indexOf(alias)) yargs.normalize(key) + if (~options.array.indexOf(alias)) yargs.array(key) + if (~options.number.indexOf(alias)) yargs.number(key) + }) + }) + } + + // given a set of keys, place any keys that are + // ungrouped under the 'Options:' grouping. + function addUngroupedKeys (keys, aliases, groups) { + let groupedKeys = [] + let toCheck = null + Object.keys(groups).forEach((group) => { + groupedKeys = groupedKeys.concat(groups[group]) + }) + + keys.forEach((key) => { + toCheck = [key].concat(aliases[key]) + if (!toCheck.some(k => groupedKeys.indexOf(k) !== -1)) { + groups[defaultGroup].push(key) + } + }) + return groupedKeys + } + + self.showHelp = (level) => { + const logger = yargs._getLoggerInstance() + if (!level) level = 'error' + const emit = typeof level === 'function' ? level : logger[level] + emit(self.help()) + } + + self.functionDescription = (fn) => { + const description = fn.name ? require('decamelize')(fn.name, '-') : __('generated-value') + return ['(', description, ')'].join('') + } + + self.stringifiedValues = function stringifiedValues (values, separator) { + let string = '' + const sep = separator || ', ' + const array = [].concat(values) + + if (!values || !array.length) return string + + array.forEach((value) => { + if (string.length) string += sep + string += JSON.stringify(value) + }) + + return string + } + + // format the default-value-string displayed in + // the right-hand column. + function defaultString (value, defaultDescription) { + let string = `[${__('default:')} ` + + if (value === undefined && !defaultDescription) return null + + if (defaultDescription) { + string += defaultDescription + } else { + switch (typeof value) { + case 'string': + string += `"${value}"` + break + case 'object': + string += JSON.stringify(value) + break + default: + string += value + } + } + + return `${string}]` + } + + // guess the width of the console window, max-width 80. + function windowWidth () { + const maxWidth = 80 + if (typeof process === 'object' && process.stdout && process.stdout.columns) { + return Math.min(maxWidth, process.stdout.columns) + } else { + return maxWidth + } + } + + // logic for displaying application version. + let version = null + self.version = (ver) => { + version = ver + } + + self.showVersion = () => { + const logger = yargs._getLoggerInstance() + logger.log(version) + } + + self.reset = function reset (localLookup) { + // do not reset wrap here + // do not reset fails here + failMessage = null + failureOutput = false + usages = [] + usageDisabled = false + epilog = undefined + examples = [] + commands = [] + descriptions = objFilter(descriptions, (k, v) => !localLookup[k]) + return self + } + + let frozen + self.freeze = function freeze () { + frozen = {} + frozen.failMessage = failMessage + frozen.failureOutput = failureOutput + frozen.usages = usages + frozen.usageDisabled = usageDisabled + frozen.epilog = epilog + frozen.examples = examples + frozen.commands = commands + frozen.descriptions = descriptions + } + self.unfreeze = function unfreeze () { + failMessage = frozen.failMessage + failureOutput = frozen.failureOutput + usages = frozen.usages + usageDisabled = frozen.usageDisabled + epilog = frozen.epilog + examples = frozen.examples + commands = frozen.commands + descriptions = frozen.descriptions + frozen = undefined + } + + return self +} diff --git a/node_modules/yargs/lib/validation.js b/node_modules/yargs/lib/validation.js new file mode 100644 index 0000000..f4655b4 --- /dev/null +++ b/node_modules/yargs/lib/validation.js @@ -0,0 +1,341 @@ +'use strict' +const argsert = require('./argsert') +const objFilter = require('./obj-filter') +const specialKeys = ['$0', '--', '_'] + +// validation-type-stuff, missing params, +// bad implications, custom checks. +module.exports = function validation (yargs, usage, y18n) { + const __ = y18n.__ + const __n = y18n.__n + const self = {} + + // validate appropriate # of non-option + // arguments were provided, i.e., '_'. + self.nonOptionCount = function nonOptionCount (argv) { + const demandedCommands = yargs.getDemandedCommands() + // don't count currently executing commands + const _s = argv._.length - yargs.getContext().commands.length + + if (demandedCommands._ && (_s < demandedCommands._.min || _s > demandedCommands._.max)) { + if (_s < demandedCommands._.min) { + if (demandedCommands._.minMsg !== undefined) { + usage.fail( + // replace $0 with observed, $1 with expected. + demandedCommands._.minMsg ? demandedCommands._.minMsg.replace(/\$0/g, _s).replace(/\$1/, demandedCommands._.min) : null + ) + } else { + usage.fail( + __('Not enough non-option arguments: got %s, need at least %s', _s, demandedCommands._.min) + ) + } + } else if (_s > demandedCommands._.max) { + if (demandedCommands._.maxMsg !== undefined) { + usage.fail( + // replace $0 with observed, $1 with expected. + demandedCommands._.maxMsg ? demandedCommands._.maxMsg.replace(/\$0/g, _s).replace(/\$1/, demandedCommands._.max) : null + ) + } else { + usage.fail( + __('Too many non-option arguments: got %s, maximum of %s', _s, demandedCommands._.max) + ) + } + } + } + } + + // validate the appropriate # of <required> + // positional arguments were provided: + self.positionalCount = function positionalCount (required, observed) { + if (observed < required) { + usage.fail( + __('Not enough non-option arguments: got %s, need at least %s', observed, required) + ) + } + } + + // make sure all the required arguments are present. + self.requiredArguments = function requiredArguments (argv) { + const demandedOptions = yargs.getDemandedOptions() + let missing = null + + Object.keys(demandedOptions).forEach((key) => { + if (!argv.hasOwnProperty(key) || typeof argv[key] === 'undefined') { + missing = missing || {} + missing[key] = demandedOptions[key] + } + }) + + if (missing) { + const customMsgs = [] + Object.keys(missing).forEach((key) => { + const msg = missing[key] + if (msg && customMsgs.indexOf(msg) < 0) { + customMsgs.push(msg) + } + }) + + const customMsg = customMsgs.length ? `\n${customMsgs.join('\n')}` : '' + + usage.fail(__n( + 'Missing required argument: %s', + 'Missing required arguments: %s', + Object.keys(missing).length, + Object.keys(missing).join(', ') + customMsg + )) + } + } + + // check for unknown arguments (strict-mode). + self.unknownArguments = function unknownArguments (argv, aliases, positionalMap) { + const commandKeys = yargs.getCommandInstance().getCommands() + const unknown = [] + const currentContext = yargs.getContext() + + Object.keys(argv).forEach((key) => { + if (specialKeys.indexOf(key) === -1 && + !positionalMap.hasOwnProperty(key) && + !yargs._getParseContext().hasOwnProperty(key) && + !aliases.hasOwnProperty(key) + ) { + unknown.push(key) + } + }) + + if (commandKeys.length > 0) { + argv._.slice(currentContext.commands.length).forEach((key) => { + if (commandKeys.indexOf(key) === -1) { + unknown.push(key) + } + }) + } + + if (unknown.length > 0) { + usage.fail(__n( + 'Unknown argument: %s', + 'Unknown arguments: %s', + unknown.length, + unknown.join(', ') + )) + } + } + + // validate arguments limited to enumerated choices + self.limitedChoices = function limitedChoices (argv) { + const options = yargs.getOptions() + const invalid = {} + + if (!Object.keys(options.choices).length) return + + Object.keys(argv).forEach((key) => { + if (specialKeys.indexOf(key) === -1 && + options.choices.hasOwnProperty(key)) { + [].concat(argv[key]).forEach((value) => { + // TODO case-insensitive configurability + if (options.choices[key].indexOf(value) === -1 && + value !== undefined) { + invalid[key] = (invalid[key] || []).concat(value) + } + }) + } + }) + + const invalidKeys = Object.keys(invalid) + + if (!invalidKeys.length) return + + let msg = __('Invalid values:') + invalidKeys.forEach((key) => { + msg += `\n ${__( + 'Argument: %s, Given: %s, Choices: %s', + key, + usage.stringifiedValues(invalid[key]), + usage.stringifiedValues(options.choices[key]) + )}` + }) + usage.fail(msg) + } + + // custom checks, added using the `check` option on yargs. + let checks = [] + self.check = function check (f, global) { + checks.push({ + func: f, + global + }) + } + + self.customChecks = function customChecks (argv, aliases) { + for (let i = 0, f; (f = checks[i]) !== undefined; i++) { + const func = f.func + let result = null + try { + result = func(argv, aliases) + } catch (err) { + usage.fail(err.message ? err.message : err, err) + continue + } + + if (!result) { + usage.fail(__('Argument check failed: %s', func.toString())) + } else if (typeof result === 'string' || result instanceof Error) { + usage.fail(result.toString(), result) + } + } + } + + // check implications, argument foo implies => argument bar. + let implied = {} + self.implies = function implies (key, value) { + argsert('<string|object> [array|number|string]', [key, value], arguments.length) + + if (typeof key === 'object') { + Object.keys(key).forEach((k) => { + self.implies(k, key[k]) + }) + } else { + yargs.global(key) + if (!implied[key]) { + implied[key] = [] + } + if (Array.isArray(value)) { + value.forEach((i) => self.implies(key, i)) + } else { + implied[key].push(value) + } + } + } + self.getImplied = function getImplied () { + return implied + } + + self.implications = function implications (argv) { + const implyFail = [] + + Object.keys(implied).forEach((key) => { + const origKey = key + ;(implied[key] || []).forEach((value) => { + let num + let key = origKey + const origValue = value + + // convert string '1' to number 1 + num = Number(key) + key = isNaN(num) ? key : num + + if (typeof key === 'number') { + // check length of argv._ + key = argv._.length >= key + } else if (key.match(/^--no-.+/)) { + // check if key doesn't exist + key = key.match(/^--no-(.+)/)[1] + key = !argv[key] + } else { + // check if key exists + key = argv[key] + } + + num = Number(value) + value = isNaN(num) ? value : num + + if (typeof value === 'number') { + value = argv._.length >= value + } else if (value.match(/^--no-.+/)) { + value = value.match(/^--no-(.+)/)[1] + value = !argv[value] + } else { + value = argv[value] + } + if (key && !value) { + implyFail.push(` ${origKey} -> ${origValue}`) + } + }) + }) + + if (implyFail.length) { + let msg = `${__('Implications failed:')}\n` + + implyFail.forEach((value) => { + msg += (value) + }) + + usage.fail(msg) + } + } + + let conflicting = {} + self.conflicts = function conflicts (key, value) { + argsert('<string|object> [array|string]', [key, value], arguments.length) + + if (typeof key === 'object') { + Object.keys(key).forEach((k) => { + self.conflicts(k, key[k]) + }) + } else { + yargs.global(key) + if (!conflicting[key]) { + conflicting[key] = [] + } + if (Array.isArray(value)) { + value.forEach((i) => self.conflicts(key, i)) + } else { + conflicting[key].push(value) + } + } + } + self.getConflicting = () => conflicting + + self.conflicting = function conflictingFn (argv) { + Object.keys(argv).forEach((key) => { + if (conflicting[key]) { + conflicting[key].forEach((value) => { + // we default keys to 'undefined' that have been configured, we should not + // apply conflicting check unless they are a value other than 'undefined'. + if (value && argv[key] !== undefined && argv[value] !== undefined) { + usage.fail(__(`Arguments ${key} and ${value} are mutually exclusive`)) + } + }) + } + }) + } + + self.recommendCommands = function recommendCommands (cmd, potentialCommands) { + const distance = require('./levenshtein') + const threshold = 3 // if it takes more than three edits, let's move on. + potentialCommands = potentialCommands.sort((a, b) => b.length - a.length) + + let recommended = null + let bestDistance = Infinity + for (let i = 0, candidate; (candidate = potentialCommands[i]) !== undefined; i++) { + const d = distance(cmd, candidate) + if (d <= threshold && d < bestDistance) { + bestDistance = d + recommended = candidate + } + } + if (recommended) usage.fail(__('Did you mean %s?', recommended)) + } + + self.reset = function reset (localLookup) { + implied = objFilter(implied, (k, v) => !localLookup[k]) + conflicting = objFilter(conflicting, (k, v) => !localLookup[k]) + checks = checks.filter(c => c.global) + return self + } + + let frozen + self.freeze = function freeze () { + frozen = {} + frozen.implied = implied + frozen.checks = checks + frozen.conflicting = conflicting + } + self.unfreeze = function unfreeze () { + implied = frozen.implied + checks = frozen.checks + conflicting = frozen.conflicting + frozen = undefined + } + + return self +} diff --git a/node_modules/yargs/lib/yerror.js b/node_modules/yargs/lib/yerror.js new file mode 100644 index 0000000..53375a0 --- /dev/null +++ b/node_modules/yargs/lib/yerror.js @@ -0,0 +1,11 @@ +'use strict' +function YError (msg) { + this.name = 'YError' + this.message = msg || 'yargs error' + Error.captureStackTrace(this, YError) +} + +YError.prototype = Object.create(Error.prototype) +YError.prototype.constructor = YError + +module.exports = YError |