configorama 0.6.0 → 0.6.2
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 +4 -2
- package/src/main.js +216 -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.2",
|
|
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,6 +34,7 @@
|
|
|
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",
|
|
39
40
|
"find-up": "^3.0.0",
|
|
@@ -60,6 +61,7 @@
|
|
|
60
61
|
"lodash.split": "^4.4.2",
|
|
61
62
|
"minimist": "^1.2.8",
|
|
62
63
|
"promise.prototype.finally": "^3.1.8",
|
|
64
|
+
"safe-chalk": "^1.0.0",
|
|
63
65
|
"sync-rpc": "^1.3.6",
|
|
64
66
|
"traverse": "^0.6.8"
|
|
65
67
|
},
|
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
|
*
|
|
@@ -407,7 +411,7 @@ class Configorama {
|
|
|
407
411
|
}
|
|
408
412
|
|
|
409
413
|
if (VERBOSE) {
|
|
410
|
-
|
|
414
|
+
logHeader('Config Input before processing')
|
|
411
415
|
console.log()
|
|
412
416
|
deepLog(this.originalConfig)
|
|
413
417
|
console.log()
|
|
@@ -415,60 +419,233 @@ class Configorama {
|
|
|
415
419
|
|
|
416
420
|
if (VERBOSE || showFoundVariables) {
|
|
417
421
|
const foundVariables = []
|
|
418
|
-
|
|
422
|
+
const variableData = {}
|
|
423
|
+
let matchCount = 1
|
|
419
424
|
traverse(this.originalConfig).forEach(function (rawValue) {
|
|
420
425
|
if (typeof rawValue === 'string' && rawValue.match(variableSyntax)) {
|
|
421
426
|
const configValuePath = this.path.join('.')
|
|
422
427
|
if (configValuePath.endsWith('Fn::Sub')) {
|
|
423
428
|
return
|
|
424
429
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
if (!loggedHeader) {
|
|
428
|
-
console.log('───────────── Variables Detected ──────────────────────')
|
|
429
|
-
console.log()
|
|
430
|
-
loggedHeader = true
|
|
431
|
-
}
|
|
432
430
|
|
|
433
431
|
const nested = findNestedVariables(rawValue, variableSyntax, variablesKnownTypes, configValuePath)
|
|
434
432
|
/*
|
|
435
|
-
console.log(nested)
|
|
433
|
+
console.log('traverse nested result', nested)
|
|
436
434
|
/** */
|
|
437
435
|
|
|
438
|
-
console.log(`▷ Path: ${configValuePath}`)
|
|
439
|
-
console.log('\n Key/value:')
|
|
440
|
-
console.log(` ${configValuePath}: ${rawValue}`)
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
436
|
+
// console.log(`▷ Path: ${configValuePath}`)
|
|
437
|
+
// console.log('\n Key/value:')
|
|
438
|
+
// console.log(` ${configValuePath}: ${rawValue}`)
|
|
439
|
+
const lastItem = nested[nested.length - 1]
|
|
440
|
+
const lastKeyPath = this.path[this.path.length - 1]
|
|
441
|
+
const itemKey = (lastKeyPath.match(/[\d+]$/)) ? `${this.path[this.path.length - 2]}[${lastKeyPath}]` : lastKeyPath
|
|
442
|
+
const key = lastItem.fullMatch
|
|
443
|
+
const varData = {
|
|
444
|
+
path: configValuePath,
|
|
445
|
+
key: itemKey,
|
|
446
|
+
value: rawValue,
|
|
447
|
+
variable: lastItem.fullMatch,
|
|
448
|
+
isRequired: false,
|
|
449
|
+
defaultValue: undefined,
|
|
450
|
+
matchIndex: matchCount++,
|
|
451
|
+
// hasFallback: false,
|
|
452
|
+
resolveOrder: [],
|
|
453
|
+
resolveDetails: nested,
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function calculateResolveOrder(item) {
|
|
457
|
+
if (item && item.fallbackValues) {
|
|
458
|
+
let hasResolvedFallback
|
|
459
|
+
const order = ([item.valueBeforeFallback]).concat(item.fallbackValues.map((f, i) => {
|
|
460
|
+
if (f.fallbackValues) {
|
|
461
|
+
const [nestedOrder, nestedResolvedFallback] = calculateResolveOrder(f)
|
|
462
|
+
if (!hasResolvedFallback && nestedResolvedFallback) {
|
|
463
|
+
hasResolvedFallback = nestedResolvedFallback
|
|
464
|
+
}
|
|
465
|
+
return nestedOrder // Return just the order part
|
|
466
|
+
}
|
|
467
|
+
if (!hasResolvedFallback && f.isResolvedFallback) {
|
|
468
|
+
hasResolvedFallback = f.stringValue
|
|
469
|
+
}
|
|
470
|
+
return `${f.stringValue || f.variable}${f.isResolvedFallback ? ' (Resolved default fallback)' : ''}`
|
|
471
|
+
})).flat()
|
|
472
|
+
|
|
473
|
+
return [order, hasResolvedFallback]
|
|
448
474
|
}
|
|
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
|
-
})
|
|
475
|
+
return [[item.variable], false] // Return array instead of just the value
|
|
462
476
|
}
|
|
463
|
-
|
|
477
|
+
|
|
478
|
+
const [resolveOrder, hasResolvedFallback] = calculateResolveOrder(lastItem)
|
|
479
|
+
varData.resolveOrder = resolveOrder
|
|
480
|
+
|
|
481
|
+
if (hasResolvedFallback) {
|
|
482
|
+
varData.defaultValue = hasResolvedFallback
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
if (!varData.defaultValue) {
|
|
487
|
+
varData.isRequired = true
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
if (varData.resolveOrder.length > 1) {
|
|
492
|
+
varData.hasFallback = true
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
variableData[key] = (variableData[key] || []).concat(varData)
|
|
496
|
+
|
|
464
497
|
foundVariables.push(rawValue)
|
|
465
498
|
}
|
|
466
499
|
})
|
|
467
500
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
501
|
+
|
|
502
|
+
if (!foundVariables.length) {
|
|
503
|
+
logHeader('No Variables Found in Config')
|
|
504
|
+
if (this.configFilePath) {
|
|
505
|
+
console.log(`File: ${this.configFilePath}`)
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
console.log(`\nVariable syntax: `, variableSyntax)
|
|
509
|
+
|
|
510
|
+
const varTypes = Object.keys(this.variableTypes)
|
|
511
|
+
if (varTypes.length) {
|
|
512
|
+
const exclude = ['fallthrough', 'deep']
|
|
513
|
+
console.log('\nAllowed variable types:')
|
|
514
|
+
varTypes.filter((v) => v.type !== 'fallthrough').forEach((v) => {
|
|
515
|
+
const vData = this.variableTypes[v]
|
|
516
|
+
if (exclude.includes(vData.type)) {
|
|
517
|
+
return
|
|
518
|
+
}
|
|
519
|
+
console.log(` - ${vData.type}: `, vData.match)
|
|
520
|
+
})
|
|
521
|
+
}
|
|
522
|
+
console.log()
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// make foundVariables array unique
|
|
526
|
+
const finalFoundVariables = [...new Set(foundVariables)]
|
|
527
|
+
if (finalFoundVariables.length > 0) {
|
|
528
|
+
const varKeys = Object.keys(variableData)
|
|
529
|
+
const fileName = this.configFilePath ? ` in ${this.configFilePath}` : ''
|
|
530
|
+
|
|
531
|
+
logHeader(`Found ${varKeys.length} Variables${fileName}`)
|
|
532
|
+
|
|
533
|
+
// deepLog('variableData', variableData)
|
|
534
|
+
|
|
535
|
+
if (varKeys.length) {
|
|
536
|
+
console.log()
|
|
537
|
+
const longestKey = varKeys.reduce((acc, k) => {
|
|
538
|
+
return Math.max(acc, k.length)
|
|
539
|
+
}, 0)
|
|
540
|
+
console.log(varKeys.map((k) => {
|
|
541
|
+
const placesWord = variableData[k].length > 1 ? 'places' : 'place'
|
|
542
|
+
return `- ${k.padEnd(longestKey).padEnd(longestKey + 10)} referenced ${variableData[k].length} ${placesWord}`
|
|
543
|
+
}).join('\n'))
|
|
544
|
+
console.log()
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
logHeader('Variable Details')
|
|
548
|
+
|
|
549
|
+
const indent = ''
|
|
550
|
+
varKeys.forEach((key, i) => {
|
|
551
|
+
const variableInstances = variableData[key]
|
|
552
|
+
|
|
553
|
+
const firstInstance = variableInstances[0]
|
|
554
|
+
|
|
555
|
+
let requiredText = ''
|
|
556
|
+
let defaultValueSrc = ''
|
|
557
|
+
if (!firstInstance.defaultValue) {
|
|
558
|
+
// console.log('no default value', firstInstance)
|
|
559
|
+
/* Check if the fallback variable is a self reference */
|
|
560
|
+
const hasDotPropOrSelf = variableInstances.reduce((acc, v) => {
|
|
561
|
+
const dotProp = v.resolveDetails.find((d) => d.varType === 'dot.prop')
|
|
562
|
+
if (dotProp) {
|
|
563
|
+
acc.push(dotProp)
|
|
564
|
+
}
|
|
565
|
+
if (v.resolveDetails && v.resolveDetails.length === 1 && v.resolveDetails[0].varType === 'self:') {
|
|
566
|
+
// console.log('dot.prop', v.resolveDetails)
|
|
567
|
+
acc.push(v.resolveDetails[0])
|
|
568
|
+
}
|
|
569
|
+
return acc
|
|
570
|
+
}, [])
|
|
571
|
+
// console.log('hasDotPropOrSelf', hasDotPropOrSelf)
|
|
572
|
+
if (!hasDotPropOrSelf.length) {
|
|
573
|
+
requiredText = '[Required] '
|
|
574
|
+
} else {
|
|
575
|
+
const fallBackValues = variableInstances.filter((v) => v.resolveDetails.find((d) => d.hasFallback)).map((v) => v.resolveDetails)
|
|
576
|
+
// console.log('fallBackValues', fallBackValues)
|
|
577
|
+
if (fallBackValues.length) {
|
|
578
|
+
// console.log('fallBackValues.resolveDetails', fallBackValues)
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const cleanPath = hasDotPropOrSelf[0].variable.replace('self:', '')
|
|
582
|
+
defaultValueSrc = cleanPath
|
|
583
|
+
// Find the dot prop value in the original config
|
|
584
|
+
const dotPropValue = dotProp.get(this.originalConfig, cleanPath)
|
|
585
|
+
// console.log('dotPropValue', dotPropValue)
|
|
586
|
+
if (typeof dotPropValue !== 'undefined') {
|
|
587
|
+
requiredText = ''
|
|
588
|
+
const niceString = typeof dotPropValue === 'object' ? JSON.stringify(dotPropValue) : dotPropValue
|
|
589
|
+
// truncate niceString to 100 characters
|
|
590
|
+
const truncatedString = niceString.length > 100 ? niceString.substring(0, 90) + '...' : niceString
|
|
591
|
+
firstInstance.defaultValue = truncatedString
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
//this.originalConfig[key] = undefined
|
|
595
|
+
}
|
|
596
|
+
const spacing = ' '
|
|
597
|
+
const titleText = `Variable:${spacing}`
|
|
598
|
+
const reqText = (requiredText) ? `${chalk.red.bold(requiredText)}\n` : ''
|
|
599
|
+
let varMsg = `${reqText}`
|
|
600
|
+
const VALUE_HEX = '#899499' // '#708090'
|
|
601
|
+
const keyChalk = chalk.whiteBright
|
|
602
|
+
const valueChalk = chalk.hex(VALUE_HEX)
|
|
603
|
+
|
|
604
|
+
if (firstInstance.defaultValue) {
|
|
605
|
+
const defaultValueText = `${indent}${keyChalk(`DefaultValue:`.padEnd(titleText.length, ' '))}`
|
|
606
|
+
// ensure padding is even
|
|
607
|
+
varMsg += `${defaultValueText} ${valueChalk(firstInstance.defaultValue)}`
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
if(defaultValueSrc) {
|
|
611
|
+
varMsg += `\n${indent}${keyChalk('DefaultValue path:'.padEnd(titleText.length, ' '))} `
|
|
612
|
+
varMsg += `${valueChalk(defaultValueSrc)}`
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (firstInstance.resolveOrder.length > 1) {
|
|
616
|
+
varMsg += `\n${indent}${keyChalk('Resolve Order:'.padEnd(titleText.length, ' '))}`
|
|
617
|
+
const resolveOrder = firstInstance.resolveOrder.join(', ')
|
|
618
|
+
varMsg += ` ${valueChalk(resolveOrder)}`
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
let locationRender = valueChalk(variableInstances[0].path)
|
|
622
|
+
|
|
623
|
+
let locationLabel = `${indent}${keyChalk('Used at:'.padEnd(titleText.length, ' '))}`
|
|
624
|
+
if (variableInstances.length > 1) {
|
|
625
|
+
locationRender = `\n${variableInstances.map((v) => valueChalk(`${indent}- ${v.path}`)).join('\n')}`
|
|
626
|
+
const locationLabelText = `${indent}${keyChalk('Used at:')}`
|
|
627
|
+
locationLabel = locationLabelText
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
varMsg += `\n${locationLabel} ${locationRender}`
|
|
631
|
+
|
|
632
|
+
// console.log(` ${chalk.bold(key)}`)
|
|
633
|
+
console.log(makeBox(varMsg, {
|
|
634
|
+
title: `${key}`,
|
|
635
|
+
borderColor: 'gray',
|
|
636
|
+
// style: 'bold',
|
|
637
|
+
minWidth: 120,
|
|
638
|
+
}))
|
|
639
|
+
if(i < varKeys.length - 1) {
|
|
640
|
+
//console.log()
|
|
641
|
+
}
|
|
642
|
+
})
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/* Exit early if list or info flag is set */
|
|
646
|
+
if (showFoundVariables) {
|
|
647
|
+
process.exit(0)
|
|
648
|
+
}
|
|
472
649
|
}
|
|
473
650
|
|
|
474
651
|
this.deep = []
|
|
@@ -567,7 +744,7 @@ class Configorama {
|
|
|
567
744
|
this.config = mergeByKeys(this.config, '', this.mergeKeys)
|
|
568
745
|
}
|
|
569
746
|
if (VERBOSE) {
|
|
570
|
-
|
|
747
|
+
logHeader('Resolved Configuration value')
|
|
571
748
|
console.log()
|
|
572
749
|
deepLog(this.config)
|
|
573
750
|
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
|
+
}
|