153 lines
4.4 KiB
JavaScript
Raw Normal View History

2018-05-09 14:31:22 +02:00
'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