毕设专用git仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

243 lines
6.2 KiB

/**
* @author Toru Nagashima
* @copyright 2016 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
*/
'use strict'
// ------------------------------------------------------------------------------
// Helpers
// ------------------------------------------------------------------------------
const OVERWRITE_OPTION = /^--([^:]+?):([^=]+?)(?:=(.+))?$/
const CONFIG_OPTION = /^--([^=]+?)(?:=(.+))$/
const PACKAGE_CONFIG_PATTERN = /^npm_package_config_(.+)$/
const CONCAT_OPTIONS = /^-[clnprs]+$/
/**
* Overwrites a specified package config.
*
* @param {object} config - A config object to be overwritten.
* @param {string} packageName - A package name to overwrite.
* @param {string} variable - A variable name to overwrite.
* @param {string} value - A new value to overwrite.
* @returns {void}
*/
function overwriteConfig (config, packageName, variable, value) {
const scope = config[packageName] || (config[packageName] = {})
scope[variable] = value
}
/**
* Creates a package config object.
* This checks `process.env` and creates the default value.
*
* @returns {object} Created config object.
*/
function createPackageConfig () {
const retv = {}
const packageName = process.env.npm_package_name
if (!packageName) {
return retv
}
for (const key of Object.keys(process.env)) {
const m = PACKAGE_CONFIG_PATTERN.exec(key)
if (m != null) {
overwriteConfig(retv, packageName, m[1], process.env[key])
}
}
return retv
}
/**
* Adds a new group into a given list.
*
* @param {object[]} groups - A group list to add.
* @param {object} initialValues - A key-value map for the default of new value.
* @returns {void}
*/
function addGroup (groups, initialValues) {
groups.push(Object.assign(
{ parallel: false, patterns: [] },
initialValues || {}
))
}
/**
* ArgumentSet is values of parsed CLI arguments.
* This class provides the getter to get the last group.
*/
class ArgumentSet {
/**
* @param {object} initialValues - A key-value map for the default of new value.
* @param {object} options - A key-value map for the options.
*/
constructor (initialValues, options) {
this.config = {}
this.continueOnError = false
this.groups = []
this.maxParallel = 0
this.npmPath = null
this.packageConfig = createPackageConfig()
this.printLabel = false
this.printName = false
this.race = false
this.rest = []
this.silent = process.env.npm_config_loglevel === 'silent'
this.singleMode = Boolean(options && options.singleMode)
addGroup(this.groups, initialValues)
}
/**
* Gets the last group.
*/
get lastGroup () {
return this.groups[this.groups.length - 1]
}
/**
* Gets "parallel" flag.
*/
get parallel () {
return this.groups.some(g => g.parallel)
}
}
/**
* Parses CLI arguments.
*
* @param {ArgumentSet} set - The parsed CLI arguments.
* @param {string[]} args - CLI arguments.
* @returns {ArgumentSet} set itself.
*/
function parseCLIArgsCore (set, args) {
LOOP: // eslint-disable-line no-labels
for (let i = 0; i < args.length; ++i) {
const arg = args[i]
switch (arg) {
case '--':
set.rest = args.slice(1 + i)
break LOOP // eslint-disable-line no-labels
case '--color':
case '--no-color':
// do nothing.
break
case '-c':
case '--continue-on-error':
set.continueOnError = true
break
case '-l':
case '--print-label':
set.printLabel = true
break
case '-n':
case '--print-name':
set.printName = true
break
case '-r':
case '--race':
set.race = true
break
case '--silent':
set.silent = true
break
case '--max-parallel':
set.maxParallel = parseInt(args[++i], 10)
if (!Number.isFinite(set.maxParallel) || set.maxParallel <= 0) {
throw new Error(`Invalid Option: --max-parallel ${args[i]}`)
}
break
case '-s':
case '--sequential':
case '--serial':
if (set.singleMode && arg === '-s') {
set.silent = true
break
}
if (set.singleMode) {
throw new Error(`Invalid Option: ${arg}`)
}
addGroup(set.groups)
break
case '--aggregate-output':
set.aggregateOutput = true
break
case '-p':
case '--parallel':
if (set.singleMode) {
throw new Error(`Invalid Option: ${arg}`)
}
addGroup(set.groups, { parallel: true })
break
case '--npm-path':
set.npmPath = args[++i] || null
break
default: {
let matched = null
if ((matched = OVERWRITE_OPTION.exec(arg))) {
overwriteConfig(
set.packageConfig,
matched[1],
matched[2],
matched[3] || args[++i]
)
} else if ((matched = CONFIG_OPTION.exec(arg))) {
set.config[matched[1]] = matched[2]
} else if (CONCAT_OPTIONS.test(arg)) {
parseCLIArgsCore(
set,
arg.slice(1).split('').map(c => `-${c}`)
)
} else if (arg[0] === '-') {
throw new Error(`Invalid Option: ${arg}`)
} else {
set.lastGroup.patterns.push(arg)
}
break
}
}
}
if (!set.parallel && set.aggregateOutput) {
throw new Error('Invalid Option: --aggregate-output (without parallel)')
}
if (!set.parallel && set.race) {
const race = args.indexOf('--race') !== -1 ? '--race' : '-r'
throw new Error(`Invalid Option: ${race} (without parallel)`)
}
if (!set.parallel && set.maxParallel !== 0) {
throw new Error('Invalid Option: --max-parallel (without parallel)')
}
return set
}
/**
* Parses CLI arguments.
*
* @param {string[]} args - CLI arguments.
* @param {object} initialValues - A key-value map for the default of new value.
* @param {object} options - A key-value map for the options.
* @param {boolean} options.singleMode - The flag to be single group mode.
* @returns {ArgumentSet} The parsed CLI arguments.
*/
module.exports = function parseCLIArgs (args, initialValues, options) {
return parseCLIArgsCore(new ArgumentSet(initialValues, options), args)
}