UNPKG

4.47 kBJavaScriptView Raw
1'use strict'
2const t = require('typical')
3const arrayify = require('array-back')
4
5class OutputValue {
6 constructor (value) {
7 this.value = value
8 this.hasDefaultArrayValue = false
9 this.valueSource = 'unknown'
10 }
11
12 isDefined () {
13 return t.isDefined(this.value)
14 }
15}
16
17class Output {
18 constructor (definitions, options) {
19 this.options = options || {}
20 this.output = {}
21 this.unknown = []
22 this.definitions = definitions
23 this._assignDefaultValues()
24 }
25
26 _assignDefaultValues () {
27 this.definitions.forEach(def => {
28 if (t.isDefined(def.defaultValue)) {
29 if (def.multiple) {
30 this.output[def.name] = new OutputValue(arrayify(def.defaultValue))
31 this.output[def.name].hasDefaultArrayValue = true
32 } else {
33 this.output[def.name] = new OutputValue(def.defaultValue)
34 }
35 this.output[def.name].valueSource = 'default'
36 }
37 })
38 }
39
40 setFlag (optionArg) {
41 const def = this.definitions.get(optionArg)
42
43 if (def) {
44 this.output[def.name] = this.output[def.name] || new OutputValue()
45 const outputValue = this.output[def.name]
46
47 if (def.multiple) outputValue.value = outputValue.value || []
48
49 /* for boolean types, set value to `true`. For all other types run value through setter function. */
50 if (def.isBoolean()) {
51 if (Array.isArray(outputValue.value)) {
52 outputValue.value.push(true)
53 } else {
54 outputValue.value = true
55 }
56 return true
57 } else {
58 if (!Array.isArray(outputValue.value) && outputValue.valueSource === 'unknown') outputValue.value = null
59 return false
60 }
61 } else {
62 this.unknown.push(optionArg)
63 return true
64 }
65 }
66
67 setOptionValue (optionArg, value) {
68 const ValueArg = require('./value-arg')
69 const valueArg = new ValueArg(value)
70
71 const def = this.definitions.get(optionArg)
72
73 this.output[def.name] = this.output[def.name] || new OutputValue()
74 const outputValue = this.output[def.name]
75
76 if (def.multiple) outputValue.value = outputValue.value || []
77
78 /* run value through setter function. */
79 valueArg.value = def.type(valueArg.value)
80 outputValue.valueSource = 'argv'
81 if (Array.isArray(outputValue.value)) {
82 if (outputValue.hasDefaultArrayValue) {
83 outputValue.value = [ valueArg.value ]
84 outputValue.hasDefaultArrayValue = false
85 } else {
86 outputValue.value.push(valueArg.value)
87 }
88 return false
89 } else {
90 outputValue.value = valueArg.value
91 return true
92 }
93 }
94
95 /**
96 * 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.
97 */
98 setValue (value) {
99 const ValueArg = require('./value-arg')
100 const valueArg = new ValueArg(value)
101
102 /* use the defaultOption */
103 const def = this.definitions.getDefault()
104
105 /* handle unknown values in the case a value was already set on a defaultOption */
106 if (def) {
107 const currentValue = this.output[def.name]
108 if (valueArg.isDefined() && currentValue && t.isDefined(currentValue.value)) {
109 if (def.multiple) {
110 /* in the case we're setting an --option=value value on a multiple defaultOption, tag the value onto the previous unknown */
111 if (valueArg.isOptionValueNotationValue && this.unknown.length) {
112 this.unknown[this.unknown.length - 1] += `=${valueArg.value}`
113 return true
114 }
115 } else {
116 /* currentValue has already been set by argv,log this value as unknown and move on */
117 if (currentValue.valueSource === 'argv') {
118 this.unknown.push(valueArg.value)
119 return true
120 }
121 }
122 }
123 return this.setOptionValue(`--${def.name}`, value)
124 } else {
125 if (valueArg.isOptionValueNotationValue) {
126 this.unknown[this.unknown.length - 1] += `=${valueArg.value}`
127 } else {
128 this.unknown.push(valueArg.value)
129 }
130 return true
131 }
132 }
133
134 get (name) {
135 return this.output[name] && this.output[name].value
136 }
137
138 toObject () {
139 let output = Object.assign({}, this.output)
140 if (this.options.partial && this.unknown.length) {
141 output._unknown = this.unknown
142 }
143 for (const prop in output) {
144 if (prop !== '_unknown') {
145 output[prop] = output[prop].value
146 }
147 }
148 return output
149 }
150}
151
152module.exports = Output