configorama 0.6.1 → 0.6.3
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 +2 -1
- package/package.json +5 -2
- package/src/main.js +232 -39
- package/src/parsers/yaml.js +12 -1
- package/src/utils/chalk.js +9 -0
- package/src/utils/find-nested-variables.js +120 -25
- package/src/utils/logs.js +15 -0
package/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ const fs = require('fs')
|
|
|
4
4
|
const minimist = require('minimist')
|
|
5
5
|
const Configorama = require('./src/main')
|
|
6
6
|
const deepLog = require('./src/utils/deep-log')
|
|
7
|
+
const { logHeader } = require('./src/utils/logs')
|
|
7
8
|
|
|
8
9
|
// Parse command line arguments
|
|
9
10
|
const argv = minimist(process.argv.slice(2), {
|
|
@@ -79,7 +80,7 @@ const options = {
|
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
if (options.dynamicArgs.verbose) {
|
|
82
|
-
|
|
83
|
+
logHeader('Config Input Options')
|
|
83
84
|
const dynamicArgs = options.dynamicArgs || {}
|
|
84
85
|
const {
|
|
85
86
|
_,
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "configorama",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "Variable support for configuration files",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"cli.js",
|
|
8
8
|
"src",
|
|
@@ -34,8 +34,10 @@
|
|
|
34
34
|
"url": "https://github.com/DavidWells/configorama"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"@davidwells/box-logger": "^1.0.10",
|
|
37
38
|
"@iarna/toml": "^2.2.5",
|
|
38
39
|
"dot-prop": "^5.3.0",
|
|
40
|
+
"env-stage-loader": "^1.1.1",
|
|
39
41
|
"find-up": "^3.0.0",
|
|
40
42
|
"git-url-parse": "^14.0.0",
|
|
41
43
|
"js-yaml": "^3.14.1",
|
|
@@ -60,6 +62,7 @@
|
|
|
60
62
|
"lodash.split": "^4.4.2",
|
|
61
63
|
"minimist": "^1.2.8",
|
|
62
64
|
"promise.prototype.finally": "^3.1.8",
|
|
65
|
+
"safe-chalk": "^1.0.0",
|
|
63
66
|
"sync-rpc": "^1.3.6",
|
|
64
67
|
"traverse": "^0.6.8"
|
|
65
68
|
},
|
package/src/main.js
CHANGED
|
@@ -12,6 +12,8 @@ const promiseFinallyShim = require('promise.prototype.finally').shim()
|
|
|
12
12
|
const findUp = require('find-up')
|
|
13
13
|
const traverse = require('traverse')
|
|
14
14
|
const dotProp = require('dot-prop')
|
|
15
|
+
const chalk = require('./utils/chalk')
|
|
16
|
+
|
|
15
17
|
/* Default Value resolvers */
|
|
16
18
|
const getValueFromString = require('./resolvers/valueFromString')
|
|
17
19
|
const getValueFromNumber = require('./resolvers/valueFromNumber')
|
|
@@ -48,6 +50,8 @@ const { encodeUnknown, decodeUnknown } = require('./utils/unknownValues')
|
|
|
48
50
|
const { mergeByKeys } = require('./utils/mergeByKeys')
|
|
49
51
|
const { arrayToJsonPath } = require('./utils/arrayToJsonPath')
|
|
50
52
|
const { findNestedVariables } = require('./utils/find-nested-variables')
|
|
53
|
+
const { makeBox } = require('@davidwells/box-logger')
|
|
54
|
+
const { logHeader } = require('./utils/logs')
|
|
51
55
|
/**
|
|
52
56
|
* Maintainer's notes:
|
|
53
57
|
*
|
|
@@ -160,6 +164,26 @@ class Configorama {
|
|
|
160
164
|
this.originalString = fileContents
|
|
161
165
|
// Keep a copy
|
|
162
166
|
this.originalConfig = cloneDeep(configObject)
|
|
167
|
+
|
|
168
|
+
const useDotEnv = this.originalConfig.useDotenv || this.originalConfig.useDotEnv
|
|
169
|
+
if ((useDotEnv && useDotEnv === true) || this.opts.useDotEnvFiles) {
|
|
170
|
+
const loadStageEnv = require('env-stage-loader')
|
|
171
|
+
let providerStage
|
|
172
|
+
if (this.originalConfig && this.originalConfig.provider && this.originalConfig.provider.stage) {
|
|
173
|
+
providerStage = this.originalConfig.provider.stage
|
|
174
|
+
// @TODO check value to see if variable and needs pre-resolving to resolve stage vars
|
|
175
|
+
}
|
|
176
|
+
const stage = this.opts.stage || providerStage || 'dev'
|
|
177
|
+
/* Load env variables into process.env */
|
|
178
|
+
const values = loadStageEnv({
|
|
179
|
+
// silent: true,
|
|
180
|
+
// debug: true,
|
|
181
|
+
env: stage,
|
|
182
|
+
// defaultEnv: 'prod',
|
|
183
|
+
// ignoreFiles: ['.env']
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
|
|
163
187
|
// Set configPath for file references
|
|
164
188
|
this.configPath = fileDirectory
|
|
165
189
|
}
|
|
@@ -407,7 +431,7 @@ class Configorama {
|
|
|
407
431
|
}
|
|
408
432
|
|
|
409
433
|
if (VERBOSE) {
|
|
410
|
-
|
|
434
|
+
logHeader('Config Input before processing')
|
|
411
435
|
console.log()
|
|
412
436
|
deepLog(this.originalConfig)
|
|
413
437
|
console.log()
|
|
@@ -415,60 +439,229 @@ class Configorama {
|
|
|
415
439
|
|
|
416
440
|
if (VERBOSE || showFoundVariables) {
|
|
417
441
|
const foundVariables = []
|
|
418
|
-
|
|
442
|
+
const variableData = {}
|
|
443
|
+
let matchCount = 1
|
|
419
444
|
traverse(this.originalConfig).forEach(function (rawValue) {
|
|
420
445
|
if (typeof rawValue === 'string' && rawValue.match(variableSyntax)) {
|
|
421
446
|
const configValuePath = this.path.join('.')
|
|
422
447
|
if (configValuePath.endsWith('Fn::Sub')) {
|
|
423
448
|
return
|
|
424
449
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
if (!loggedHeader) {
|
|
428
|
-
console.log('───────────── Variables Detected ──────────────────────')
|
|
429
|
-
console.log()
|
|
430
|
-
loggedHeader = true
|
|
431
|
-
}
|
|
432
450
|
|
|
433
451
|
const nested = findNestedVariables(rawValue, variableSyntax, variablesKnownTypes, configValuePath)
|
|
434
452
|
/*
|
|
435
|
-
console.log(nested)
|
|
453
|
+
console.log('traverse nested result', nested)
|
|
436
454
|
/** */
|
|
437
455
|
|
|
438
|
-
console.log(`▷ Path: ${configValuePath}`)
|
|
439
|
-
console.log('\n Key/value:')
|
|
440
|
-
console.log(` ${configValuePath}: ${rawValue}`)
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
456
|
+
// console.log(`▷ Path: ${configValuePath}`)
|
|
457
|
+
// console.log('\n Key/value:')
|
|
458
|
+
// console.log(` ${configValuePath}: ${rawValue}`)
|
|
459
|
+
const lastItem = nested[nested.length - 1]
|
|
460
|
+
const lastKeyPath = this.path[this.path.length - 1]
|
|
461
|
+
const itemKey = (lastKeyPath.match(/[\d+]$/)) ? `${this.path[this.path.length - 2]}[${lastKeyPath}]` : lastKeyPath
|
|
462
|
+
const key = lastItem.fullMatch
|
|
463
|
+
const varData = {
|
|
464
|
+
path: configValuePath,
|
|
465
|
+
key: itemKey,
|
|
466
|
+
value: rawValue,
|
|
467
|
+
variable: lastItem.fullMatch,
|
|
468
|
+
isRequired: false,
|
|
469
|
+
defaultValue: undefined,
|
|
470
|
+
matchIndex: matchCount++,
|
|
471
|
+
// hasFallback: false,
|
|
472
|
+
resolveOrder: [],
|
|
473
|
+
resolveDetails: nested,
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function calculateResolveOrder(item) {
|
|
477
|
+
if (item && item.fallbackValues) {
|
|
478
|
+
let hasResolvedFallback
|
|
479
|
+
const order = ([item.valueBeforeFallback]).concat(item.fallbackValues.map((f, i) => {
|
|
480
|
+
if (f.fallbackValues) {
|
|
481
|
+
const [nestedOrder, nestedResolvedFallback] = calculateResolveOrder(f)
|
|
482
|
+
if (!hasResolvedFallback && nestedResolvedFallback) {
|
|
483
|
+
hasResolvedFallback = nestedResolvedFallback
|
|
484
|
+
}
|
|
485
|
+
return nestedOrder // Return just the order part
|
|
486
|
+
}
|
|
487
|
+
if (!hasResolvedFallback && f.isResolvedFallback) {
|
|
488
|
+
hasResolvedFallback = f.stringValue
|
|
489
|
+
}
|
|
490
|
+
return `${f.stringValue || f.variable}${f.isResolvedFallback ? ' (Resolved default fallback)' : ''}`
|
|
491
|
+
})).flat()
|
|
492
|
+
|
|
493
|
+
return [order, hasResolvedFallback]
|
|
448
494
|
}
|
|
449
|
-
|
|
450
|
-
// non mutate remove last
|
|
451
|
-
const removeLast = (nested.length > 1) ? nested.slice(0, -1) : nested
|
|
452
|
-
console.log()
|
|
453
|
-
removeLast.forEach((v) => {
|
|
454
|
-
if (v.hasFallback) {
|
|
455
|
-
console.log(' Resolve order:')
|
|
456
|
-
console.log(` 1. ${v.valueBeforeFallback}`)
|
|
457
|
-
v.fallbackValues.forEach((f, i) => {
|
|
458
|
-
console.log(` ${i + 2}. ${f.fullMatch}${f.isFallback ? ' (Fallback string value)' : ''}`)
|
|
459
|
-
})
|
|
460
|
-
}
|
|
461
|
-
})
|
|
495
|
+
return [[item.variable], false] // Return array instead of just the value
|
|
462
496
|
}
|
|
463
|
-
|
|
497
|
+
|
|
498
|
+
const [resolveOrder, hasResolvedFallback] = calculateResolveOrder(lastItem)
|
|
499
|
+
varData.resolveOrder = resolveOrder
|
|
500
|
+
|
|
501
|
+
if (hasResolvedFallback) {
|
|
502
|
+
varData.defaultValue = hasResolvedFallback
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
if (!varData.defaultValue) {
|
|
507
|
+
varData.isRequired = true
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
if (varData.resolveOrder.length > 1) {
|
|
512
|
+
varData.hasFallback = true
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
variableData[key] = (variableData[key] || []).concat(varData)
|
|
516
|
+
|
|
464
517
|
foundVariables.push(rawValue)
|
|
465
518
|
}
|
|
466
519
|
})
|
|
467
520
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
521
|
+
|
|
522
|
+
if (!foundVariables.length) {
|
|
523
|
+
logHeader('No Variables Found in Config')
|
|
524
|
+
if (this.configFilePath) {
|
|
525
|
+
console.log(`File: ${this.configFilePath}`)
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
console.log(`\nVariable syntax: `, variableSyntax)
|
|
529
|
+
|
|
530
|
+
const varTypes = Object.keys(this.variableTypes)
|
|
531
|
+
if (varTypes.length) {
|
|
532
|
+
const exclude = ['fallthrough', 'deep']
|
|
533
|
+
console.log('\nAllowed variable types:')
|
|
534
|
+
varTypes.filter((v) => v.type !== 'fallthrough').forEach((v) => {
|
|
535
|
+
const vData = this.variableTypes[v]
|
|
536
|
+
if (exclude.includes(vData.type)) {
|
|
537
|
+
return
|
|
538
|
+
}
|
|
539
|
+
console.log(` - ${vData.type}: `, vData.match)
|
|
540
|
+
})
|
|
541
|
+
}
|
|
542
|
+
console.log()
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// make foundVariables array unique
|
|
546
|
+
const finalFoundVariables = [...new Set(foundVariables)]
|
|
547
|
+
if (finalFoundVariables.length > 0) {
|
|
548
|
+
const varKeys = Object.keys(variableData)
|
|
549
|
+
const fileName = this.configFilePath ? ` in ${this.configFilePath}` : ''
|
|
550
|
+
|
|
551
|
+
logHeader(`Found ${varKeys.length} Variables${fileName}`)
|
|
552
|
+
|
|
553
|
+
// deepLog('variableData', variableData)
|
|
554
|
+
|
|
555
|
+
if (varKeys.length) {
|
|
556
|
+
console.log()
|
|
557
|
+
const longestKey = varKeys.reduce((acc, k) => {
|
|
558
|
+
return Math.max(acc, k.length)
|
|
559
|
+
}, 0)
|
|
560
|
+
console.log(varKeys.map((k) => {
|
|
561
|
+
const placesWord = variableData[k].length > 1 ? 'places' : 'place'
|
|
562
|
+
return `- ${k.padEnd(longestKey).padEnd(longestKey + 10)} referenced ${variableData[k].length} ${placesWord}`
|
|
563
|
+
}).join('\n'))
|
|
564
|
+
console.log()
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
logHeader('Variable Details')
|
|
568
|
+
|
|
569
|
+
const indent = ''
|
|
570
|
+
varKeys.forEach((key, i) => {
|
|
571
|
+
const variableInstances = variableData[key]
|
|
572
|
+
|
|
573
|
+
const firstInstance = variableInstances[0]
|
|
574
|
+
|
|
575
|
+
let requiredText = ''
|
|
576
|
+
let defaultValueSrc = ''
|
|
577
|
+
if (!firstInstance.defaultValue) {
|
|
578
|
+
// console.log('no default value', firstInstance)
|
|
579
|
+
/* Check if the fallback variable is a self reference */
|
|
580
|
+
const hasDotPropOrSelf = variableInstances.reduce((acc, v) => {
|
|
581
|
+
const dotProp = v.resolveDetails.find((d) => d.varType === 'dot.prop')
|
|
582
|
+
if (dotProp) {
|
|
583
|
+
acc.push(dotProp)
|
|
584
|
+
}
|
|
585
|
+
if (v.resolveDetails && v.resolveDetails.length === 1 && v.resolveDetails[0].varType === 'self:') {
|
|
586
|
+
// console.log('dot.prop', v.resolveDetails)
|
|
587
|
+
acc.push(v.resolveDetails[0])
|
|
588
|
+
}
|
|
589
|
+
return acc
|
|
590
|
+
}, [])
|
|
591
|
+
// console.log('hasDotPropOrSelf', hasDotPropOrSelf)
|
|
592
|
+
if (!hasDotPropOrSelf.length) {
|
|
593
|
+
requiredText = '[Required] '
|
|
594
|
+
} else {
|
|
595
|
+
const fallBackValues = variableInstances.filter((v) => v.resolveDetails.find((d) => d.hasFallback)).map((v) => v.resolveDetails)
|
|
596
|
+
// console.log('fallBackValues', fallBackValues)
|
|
597
|
+
if (fallBackValues.length) {
|
|
598
|
+
// console.log('fallBackValues.resolveDetails', fallBackValues)
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
const cleanPath = hasDotPropOrSelf[0].variable.replace('self:', '')
|
|
602
|
+
defaultValueSrc = cleanPath
|
|
603
|
+
// Find the dot prop value in the original config
|
|
604
|
+
const dotPropValue = dotProp.get(this.originalConfig, cleanPath)
|
|
605
|
+
// console.log('dotPropValue', dotPropValue)
|
|
606
|
+
if (typeof dotPropValue !== 'undefined') {
|
|
607
|
+
requiredText = ''
|
|
608
|
+
const niceString = typeof dotPropValue === 'object' ? JSON.stringify(dotPropValue) : dotPropValue
|
|
609
|
+
// truncate niceString to 100 characters
|
|
610
|
+
const truncatedString = niceString.length > 100 ? niceString.substring(0, 90) + '...' : niceString
|
|
611
|
+
firstInstance.defaultValue = truncatedString
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
//this.originalConfig[key] = undefined
|
|
615
|
+
}
|
|
616
|
+
const spacing = ' '
|
|
617
|
+
const titleText = `Variable:${spacing}`
|
|
618
|
+
const reqText = (requiredText) ? `${chalk.red.bold(requiredText)}\n` : ''
|
|
619
|
+
let varMsg = `${reqText}`
|
|
620
|
+
const VALUE_HEX = '#899499' // '#708090'
|
|
621
|
+
const keyChalk = chalk.whiteBright
|
|
622
|
+
const valueChalk = chalk.hex(VALUE_HEX)
|
|
623
|
+
|
|
624
|
+
if (firstInstance.defaultValue) {
|
|
625
|
+
const defaultValueText = `${indent}${keyChalk(`DefaultValue:`.padEnd(titleText.length, ' '))}`
|
|
626
|
+
// ensure padding is even
|
|
627
|
+
varMsg += `${defaultValueText} ${valueChalk(firstInstance.defaultValue)}`
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if(defaultValueSrc) {
|
|
631
|
+
varMsg += `\n${indent}${keyChalk('DefaultValue path:'.padEnd(titleText.length, ' '))} `
|
|
632
|
+
varMsg += `${valueChalk(defaultValueSrc)}`
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
if (firstInstance.resolveOrder.length > 1) {
|
|
636
|
+
varMsg += `\n${indent}${keyChalk('Resolve Order:'.padEnd(titleText.length, ' '))}`
|
|
637
|
+
const resolveOrder = firstInstance.resolveOrder.join(', ')
|
|
638
|
+
varMsg += ` ${valueChalk(resolveOrder)}`
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
let locationRender = valueChalk(variableInstances[0].path)
|
|
642
|
+
|
|
643
|
+
let locationLabel = `${indent}${keyChalk('Used at:'.padEnd(titleText.length, ' '))}`
|
|
644
|
+
if (variableInstances.length > 1) {
|
|
645
|
+
locationRender = `\n${variableInstances.map((v) => valueChalk(`${indent}- ${v.path}`)).join('\n')}`
|
|
646
|
+
const locationLabelText = `${indent}${keyChalk('Used at:')}`
|
|
647
|
+
locationLabel = locationLabelText
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
varMsg += `\n${locationLabel} ${locationRender}`
|
|
651
|
+
|
|
652
|
+
// console.log(` ${chalk.bold(key)}`)
|
|
653
|
+
console.log(makeBox(varMsg, {
|
|
654
|
+
title: `${key}`,
|
|
655
|
+
borderColor: 'gray',
|
|
656
|
+
// style: 'bold',
|
|
657
|
+
minWidth: 120,
|
|
658
|
+
}))
|
|
659
|
+
if(i < varKeys.length - 1) {
|
|
660
|
+
//console.log()
|
|
661
|
+
}
|
|
662
|
+
})
|
|
663
|
+
}
|
|
664
|
+
|
|
472
665
|
/* Exit early if list or info flag is set */
|
|
473
666
|
if (showFoundVariables) {
|
|
474
667
|
process.exit(0)
|
|
@@ -571,7 +764,7 @@ class Configorama {
|
|
|
571
764
|
this.config = mergeByKeys(this.config, '', this.mergeKeys)
|
|
572
765
|
}
|
|
573
766
|
if (VERBOSE) {
|
|
574
|
-
|
|
767
|
+
logHeader('Resolved Configuration value')
|
|
575
768
|
console.log()
|
|
576
769
|
deepLog(this.config)
|
|
577
770
|
console.log()
|
package/src/parsers/yaml.js
CHANGED
|
@@ -153,7 +153,9 @@ function preProcess(ymlStr = '') {
|
|
|
153
153
|
|
|
154
154
|
/* If have yaml object and vars not wrapped in quotes, wrap them */
|
|
155
155
|
if (ymlStr.match(KEY_OBJECT)) {
|
|
156
|
-
const
|
|
156
|
+
const values = matchOutermostBraces(ymlStr)
|
|
157
|
+
// console.log('values', values)
|
|
158
|
+
const hasObjects = values.filter((x) => !x.match(/{{resolve:/))
|
|
157
159
|
// console.log('hasObjects', hasObjects)
|
|
158
160
|
if (hasObjects && hasObjects.length) {
|
|
159
161
|
hasObjects.forEach((txt) => {
|
|
@@ -187,6 +189,15 @@ function preProcess(ymlStr = '') {
|
|
|
187
189
|
}
|
|
188
190
|
})
|
|
189
191
|
}
|
|
192
|
+
// Automagically wrap CF https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references-ssm.html
|
|
193
|
+
const cfParams = values.filter((x) => !x.match(/\s/) && x.match(/{{resolve:/))
|
|
194
|
+
if (cfParams && cfParams.length) {
|
|
195
|
+
cfParams.forEach((txt) => {
|
|
196
|
+
const pat = new RegExp(`([^'"])${txt}([^'"])`, 'g')
|
|
197
|
+
const fixedText = `$1"${txt}"$2`
|
|
198
|
+
ymlStr = ymlStr.replace(pat, fixedText)
|
|
199
|
+
})
|
|
200
|
+
}
|
|
190
201
|
}
|
|
191
202
|
// console.log('ymlStr', ymlStr)
|
|
192
203
|
return ymlStr
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const safeChalk = require('safe-chalk')
|
|
2
|
+
const minimist = require('minimist')
|
|
3
|
+
const argv = minimist(process.argv.slice(2))
|
|
4
|
+
|
|
5
|
+
// If --json flag disable chalk colors
|
|
6
|
+
const DISABLE_COLORS = argv.json || process.env.NO_COLORS
|
|
7
|
+
|
|
8
|
+
// Export chalk instance for usage in CLI
|
|
9
|
+
module.exports = safeChalk(DISABLE_COLORS)
|
|
@@ -51,6 +51,7 @@ function findNestedVariables(input, regex, variablesKnownTypes, location, debug
|
|
|
51
51
|
|
|
52
52
|
// Store match details
|
|
53
53
|
const matchInfo = {
|
|
54
|
+
varType: undefined,
|
|
54
55
|
location,
|
|
55
56
|
value: input,
|
|
56
57
|
fullMatch: match[0],
|
|
@@ -91,32 +92,33 @@ function findNestedVariables(input, regex, variablesKnownTypes, location, debug
|
|
|
91
92
|
matches[i].varString = matches[i].variable
|
|
92
93
|
/* Save additional meta data about the variable */
|
|
93
94
|
// console.log('matches[i].varString', matches[i].varString)
|
|
94
|
-
if (variablesKnownTypes && variablesKnownTypes.test(matches[i].varString)) {
|
|
95
|
-
matches[i].varType = matches[i].varString.match(variablesKnownTypes)[1]
|
|
96
|
-
if (FALLBACK_REGEX.test(matches[i].varString)) {
|
|
97
|
-
const split = splitByComma(matches[i].varString, regex)
|
|
98
|
-
matches[i].hasFallback = true
|
|
99
95
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const fallbackData = {
|
|
106
|
-
isVariable,
|
|
107
|
-
fullMatch: item,
|
|
108
|
-
variable: item
|
|
109
|
-
}
|
|
96
|
+
// if (variablesKnownTypes && variablesKnownTypes.test(matches[i].varString)) {
|
|
97
|
+
// matches[i].varType = matches[i].varString.match(variablesKnownTypes)[1]
|
|
98
|
+
// if (FALLBACK_REGEX.test(matches[i].varString)) {
|
|
99
|
+
// const split = splitByComma(matches[i].varString, regex)
|
|
100
|
+
// matches[i].hasFallback = true
|
|
110
101
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
102
|
+
// matches[i].valueBeforeFallback = split[0]
|
|
103
|
+
// // remove first element from split
|
|
104
|
+
// matches[i].fallbackValues = split.slice(1).map((item) => {
|
|
105
|
+
// // console.log('item', item)
|
|
106
|
+
// const isVariable = variablesKnownTypes.test(item) || VAR_MATCH_REGEX.test(item)
|
|
107
|
+
// const fallbackData = {
|
|
108
|
+
// isVariable,
|
|
109
|
+
// fullMatch: item,
|
|
110
|
+
// variable: item,
|
|
111
|
+
// }
|
|
112
|
+
|
|
113
|
+
// if (!isVariable && typeof item === 'string') {
|
|
114
|
+
// fallbackData.stringValue = trimQuotes(item)
|
|
115
|
+
// fallbackData.isResolvedFallback = true
|
|
116
|
+
// }
|
|
115
117
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
118
|
+
// return fallbackData
|
|
119
|
+
// })
|
|
120
|
+
// }
|
|
121
|
+
// }
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
// Second pass: Reconstruct each variable with original nested syntax
|
|
@@ -161,9 +163,102 @@ function findNestedVariables(input, regex, variablesKnownTypes, location, debug
|
|
|
161
163
|
// Reconstruct with all nested variables
|
|
162
164
|
currentMatch.fullMatch = replaceAllPlaceholders(currentMatch.fullMatch, matches)
|
|
163
165
|
currentMatch.variable = replaceAllPlaceholders(currentMatch.variable, matches)
|
|
166
|
+
}
|
|
164
167
|
|
|
165
|
-
|
|
168
|
+
|
|
169
|
+
// We need to store varString - the variable string with placeholders
|
|
170
|
+
for (let i = 0; i < matches.length; i++) {
|
|
171
|
+
matches[i].varString = matches[i].variable
|
|
172
|
+
/* Save additional meta data about the variable */
|
|
173
|
+
// console.log('matches[i].varString', matches[i].varString)
|
|
174
|
+
|
|
175
|
+
if (variablesKnownTypes && variablesKnownTypes.test(matches[i].varString)) {
|
|
176
|
+
matches[i].varType = matches[i].varString.match(variablesKnownTypes)[1]
|
|
177
|
+
if (FALLBACK_REGEX.test(matches[i].varString)) {
|
|
178
|
+
const split = splitByComma(matches[i].varString, regex)
|
|
179
|
+
matches[i].hasFallback = true
|
|
180
|
+
|
|
181
|
+
matches[i].valueBeforeFallback = split[0]
|
|
182
|
+
// remove first element from split
|
|
183
|
+
matches[i].fallbackValues = split.slice(1).map((item) => {
|
|
184
|
+
// console.log('item', item)
|
|
185
|
+
const isVariable = variablesKnownTypes.test(item) || VAR_MATCH_REGEX.test(item)
|
|
186
|
+
const fallbackData = {
|
|
187
|
+
isVariable,
|
|
188
|
+
fullMatch: item,
|
|
189
|
+
variable: item,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (!isVariable && typeof item === 'string') {
|
|
193
|
+
fallbackData.stringValue = trimQuotes(item)
|
|
194
|
+
fallbackData.isResolvedFallback = true
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return fallbackData
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
} else if (typeof matches[i].varType === 'undefined') {
|
|
201
|
+
matches[i].varType = 'dot.prop'
|
|
202
|
+
}
|
|
166
203
|
}
|
|
204
|
+
|
|
205
|
+
const finalMatches = matches.map((m) => {
|
|
206
|
+
delete m.placeholder
|
|
207
|
+
if (typeof m.varType === 'undefined') {
|
|
208
|
+
/*
|
|
209
|
+
{
|
|
210
|
+
varType: 'dot.prop',
|
|
211
|
+
location: 'resolvedDomainName',
|
|
212
|
+
value: '${domainByStage.${opt:stage, ${defaultStage}}}',
|
|
213
|
+
fullMatch: '${domainByStage.${opt:stage, ${defaultStage}}}',
|
|
214
|
+
variable: 'domainByStage.${opt:stage, ${defaultStage}}',
|
|
215
|
+
varString: 'domainByStage.__VAR_1__',
|
|
216
|
+
resolveOrder: 3,
|
|
217
|
+
start: 0,
|
|
218
|
+
end: 26
|
|
219
|
+
}
|
|
220
|
+
{
|
|
221
|
+
varType: 'dot.prop',
|
|
222
|
+
location: 'resolvedDomainName',
|
|
223
|
+
value: '${domainByStage.${opt:stage, ${defaultStage}}}',
|
|
224
|
+
fullMatch: '${defaultStage}',
|
|
225
|
+
variable: 'defaultStage',
|
|
226
|
+
varString: 'defaultStage',
|
|
227
|
+
resolveOrder: 1,
|
|
228
|
+
start: 29,
|
|
229
|
+
end: 44
|
|
230
|
+
}
|
|
231
|
+
*/
|
|
232
|
+
// console.log('m', m)
|
|
233
|
+
}
|
|
234
|
+
if (m.hasFallback) {
|
|
235
|
+
const combinedFallbacks = m.fallbackValues.reduce((acc, f) => {
|
|
236
|
+
const child = matches.find((m) => m.variable === f.variable)
|
|
237
|
+
if (child && child.fallbackValues && child.fallbackValues.length) {
|
|
238
|
+
const split = splitByComma(child.variable, regex)
|
|
239
|
+
f.valueBeforeFallback = split[0]
|
|
240
|
+
f.fallbackValues = child.fallbackValues
|
|
241
|
+
}
|
|
242
|
+
return acc
|
|
243
|
+
}, m.fallbackValues)
|
|
244
|
+
m.fallbackValues = combinedFallbacks
|
|
245
|
+
}
|
|
246
|
+
if (m.varType === 'dot.prop') {
|
|
247
|
+
// const reversedMatches = matches.reverse()
|
|
248
|
+
// const test = reversedMatches.reduce((acc, f) => {
|
|
249
|
+
// console.log('f', f)
|
|
250
|
+
// const child = reversedMatches.find((m) => m.variable === f.variable)
|
|
251
|
+
// if (child && child.fallbackValues && child.fallbackValues.length) {
|
|
252
|
+
// const split = splitByComma(child.variable, regex)
|
|
253
|
+
// f.valueBeforeFallback = split[0]
|
|
254
|
+
// f.fallbackValues = child.fallbackValues
|
|
255
|
+
// }
|
|
256
|
+
// return acc
|
|
257
|
+
// }, reversedMatches)
|
|
258
|
+
// console.log('test', test)
|
|
259
|
+
}
|
|
260
|
+
return m
|
|
261
|
+
})
|
|
167
262
|
|
|
168
263
|
if (debug) {
|
|
169
264
|
console.log("\nReconstructed matches:")
|
|
@@ -176,7 +271,7 @@ function findNestedVariables(input, regex, variablesKnownTypes, location, debug
|
|
|
176
271
|
})
|
|
177
272
|
}
|
|
178
273
|
|
|
179
|
-
return
|
|
274
|
+
return finalMatches
|
|
180
275
|
}
|
|
181
276
|
|
|
182
277
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { makeHeader } = require('@davidwells/box-logger')
|
|
2
|
+
|
|
3
|
+
function logHeader(message) {
|
|
4
|
+
console.log(makeHeader({
|
|
5
|
+
text: message,
|
|
6
|
+
rightBorder: true,
|
|
7
|
+
minWidth: 80,
|
|
8
|
+
textStyle: 'normal',
|
|
9
|
+
borderColor: 'cyanBright',
|
|
10
|
+
}))
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = {
|
|
14
|
+
logHeader
|
|
15
|
+
}
|