153 lines
4.4 KiB
JavaScript
153 lines
4.4 KiB
JavaScript
'use strict'
|
|
const t = require('typical')
|
|
const arrayify = require('array-back')
|
|
|
|
class OutputValue {
|
|
constructor (value) {
|
|
this.value = value
|
|
this.hasDefaultArrayValue = false
|
|
this.valueSource = 'unknown'
|
|
}
|
|
|
|
isDefined () {
|
|
return t.isDefined(this.value)
|
|
}
|
|
}
|
|
|
|
class Output {
|
|
constructor (definitions, options) {
|
|
this.options = options || {}
|
|
this.output = {}
|
|
this.unknown = []
|
|
this.definitions = definitions
|
|
this._assignDefaultValues()
|
|
}
|
|
|
|
_assignDefaultValues () {
|
|
this.definitions.forEach(def => {
|
|
if (t.isDefined(def.defaultValue)) {
|
|
if (def.multiple) {
|
|
this.output[def.name] = new OutputValue(arrayify(def.defaultValue))
|
|
this.output[def.name].hasDefaultArrayValue = true
|
|
} else {
|
|
this.output[def.name] = new OutputValue(def.defaultValue)
|
|
}
|
|
this.output[def.name].valueSource = 'default'
|
|
}
|
|
})
|
|
}
|
|
|
|
setFlag (optionArg) {
|
|
const def = this.definitions.get(optionArg)
|
|
|
|
if (def) {
|
|
this.output[def.name] = this.output[def.name] || new OutputValue()
|
|
const outputValue = this.output[def.name]
|
|
|
|
if (def.multiple) outputValue.value = outputValue.value || []
|
|
|
|
/* for boolean types, set value to `true`. For all other types run value through setter function. */
|
|
if (def.isBoolean()) {
|
|
if (Array.isArray(outputValue.value)) {
|
|
outputValue.value.push(true)
|
|
} else {
|
|
outputValue.value = true
|
|
}
|
|
return true
|
|
} else {
|
|
if (!Array.isArray(outputValue.value) && outputValue.valueSource === 'unknown') outputValue.value = null
|
|
return false
|
|
}
|
|
} else {
|
|
this.unknown.push(optionArg)
|
|
return true
|
|
}
|
|
}
|
|
|
|
setOptionValue (optionArg, value) {
|
|
const ValueArg = require('./value-arg')
|
|
const valueArg = new ValueArg(value)
|
|
|
|
const def = this.definitions.get(optionArg)
|
|
|
|
this.output[def.name] = this.output[def.name] || new OutputValue()
|
|
const outputValue = this.output[def.name]
|
|
|
|
if (def.multiple) outputValue.value = outputValue.value || []
|
|
|
|
/* run value through setter function. */
|
|
valueArg.value = def.type(valueArg.value)
|
|
outputValue.valueSource = 'argv'
|
|
if (Array.isArray(outputValue.value)) {
|
|
if (outputValue.hasDefaultArrayValue) {
|
|
outputValue.value = [ valueArg.value ]
|
|
outputValue.hasDefaultArrayValue = false
|
|
} else {
|
|
outputValue.value.push(valueArg.value)
|
|
}
|
|
return false
|
|
} else {
|
|
outputValue.value = valueArg.value
|
|
return true
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return `true` when an option value was set and is not a multiple. Return `false` if option was a multiple or if a value was not yet set.
|
|
*/
|
|
setValue (value) {
|
|
const ValueArg = require('./value-arg')
|
|
const valueArg = new ValueArg(value)
|
|
|
|
/* use the defaultOption */
|
|
const def = this.definitions.getDefault()
|
|
|
|
/* handle unknown values in the case a value was already set on a defaultOption */
|
|
if (def) {
|
|
const currentValue = this.output[def.name]
|
|
if (valueArg.isDefined() && currentValue && t.isDefined(currentValue.value)) {
|
|
if (def.multiple) {
|
|
/* in the case we're setting an --option=value value on a multiple defaultOption, tag the value onto the previous unknown */
|
|
if (valueArg.isOptionValueNotationValue && this.unknown.length) {
|
|
this.unknown[this.unknown.length - 1] += `=${valueArg.value}`
|
|
return true
|
|
}
|
|
} else {
|
|
/* currentValue has already been set by argv,log this value as unknown and move on */
|
|
if (currentValue.valueSource === 'argv') {
|
|
this.unknown.push(valueArg.value)
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return this.setOptionValue(`--${def.name}`, value)
|
|
} else {
|
|
if (valueArg.isOptionValueNotationValue) {
|
|
this.unknown[this.unknown.length - 1] += `=${valueArg.value}`
|
|
} else {
|
|
this.unknown.push(valueArg.value)
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
|
|
get (name) {
|
|
return this.output[name] && this.output[name].value
|
|
}
|
|
|
|
toObject () {
|
|
let output = Object.assign({}, this.output)
|
|
if (this.options.partial && this.unknown.length) {
|
|
output._unknown = this.unknown
|
|
}
|
|
for (const prop in output) {
|
|
if (prop !== '_unknown') {
|
|
output[prop] = output[prop].value
|
|
}
|
|
}
|
|
return output
|
|
}
|
|
}
|
|
|
|
module.exports = Output
|