configorama 0.4.10 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.js +116 -0
- package/lib/main.js +371 -451
- package/lib/parsers/yaml.js +30 -18
- package/lib/parsers/yaml.test.js +169 -0
- package/lib/resolvers/valueFromEnv.js +10 -0
- package/lib/resolvers/valueFromGit.js +95 -1
- package/lib/utils/PromiseTracker.js +7 -4
- package/lib/utils/arrayToJsonPath.js +11 -0
- package/lib/utils/find-project-root.js +25 -0
- package/lib/utils/formatFunctionArgs.js +1 -1
- package/lib/utils/lodash.js +91 -0
- package/lib/utils/mergeByKeys.js +29 -0
- package/lib/utils/parse.js +62 -0
- package/lib/utils/replaceAll.js +16 -0
- package/lib/utils/splitByComma.js +7 -2
- package/lib/utils/splitCsv.js +29 -0
- package/lib/utils/textUtils.js +31 -0
- package/lib/utils/unknownValues.js +46 -0
- package/lib/utils/variableUtils.js +52 -0
- package/package.json +7 -5
package/lib/main.js
CHANGED
|
@@ -3,26 +3,8 @@ const path = require('path')
|
|
|
3
3
|
const fs = require('fs')
|
|
4
4
|
const promiseFinallyShim = require('promise.prototype.finally').shim()
|
|
5
5
|
// @TODO only import lodash we need
|
|
6
|
-
|
|
7
|
-
const isString = require('lodash.isstring')
|
|
8
|
-
const isNumber = require('lodash.isnumber')
|
|
9
|
-
const isObject = require('lodash.isobject')
|
|
10
|
-
const isDate = require('lodash.isdate')
|
|
11
|
-
const isRegExp = require('lodash.isregexp')
|
|
12
|
-
const isFunction = require('lodash.isfunction')
|
|
13
|
-
const isEmpty = require('lodash.isempty')
|
|
14
|
-
const trim = require('lodash.trim')
|
|
15
|
-
const camelCase = require('lodash.camelcase')
|
|
16
|
-
const kebabCase = require('lodash.kebabcase')
|
|
17
|
-
const capitalize = require('lodash.capitalize')
|
|
18
|
-
const split = require('lodash.split')
|
|
19
|
-
const map = require('lodash.map')
|
|
20
|
-
const mapValues = require('lodash.mapvalues')
|
|
21
|
-
const assign = require('lodash.assign')
|
|
22
|
-
const set = require('lodash.set')
|
|
23
|
-
const cloneDeep = require('lodash.clonedeep')
|
|
6
|
+
|
|
24
7
|
const findUp = require('find-up')
|
|
25
|
-
const replaceAll = require('replaceall')
|
|
26
8
|
const traverse = require('traverse')
|
|
27
9
|
const dotProp = require('dot-prop')
|
|
28
10
|
/* Default Value resolvers */
|
|
@@ -38,16 +20,29 @@ const TOML = require('./parsers/toml')
|
|
|
38
20
|
const md5Function = require('./functions/md5')
|
|
39
21
|
|
|
40
22
|
/* Utility/helpers */
|
|
41
|
-
const splitByComma = require('./utils/splitByComma')
|
|
42
23
|
const cleanVariable = require('./utils/cleanVariable')
|
|
43
24
|
const appendDeepVariable = require('./utils/appendDeepVariable')
|
|
44
25
|
const isValidValue = require('./utils/isValidValue')
|
|
45
26
|
const PromiseTracker = require('./utils/PromiseTracker')
|
|
46
27
|
const handleSignalEvents = require('./utils/handleSignalEvents')
|
|
47
28
|
const formatFunctionArgs = require('./utils/formatFunctionArgs')
|
|
48
|
-
const cloudFormationSchema = require('./utils/cloudformationSchema')
|
|
49
29
|
const trimSurroundingQuotes = require('./utils/trimSurroundingQuotes')
|
|
50
30
|
const deepLog = require('./utils/deep-log')
|
|
31
|
+
const { splitByComma } = require('./utils/splitByComma')
|
|
32
|
+
const {
|
|
33
|
+
isArray, isString, isNumber, isObject, isDate, isRegExp, isFunction,
|
|
34
|
+
isEmpty, trim, camelCase, kebabCase, capitalize, split, map, mapValues,
|
|
35
|
+
assign, set, cloneDeep
|
|
36
|
+
} = require('./utils/lodash')
|
|
37
|
+
const { parseFileContents } = require('./utils/parse')
|
|
38
|
+
const { splitCsv } = require('./utils/splitCsv')
|
|
39
|
+
const { replaceAll } = require('./utils/replaceAll')
|
|
40
|
+
const { getTextAfterOccurance, findNestedVariable } = require('./utils/textUtils')
|
|
41
|
+
const { getFallbackString, verifyVariable } = require('./utils/variableUtils')
|
|
42
|
+
const { encodeUnknown, decodeUnknown } = require('./utils/unknownValues')
|
|
43
|
+
const { mergeByKeys } = require('./utils/mergeByKeys')
|
|
44
|
+
const { arrayToJsonPath } = require('./utils/arrayToJsonPath')
|
|
45
|
+
|
|
51
46
|
/**
|
|
52
47
|
* Maintainer's notes:
|
|
53
48
|
*
|
|
@@ -62,8 +57,10 @@ const deepLog = require('./utils/deep-log')
|
|
|
62
57
|
* pause population, noting the continued depth to traverse. This motivated "deep" variables.
|
|
63
58
|
* Original issue #4687
|
|
64
59
|
*/
|
|
65
|
-
|
|
66
60
|
const deepRefSyntax = RegExp(/(\${)?deep:\d+(\.[^}]+)*()}?/)
|
|
61
|
+
const deepIndexReplacePattern = new RegExp(/^deep:|(\.[^}]+)*$/g)
|
|
62
|
+
const deepIndexPattern = /deep\:(\d*)/
|
|
63
|
+
const deepPrefixReplacePattern = /(?:^deep:)\d+\.?/g
|
|
67
64
|
const fileRefSyntax = RegExp(/^file\((~?[a-zA-Z0-9._\-\/,'" ]+?)\)/g)
|
|
68
65
|
// TODO update file regex ^file\((~?[a-zA-Z0-9._\-\/, ]+?)\)
|
|
69
66
|
// To match file(asyncValue.js, lol) input params
|
|
@@ -75,7 +72,9 @@ const funcStartOfLineRegex = /^(\w+)\s*\(((?:[^()]+)*)?\s*\)\s*/
|
|
|
75
72
|
const subFunctionRegex = /(\w+):(\w+)\s*\(((?:[^()]+)*)?\s*\)\s*/
|
|
76
73
|
const base64WrapperRegex = /\[_\[([A-Za-z0-9+/=\s]*)\]_\]/g
|
|
77
74
|
const logLines = '─────────────────────────────────────────────────'
|
|
78
|
-
|
|
75
|
+
|
|
76
|
+
let DEBUG = process.argv.includes('--debug') ? true : false
|
|
77
|
+
// DEBUG = true
|
|
79
78
|
|
|
80
79
|
const ENABLE_FUNCTIONS = true
|
|
81
80
|
|
|
@@ -94,17 +93,18 @@ class Configorama {
|
|
|
94
93
|
allowUndefinedValues: false,
|
|
95
94
|
}, options)
|
|
96
95
|
|
|
97
|
-
|
|
96
|
+
this.filterCache = {}
|
|
97
|
+
|
|
98
98
|
const defaultSyntax = '\\${((?!AWS|stageVariables)[ ~:a-zA-Z0-9=+!@#%*<>?._\'",|\\-\\/\\(\\)\\\\]+?)}'
|
|
99
|
+
|
|
99
100
|
const variableSyntax = options.syntax || defaultSyntax
|
|
100
101
|
let varRegex
|
|
101
102
|
if (typeof variableSyntax === 'string') {
|
|
102
|
-
varRegex = RegExp(variableSyntax, 'g')
|
|
103
|
+
varRegex = new RegExp(variableSyntax, 'g')
|
|
103
104
|
// this.variableSyntax = /\${((?!AWS)([ ~:a-zA-Z0-9=+!@#%*<>?._'",|\-\/\(\)\\]+?|(\w+)\s*\(((?:[^()]+)*)?\s*\)\s*))}/
|
|
104
105
|
} else if (variableSyntax instanceof RegExp) {
|
|
105
106
|
varRegex = variableSyntax
|
|
106
107
|
}
|
|
107
|
-
// console.log('varRegex', varRegex)
|
|
108
108
|
this.variableSyntax = varRegex
|
|
109
109
|
|
|
110
110
|
// Set initial config object to populate
|
|
@@ -121,47 +121,15 @@ class Configorama {
|
|
|
121
121
|
const fileDirectory = path.dirname(path.resolve(fileOrObject))
|
|
122
122
|
const fileType = path.extname(fileOrObject)
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const ymlText = YAML.preProcess(fileContents, varRegex)
|
|
134
|
-
const result = YAML.load(ymlText, {
|
|
135
|
-
filename: fileOrObject,
|
|
136
|
-
schema: cloudFormationSchema.schema
|
|
137
|
-
})
|
|
138
|
-
if (result.error) {
|
|
139
|
-
throw result.error
|
|
140
|
-
}
|
|
141
|
-
configObject = result.data
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
} else if (fileType.match(/\.(toml)/)) {
|
|
145
|
-
configObject = TOML.parse(fileContents)
|
|
146
|
-
} else if (fileType.match(/\.(json)/)) {
|
|
147
|
-
configObject = JSON.parse(fileContents)
|
|
148
|
-
} else if (fileType.match(/\.(js)/)) {
|
|
149
|
-
let jsFile
|
|
150
|
-
try {
|
|
151
|
-
jsFile = require(fileOrObject)
|
|
152
|
-
if (typeof jsFile !== 'function') {
|
|
153
|
-
configObject = jsFile
|
|
154
|
-
} else {
|
|
155
|
-
let jsArgs = opts.dynamicArgs || {}
|
|
156
|
-
if (jsArgs && typeof jsArgs === 'function') {
|
|
157
|
-
jsArgs = jsArgs()
|
|
158
|
-
}
|
|
159
|
-
configObject = jsFile(jsArgs)
|
|
160
|
-
}
|
|
161
|
-
} catch (err) {
|
|
162
|
-
throw new Error(err)
|
|
163
|
-
}
|
|
164
|
-
}
|
|
124
|
+
// Parse file contents using extracted function
|
|
125
|
+
const configObject = parseFileContents(
|
|
126
|
+
fileContents,
|
|
127
|
+
fileType,
|
|
128
|
+
fileOrObject,
|
|
129
|
+
varRegex,
|
|
130
|
+
this.opts
|
|
131
|
+
)
|
|
132
|
+
|
|
165
133
|
// set config objects
|
|
166
134
|
this.config = configObject
|
|
167
135
|
// Keep a copy
|
|
@@ -200,7 +168,7 @@ class Configorama {
|
|
|
200
168
|
match: selfRefSyntax,
|
|
201
169
|
resolver: (varString, o, x, pathValue) => {
|
|
202
170
|
return this.getValueFromSelf(varString, o, x, pathValue)
|
|
203
|
-
}
|
|
171
|
+
},
|
|
204
172
|
},
|
|
205
173
|
/**
|
|
206
174
|
* File references
|
|
@@ -213,7 +181,7 @@ class Configorama {
|
|
|
213
181
|
resolver: (varString, o, x, pathValue) => {
|
|
214
182
|
// console.log('pathValue getValueFromFile', pathValue)
|
|
215
183
|
return this.getValueFromFile(varString)
|
|
216
|
-
}
|
|
184
|
+
},
|
|
217
185
|
},
|
|
218
186
|
|
|
219
187
|
// Git refs
|
|
@@ -225,20 +193,14 @@ class Configorama {
|
|
|
225
193
|
// return this.getValueFromFunction(varString)
|
|
226
194
|
// }
|
|
227
195
|
// },
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
resolver: (varString, o, x, pathValue) => {
|
|
232
|
-
// console.log('pathValue getValueFromString', pathValue)
|
|
233
|
-
return this.getValueFromString(varString)
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
// Deep references
|
|
196
|
+
/* Resolve string references */
|
|
197
|
+
getValueFromString,
|
|
198
|
+
/* Resolve deep references */
|
|
237
199
|
{
|
|
238
200
|
match: deepRefSyntax,
|
|
239
201
|
resolver: (varString) => {
|
|
240
202
|
return this.getValueFromDeep(varString)
|
|
241
|
-
}
|
|
203
|
+
},
|
|
242
204
|
},
|
|
243
205
|
// Numbers
|
|
244
206
|
getValueFromNumber,
|
|
@@ -269,7 +231,7 @@ class Configorama {
|
|
|
269
231
|
},
|
|
270
232
|
resolver: (varString, o, x, pathValue) => {
|
|
271
233
|
return this.getValueFromSelf(varString, o, x, pathValue)
|
|
272
|
-
}
|
|
234
|
+
},
|
|
273
235
|
}
|
|
274
236
|
|
|
275
237
|
/* Apply user defined variable sources */
|
|
@@ -282,6 +244,9 @@ class Configorama {
|
|
|
282
244
|
|
|
283
245
|
// Additional filters on values. ${thing | filterFunction}
|
|
284
246
|
this.filters = {
|
|
247
|
+
capitalize: (val) => {
|
|
248
|
+
return capitalize(val)
|
|
249
|
+
},
|
|
285
250
|
toUpperCase: (val) => {
|
|
286
251
|
if (typeof val === 'string') {
|
|
287
252
|
return val.toUpperCase()
|
|
@@ -306,9 +271,23 @@ class Configorama {
|
|
|
306
271
|
toKebabCase: (val) => {
|
|
307
272
|
return kebabCase(val)
|
|
308
273
|
},
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
274
|
+
/* Type filters */
|
|
275
|
+
toNumber: (val, from) => {
|
|
276
|
+
const newVal = Number(val)
|
|
277
|
+
return newVal
|
|
278
|
+
},
|
|
279
|
+
toString: (val) => {
|
|
280
|
+
return String(val)
|
|
281
|
+
},
|
|
282
|
+
toBoolean: (val) => {
|
|
283
|
+
return Boolean(val)
|
|
284
|
+
},
|
|
285
|
+
toJson: (val) => {
|
|
286
|
+
return JSON.stringify(val)
|
|
287
|
+
},
|
|
288
|
+
toObject: (val) => {
|
|
289
|
+
return JSON.parse(val)
|
|
290
|
+
},
|
|
312
291
|
}
|
|
313
292
|
|
|
314
293
|
// Apply user defined filters
|
|
@@ -316,6 +295,10 @@ class Configorama {
|
|
|
316
295
|
this.filters = Object.assign({}, this.filters, options.filters)
|
|
317
296
|
}
|
|
318
297
|
|
|
298
|
+
// (\|\s*(toUpperCase|toLowerCase|toCamelCase|toKebabCase|capitalize)\s*)+$
|
|
299
|
+
this.filterMatch = new RegExp(`(\\|\\s*(${Object.keys(this.filters).join('|')})\\s*)+}?$`)
|
|
300
|
+
// console.log('this.filterMatch', this.filterMatch)
|
|
301
|
+
|
|
319
302
|
this.functions = {
|
|
320
303
|
split: (value, delimiter, limit) => {
|
|
321
304
|
const delimit = delimiter || ','
|
|
@@ -359,9 +342,9 @@ class Configorama {
|
|
|
359
342
|
},
|
|
360
343
|
math: () => {},
|
|
361
344
|
upperKeys: (o) => {
|
|
362
|
-
return Object.keys(o).reduce((c, k) => (c[k.toUpperCase()] = o[k], c), {}) // eslint-disable-line
|
|
345
|
+
return Object.keys(o).reduce((c, k) => ((c[k.toUpperCase()] = o[k]), c), {}) // eslint-disable-line
|
|
363
346
|
},
|
|
364
|
-
md5: md5Function
|
|
347
|
+
md5: md5Function,
|
|
365
348
|
}
|
|
366
349
|
|
|
367
350
|
// Apply user defined functions
|
|
@@ -393,66 +376,72 @@ class Configorama {
|
|
|
393
376
|
const configoramaOpts = this.opts
|
|
394
377
|
const originalConfig = this.originalConfig
|
|
395
378
|
return this.initialCall(() => {
|
|
396
|
-
return Promise.resolve()
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
379
|
+
return Promise.resolve()
|
|
380
|
+
.then(() => {
|
|
381
|
+
return this.populateObjectImpl(this.config).finally(() => {
|
|
382
|
+
// TODO populate function values here?
|
|
383
|
+
// console.log('Final Config', this.config)
|
|
384
|
+
const transform = this.runFunction.bind(this)
|
|
385
|
+
const varSyntax = this.variableSyntax
|
|
386
|
+
// Traverse resolved object and run functions
|
|
387
|
+
// console.log('this.config', this.config)
|
|
388
|
+
traverse(this.config).forEach(function (rawValue) {
|
|
389
|
+
/* Pass through unknown variables */
|
|
390
|
+
if (!configoramaOpts.allowUndefinedValues && typeof rawValue === 'undefined') {
|
|
391
|
+
const configValuePath = this.path.join('.')
|
|
392
|
+
const ogValue = dotProp.get(originalConfig, configValuePath)
|
|
393
|
+
const varDisplay = ogValue ? `"${ogValue}" variable` : 'variable'
|
|
394
|
+
const errorMessage = `
|
|
411
395
|
Config error:
|
|
412
396
|
"${configValuePath}" resolved to "undefined"
|
|
413
397
|
Verify the ${varDisplay} in config at "${configValuePath}"`
|
|
414
|
-
|
|
415
|
-
}
|
|
416
|
-
if (typeof rawValue === 'string') {
|
|
417
|
-
/* Process inline functions like merge() */
|
|
418
|
-
if (ENABLE_FUNCTIONS && rawValue.match(/> function /)) {
|
|
419
|
-
// console.log('RAW FUNCTION', rawFunction)
|
|
420
|
-
const funcString = rawValue.replace(/> function /g, '')
|
|
421
|
-
// console.log('funcString', funcString)
|
|
422
|
-
const func = cleanVariable(funcString, varSyntax, true)
|
|
423
|
-
const funcVal = transform(func)
|
|
424
|
-
const hasObjectRef = rawValue.match(/\.\S*$/)
|
|
425
|
-
if (hasObjectRef && typeof funcVal === 'object') {
|
|
426
|
-
const objectPath = hasObjectRef[0].replace(/^\./, '')
|
|
427
|
-
// console.log('objectPath', objectPath)
|
|
428
|
-
/* get value from object and update */
|
|
429
|
-
const valueFromObject = dotProp.get(funcVal, objectPath)
|
|
430
|
-
// console.log('valueFromObject', valueFromObject)
|
|
431
|
-
this.update(valueFromObject)
|
|
432
|
-
} else {
|
|
433
|
-
this.update(funcVal)
|
|
434
|
-
}
|
|
398
|
+
throw new Error(errorMessage)
|
|
435
399
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
400
|
+
if (typeof rawValue === 'string') {
|
|
401
|
+
/* Process inline functions like merge() */
|
|
402
|
+
if (ENABLE_FUNCTIONS && rawValue.match(/> function /)) {
|
|
403
|
+
// console.log('RAW FUNCTION', rawFunction)
|
|
404
|
+
const funcString = rawValue.replace(/> function /g, '')
|
|
405
|
+
// console.log('funcString', funcString)
|
|
406
|
+
const func = cleanVariable(funcString, varSyntax, true)
|
|
407
|
+
const funcVal = transform(func)
|
|
408
|
+
const hasObjectRef = rawValue.match(/\.\S*$/)
|
|
409
|
+
if (hasObjectRef && typeof funcVal === 'object') {
|
|
410
|
+
const objectPath = hasObjectRef[0].replace(/^\./, '')
|
|
411
|
+
// console.log('objectPath', objectPath)
|
|
412
|
+
/* get value from object and update */
|
|
413
|
+
const valueFromObject = dotProp.get(funcVal, objectPath)
|
|
414
|
+
// console.log('valueFromObject', valueFromObject)
|
|
415
|
+
this.update(valueFromObject)
|
|
416
|
+
} else {
|
|
417
|
+
this.update(funcVal)
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/* Allow for unknown variables to pass through */
|
|
422
|
+
if (rawValue.match(/>passthrough/)) {
|
|
423
|
+
const newValues = decodeUnknown(rawValue)
|
|
424
|
+
// console.log('>>>> newValues', newValues)
|
|
425
|
+
this.update(newValues)
|
|
426
|
+
}
|
|
443
427
|
}
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
if (DEBUG) {
|
|
431
|
+
console.log(`Variable process ran ${this.callCount} times`)
|
|
432
|
+
// console.log('FINAL Value', this.config)
|
|
433
|
+
// console.log(this.deep)
|
|
444
434
|
}
|
|
445
435
|
})
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
436
|
+
})
|
|
437
|
+
.then(() => {
|
|
438
|
+
// console.log('this.config', this.config)
|
|
439
|
+
/* Final post-processing here */
|
|
440
|
+
if (this.mergeKeys && this.config) {
|
|
441
|
+
this.config = mergeByKeys(this.config, '', this.mergeKeys)
|
|
451
442
|
}
|
|
443
|
+
return this.config
|
|
452
444
|
})
|
|
453
|
-
}).then(() => {
|
|
454
|
-
return this.config
|
|
455
|
-
})
|
|
456
445
|
})
|
|
457
446
|
}
|
|
458
447
|
runFunction(variableString) {
|
|
@@ -470,7 +459,6 @@ class Configorama {
|
|
|
470
459
|
// test for object
|
|
471
460
|
const functionName = hasFunc[1]
|
|
472
461
|
const rawArgs = hasFunc[2]
|
|
473
|
-
|
|
474
462
|
// TODO @DWELLS. Loop through all raw args and parse to correct datatype
|
|
475
463
|
// argument is object
|
|
476
464
|
let argsToPass
|
|
@@ -488,9 +476,7 @@ class Configorama {
|
|
|
488
476
|
// TODO check for camelCase version. | toUpperCase messes with function name
|
|
489
477
|
const theFunction = this.functions[functionName] || this.functions[functionName.toLowerCase()]
|
|
490
478
|
|
|
491
|
-
if (!theFunction) {
|
|
492
|
-
throw new Error(`Function "${functionName}" not found`)
|
|
493
|
-
}
|
|
479
|
+
if (!theFunction) throw new Error(`Function "${functionName}" not found`)
|
|
494
480
|
|
|
495
481
|
const funcValue = theFunction(...argsToPass)
|
|
496
482
|
// console.log('funcValue', funcValue)
|
|
@@ -545,13 +531,10 @@ class Configorama {
|
|
|
545
531
|
*/
|
|
546
532
|
getProperties(root, atRoot, current, _context, _results) {
|
|
547
533
|
let context = _context
|
|
548
|
-
if (!context)
|
|
549
|
-
context = []
|
|
550
|
-
}
|
|
534
|
+
if (!context) context = []
|
|
551
535
|
let results = _results
|
|
552
|
-
if (!results)
|
|
553
|
-
|
|
554
|
-
}
|
|
536
|
+
if (!results) results = []
|
|
537
|
+
|
|
555
538
|
const addContext = (value, key) => {
|
|
556
539
|
return this.getProperties(root, false, value, context.concat(key), results)
|
|
557
540
|
}
|
|
@@ -567,13 +550,12 @@ class Configorama {
|
|
|
567
550
|
path: context,
|
|
568
551
|
value: current,
|
|
569
552
|
}
|
|
570
|
-
|
|
571
|
-
const thePath = (leaf.path.length > 1) ? leaf.path.join('.') : leaf.path[0]
|
|
553
|
+
const thePath = leaf.path.length > 1 ? leaf.path.join('.') : leaf.path[0]
|
|
572
554
|
let originalValue = dotProp.get(this.originalConfig, thePath)
|
|
573
555
|
// TODO @DWELLS make recursive
|
|
574
556
|
if (!originalValue) {
|
|
575
557
|
const parentArray = leaf.path.slice(0, -1)
|
|
576
|
-
const parentPath =
|
|
558
|
+
const parentPath = parentArray > 1 ? parentArray.join('.') : parentArray[0]
|
|
577
559
|
originalValue = dotProp.get(this.originalConfig, parentPath)
|
|
578
560
|
}
|
|
579
561
|
leaf.originalSource = originalValue
|
|
@@ -583,7 +565,7 @@ class Configorama {
|
|
|
583
565
|
leaf.isFileRef = true
|
|
584
566
|
}
|
|
585
567
|
}
|
|
586
|
-
//
|
|
568
|
+
// dotProp.get(this.originalConfig, thePath)
|
|
587
569
|
results.push(leaf)
|
|
588
570
|
}
|
|
589
571
|
return results
|
|
@@ -605,12 +587,12 @@ class Configorama {
|
|
|
605
587
|
// Initial check if value has variable string in it
|
|
606
588
|
return isString(property.value) && property.value.match(this.variableSyntax)
|
|
607
589
|
})
|
|
590
|
+
// console.log('variables', variables)
|
|
608
591
|
return map(variables, (valueObject) => {
|
|
609
592
|
// console.log('valueObject', valueObject)
|
|
610
|
-
return this.populateValue(valueObject, false)
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
})
|
|
593
|
+
return this.populateValue(valueObject, false, '_populateVariables').then((populated) => {
|
|
594
|
+
return assign({}, valueObject, { populated: populated.value })
|
|
595
|
+
})
|
|
614
596
|
})
|
|
615
597
|
}
|
|
616
598
|
/**
|
|
@@ -620,13 +602,15 @@ class Configorama {
|
|
|
620
602
|
* @returns {Promise<number>} resolving with the number of changes that were applied to the given
|
|
621
603
|
* target
|
|
622
604
|
*/
|
|
623
|
-
assignProperties(target, populations) {
|
|
624
|
-
|
|
625
|
-
|
|
605
|
+
assignProperties(target, populations) {
|
|
606
|
+
// eslint-disable-line class-methods-use-this
|
|
607
|
+
return Promise.all(populations).then((results) => {
|
|
608
|
+
return results.forEach((result) => {
|
|
626
609
|
if (result.value !== result.populated) {
|
|
627
610
|
set(target, result.path, result.populated)
|
|
628
611
|
}
|
|
629
|
-
})
|
|
612
|
+
})
|
|
613
|
+
})
|
|
630
614
|
}
|
|
631
615
|
/**
|
|
632
616
|
* Populate the variables in the given object.
|
|
@@ -638,20 +622,19 @@ class Configorama {
|
|
|
638
622
|
}
|
|
639
623
|
populateObjectImpl(objectToPopulate) {
|
|
640
624
|
this.callCount = this.callCount + 1
|
|
641
|
-
|
|
625
|
+
|
|
642
626
|
if (DEBUG) {
|
|
643
|
-
deepLog(`objectToPopulate ${this.callCount}`, objectToPopulate)
|
|
627
|
+
deepLog(`objectToPopulate called ${this.callCount} times`, objectToPopulate)
|
|
628
|
+
// process.exit(0)
|
|
644
629
|
}
|
|
645
630
|
|
|
646
631
|
const leaves = this.getProperties(objectToPopulate, true, objectToPopulate)
|
|
632
|
+
// console.log('leaves', leaves)
|
|
647
633
|
const populations = this.populateVariables(leaves)
|
|
648
|
-
|
|
649
634
|
// console.log("FILL LEAVES", populations)
|
|
650
635
|
|
|
651
636
|
if (populations.length === 0) {
|
|
652
|
-
if (DEBUG)
|
|
653
|
-
console.log('Config Population Finished')
|
|
654
|
-
}
|
|
637
|
+
if (DEBUG) console.log('Config Population Finished')
|
|
655
638
|
return Promise.resolve(objectToPopulate)
|
|
656
639
|
}
|
|
657
640
|
|
|
@@ -674,20 +657,15 @@ class Configorama {
|
|
|
674
657
|
* @returns {Object|String|MatchResult[]} The given property or the identified matches
|
|
675
658
|
*/
|
|
676
659
|
getMatches(property) {
|
|
677
|
-
if (typeof property !== 'string')
|
|
678
|
-
return property
|
|
679
|
-
}
|
|
660
|
+
if (typeof property !== 'string') return property
|
|
680
661
|
const matches = property.match(this.variableSyntax)
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
return property
|
|
684
|
-
}
|
|
685
|
-
return map(matches, match => {
|
|
662
|
+
if (!matches || !matches.length) return property
|
|
663
|
+
return map(matches, (match) => {
|
|
686
664
|
// console.log('match', match)
|
|
687
|
-
return
|
|
665
|
+
return {
|
|
688
666
|
match: match,
|
|
689
667
|
variable: cleanVariable(match, this.variableSyntax),
|
|
690
|
-
}
|
|
668
|
+
}
|
|
691
669
|
})
|
|
692
670
|
}
|
|
693
671
|
/**
|
|
@@ -723,7 +701,6 @@ class Configorama {
|
|
|
723
701
|
if (results[i] && typeof results[i] === 'object' && results[i].__internal_only_flag) {
|
|
724
702
|
valueToPop = results[i].value
|
|
725
703
|
}
|
|
726
|
-
|
|
727
704
|
result = this.populateVariable(valueObject, matches[i].match, valueToPop)
|
|
728
705
|
/*
|
|
729
706
|
console.log('> valueToPop', valueToPop)
|
|
@@ -742,30 +719,27 @@ class Configorama {
|
|
|
742
719
|
* @returns {PromiseLike<T>} A promise that resolves to the populated value, recursively if root
|
|
743
720
|
* is true
|
|
744
721
|
*/
|
|
745
|
-
populateValue(valueObject, root) {
|
|
722
|
+
populateValue(valueObject, root, caller) {
|
|
746
723
|
if (DEBUG) {
|
|
747
724
|
console.log('─────────────────────────────────────────────▶')
|
|
748
|
-
console.log('>>>>>>>> populateValue')
|
|
725
|
+
console.log('>>>>>>>> populateValue', caller)
|
|
749
726
|
console.log(valueObject)
|
|
750
727
|
}
|
|
751
728
|
const property = valueObject.value
|
|
752
729
|
const matches = this.getMatches(property)
|
|
753
730
|
/*
|
|
754
|
-
console.log('
|
|
731
|
+
console.log('populateValue matches', matches)
|
|
755
732
|
/** */
|
|
756
733
|
if (!isArray(matches)) {
|
|
757
734
|
return Promise.resolve(property)
|
|
758
735
|
}
|
|
759
736
|
const populations = this.populateMatches(matches, valueObject, root)
|
|
760
737
|
return Promise.all(populations)
|
|
761
|
-
.then(results => this.renderMatches(valueObject, matches, results))
|
|
738
|
+
.then((results) => this.renderMatches(valueObject, matches, results))
|
|
762
739
|
.then((result) => {
|
|
763
|
-
|
|
764
|
-
console.log('renderMatches result', result)
|
|
765
|
-
/** */
|
|
766
|
-
|
|
740
|
+
// console.log('renderMatches result', result)
|
|
767
741
|
if (root && isArray(matches)) {
|
|
768
|
-
return this.populateValue({ value: result.value }, root)
|
|
742
|
+
return this.populateValue({ value: result.value }, root, 'self populateValue')
|
|
769
743
|
}
|
|
770
744
|
return result
|
|
771
745
|
})
|
|
@@ -794,29 +768,26 @@ class Configorama {
|
|
|
794
768
|
console.log('valueObject', valueObject)
|
|
795
769
|
console.log('root', root)
|
|
796
770
|
}
|
|
797
|
-
|
|
798
771
|
/* requires node 8.11+
|
|
799
772
|
if (valueObject.value.match(/(?<!^)> function /)) {
|
|
800
773
|
// valueObject.value = valueObject.value.replace(/(?<!^)> function /, '')
|
|
801
774
|
// valueObject.value = valueObject.value.replace(/^> function /, '')
|
|
802
775
|
// valueObject.value = `> function ${valueObject.value}`
|
|
803
|
-
}
|
|
804
|
-
*/
|
|
776
|
+
}*/
|
|
805
777
|
|
|
806
778
|
const parts = splitByComma(variable)
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
console.log('All parts:', parts)
|
|
814
|
-
console.log('-----')
|
|
815
|
-
}
|
|
816
|
-
return this.overwrite(parts, valueObject)
|
|
779
|
+
if (DEBUG) {
|
|
780
|
+
console.log('parts', parts)
|
|
781
|
+
console.log('parts variable:', variable)
|
|
782
|
+
console.log('parts property:', valueObject.value)
|
|
783
|
+
console.log('All parts:', parts)
|
|
784
|
+
console.log('-----')
|
|
817
785
|
}
|
|
818
|
-
|
|
819
|
-
|
|
786
|
+
if (parts.length <= 1) {
|
|
787
|
+
return this.getValueFromSource(parts[0], valueObject, 'splitAndGet')
|
|
788
|
+
}
|
|
789
|
+
// More than 2 parts, so we need to overwrite
|
|
790
|
+
return this.overwrite(parts, valueObject)
|
|
820
791
|
}
|
|
821
792
|
/**
|
|
822
793
|
* Populate a given property, given the matched string to replace and the value to replace the
|
|
@@ -829,35 +800,54 @@ class Configorama {
|
|
|
829
800
|
*/
|
|
830
801
|
populateVariable(valueObject, matchedString, valueToPopulate) {
|
|
831
802
|
let property = valueObject.value
|
|
803
|
+
// console.log('init property', property)
|
|
804
|
+
let DEBUG_TYPE = false
|
|
832
805
|
if (DEBUG) {
|
|
833
|
-
console.log('────────START
|
|
834
|
-
console.log('
|
|
835
|
-
console.log('
|
|
836
|
-
console.log(
|
|
837
|
-
console.log(
|
|
806
|
+
console.log('────────START populateVar──────────────')
|
|
807
|
+
console.log('populateVar: valueToPopulate', valueToPopulate)
|
|
808
|
+
console.log('populateVar: typeof valueToPopulate', typeof valueToPopulate)
|
|
809
|
+
console.log(`populateVar: path "${valueObject.path}"`)
|
|
810
|
+
console.log(`populateVar: value \`${valueObject.value}\``)
|
|
811
|
+
console.log(`populateVar: originalSource \`${valueObject.originalSource}\``)
|
|
812
|
+
console.log('populateVar: property', property)
|
|
813
|
+
console.log('populateVar: matchedString', matchedString)
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
const originalSrc = valueObject.originalSource || ''
|
|
817
|
+
const hasFilters = originalSrc.match(this.filterMatch)
|
|
818
|
+
let foundFilters = []
|
|
819
|
+
if (hasFilters) {
|
|
820
|
+
foundFilters = hasFilters[1]
|
|
821
|
+
.split('|')
|
|
822
|
+
.map((filter) => filter.trim())
|
|
823
|
+
.filter(Boolean)
|
|
838
824
|
}
|
|
825
|
+
// console.log('foundFilters', foundFilters)
|
|
839
826
|
|
|
840
827
|
// total replacement
|
|
841
828
|
if (property === matchedString) {
|
|
829
|
+
if (DEBUG_TYPE) console.log('DEBUG_TYPE total replacement')
|
|
842
830
|
const v = valueObject.value || ''
|
|
843
|
-
const originalSrc = valueObject.originalSource || ''
|
|
844
831
|
property = valueToPopulate
|
|
832
|
+
|
|
845
833
|
/* Handle ${self:custom.ref, ''} with deep values */
|
|
846
834
|
if (v.match(deepRefSyntax) && originalSrc.match(this.variableSyntax) && !v.match(/deep\:(\d*)\..*}$/)) {
|
|
847
835
|
// console.log('deep var', this.deep)
|
|
848
836
|
// console.log('originalSrc', originalSrc)
|
|
849
837
|
// console.log('value', v)
|
|
850
|
-
let deepIndex = Number(v.match(
|
|
838
|
+
let deepIndex = Number(v.match(deepIndexPattern)[1])
|
|
851
839
|
let item = this.deep[deepIndex]
|
|
852
|
-
|
|
840
|
+
|
|
853
841
|
if (item.match(deepRefSyntax)) {
|
|
854
|
-
deepIndex = Number(item.match(
|
|
842
|
+
deepIndex = Number(item.match(deepIndexPattern)[1])
|
|
855
843
|
item = this.deep[deepIndex]
|
|
856
844
|
}
|
|
857
845
|
property = this.deep[deepIndex]
|
|
846
|
+
// console.log('NEW PROPERTY after deep ref', property)
|
|
858
847
|
}
|
|
859
848
|
// partial replacement, string
|
|
860
849
|
} else if (isString(valueToPopulate)) {
|
|
850
|
+
if (DEBUG_TYPE) console.log('DEBUG_TYPE isString')
|
|
861
851
|
// if (property.match(/^> function /g)) {
|
|
862
852
|
//
|
|
863
853
|
// const innerFunc = /> function (\w+)\s*\(((?:[^()]+)*)?\s*\)\s*/
|
|
@@ -867,7 +857,6 @@ class Configorama {
|
|
|
867
857
|
// console.log('xxxx', rep)
|
|
868
858
|
// console.log('valueToPopulate', valueToPopulate)
|
|
869
859
|
// }
|
|
870
|
-
|
|
871
860
|
|
|
872
861
|
let currentMatchedString = matchedString
|
|
873
862
|
/* Address fall through values if found */
|
|
@@ -877,7 +866,6 @@ class Configorama {
|
|
|
877
866
|
currentMatchedString = valueObject.value
|
|
878
867
|
}
|
|
879
868
|
}
|
|
880
|
-
|
|
881
869
|
/*
|
|
882
870
|
console.log('>------')
|
|
883
871
|
console.log('isString og matchedString', matchedString)
|
|
@@ -888,28 +876,56 @@ class Configorama {
|
|
|
888
876
|
console.log('isString currentMatchedString', currentMatchedString)
|
|
889
877
|
console.log('>------')
|
|
890
878
|
/** */
|
|
891
|
-
|
|
892
|
-
|
|
879
|
+
// Handle comma ${opt:stage, dev} and remove extra }
|
|
880
|
+
if (
|
|
881
|
+
currentMatchedString.match(this.variableSyntax) &&
|
|
882
|
+
!valueToPopulate.match(this.variableSyntax) &&
|
|
883
|
+
valueToPopulate.match(/}$/)
|
|
884
|
+
) {
|
|
885
|
+
valueToPopulate = valueToPopulate.replace(/}$/, '')
|
|
886
|
+
}
|
|
887
|
+
|
|
893
888
|
property = replaceAll(currentMatchedString, valueToPopulate, property)
|
|
894
|
-
// console.log('property', property)
|
|
889
|
+
// console.log('property replaceAll', property)
|
|
895
890
|
|
|
896
891
|
// if (property.match(/^> function /g)) {
|
|
897
892
|
// console.log('REPLACE after', property)
|
|
898
893
|
// }
|
|
899
|
-
|
|
894
|
+
|
|
900
895
|
// partial replacement, number
|
|
901
896
|
} else if (isNumber(valueToPopulate)) {
|
|
897
|
+
if (DEBUG_TYPE) console.log('DEBUG_TYPE isNumber')
|
|
902
898
|
property = replaceAll(matchedString, String(valueToPopulate), property)
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
899
|
+
// TODO This was temp fix for array value mismatch from filters. This fixes filterInner: ${commas | split(${self:inner}, 2) }
|
|
900
|
+
// } else if (isArray(valueToPopulate) && valueToPopulate.length === 1) {
|
|
901
|
+
// property = replaceAll(matchedString, String(valueToPopulate[0]), property)
|
|
906
902
|
} else if (isObject(valueToPopulate)) {
|
|
907
|
-
|
|
908
|
-
|
|
903
|
+
if (DEBUG_TYPE) console.log('DEBUG_TYPEisObject')
|
|
904
|
+
|
|
905
|
+
const objStr = JSON.stringify(valueToPopulate)
|
|
906
|
+
/* Check if variable inside another variable. E.g. ${env:${self:someObject}} that resolves to ${env:{...}} */
|
|
907
|
+
if (
|
|
908
|
+
property.trim() !== matchedString.trim() &&
|
|
909
|
+
property.indexOf(matchedString) !== -1 &&
|
|
910
|
+
matchedString.match(this.variableSyntax) &&
|
|
911
|
+
property.match(this.variableSyntax)
|
|
912
|
+
) {
|
|
913
|
+
const isVar = /^\${[a-zA-Z0-9_]+:/.test(property)
|
|
914
|
+
if (isVar) {
|
|
915
|
+
// console.log('INSIDE', property, matchedString)
|
|
916
|
+
// console.log('isVar', isVar)
|
|
917
|
+
throw new Error(
|
|
918
|
+
`Invalid variable syntax "${property}" resolves to "${replaceAll(matchedString, objStr, property)}"`,
|
|
919
|
+
)
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
// console.log('OBJECT MATCH', `"${objStr}"`)
|
|
923
|
+
property = replaceAll(matchedString, objStr, property) // .replace(/}$/, '').replace(/^\$\{/, '')
|
|
909
924
|
// console.log('property', property)
|
|
910
925
|
// TODO run functions here
|
|
911
926
|
// console.log('other new prop', property)
|
|
912
927
|
} else {
|
|
928
|
+
if (DEBUG_TYPE) console.log('DEBUG_TYPE else')
|
|
913
929
|
let missingValue = matchedString
|
|
914
930
|
|
|
915
931
|
if (matchedString.match(deepRefSyntax)) {
|
|
@@ -935,18 +951,15 @@ class Configorama {
|
|
|
935
951
|
originalSource: valueObject.originalSource,
|
|
936
952
|
// set __internal_only_flag to note this is object we make not a resolved value
|
|
937
953
|
__internal_only_flag: true,
|
|
938
|
-
caller: 'nestedVar'
|
|
954
|
+
caller: 'nestedVar',
|
|
939
955
|
}
|
|
940
956
|
}
|
|
941
957
|
|
|
942
958
|
const errorMessage = `
|
|
943
959
|
Missing Value ${missingValue} - ${matchedString}
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
For variable:
|
|
948
|
-
|
|
949
|
-
${valueObject.path}: ${valueObject.originalSource}
|
|
960
|
+
\nMake sure the property is being passed in correctly
|
|
961
|
+
\nFor variable:
|
|
962
|
+
\n${valueObject.path}: ${valueObject.originalSource}
|
|
950
963
|
`
|
|
951
964
|
throw new Error(errorMessage)
|
|
952
965
|
}
|
|
@@ -964,10 +977,10 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
964
977
|
if (func && property.match(/^> function /g)) {
|
|
965
978
|
/* IMPORTANT fix `finalProp` for nested function reference
|
|
966
979
|
nestedOne: 'hi'
|
|
967
|
-
nestedTwo: ${merge('
|
|
980
|
+
nestedTwo: ${merge('nice', 'wow')}
|
|
968
981
|
mergeNested: ${merge('lol', ${nestedTwo})}
|
|
969
982
|
*/
|
|
970
|
-
const finalProp =
|
|
983
|
+
const finalProp = property.match(/(?<!^)> function /) ? prop : property
|
|
971
984
|
|
|
972
985
|
return {
|
|
973
986
|
value: finalProp, // prop to fix nested ¯\_(ツ)_/¯
|
|
@@ -1007,17 +1020,44 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
1007
1020
|
// property = newer
|
|
1008
1021
|
// }
|
|
1009
1022
|
}
|
|
1010
|
-
|
|
1023
|
+
|
|
1024
|
+
// console.log('foundFilters', foundFilters)
|
|
1025
|
+
|
|
1026
|
+
/* Apply filters if found */
|
|
1027
|
+
//console.log('> property', property)
|
|
1028
|
+
if (
|
|
1029
|
+
foundFilters.length > 0 &&
|
|
1030
|
+
typeof valueToPopulate === 'string' &&
|
|
1031
|
+
!valueToPopulate.match(deepRefSyntax) &&
|
|
1032
|
+
!property.match(this.variableSyntax)
|
|
1033
|
+
) {
|
|
1034
|
+
// If filter cache exists we need to remove filter that have already been run
|
|
1035
|
+
if (this.filterCache[valueObject.path]) {
|
|
1036
|
+
foundFilters = foundFilters.filter((filter) => {
|
|
1037
|
+
return !this.filterCache[valueObject.path].includes(filter)
|
|
1038
|
+
})
|
|
1039
|
+
}
|
|
1040
|
+
property = foundFilters.reduce((acc, filter) => {
|
|
1041
|
+
const newVal = this.filters[filter](acc, 'from populateVariable')
|
|
1042
|
+
// console.log('PROPERTY', newVal)
|
|
1043
|
+
return newVal
|
|
1044
|
+
}, property)
|
|
1045
|
+
this.filterCache[valueObject.path] = (this.filterCache[valueObject.path] || []).concat(foundFilters)
|
|
1046
|
+
// console.log('NEW PROPERTY', property)
|
|
1047
|
+
// console.log('typeof property', typeof property)
|
|
1048
|
+
}
|
|
1049
|
+
// console.log('filterCache', this.filterCache)
|
|
1050
|
+
// console.log('XXXX property', typeof property)
|
|
1011
1051
|
// console.log('XXXX path', valueObject.path)
|
|
1012
1052
|
// console.log('XXXX originalSource', valueObject.originalSource)
|
|
1053
|
+
// console.log('end property', property)
|
|
1013
1054
|
return {
|
|
1014
1055
|
value: property,
|
|
1015
1056
|
path: valueObject.path,
|
|
1016
1057
|
originalSource: valueObject.originalSource,
|
|
1017
|
-
// set __internal_only_flag to note this is object we make not a resolved value
|
|
1018
|
-
__internal_only_flag: true,
|
|
1058
|
+
__internal_only_flag: true, // set __internal_only_flag to note this is object we make not a resolved value
|
|
1019
1059
|
caller: 'end',
|
|
1020
|
-
count: this.callCount
|
|
1060
|
+
count: this.callCount,
|
|
1021
1061
|
}
|
|
1022
1062
|
}
|
|
1023
1063
|
// ###############
|
|
@@ -1033,16 +1073,13 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
1033
1073
|
overwrite(variableStrings, valueObject) {
|
|
1034
1074
|
const propertyString = valueObject.value
|
|
1035
1075
|
// console.log('variableStrings', variableStrings)
|
|
1036
|
-
|
|
1037
1076
|
// console.log('propertyString', typeof propertyString)
|
|
1038
1077
|
const variableValues = variableStrings.map((variableString) => {
|
|
1039
1078
|
// This runs on nested variable resolution
|
|
1040
1079
|
return this.getValueFromSource(variableString, valueObject, 'overwrite')
|
|
1041
1080
|
})
|
|
1042
|
-
|
|
1043
1081
|
// console.log('variableValues', variableValues)
|
|
1044
|
-
|
|
1045
|
-
return Promise.all(variableValues).then(values => {
|
|
1082
|
+
return Promise.all(variableValues).then((values) => {
|
|
1046
1083
|
let deepPropertyStr = propertyString
|
|
1047
1084
|
let deepProperties = 0
|
|
1048
1085
|
values.forEach((value, index) => {
|
|
@@ -1059,19 +1096,20 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
1059
1096
|
})
|
|
1060
1097
|
return deepProperties > 0
|
|
1061
1098
|
? Promise.resolve(deepPropertyStr) // return deep variable replacement of original
|
|
1062
|
-
: Promise.resolve(values.find(isValidValue))// resolve first valid value, else undefined
|
|
1099
|
+
: Promise.resolve(values.find(isValidValue)) // resolve first valid value, else undefined
|
|
1063
1100
|
})
|
|
1064
1101
|
}
|
|
1065
|
-
|
|
1066
1102
|
/**
|
|
1067
1103
|
* Given any variable string, return the value it should be populated with.
|
|
1068
1104
|
* @param variableString The variable string to retrieve a value for.
|
|
1069
1105
|
* @returns {Promise.<TResult>|*} A promise resolving to the given variables value.
|
|
1070
1106
|
*/
|
|
1071
1107
|
getValueFromSource(variableString, valueObject, caller) {
|
|
1108
|
+
// console.log('getValueFromSource caller', caller)
|
|
1072
1109
|
const propertyString = valueObject.value
|
|
1073
1110
|
const pathValue = valueObject.path
|
|
1074
|
-
//
|
|
1111
|
+
// console.log('getValueFromSource propertyString', propertyString)
|
|
1112
|
+
// console.log(`tracker contains ${variableString}`, this.tracker.contains(variableString))
|
|
1075
1113
|
if (this.tracker.contains(variableString)) {
|
|
1076
1114
|
// console.log('try to get', variableString)
|
|
1077
1115
|
return this.tracker.get(variableString, propertyString)
|
|
@@ -1089,28 +1127,38 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
1089
1127
|
}
|
|
1090
1128
|
|
|
1091
1129
|
const filters = propertyString.match(/\s\|/)
|
|
1130
|
+
let promiseKey
|
|
1092
1131
|
// TODO match () or pipes |
|
|
1093
1132
|
if (filters) {
|
|
1133
|
+
const string = cleanVariable(propertyString, this.variableSyntax, true)
|
|
1134
|
+
// console.log('string', string)
|
|
1135
|
+
const deeperValue = getTextAfterOccurance(string, variableString)
|
|
1136
|
+
// console.log('deeperValue', deeperValue)
|
|
1137
|
+
// console.log('filters', filters)
|
|
1094
1138
|
// console.log('variableString', variableString)
|
|
1139
|
+
promiseKey = deeperValue.match(/\s\|/) ? deeperValue : undefined
|
|
1095
1140
|
|
|
1096
1141
|
// TODO clean this up
|
|
1097
1142
|
const t = variableString.split('|')
|
|
1143
|
+
// console.log('variableString', variableString)
|
|
1144
|
+
// console.log('valueObject', valueObject)
|
|
1145
|
+
// console.log('t', t)
|
|
1146
|
+
const _filter = string
|
|
1147
|
+
.split('|')
|
|
1148
|
+
.filter((value, index, arr) => {
|
|
1149
|
+
return index > 0
|
|
1150
|
+
})
|
|
1151
|
+
.map((f) => {
|
|
1152
|
+
return trim(f)
|
|
1153
|
+
})
|
|
1154
|
+
// console.log('filters to run', _filter)
|
|
1098
1155
|
|
|
1099
|
-
|
|
1100
|
-
const filterz = string.split('|').filter((value, index, arr) => {
|
|
1101
|
-
return index > 0
|
|
1102
|
-
}).map((f) => {
|
|
1103
|
-
return trim(f)
|
|
1104
|
-
})
|
|
1105
|
-
// console.log('filters to run', filterz)
|
|
1106
|
-
|
|
1107
|
-
newHasFilter = filterz
|
|
1156
|
+
newHasFilter = _filter
|
|
1108
1157
|
// If current variable string has no pipes, it has no filters
|
|
1109
1158
|
if (!variableString.match(/\|/)) {
|
|
1110
1159
|
newHasFilter = null
|
|
1111
1160
|
}
|
|
1112
|
-
// console.log('
|
|
1113
|
-
// console.log('t', t)
|
|
1161
|
+
// console.log('newHasFilter', newHasFilter)
|
|
1114
1162
|
variableString = trim(t[0])
|
|
1115
1163
|
}
|
|
1116
1164
|
|
|
@@ -1131,19 +1179,15 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
1131
1179
|
}
|
|
1132
1180
|
return false
|
|
1133
1181
|
})
|
|
1134
|
-
|
|
1135
1182
|
// console.log('found', found)
|
|
1136
1183
|
|
|
1137
1184
|
if (found && resolverFunction) {
|
|
1138
1185
|
// TODO finalize resolverFunction API
|
|
1139
|
-
const valuePromise = resolverFunction(
|
|
1140
|
-
variableString,
|
|
1141
|
-
this.options,
|
|
1142
|
-
this.config,
|
|
1143
|
-
valueObject
|
|
1144
|
-
).then((val) => {
|
|
1186
|
+
const valuePromise = resolverFunction(variableString, this.options, this.config, valueObject).then((val) => {
|
|
1145
1187
|
// console.log('VALUE', val)
|
|
1146
|
-
if (
|
|
1188
|
+
if (
|
|
1189
|
+
val === null ||
|
|
1190
|
+
typeof val === 'undefined' ||
|
|
1147
1191
|
/* match deep refs as empty {}, they need resolving via functions */
|
|
1148
1192
|
(typeof val === 'object' && isEmpty(val) && variableString.match(/deep\:/))
|
|
1149
1193
|
) {
|
|
@@ -1153,9 +1197,8 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
1153
1197
|
|
|
1154
1198
|
if (variableString.match(/deep\:/)) {
|
|
1155
1199
|
// return Promise.resolve(this.getValueFromDeep(variableString))
|
|
1156
|
-
const deepIndex = variableString.match(
|
|
1157
|
-
const
|
|
1158
|
-
const deepRef = variableString.replace(deepPrefixReplace, '')
|
|
1200
|
+
const deepIndex = variableString.match(deepIndexPattern)
|
|
1201
|
+
const deepRef = variableString.replace(deepPrefixReplacePattern, '')
|
|
1159
1202
|
// console.log('deepRef', deepRef)
|
|
1160
1203
|
// console.log('deepIndexMatch', deepIndex)
|
|
1161
1204
|
if (deepIndex[1] && this.deep.length) {
|
|
@@ -1170,22 +1213,21 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
1170
1213
|
// TODO throw on empty values?
|
|
1171
1214
|
// No fallback value found AND this is undefined, throw error
|
|
1172
1215
|
if (valueCount.length === 1) {
|
|
1173
|
-
throw new Error(`
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
Please fix this reference or provide a valid fallback value.
|
|
1178
|
-
Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
1216
|
+
throw new Error(`
|
|
1217
|
+
Unable to resolve variable ${propertyString} from "${valueObject.originalSource}" at path ${valueObject.path ? `"${arrayToJsonPath(valueObject.path)}"` : 'na'}
|
|
1218
|
+
\nFix this reference, your inputs and/or provide a valid fallback value.
|
|
1219
|
+
\nExample of setting a fallback value: \${${variableString}, "fallbackValue"\}\n`)
|
|
1179
1220
|
}
|
|
1180
|
-
|
|
1181
1221
|
// no value resolved but fallback value exists, keep moving on
|
|
1182
1222
|
return Promise.resolve(val)
|
|
1183
1223
|
}
|
|
1224
|
+
/*
|
|
1184
1225
|
// console.log('------')
|
|
1185
1226
|
// console.log('propertyString', propertyString)
|
|
1186
1227
|
// console.log('resolved val', val)
|
|
1187
1228
|
// console.log('------')
|
|
1188
1229
|
// console.log('newHasFilter', newHasFilter)
|
|
1230
|
+
/** */
|
|
1189
1231
|
// No filters found. return value
|
|
1190
1232
|
if (!newHasFilter) {
|
|
1191
1233
|
return Promise.resolve(val)
|
|
@@ -1197,47 +1239,50 @@ Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
|
1197
1239
|
}
|
|
1198
1240
|
return acc.concat({
|
|
1199
1241
|
filter: this.filters[currentFilter],
|
|
1242
|
+
filterName: currentFilter,
|
|
1200
1243
|
// args: argsToPass
|
|
1201
1244
|
})
|
|
1202
1245
|
}, [])
|
|
1246
|
+
// console.log('newUse', newUse)
|
|
1203
1247
|
|
|
1204
1248
|
if (typeof val === 'string' && val.match(/deep:/)) {
|
|
1205
1249
|
// TODO refactor the deep filter logic here. match | filter | filter..
|
|
1206
|
-
const allFilters = propertyString
|
|
1207
|
-
|
|
1250
|
+
const allFilters = propertyString
|
|
1251
|
+
.replace(/}$/, '')
|
|
1252
|
+
.split('|')
|
|
1253
|
+
.reduce((acc, currentFilter, i) => {
|
|
1254
|
+
if (i === 0) {
|
|
1255
|
+
return acc
|
|
1256
|
+
}
|
|
1257
|
+
acc += `| ${trim(currentFilter)}`
|
|
1208
1258
|
return acc
|
|
1209
|
-
}
|
|
1210
|
-
acc += `| ${trim(currentFilter)}`
|
|
1211
|
-
return acc
|
|
1212
|
-
}, '')
|
|
1213
|
-
|
|
1259
|
+
}, '')
|
|
1214
1260
|
// add filters to deep references if filter is used
|
|
1215
|
-
const deepValueWithFilters =
|
|
1261
|
+
const deepValueWithFilters = newHasFilter[1] ? val.replace(/}$/, ` ${allFilters}}`) : val
|
|
1216
1262
|
// console.log('deepValueWithFilters', deepValueWithFilters)
|
|
1217
1263
|
return Promise.resolve(deepValueWithFilters)
|
|
1218
1264
|
}
|
|
1219
|
-
|
|
1220
|
-
// console.log('newUse', newUse)
|
|
1221
1265
|
/* Loop over filters used and produce new value */
|
|
1222
1266
|
const newValue = newUse.reduce((a, c) => {
|
|
1223
1267
|
// Fix for async value resolution. That code file refs returns object with .value
|
|
1224
|
-
const theValue =
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
if (c.args) {
|
|
1228
|
-
return c.filter(theValue, ...c.args)
|
|
1229
|
-
}
|
|
1230
|
-
return c.filter(theValue)
|
|
1268
|
+
const theValue = typeof a === 'object' && a.__internal_only_flag ? a.value : a
|
|
1269
|
+
if (typeof c.filter !== 'function') {
|
|
1270
|
+
return theValue
|
|
1231
1271
|
}
|
|
1232
|
-
|
|
1272
|
+
if (c.args) {
|
|
1273
|
+
this.filterCache[pathValue] = (this.filterCache[pathValue] || []).concat(c.filterName)
|
|
1274
|
+
return c.filter(theValue, ...c.args, 'from getValueFromSource with args')
|
|
1275
|
+
}
|
|
1276
|
+
this.filterCache[pathValue] = (this.filterCache[pathValue] || []).concat(c.filterName)
|
|
1277
|
+
return c.filter(theValue, 'from getValueFromSource')
|
|
1233
1278
|
}, val)
|
|
1279
|
+
// console.log('newValue', newValue)
|
|
1234
1280
|
|
|
1235
1281
|
return Promise.resolve(newValue)
|
|
1236
1282
|
})
|
|
1237
|
-
|
|
1283
|
+
// console.log('newHasFilter', newHasFilter)
|
|
1238
1284
|
// TODO do something with func here?
|
|
1239
|
-
|
|
1240
|
-
return this.tracker.add(variableString, valuePromise, propertyString, newHasFilter)
|
|
1285
|
+
return this.tracker.add(variableString, valuePromise, propertyString, newHasFilter, promiseKey)
|
|
1241
1286
|
}
|
|
1242
1287
|
|
|
1243
1288
|
/* fall through case with self refs */
|
|
@@ -1271,7 +1316,7 @@ Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
|
1271
1316
|
}
|
|
1272
1317
|
const fallbackStr = getFallbackString(split, nestedVar)
|
|
1273
1318
|
return this.getValueFromSource(variableString, {
|
|
1274
|
-
value: fallbackStr
|
|
1319
|
+
value: fallbackStr,
|
|
1275
1320
|
}, 'nestedVar')
|
|
1276
1321
|
}
|
|
1277
1322
|
|
|
@@ -1283,7 +1328,7 @@ Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
|
1283
1328
|
if (fallbackValue) {
|
|
1284
1329
|
// recurse on fallback and check again
|
|
1285
1330
|
return this.getValueFromSource(`${variableString})`, {
|
|
1286
|
-
value: propertyString
|
|
1331
|
+
value: propertyString,
|
|
1287
1332
|
}, 'cleanClean.match(fileRefSyntax)')
|
|
1288
1333
|
}
|
|
1289
1334
|
}
|
|
@@ -1299,20 +1344,23 @@ Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
|
1299
1344
|
|
|
1300
1345
|
// has fallback but needs deeper lookup. Call getValueFromSource again
|
|
1301
1346
|
if (fallbackValue) {
|
|
1302
|
-
if (DEBUG)
|
|
1303
|
-
|
|
1304
|
-
}
|
|
1347
|
+
if (DEBUG) console.log('fallbackValue', fallbackValue)
|
|
1348
|
+
// console.log('fallbackValue', fallbackValue)
|
|
1305
1349
|
// recurse on fallback and check again
|
|
1306
|
-
return this.getValueFromSource(
|
|
1307
|
-
|
|
1308
|
-
|
|
1350
|
+
return this.getValueFromSource(
|
|
1351
|
+
fallbackValue,
|
|
1352
|
+
{
|
|
1353
|
+
value: propertyString,
|
|
1354
|
+
},
|
|
1355
|
+
'fallbackValue',
|
|
1356
|
+
)
|
|
1309
1357
|
}
|
|
1310
1358
|
}
|
|
1311
1359
|
|
|
1312
1360
|
// Variable NOT FOUND. Warn user
|
|
1313
1361
|
const errorMessage = [
|
|
1314
1362
|
`Invalid variable reference syntax`,
|
|
1315
|
-
`Key: "${
|
|
1363
|
+
`Key: "${valueObject.path ? valueObject.path.join('.') : 'na'}"`,
|
|
1316
1364
|
`Variable: "${variableString}" from ${propertyString} not found`,
|
|
1317
1365
|
]
|
|
1318
1366
|
|
|
@@ -1343,28 +1391,21 @@ Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
|
1343
1391
|
|
|
1344
1392
|
return this.tracker.add(variableString, notFoundPromise, propertyString, newHasFilter)
|
|
1345
1393
|
}
|
|
1346
|
-
getValueFromString(variableString) {
|
|
1347
|
-
const valueToPopulate = variableString.replace(/^['"]|['"]$/g, '')
|
|
1348
|
-
return Promise.resolve(valueToPopulate)
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
1394
|
getValueFromSelf(variableString, o, x, data) {
|
|
1352
1395
|
/*
|
|
1353
1396
|
console.log('getValueFromSelf variableString', variableString)
|
|
1354
1397
|
/** */
|
|
1355
|
-
|
|
1356
1398
|
// console.log('self data', data)
|
|
1357
|
-
|
|
1358
1399
|
const split = variableString.split(':')
|
|
1359
|
-
const variable =
|
|
1400
|
+
const variable = split.length && split[1] ? split[1] : variableString
|
|
1360
1401
|
const valueToPopulate = this.config
|
|
1361
|
-
let deepProperties = variable.split('.').filter(property => property)
|
|
1402
|
+
let deepProperties = variable.split('.').filter((property) => property)
|
|
1362
1403
|
// console.log('self deep', deepProperties)
|
|
1363
1404
|
// console.log('self valueToPopulate', valueToPopulate)
|
|
1364
1405
|
|
|
1365
1406
|
/* its file ref so we need to shift lookup for self in nested files */
|
|
1366
1407
|
if (data.isFileRef) {
|
|
1367
|
-
const dotPropPath =
|
|
1408
|
+
const dotPropPath = deepProperties.length > 1 ? deepProperties.join('.') : deepProperties[0]
|
|
1368
1409
|
const exists = dotProp.get(valueToPopulate, dotPropPath)
|
|
1369
1410
|
// console.log('self exists', exists)
|
|
1370
1411
|
if (!exists) {
|
|
@@ -1373,7 +1414,6 @@ Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
|
1373
1414
|
// console.log('self fixed deepProperties', deepProperties)
|
|
1374
1415
|
}
|
|
1375
1416
|
}
|
|
1376
|
-
|
|
1377
1417
|
return this.getDeeperValue(deepProperties, valueToPopulate).then((res) => {
|
|
1378
1418
|
/*
|
|
1379
1419
|
console.log('self getDeeperValue variableString', variableString)
|
|
@@ -1382,7 +1422,6 @@ Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
|
1382
1422
|
return res
|
|
1383
1423
|
})
|
|
1384
1424
|
}
|
|
1385
|
-
|
|
1386
1425
|
getValueFromFile(variableString) {
|
|
1387
1426
|
// console.log('From file', `"${variableString}"`)
|
|
1388
1427
|
let matchedFileString = variableString.match(fileRefSyntax)[0]
|
|
@@ -1410,12 +1449,11 @@ Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
|
1410
1449
|
}
|
|
1411
1450
|
// console.log('argsToPass', argsToPass)
|
|
1412
1451
|
|
|
1413
|
-
const relativePath = trimSurroundingQuotes(
|
|
1414
|
-
.replace(fileRefSyntax, (match, varName) => varName.trim())
|
|
1415
|
-
|
|
1416
|
-
|
|
1452
|
+
const relativePath = trimSurroundingQuotes(
|
|
1453
|
+
matchedFileString.replace(fileRefSyntax, (match, varName) => varName.trim()).replace('~', os.homedir()),
|
|
1454
|
+
)
|
|
1417
1455
|
|
|
1418
|
-
let fullFilePath =
|
|
1456
|
+
let fullFilePath = path.isAbsolute(relativePath) ? relativePath : path.join(this.configPath, relativePath)
|
|
1419
1457
|
|
|
1420
1458
|
// console.log('fullFilePath', fullFilePath)
|
|
1421
1459
|
|
|
@@ -1423,7 +1461,7 @@ Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
|
1423
1461
|
// Get real path to handle potential symlinks (but don't fatal error)
|
|
1424
1462
|
fullFilePath = fs.realpathSync(fullFilePath)
|
|
1425
1463
|
|
|
1426
|
-
|
|
1464
|
+
// Only match files that are relative
|
|
1427
1465
|
} else if (relativePath.match(/\.\//)) {
|
|
1428
1466
|
// TODO test higher parent refs
|
|
1429
1467
|
const cleanName = path.basename(relativePath)
|
|
@@ -1491,15 +1529,14 @@ Check if your javascript is exporting a function that returns a value.`
|
|
|
1491
1529
|
deepProperties = deepProperties.map((prop) => {
|
|
1492
1530
|
return trim(prop)
|
|
1493
1531
|
})
|
|
1494
|
-
return this.getDeeperValue(deepProperties, valueToPopulateResolved)
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
const errorMessage = `Invalid variable syntax when referencing file "${relativePath}".
|
|
1532
|
+
return this.getDeeperValue(deepProperties, valueToPopulateResolved).then((deepValueToPopulateResolved) => {
|
|
1533
|
+
if (typeof deepValueToPopulateResolved === 'undefined') {
|
|
1534
|
+
const errorMessage = `Invalid variable syntax when referencing file "${relativePath}".
|
|
1498
1535
|
Check if your javascript is returning the correct data.`
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1536
|
+
return Promise.reject(new Error(errorMessage))
|
|
1537
|
+
}
|
|
1538
|
+
return Promise.resolve(deepValueToPopulateResolved)
|
|
1539
|
+
})
|
|
1503
1540
|
})
|
|
1504
1541
|
}
|
|
1505
1542
|
|
|
@@ -1545,13 +1582,9 @@ Please use ":" to reference sub properties`
|
|
|
1545
1582
|
}
|
|
1546
1583
|
return Promise.resolve(valueToPopulate)
|
|
1547
1584
|
}
|
|
1548
|
-
|
|
1549
|
-
getDeepIndex(variableString) {
|
|
1550
|
-
const deepIndexReplace = RegExp(/^deep:|(\.[^}]+)*$/g)
|
|
1551
|
-
return variableString.replace(deepIndexReplace, '')
|
|
1552
|
-
}
|
|
1553
1585
|
getVariableFromDeep(variableString) {
|
|
1554
|
-
const index =
|
|
1586
|
+
const index = variableString.replace(deepIndexReplacePattern, '')
|
|
1587
|
+
// const index = this.getDeepIndex(variableString)
|
|
1555
1588
|
/*
|
|
1556
1589
|
console.log('FIND INDEX', index)
|
|
1557
1590
|
console.log(this.deep)
|
|
@@ -1559,17 +1592,17 @@ Please use ":" to reference sub properties`
|
|
|
1559
1592
|
return this.deep[index]
|
|
1560
1593
|
}
|
|
1561
1594
|
getValueFromDeep(variableString) {
|
|
1562
|
-
const deepPrefixReplace = RegExp(/(?:^deep:)\d+\.?/g)
|
|
1563
1595
|
const variable = this.getVariableFromDeep(variableString)
|
|
1564
|
-
const deepRef = variableString.replace(
|
|
1596
|
+
const deepRef = variableString.replace(deepPrefixReplacePattern, '')
|
|
1565
1597
|
/*
|
|
1566
1598
|
console.log("GET getValueFromDeep", variableString)
|
|
1567
1599
|
console.log('deepRef', deepRef)
|
|
1568
1600
|
console.log('getValueFromDeep variable', variable)
|
|
1569
1601
|
/** */
|
|
1570
|
-
let ret = this.populateValue({ value: variable })
|
|
1602
|
+
let ret = this.populateValue({ value: variable }, undefined, 'getValueFromDeep')
|
|
1571
1603
|
// console.log('variable ret', ret)
|
|
1572
|
-
if (deepRef.length) {
|
|
1604
|
+
if (deepRef.length) {
|
|
1605
|
+
// if there is a deep reference remaining
|
|
1573
1606
|
ret = ret.then((result) => {
|
|
1574
1607
|
// console.log('DEEP RESULT', result)
|
|
1575
1608
|
if (isString(result.value) && result.value.match(this.variableSyntax)) {
|
|
@@ -1582,7 +1615,6 @@ Please use ":" to reference sub properties`
|
|
|
1582
1615
|
}
|
|
1583
1616
|
return ret
|
|
1584
1617
|
}
|
|
1585
|
-
|
|
1586
1618
|
makeDeepVariable(variable) {
|
|
1587
1619
|
// console.log('MAKE DEEP', variable)
|
|
1588
1620
|
let index = this.deep.findIndex((item) => variable === item)
|
|
@@ -1599,7 +1631,6 @@ Please use ":" to reference sub properties`
|
|
|
1599
1631
|
|
|
1600
1632
|
return deepVar
|
|
1601
1633
|
}
|
|
1602
|
-
|
|
1603
1634
|
/**
|
|
1604
1635
|
* Get a value that is within the given valueToPopulate. The deepProperties specify what value
|
|
1605
1636
|
* to retrieve from the given valueToPopulate. The trouble is that anywhere along this chain a
|
|
@@ -1619,16 +1650,17 @@ Please use ":" to reference sub properties`
|
|
|
1619
1650
|
console.log('deepProperties', deepProperties)
|
|
1620
1651
|
console.log('valueToPopulate', valueToPopulate)
|
|
1621
1652
|
/** */
|
|
1622
|
-
|
|
1623
1653
|
const veryDeep = deepProperties.reduce(async (reducedValueParam, subProperty) => {
|
|
1624
1654
|
let reducedValue = await reducedValueParam
|
|
1625
1655
|
// console.log('reducedValue', reducedValue)
|
|
1626
1656
|
// console.log(typeof reducedValue)
|
|
1627
1657
|
// console.log('subProperty', `"${subProperty}"`)
|
|
1628
1658
|
|
|
1629
|
-
if (isString(reducedValue) && reducedValue.match(deepRefSyntax)) {
|
|
1659
|
+
if (isString(reducedValue) && reducedValue.match(deepRefSyntax)) {
|
|
1660
|
+
// build mode
|
|
1630
1661
|
reducedValue = appendDeepVariable(reducedValue, subProperty)
|
|
1631
|
-
} else {
|
|
1662
|
+
} else {
|
|
1663
|
+
// get mode
|
|
1632
1664
|
if (typeof reducedValue === 'undefined') {
|
|
1633
1665
|
// was reducedValue = {}
|
|
1634
1666
|
// Adding internal flag signals this value is unknown
|
|
@@ -1684,126 +1716,14 @@ Please use ":" to reference sub properties`
|
|
|
1684
1716
|
// console.log("MISSING", variableString)
|
|
1685
1717
|
// console.log(this.deep)
|
|
1686
1718
|
// console.log(valueToPopulate)
|
|
1687
|
-
|
|
1688
1719
|
const notFoundMsg = `No ${varType} found to satisfy the '\${${variableString}}' variable. Attempting fallback value`
|
|
1689
1720
|
if (DEBUG) {
|
|
1690
1721
|
console.log(notFoundMsg)
|
|
1691
1722
|
}
|
|
1692
|
-
|
|
1693
1723
|
// errors make fallbacks not function. throw new Error(errorMsg)
|
|
1694
1724
|
}
|
|
1695
1725
|
return valueToPopulate
|
|
1696
1726
|
}
|
|
1697
1727
|
}
|
|
1698
1728
|
|
|
1699
|
-
function findNestedVariable(split, originalSource) {
|
|
1700
|
-
return split.find((thing) => {
|
|
1701
|
-
if (originalSource && typeof originalSource === 'string') {
|
|
1702
|
-
return originalSource.indexOf(`\${${thing}}`) > -1
|
|
1703
|
-
}
|
|
1704
|
-
return false
|
|
1705
|
-
})
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
/**
|
|
1709
|
-
* Get fallback variable string
|
|
1710
|
-
* @param {array} split - array from split at comma
|
|
1711
|
-
* @param {string} nestedVar - fallback variable to reconstruct variable string from
|
|
1712
|
-
* @return {string} - returns new ${variable, string}
|
|
1713
|
-
*/
|
|
1714
|
-
function getFallbackString(split, nestedVar) {
|
|
1715
|
-
let isSet = false
|
|
1716
|
-
const newVar = split.reduce((acc, curr) => {
|
|
1717
|
-
if (curr === nestedVar || isSet) {
|
|
1718
|
-
acc = acc.concat(curr)
|
|
1719
|
-
isSet = true
|
|
1720
|
-
}
|
|
1721
|
-
return acc
|
|
1722
|
-
}, []).join(', ')
|
|
1723
|
-
const cleanC = `\${${newVar.replace(/^\${/, '').replace(/}$/, '')}}`
|
|
1724
|
-
return cleanC
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1727
|
-
function verifyVariable(variableString, valueObject, variableTypes, config) {
|
|
1728
|
-
const isRealVariable = variableTypes.some((r, i) => {
|
|
1729
|
-
if (r.match instanceof RegExp && variableString.match(r.match)) {
|
|
1730
|
-
return true
|
|
1731
|
-
} else if (typeof r.match === 'function') {
|
|
1732
|
-
if (r.match(variableString, config, valueObject)) {
|
|
1733
|
-
return true
|
|
1734
|
-
}
|
|
1735
|
-
}
|
|
1736
|
-
return false
|
|
1737
|
-
})
|
|
1738
|
-
// If not found in variable resolvers and is missing a colon throw
|
|
1739
|
-
if (!isRealVariable && variableString.match(/:/)) {
|
|
1740
|
-
// console.log('variableString', variableString)
|
|
1741
|
-
throw new Error(`
|
|
1742
|
-
Variable \${${variableString}} is invalid variable syntax.
|
|
1743
|
-
Value Path: ${(valueObject.path) ? valueObject.path.join('.') : 'na'}
|
|
1744
|
-
Original Value: ${valueObject.originalSource}
|
|
1745
|
-
|
|
1746
|
-
Remove or update the \${${variableString}} to fix
|
|
1747
|
-
`)
|
|
1748
|
-
}
|
|
1749
|
-
return isRealVariable
|
|
1750
|
-
}
|
|
1751
|
-
|
|
1752
|
-
function encodeUnknown(v) {
|
|
1753
|
-
return `>passthrough[_[${Buffer.from(v).toString('base64')}]_]`
|
|
1754
|
-
}
|
|
1755
|
-
|
|
1756
|
-
function decodeUnknown(rawValue) {
|
|
1757
|
-
const x = findUnknownValues(rawValue)
|
|
1758
|
-
let val = rawValue.replace(/>passthrough/g, '')
|
|
1759
|
-
if (x.length) {
|
|
1760
|
-
x.forEach(({ match, value }) => {
|
|
1761
|
-
// console.log('match', match)
|
|
1762
|
-
const decodedValue = Buffer.from(value, 'base64').toString('ascii')
|
|
1763
|
-
// console.log('decodedValue', decodedValue)
|
|
1764
|
-
val = val.replace(match, decodedValue)
|
|
1765
|
-
})
|
|
1766
|
-
}
|
|
1767
|
-
return val
|
|
1768
|
-
}
|
|
1769
|
-
|
|
1770
|
-
function findUnknownValues(text) {
|
|
1771
|
-
let matches
|
|
1772
|
-
let links = []
|
|
1773
|
-
while ((matches = base64WrapperRegex.exec(text)) !== null) {
|
|
1774
|
-
if (matches.index === base64WrapperRegex.lastIndex) {
|
|
1775
|
-
base64WrapperRegex.lastIndex++ // avoid infinite loops with zero-width matches
|
|
1776
|
-
}
|
|
1777
|
-
links.push({
|
|
1778
|
-
match: matches[0],
|
|
1779
|
-
value: matches[1]
|
|
1780
|
-
})
|
|
1781
|
-
}
|
|
1782
|
-
return links
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
|
-
function isPromise(obj) { // eslint-disable-line
|
|
1786
|
-
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
|
|
1787
|
-
}
|
|
1788
|
-
|
|
1789
|
-
// TODO fix argument parsing to handle commas
|
|
1790
|
-
function splitCsv(str, splitter) {
|
|
1791
|
-
const splitSyntax = splitter || ','
|
|
1792
|
-
// Split at comma SPACE ", "
|
|
1793
|
-
return str.split(splitSyntax).reduce((accum, curr) => {
|
|
1794
|
-
if (accum.isConcatting) {
|
|
1795
|
-
accum.soFar[accum.soFar.length - 1] += ',' + curr
|
|
1796
|
-
} else {
|
|
1797
|
-
accum.soFar.push(curr)
|
|
1798
|
-
}
|
|
1799
|
-
if (curr.split('"').length % 2 == 0) { // eslint-disable-line
|
|
1800
|
-
accum.isConcatting = !accum.isConcatting
|
|
1801
|
-
}
|
|
1802
|
-
return accum
|
|
1803
|
-
}, {
|
|
1804
|
-
soFar: [],
|
|
1805
|
-
isConcatting: false
|
|
1806
|
-
}).soFar
|
|
1807
|
-
}
|
|
1808
|
-
|
|
1809
1729
|
module.exports = Configorama
|