configorama 0.6.18 → 0.7.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/README.md +78 -2
- package/cli.js +1 -0
- package/index.d.ts +90 -37
- package/package.json +8 -2
- package/src/index.js +42 -14
- package/src/main.js +135 -62
- package/src/parsers/index.js +10 -0
- package/src/parsers/typescript.js +20 -43
- package/src/parsers/yaml.js +35 -2
- package/src/resolvers/valueFromFile.js +87 -24
- package/src/resolvers/valueFromGit.js +11 -3
- package/src/utils/encoders/js-fixes.js +44 -0
- package/src/utils/parsing/mergeByKeys.js +4 -3
- package/src/utils/parsing/parse.js +4 -2
- package/src/utils/parsing/preProcess.js +42 -25
- package/src/utils/parsing/preProcess.test.js +214 -0
- package/src/utils/paths/getFullFilePath.js +1 -1
- package/src/utils/resolution/preResolveVariable.js +1 -0
- package/src/utils/strings/quoteUtils.js +2 -2
- package/src/utils/strings/splitCsv.js +1 -1
- package/src/utils/ui/logs.js +4 -4
- package/src/utils/validation/warnIfNotFound.js +3 -3
- package/src/utils/variables/findNestedVariables.js +2 -2
- package/src/utils/variables/variableUtils.js +43 -0
- package/src/utils/variables/variableUtils.test.js +38 -1
- package/types/cli.d.ts +3 -0
- package/types/cli.d.ts.map +1 -0
- package/types/src/functions/md5.d.ts +3 -0
- package/types/src/functions/md5.d.ts.map +1 -0
- package/types/src/index.d.ts +100 -0
- package/types/src/index.d.ts.map +1 -0
- package/types/src/main.d.ts +275 -0
- package/types/src/main.d.ts.map +1 -0
- package/types/src/parsers/esm.d.ts +15 -0
- package/types/src/parsers/esm.d.ts.map +1 -0
- package/types/src/parsers/hcl.d.ts +1 -0
- package/types/src/parsers/hcl.d.ts.map +1 -0
- package/types/src/parsers/index.d.ts +18 -0
- package/types/src/parsers/index.d.ts.map +1 -0
- package/types/src/parsers/ini.d.ts +6 -0
- package/types/src/parsers/ini.d.ts.map +1 -0
- package/types/src/parsers/json5.d.ts +10 -0
- package/types/src/parsers/json5.d.ts.map +1 -0
- package/types/src/parsers/toml.d.ts +7 -0
- package/types/src/parsers/toml.d.ts.map +1 -0
- package/types/src/parsers/typescript.d.ts +15 -0
- package/types/src/parsers/typescript.d.ts.map +1 -0
- package/types/src/parsers/yaml.d.ts +45 -0
- package/types/src/parsers/yaml.d.ts.map +1 -0
- package/types/src/resolvers/valueFromCron.d.ts +14 -0
- package/types/src/resolvers/valueFromCron.d.ts.map +1 -0
- package/types/src/resolvers/valueFromEnv.d.ts +8 -0
- package/types/src/resolvers/valueFromEnv.d.ts.map +1 -0
- package/types/src/resolvers/valueFromEval.d.ts +7 -0
- package/types/src/resolvers/valueFromEval.d.ts.map +1 -0
- package/types/src/resolvers/valueFromFile.d.ts +58 -0
- package/types/src/resolvers/valueFromFile.d.ts.map +1 -0
- package/types/src/resolvers/valueFromGit.d.ts +11 -0
- package/types/src/resolvers/valueFromGit.d.ts.map +1 -0
- package/types/src/resolvers/valueFromNumber.d.ts +6 -0
- package/types/src/resolvers/valueFromNumber.d.ts.map +1 -0
- package/types/src/resolvers/valueFromOptions.d.ts +9 -0
- package/types/src/resolvers/valueFromOptions.d.ts.map +1 -0
- package/types/src/resolvers/valueFromSelf.d.ts +1 -0
- package/types/src/resolvers/valueFromSelf.d.ts.map +1 -0
- package/types/src/resolvers/valueFromString.d.ts +6 -0
- package/types/src/resolvers/valueFromString.d.ts.map +1 -0
- package/types/src/sync.d.ts +3 -0
- package/types/src/sync.d.ts.map +1 -0
- package/types/src/utils/PromiseTracker.d.ts +19 -0
- package/types/src/utils/PromiseTracker.d.ts.map +1 -0
- package/types/src/utils/encoders/index.d.ts +2 -0
- package/types/src/utils/encoders/index.d.ts.map +1 -0
- package/types/src/utils/encoders/js-fixes.d.ts +23 -0
- package/types/src/utils/encoders/js-fixes.d.ts.map +1 -0
- package/types/src/utils/encoders/unknown-values.d.ts +18 -0
- package/types/src/utils/encoders/unknown-values.d.ts.map +1 -0
- package/types/src/utils/handleSignalEvents.d.ts +3 -0
- package/types/src/utils/handleSignalEvents.d.ts.map +1 -0
- package/types/src/utils/lodash.d.ts +4 -0
- package/types/src/utils/lodash.d.ts.map +1 -0
- package/types/src/utils/parsing/arrayToJsonPath.d.ts +5 -0
- package/types/src/utils/parsing/arrayToJsonPath.d.ts.map +1 -0
- package/types/src/utils/parsing/cloudformationSchema.d.ts +2 -0
- package/types/src/utils/parsing/cloudformationSchema.d.ts.map +1 -0
- package/types/src/utils/parsing/enrichMetadata.d.ts +17 -0
- package/types/src/utils/parsing/enrichMetadata.d.ts.map +1 -0
- package/types/src/utils/parsing/mergeByKeys.d.ts +5 -0
- package/types/src/utils/parsing/mergeByKeys.d.ts.map +1 -0
- package/types/src/utils/parsing/parse.d.ts +54 -0
- package/types/src/utils/parsing/parse.d.ts.map +1 -0
- package/types/src/utils/parsing/preProcess.d.ts +10 -0
- package/types/src/utils/parsing/preProcess.d.ts.map +1 -0
- package/types/src/utils/paths/filePathUtils.d.ts +32 -0
- package/types/src/utils/paths/filePathUtils.d.ts.map +1 -0
- package/types/src/utils/paths/findLineForKey.d.ts +12 -0
- package/types/src/utils/paths/findLineForKey.d.ts.map +1 -0
- package/types/src/utils/paths/findProjectRoot.d.ts +2 -0
- package/types/src/utils/paths/findProjectRoot.d.ts.map +1 -0
- package/types/src/utils/paths/getFullFilePath.d.ts +25 -0
- package/types/src/utils/paths/getFullFilePath.d.ts.map +1 -0
- package/types/src/utils/paths/resolveAlias.d.ts +14 -0
- package/types/src/utils/paths/resolveAlias.d.ts.map +1 -0
- package/types/src/utils/regex/index.d.ts +14 -0
- package/types/src/utils/regex/index.d.ts.map +1 -0
- package/types/src/utils/resolution/preResolveVariable.d.ts +51 -0
- package/types/src/utils/resolution/preResolveVariable.d.ts.map +1 -0
- package/types/src/utils/strings/bracketMatcher.d.ts +25 -0
- package/types/src/utils/strings/bracketMatcher.d.ts.map +1 -0
- package/types/src/utils/strings/formatFunctionArgs.d.ts +3 -0
- package/types/src/utils/strings/formatFunctionArgs.d.ts.map +1 -0
- package/types/src/utils/strings/quoteUtils.d.ts +31 -0
- package/types/src/utils/strings/quoteUtils.d.ts.map +1 -0
- package/types/src/utils/strings/replaceAll.d.ts +9 -0
- package/types/src/utils/strings/replaceAll.d.ts.map +1 -0
- package/types/src/utils/strings/splitByComma.d.ts +2 -0
- package/types/src/utils/strings/splitByComma.d.ts.map +1 -0
- package/types/src/utils/strings/splitCsv.d.ts +10 -0
- package/types/src/utils/strings/splitCsv.d.ts.map +1 -0
- package/types/src/utils/strings/textUtils.d.ts +15 -0
- package/types/src/utils/strings/textUtils.d.ts.map +1 -0
- package/types/src/utils/ui/chalk.d.ts +70 -0
- package/types/src/utils/ui/chalk.d.ts.map +1 -0
- package/types/src/utils/ui/configWizard.d.ts +67 -0
- package/types/src/utils/ui/configWizard.d.ts.map +1 -0
- package/types/src/utils/ui/createEditorLink.d.ts +11 -0
- package/types/src/utils/ui/createEditorLink.d.ts.map +1 -0
- package/types/src/utils/ui/deep-log.d.ts +3 -0
- package/types/src/utils/ui/deep-log.d.ts.map +1 -0
- package/types/src/utils/ui/logs.d.ts +2 -0
- package/types/src/utils/ui/logs.d.ts.map +1 -0
- package/types/src/utils/validation/warnIfNotFound.d.ts +15 -0
- package/types/src/utils/validation/warnIfNotFound.d.ts.map +1 -0
- package/types/src/utils/variables/appendDeepVariable.d.ts +3 -0
- package/types/src/utils/variables/appendDeepVariable.d.ts.map +1 -0
- package/types/src/utils/variables/cleanVariable.d.ts +3 -0
- package/types/src/utils/variables/cleanVariable.d.ts.map +1 -0
- package/types/src/utils/variables/findNestedVariables.d.ts +23 -0
- package/types/src/utils/variables/findNestedVariables.d.ts.map +1 -0
- package/types/src/utils/variables/getVariableType.d.ts +8 -0
- package/types/src/utils/variables/getVariableType.d.ts.map +1 -0
- package/types/src/utils/variables/variableUtils.d.ts +21 -0
- package/types/src/utils/variables/variableUtils.d.ts.map +1 -0
package/src/main.js
CHANGED
|
@@ -27,7 +27,7 @@ const handleSignalEvents = require('./utils/handleSignalEvents')
|
|
|
27
27
|
/* Utils - encoders */
|
|
28
28
|
const { encodeUnknown, decodeUnknown } = require('./utils/encoders/unknown-values')
|
|
29
29
|
const { decodeEncodedValue } = require('./utils/encoders')
|
|
30
|
-
const { encodeJsSyntax, decodeJsSyntax, hasParenthesesPlaceholder } = require('./utils/encoders/js-fixes')
|
|
30
|
+
const { encodeJsSyntax, decodeJsSyntax, hasParenthesesPlaceholder, encodeJsonForVariable } = require('./utils/encoders/js-fixes')
|
|
31
31
|
|
|
32
32
|
/* Utils - parsing */
|
|
33
33
|
const enrichMetadata = require('./utils/parsing/enrichMetadata')
|
|
@@ -67,7 +67,7 @@ const { warnIfNotFound, isValidValue } = require('./utils/validation/warnIfNotFo
|
|
|
67
67
|
/* Utils - variables */
|
|
68
68
|
const cleanVariable = require('./utils/variables/cleanVariable')
|
|
69
69
|
const appendDeepVariable = require('./utils/variables/appendDeepVariable')
|
|
70
|
-
const { getFallbackString, verifyVariable } = require('./utils/variables/variableUtils')
|
|
70
|
+
const { extractVariableWrapper, getFallbackString, verifyVariable } = require('./utils/variables/variableUtils')
|
|
71
71
|
const { findNestedVariables } = require('./utils/variables/findNestedVariables')
|
|
72
72
|
|
|
73
73
|
/* Resolvers */
|
|
@@ -106,8 +106,8 @@ const deepRefSyntax = RegExp(/(\${)?deep:\d+(\.[^}]+)*()}?/)
|
|
|
106
106
|
const deepIndexReplacePattern = new RegExp(/^deep:|(\.[^}]+)*$/g)
|
|
107
107
|
const deepIndexPattern = /deep\:(\d*)/
|
|
108
108
|
const deepPrefixReplacePattern = /(?:^deep:)\d+\.?/g
|
|
109
|
-
const fileRefSyntax = RegExp(/^file\((~?[@\{\}\:\$a-zA-Z0-9._\-\/,'" ]+?)\)/g)
|
|
110
|
-
const textRefSyntax = RegExp(/^text\((~?[@\{\}\:\$a-zA-Z0-9._\-\/,'" ]+?)\)/g)
|
|
109
|
+
const fileRefSyntax = RegExp(/^file\((~?[@\{\}\:\$a-zA-Z0-9._\-\/,'" =+]+?)\)/g)
|
|
110
|
+
const textRefSyntax = RegExp(/^text\((~?[@\{\}\:\$a-zA-Z0-9._\-\/,'" =+]+?)\)/g)
|
|
111
111
|
// TODO update file regex ^file\((~?[a-zA-Z0-9._\-\/, ]+?)\)
|
|
112
112
|
// To match file(asyncValue.js, lol) input params
|
|
113
113
|
const envRefSyntax = RegExp(/^env:/g)
|
|
@@ -132,7 +132,7 @@ class Configorama {
|
|
|
132
132
|
|
|
133
133
|
const options = opts || {}
|
|
134
134
|
// Set opts to pass into JS file calls
|
|
135
|
-
this.
|
|
135
|
+
this.settings = Object.assign({}, {
|
|
136
136
|
// Allow for unknown variable syntax to pass through without throwing errors
|
|
137
137
|
allowUnknownVariables: false,
|
|
138
138
|
// Allow undefined to be an end result.
|
|
@@ -149,7 +149,7 @@ class Configorama {
|
|
|
149
149
|
|
|
150
150
|
// Backward compat: allowUnknownVars -> allowUnknownVariables
|
|
151
151
|
if (options.allowUnknownVars !== undefined && options.allowUnknownVariables === undefined) {
|
|
152
|
-
this.
|
|
152
|
+
this.settings.allowUnknownVariables = options.allowUnknownVars
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
this.filterCache = {}
|
|
@@ -174,6 +174,15 @@ class Configorama {
|
|
|
174
174
|
const variableSyntax = varRegex
|
|
175
175
|
this.variableSyntax = variableSyntax
|
|
176
176
|
|
|
177
|
+
// Extract variable prefix/suffix from syntax regex for reconstructing variables
|
|
178
|
+
const syntaxWrapper = extractVariableWrapper(variableSyntax.source)
|
|
179
|
+
this.varPrefix = syntaxWrapper.prefix
|
|
180
|
+
this.varSuffix = syntaxWrapper.suffix
|
|
181
|
+
const escapedSuffix = this.varSuffix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
182
|
+
this.varPrefixPattern = new RegExp('^' + this.varPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
|
183
|
+
this.varSuffixPattern = new RegExp(escapedSuffix + '$')
|
|
184
|
+
this.varSuffixWithSpacePattern = new RegExp('\\s+' + escapedSuffix + '$')
|
|
185
|
+
|
|
177
186
|
// Set initial config object to populate
|
|
178
187
|
if (typeof fileOrObject === 'object') {
|
|
179
188
|
// set config objects
|
|
@@ -366,11 +375,13 @@ class Configorama {
|
|
|
366
375
|
}
|
|
367
376
|
|
|
368
377
|
/* attach self matcher last */
|
|
369
|
-
this.variableTypes = this.variableTypes.concat(fallThroughSelfMatcher)
|
|
378
|
+
this.variableTypes = this.variableTypes.concat(/** @type {any} */ (fallThroughSelfMatcher))
|
|
370
379
|
|
|
371
380
|
// const variablesKnownTypes = new RegExp(`^(${this.variableTypes.map((v) => v.prefix || v.type).join('|')}):`)
|
|
372
381
|
const variablesKnownTypes = combineRegexes(
|
|
373
|
-
|
|
382
|
+
/** @type {RegExp[]} */ (this.variableTypes
|
|
383
|
+
.filter((v) => v.type !== 'string' && v.match instanceof RegExp)
|
|
384
|
+
.map((v) => v.match))
|
|
374
385
|
)
|
|
375
386
|
this.variablesKnownTypes = variablesKnownTypes
|
|
376
387
|
|
|
@@ -538,11 +549,11 @@ class Configorama {
|
|
|
538
549
|
* Populate all variables in the service, conveniently remove and restore the service attributes
|
|
539
550
|
* that confuse the population methods.
|
|
540
551
|
* @param cliOpts An options hive to use for ${opt:...} variables.
|
|
541
|
-
* @returns {Promise
|
|
552
|
+
* @returns {Promise<any>} A promise resolving to the populated service.
|
|
542
553
|
*/
|
|
543
554
|
async init(cliOpts) {
|
|
544
555
|
this.options = cliOpts || {}
|
|
545
|
-
const configoramaOpts = this.
|
|
556
|
+
const configoramaOpts = this.settings
|
|
546
557
|
|
|
547
558
|
const showFoundVariables = configoramaOpts && configoramaOpts.dynamicArgs && (configoramaOpts.dynamicArgs.list || configoramaOpts.dynamicArgs.info)
|
|
548
559
|
|
|
@@ -553,10 +564,10 @@ class Configorama {
|
|
|
553
564
|
contents: this.originalString,
|
|
554
565
|
filePath: this.configFilePath,
|
|
555
566
|
varRegex: this.variableSyntax,
|
|
556
|
-
dynamicArgs: this.
|
|
567
|
+
dynamicArgs: this.settings.dynamicArgs
|
|
557
568
|
})
|
|
558
569
|
this.configFileContents = ''
|
|
559
|
-
if (VERBOSE || showFoundVariables || this.
|
|
570
|
+
if (VERBOSE || showFoundVariables || this.settings.returnPreResolvedVariableDetails || SETUP_MODE) {
|
|
560
571
|
this.configFileContents = fs.readFileSync(this.configFilePath, 'utf8')
|
|
561
572
|
}
|
|
562
573
|
/*
|
|
@@ -566,7 +577,7 @@ class Configorama {
|
|
|
566
577
|
this.rawOriginalConfig = cloneDeep(configObject)
|
|
567
578
|
|
|
568
579
|
/* Preprocess step here - escapes ${} in help() args, fixes malformed fallbacks */
|
|
569
|
-
configObject = preProcess(configObject, this.variableSyntax)
|
|
580
|
+
configObject = preProcess(configObject, this.variableSyntax, this.variableTypes)
|
|
570
581
|
/*
|
|
571
582
|
console.log('after preprocess', configObject)
|
|
572
583
|
/** */
|
|
@@ -586,7 +597,7 @@ class Configorama {
|
|
|
586
597
|
const variableSyntax = this.variableSyntax
|
|
587
598
|
const variablesKnownTypes = this.variablesKnownTypes
|
|
588
599
|
|
|
589
|
-
if (VERBOSE || showFoundVariables || this.
|
|
600
|
+
if (VERBOSE || showFoundVariables || this.settings.returnPreResolvedVariableDetails || SETUP_MODE) {
|
|
590
601
|
const metadata = this.collectVariableMetadata()
|
|
591
602
|
|
|
592
603
|
const enrich = await enrichMetadata(
|
|
@@ -598,7 +609,7 @@ class Configorama {
|
|
|
598
609
|
this.configFilePath,
|
|
599
610
|
Object.keys(this.filters),
|
|
600
611
|
undefined, // resolvedConfig not available yet
|
|
601
|
-
this.
|
|
612
|
+
this.settings.options,
|
|
602
613
|
this.variableTypes
|
|
603
614
|
)
|
|
604
615
|
|
|
@@ -616,7 +627,7 @@ class Configorama {
|
|
|
616
627
|
const varKeys = Object.keys(variableData)
|
|
617
628
|
const uniqueVarKeys = Object.keys(uniqueVariables)
|
|
618
629
|
|
|
619
|
-
if (this.
|
|
630
|
+
if (this.settings.returnPreResolvedVariableDetails) {
|
|
620
631
|
return Object.assign({}, {
|
|
621
632
|
resolved: false,
|
|
622
633
|
originalConfig: this.originalConfig
|
|
@@ -635,7 +646,7 @@ class Configorama {
|
|
|
635
646
|
if (varTypes.length) {
|
|
636
647
|
const exclude = ['dot.prop', 'deep']
|
|
637
648
|
console.log('\nAllowed variable types:')
|
|
638
|
-
varTypes.
|
|
649
|
+
varTypes.forEach((v) => {
|
|
639
650
|
const vData = this.variableTypes[v]
|
|
640
651
|
if (exclude.includes(vData.type)) {
|
|
641
652
|
return
|
|
@@ -654,7 +665,7 @@ class Configorama {
|
|
|
654
665
|
const fileName = this.configFilePath ? ` in ${this.configFilePath}` : ''
|
|
655
666
|
|
|
656
667
|
// Extract base variable name from varMatch key (e.g., '${env:FOO, default}' -> 'env:FOO')
|
|
657
|
-
const getBaseVarName = (key) => key.replace(
|
|
668
|
+
const getBaseVarName = (key) => key.replace(this.varPrefixPattern, '').replace(this.varSuffixPattern, '').split(',')[0].trim()
|
|
658
669
|
|
|
659
670
|
logHeader(`Found ${varKeys.length} Variables${fileName}`)
|
|
660
671
|
|
|
@@ -1132,7 +1143,7 @@ class Configorama {
|
|
|
1132
1143
|
}
|
|
1133
1144
|
|
|
1134
1145
|
const useDotEnv = this.originalConfig.useDotenv || this.originalConfig.useDotEnv
|
|
1135
|
-
if ((useDotEnv && useDotEnv === true) || this.
|
|
1146
|
+
if ((useDotEnv && useDotEnv === true) || this.settings.useDotEnvFiles) {
|
|
1136
1147
|
let providerStage
|
|
1137
1148
|
/* has hardcoded stage */
|
|
1138
1149
|
if (
|
|
@@ -1235,8 +1246,8 @@ class Configorama {
|
|
|
1235
1246
|
.then(() => {
|
|
1236
1247
|
// console.log('this.config', this.config)
|
|
1237
1248
|
/* Final post-processing here */
|
|
1238
|
-
if (this.mergeKeys && this.config) {
|
|
1239
|
-
this.config = mergeByKeys(this.config, '', this.mergeKeys)
|
|
1249
|
+
if (this.settings.mergeKeys && this.config) {
|
|
1250
|
+
this.config = mergeByKeys(this.config, '', this.settings.mergeKeys)
|
|
1240
1251
|
}
|
|
1241
1252
|
if (VERBOSE) {
|
|
1242
1253
|
logHeader('Resolved Configuration value')
|
|
@@ -1309,9 +1320,9 @@ class Configorama {
|
|
|
1309
1320
|
.map((filter) => filter.trim())
|
|
1310
1321
|
.filter(Boolean)
|
|
1311
1322
|
|
|
1312
|
-
// Remove filters from the key (replace "| String}" with
|
|
1323
|
+
// Remove filters from the key (replace "| String}" with suffix)
|
|
1313
1324
|
// Also clean up any trailing whitespace before the closing brace
|
|
1314
|
-
keyWithoutFilters = originalSrc.replace(filterMatch,
|
|
1325
|
+
keyWithoutFilters = originalSrc.replace(filterMatch, this.varSuffix).replace(this.varSuffixWithSpacePattern, this.varSuffix)
|
|
1315
1326
|
}
|
|
1316
1327
|
|
|
1317
1328
|
const key = keyWithoutFilters
|
|
@@ -1337,7 +1348,7 @@ class Configorama {
|
|
|
1337
1348
|
if (cleaned.varMatch && filterMatch) {
|
|
1338
1349
|
const match = cleaned.varMatch.match(filterMatch)
|
|
1339
1350
|
if (match) {
|
|
1340
|
-
cleaned.varMatch = cleaned.varMatch.replace(filterMatch, '').replace(/\s+$/, '') +
|
|
1351
|
+
cleaned.varMatch = cleaned.varMatch.replace(filterMatch, '').replace(/\s+$/, '') + this.varSuffix
|
|
1341
1352
|
}
|
|
1342
1353
|
}
|
|
1343
1354
|
if (cleaned.variable && filterMatch) {
|
|
@@ -1400,6 +1411,7 @@ class Configorama {
|
|
|
1400
1411
|
})
|
|
1401
1412
|
|
|
1402
1413
|
const varData = {
|
|
1414
|
+
filters: foundFilters.length > 0 ? foundFilters : undefined,
|
|
1403
1415
|
path: configValuePath,
|
|
1404
1416
|
key: itemKey,
|
|
1405
1417
|
originalStringValue: rawValue,
|
|
@@ -1407,10 +1419,12 @@ class Configorama {
|
|
|
1407
1419
|
variableWithFilters: originalSrc,
|
|
1408
1420
|
isRequired: false,
|
|
1409
1421
|
defaultValue: undefined,
|
|
1422
|
+
defaultValueIsVar: undefined,
|
|
1423
|
+
defaultValueSrc: undefined,
|
|
1424
|
+
hasFallback: false,
|
|
1410
1425
|
matchIndex: matchCount++,
|
|
1411
1426
|
resolveOrder: [],
|
|
1412
1427
|
resolveDetails: cleanedResolveDetails,
|
|
1413
|
-
...(foundFilters.length > 0 && { filters: foundFilters }),
|
|
1414
1428
|
}
|
|
1415
1429
|
let defaultValueIsVar = false
|
|
1416
1430
|
|
|
@@ -1682,7 +1696,7 @@ class Configorama {
|
|
|
1682
1696
|
/**
|
|
1683
1697
|
* Populate the variables in the given object.
|
|
1684
1698
|
* @param objectToPopulate The object to populate variables within.
|
|
1685
|
-
* @returns {Promise
|
|
1699
|
+
* @returns {Promise<any>} A promise resolving to the in-place populated object.
|
|
1686
1700
|
*/
|
|
1687
1701
|
populateObject(objectToPopulate) {
|
|
1688
1702
|
return this.initialCall(() => this.populateObjectImpl(objectToPopulate))
|
|
@@ -1732,7 +1746,7 @@ class Configorama {
|
|
|
1732
1746
|
* ]
|
|
1733
1747
|
* @typedef {Object} TerminalProperty
|
|
1734
1748
|
* @property {String[]} path The path to the terminal property
|
|
1735
|
-
* @property {Date|
|
|
1749
|
+
* @property {Date|RegExp|String} value The value of the terminal property
|
|
1736
1750
|
*/
|
|
1737
1751
|
/**
|
|
1738
1752
|
* Generate an array of objects noting the terminal properties of the given root object and their
|
|
@@ -1848,8 +1862,7 @@ class Configorama {
|
|
|
1848
1862
|
* Assign the populated values back to the target object
|
|
1849
1863
|
* @param target The object to which the given populated terminal properties should be applied
|
|
1850
1864
|
* @param populations The fully populated terminal properties
|
|
1851
|
-
* @returns {Promise<
|
|
1852
|
-
* target
|
|
1865
|
+
* @returns {Promise<void>} resolving when changes have been applied to the given target
|
|
1853
1866
|
*/
|
|
1854
1867
|
assignProperties(target, populations) {
|
|
1855
1868
|
// eslint-disable-line class-methods-use-this
|
|
@@ -2089,7 +2102,7 @@ class Configorama {
|
|
|
2089
2102
|
* @param valueObject The value to populate variables within
|
|
2090
2103
|
* @param root Whether the caller is the root populater and thereby whether to recursively
|
|
2091
2104
|
* populate
|
|
2092
|
-
* @returns {
|
|
2105
|
+
* @returns {Promise<any>} A promise that resolves to the populated value, recursively if root
|
|
2093
2106
|
* is true
|
|
2094
2107
|
*/
|
|
2095
2108
|
populateValue(valueObject, root, caller) {
|
|
@@ -2172,11 +2185,14 @@ class Configorama {
|
|
|
2172
2185
|
/**
|
|
2173
2186
|
* Populate a given property, given the matched string to replace and the value to replace the
|
|
2174
2187
|
* matched string with.
|
|
2175
|
-
* @param valueObject
|
|
2188
|
+
* @param {object} valueObject The value object containing the property to populate
|
|
2189
|
+
* @param {any} valueObject.value The property to replace the matched string with the value.
|
|
2190
|
+
* @param {string[]} [valueObject.path] The path to the value in the config.
|
|
2191
|
+
* @param {string} [valueObject.originalSource] The original source string.
|
|
2192
|
+
* @param {Array} [valueObject.resolutionHistory] History of resolution steps.
|
|
2176
2193
|
* @param matchedString The string in the given property that was matched and is to be replaced.
|
|
2177
2194
|
* @param valueToPopulate The value to replace the given matched string in the property with.
|
|
2178
|
-
* @returns {
|
|
2179
|
-
* value for all instances of the given matched string.
|
|
2195
|
+
* @returns {{value: any, path?: string[], originalSource?: string, resolutionHistory?: Array, __internal_only_flag?: boolean, caller?: string, count?: number}} The populated property object
|
|
2180
2196
|
*/
|
|
2181
2197
|
populateVariable(valueObject, matchedString, valueToPopulate) {
|
|
2182
2198
|
let property = valueObject.value
|
|
@@ -2202,7 +2218,7 @@ class Configorama {
|
|
|
2202
2218
|
let foundFilters = []
|
|
2203
2219
|
if (hasFilters) {
|
|
2204
2220
|
foundFilters = hasFilters[0]
|
|
2205
|
-
.replace(
|
|
2221
|
+
.replace(this.varSuffixPattern, '')
|
|
2206
2222
|
.split('|')
|
|
2207
2223
|
.map((filter) => filter.trim())
|
|
2208
2224
|
.filter(Boolean)
|
|
@@ -2287,13 +2303,13 @@ class Configorama {
|
|
|
2287
2303
|
console.log('isString currentMatchedString', currentMatchedString)
|
|
2288
2304
|
console.log('>------')
|
|
2289
2305
|
/** */
|
|
2290
|
-
// Handle comma ${opt:stage, dev} and remove extra
|
|
2306
|
+
// Handle comma ${opt:stage, dev} and remove extra suffix
|
|
2291
2307
|
if (
|
|
2292
2308
|
currentMatchedString.match(this.variableSyntax) &&
|
|
2293
2309
|
!valueToPopulate.match(this.variableSyntax) &&
|
|
2294
|
-
valueToPopulate.match(
|
|
2310
|
+
valueToPopulate.match(this.varSuffixPattern)
|
|
2295
2311
|
) {
|
|
2296
|
-
valueToPopulate = valueToPopulate.replace(
|
|
2312
|
+
valueToPopulate = valueToPopulate.replace(this.varSuffixPattern, '')
|
|
2297
2313
|
}
|
|
2298
2314
|
|
|
2299
2315
|
property = replaceAll(currentMatchedString, valueToPopulate, property)
|
|
@@ -2315,23 +2331,30 @@ class Configorama {
|
|
|
2315
2331
|
|
|
2316
2332
|
const objStr = JSON.stringify(valueToPopulate)
|
|
2317
2333
|
/* Check if variable inside another variable. E.g. ${env:${self:someObject}} that resolves to ${env:{...}} */
|
|
2318
|
-
|
|
2334
|
+
const isNestedInVariable = (
|
|
2319
2335
|
property.trim() !== matchedString.trim() &&
|
|
2320
2336
|
property.indexOf(matchedString) !== -1 &&
|
|
2321
2337
|
matchedString.match(this.variableSyntax) &&
|
|
2322
2338
|
property.match(this.variableSyntax)
|
|
2323
|
-
)
|
|
2339
|
+
)
|
|
2340
|
+
// Only encode for file() or text() references where JSON braces break regex matching
|
|
2341
|
+
const isFileOrTextRef = /\bfile\s*\(|\btext\s*\(/.test(property)
|
|
2342
|
+
if (isNestedInVariable && isFileOrTextRef) {
|
|
2343
|
+
// Encode object as base64 to avoid breaking variable syntax with nested braces
|
|
2344
|
+
const encodedObj = encodeJsonForVariable(valueToPopulate)
|
|
2345
|
+
property = replaceAll(matchedString, encodedObj, property)
|
|
2346
|
+
} else if (isNestedInVariable) {
|
|
2324
2347
|
const isVar = /^\${[a-zA-Z0-9_]+:/.test(property)
|
|
2325
2348
|
if (isVar) {
|
|
2326
|
-
// console.log('INSIDE', property, matchedString)
|
|
2327
|
-
// console.log('isVar', isVar)
|
|
2328
2349
|
throw new Error(
|
|
2329
2350
|
`Invalid variable syntax "${property}" resolves to "${replaceAll(matchedString, objStr, property)}"`,
|
|
2330
2351
|
)
|
|
2331
2352
|
}
|
|
2353
|
+
property = replaceAll(matchedString, objStr, property)
|
|
2354
|
+
} else {
|
|
2355
|
+
// console.log('OBJECT MATCH', `"${objStr}"`)
|
|
2356
|
+
property = replaceAll(matchedString, objStr, property)
|
|
2332
2357
|
}
|
|
2333
|
-
// console.log('OBJECT MATCH', `"${objStr}"`)
|
|
2334
|
-
property = replaceAll(matchedString, objStr, property) // .replace(/}$/, '').replace(/^\$\{/, '')
|
|
2335
2358
|
// console.log('property', property)
|
|
2336
2359
|
// TODO run functions here
|
|
2337
2360
|
// console.log('other new prop', property)
|
|
@@ -2340,7 +2363,7 @@ class Configorama {
|
|
|
2340
2363
|
let missingValue = matchedString
|
|
2341
2364
|
|
|
2342
2365
|
if (matchedString.match(deepRefSyntax)) {
|
|
2343
|
-
const deepIndex = matchedString.split(':')[1].replace(
|
|
2366
|
+
const deepIndex = matchedString.split(':')[1].replace(this.varSuffixPattern, '')
|
|
2344
2367
|
const i = Number(deepIndex)
|
|
2345
2368
|
missingValue = this.deep[i]
|
|
2346
2369
|
}
|
|
@@ -2357,7 +2380,7 @@ class Configorama {
|
|
|
2357
2380
|
|
|
2358
2381
|
if (nestedVar) {
|
|
2359
2382
|
const fallbackStr = getFallbackString(splitVars, nestedVar)
|
|
2360
|
-
if (!this.
|
|
2383
|
+
if (!this.settings.allowUnknownVariables) {
|
|
2361
2384
|
verifyVariable(nestedVar, valueObject, this.variableTypes, this.config)
|
|
2362
2385
|
}
|
|
2363
2386
|
|
|
@@ -2372,6 +2395,38 @@ class Configorama {
|
|
|
2372
2395
|
}
|
|
2373
2396
|
}
|
|
2374
2397
|
|
|
2398
|
+
// If allowUnresolvedVariables and there are fallbacks, use the fallback
|
|
2399
|
+
if (this.settings.allowUnresolvedVariables && splitVars.length > 1) {
|
|
2400
|
+
const nextFallback = splitVars[1].trim()
|
|
2401
|
+
// Strip trailing variable suffix (handles }, }}, >, ]], etc.)
|
|
2402
|
+
const nextFallbackClean = nextFallback.replace(this.varSuffixPattern, '')
|
|
2403
|
+
const isQuotedString = /^['"].*['"]$/.test(nextFallbackClean)
|
|
2404
|
+
const isNumeric = /^-?\d+(\.\d+)?$/.test(nextFallbackClean)
|
|
2405
|
+
if (isQuotedString || isNumeric) {
|
|
2406
|
+
const strValue = nextFallbackClean.replace(/^['"]|['"]$/g, '')
|
|
2407
|
+
// Convert to number if it's a numeric fallback
|
|
2408
|
+
/** @type {string|number} */
|
|
2409
|
+
const staticValue = isNumeric ? Number(strValue) : strValue
|
|
2410
|
+
return {
|
|
2411
|
+
value: staticValue,
|
|
2412
|
+
path: valueObject.path,
|
|
2413
|
+
originalSource: valueObject.originalSource,
|
|
2414
|
+
resolutionHistory: valueObject.resolutionHistory || [],
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
// Next fallback is another variable
|
|
2418
|
+
const remainingContent = splitVars.slice(1).join(', ').replace(this.varSuffixPattern, '')
|
|
2419
|
+
const remainingFallbacks = this.varPrefix + remainingContent + this.varSuffix
|
|
2420
|
+
return {
|
|
2421
|
+
value: remainingFallbacks,
|
|
2422
|
+
path: valueObject.path,
|
|
2423
|
+
originalSource: valueObject.originalSource,
|
|
2424
|
+
resolutionHistory: valueObject.resolutionHistory || [],
|
|
2425
|
+
__internal_only_flag: true,
|
|
2426
|
+
caller: 'allowUnresolvedVariables-fallback',
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2375
2430
|
const currentPath = valueObject.path.join('.')
|
|
2376
2431
|
|
|
2377
2432
|
const errorMessage = `
|
|
@@ -2394,7 +2449,7 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
2394
2449
|
)
|
|
2395
2450
|
|
|
2396
2451
|
// Double processing needed for `${eval(${self:three} > ${self:four})}`
|
|
2397
|
-
if (prop.startsWith(
|
|
2452
|
+
if (prop.startsWith(this.varPrefix)) {
|
|
2398
2453
|
prop = cleanVariable(prop, this.variableSyntax, true, `populateVariable string ${this.callCount}`)
|
|
2399
2454
|
}
|
|
2400
2455
|
|
|
@@ -2442,7 +2497,7 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
2442
2497
|
!prop.match(this.variableSyntax)
|
|
2443
2498
|
&&
|
|
2444
2499
|
/* Not file or text refs */
|
|
2445
|
-
!prop.match(fileRefSyntax)
|
|
2500
|
+
!prop.match(fileRefSyntax)
|
|
2446
2501
|
&& !prop.match(textRefSyntax)
|
|
2447
2502
|
/* Not eval refs */
|
|
2448
2503
|
&& !prop.match(getValueFromEval.match)
|
|
@@ -2531,8 +2586,10 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
2531
2586
|
/**
|
|
2532
2587
|
* Resolve the given variable string that expresses a series of fallback values in case the
|
|
2533
2588
|
* initial values are not valid, resolving each variable and resolving to the first valid value.
|
|
2534
|
-
* @param
|
|
2535
|
-
* @
|
|
2589
|
+
* @param variableStrings The overwrite string of variables to populate and choose from.
|
|
2590
|
+
* @param valueObject The value object
|
|
2591
|
+
* @param originalVar The original variable string
|
|
2592
|
+
* @returns {Promise<any>} A promise resolving to the first validly populating variable
|
|
2536
2593
|
* in the given variable strings string.
|
|
2537
2594
|
*/
|
|
2538
2595
|
overwrite(variableStrings, valueObject, originalVar) {
|
|
@@ -2595,7 +2652,7 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
2595
2652
|
|
|
2596
2653
|
if (deepProperties > 0) {
|
|
2597
2654
|
// Reconstruct a minimal variable string with deep refs, not the full outer string
|
|
2598
|
-
const reconstructed =
|
|
2655
|
+
const reconstructed = this.varPrefix + deepVariableParts.join(', ') + this.varSuffix
|
|
2599
2656
|
return Promise.resolve(reconstructed)
|
|
2600
2657
|
}
|
|
2601
2658
|
return Promise.resolve(extractedValues.find(isValidValue)) // resolve first valid value, else undefined
|
|
@@ -2608,7 +2665,10 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
2608
2665
|
/**
|
|
2609
2666
|
* Given any variable string, return the value it should be populated with.
|
|
2610
2667
|
* @param variableString The variable string to retrieve a value for.
|
|
2611
|
-
* @
|
|
2668
|
+
* @param valueObject The value object
|
|
2669
|
+
* @param caller The caller name
|
|
2670
|
+
* @param originalVar The original variable string
|
|
2671
|
+
* @returns {Promise<any>} A promise resolving to the given variables value.
|
|
2612
2672
|
*/
|
|
2613
2673
|
getValueFromSource(variableString, valueObject, caller, originalVar) {
|
|
2614
2674
|
// console.log('getValueFromSrc caller', caller)
|
|
@@ -2694,7 +2754,7 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
2694
2754
|
.map((f) => {
|
|
2695
2755
|
return trim(f)
|
|
2696
2756
|
// TODO refactor this. This is a temp fix for filters with nested vars.
|
|
2697
|
-
.replace(
|
|
2757
|
+
.replace(this.varSuffixPattern, '')
|
|
2698
2758
|
})
|
|
2699
2759
|
// console.log('filters to run', _filter)
|
|
2700
2760
|
|
|
@@ -2707,6 +2767,7 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
2707
2767
|
variableString = trim(t[0])
|
|
2708
2768
|
}
|
|
2709
2769
|
|
|
2770
|
+
/** @type {Function|undefined} */
|
|
2710
2771
|
let resolverFunction
|
|
2711
2772
|
let resolverType
|
|
2712
2773
|
/* Loop over variables and set getterFunction when match found. */
|
|
@@ -2803,12 +2864,22 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
2803
2864
|
// console.log('nestedVars', nestedVars)
|
|
2804
2865
|
const noNestedVars = nestedVars.length < 2
|
|
2805
2866
|
|
|
2806
|
-
if (this.
|
|
2867
|
+
if (this.settings.allowUnknownFileRefs && variableString.match(fileRefSyntax)) {
|
|
2807
2868
|
// Encode the unknown file variable to pass through resolution
|
|
2808
2869
|
return Promise.resolve(encodeUnknown(propertyString))
|
|
2809
2870
|
}
|
|
2810
2871
|
|
|
2811
|
-
if (this.
|
|
2872
|
+
if (this.settings.allowUnresolvedVariables) {
|
|
2873
|
+
// Check if outer expression has fallbacks we can use
|
|
2874
|
+
// valueCount[0] is the primary var, valueCount[1+] are fallbacks
|
|
2875
|
+
if (valueCount.length > 1) {
|
|
2876
|
+
const primaryVar = valueCount[0]
|
|
2877
|
+
// If the unresolvable variableString is used INSIDE the primary var,
|
|
2878
|
+
// return undefined to trigger the outer fallback mechanism
|
|
2879
|
+
if (primaryVar.includes(variableString)) {
|
|
2880
|
+
return Promise.resolve(undefined)
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2812
2883
|
// Encode unresolved variable to pass through resolution
|
|
2813
2884
|
return Promise.resolve(encodeUnknown(propertyString))
|
|
2814
2885
|
}
|
|
@@ -2885,7 +2956,7 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
2885
2956
|
if (typeof val === 'string' && val.match(/deep:/)) {
|
|
2886
2957
|
// TODO refactor the deep filter logic here. match | filter | filter..
|
|
2887
2958
|
const allFilters = propertyString
|
|
2888
|
-
.replace(
|
|
2959
|
+
.replace(this.varSuffixPattern, '')
|
|
2889
2960
|
.split('|')
|
|
2890
2961
|
.reduce((acc, currentFilter, i) => {
|
|
2891
2962
|
if (i === 0) {
|
|
@@ -2895,7 +2966,7 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
2895
2966
|
return acc
|
|
2896
2967
|
}, '')
|
|
2897
2968
|
// add filters to deep references if filter is used
|
|
2898
|
-
const deepValueWithFilters = newHasFilter[1] ? val.replace(
|
|
2969
|
+
const deepValueWithFilters = newHasFilter[1] ? val.replace(this.varSuffixPattern, ` ${allFilters}${this.varSuffix}`) : val
|
|
2899
2970
|
// console.log('deepValueWithFilters', deepValueWithFilters)
|
|
2900
2971
|
// console.log('RESOLVER RETURN newValue 4', deepValueWithFilters)
|
|
2901
2972
|
return Promise.resolve(deepValueWithFilters)
|
|
@@ -2975,7 +3046,7 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
2975
3046
|
// console.log('nestedVar', nestedVar)
|
|
2976
3047
|
|
|
2977
3048
|
if (nestedVar) {
|
|
2978
|
-
if (!this.
|
|
3049
|
+
if (!this.settings.allowUnknownVariables) {
|
|
2979
3050
|
verifyVariable(nestedVar, valueObject, this.variableTypes, this.config)
|
|
2980
3051
|
}
|
|
2981
3052
|
const fallbackStr = getFallbackString(split, nestedVar)
|
|
@@ -3053,7 +3124,7 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
3053
3124
|
let allowSpecialCase = false
|
|
3054
3125
|
/* handle special cases for cloudformation ${Sub} values */
|
|
3055
3126
|
if (this.originalConfig && key.endsWith('Fn::Sub')) {
|
|
3056
|
-
if (this.
|
|
3127
|
+
if (this.settings.verifySubReferences) {
|
|
3057
3128
|
const params = this.originalConfig.Parameters || (this.originalConfig.resources || {}).Parameters
|
|
3058
3129
|
const resources = this.originalConfig.Resources || (this.originalConfig.resources || {}).Resources
|
|
3059
3130
|
/* Cloudformation Resource References */
|
|
@@ -3078,7 +3149,7 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
3078
3149
|
|
|
3079
3150
|
|
|
3080
3151
|
/* Pass through unknown variables */
|
|
3081
|
-
if (this.
|
|
3152
|
+
if (this.settings.allowUnknownVariables || allowSpecialCase) {
|
|
3082
3153
|
// console.log('allowUnknownVars propertyString', propertyString)
|
|
3083
3154
|
const varMatches = propertyString.match(this.variableSyntax)
|
|
3084
3155
|
let allowUnknownVars = propertyString
|
|
@@ -3136,7 +3207,7 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
3136
3207
|
variableSyntax: this.variableSyntax,
|
|
3137
3208
|
variablesKnownTypes: this.variablesKnownTypes,
|
|
3138
3209
|
variableTypes: this.variableTypes,
|
|
3139
|
-
opts: this.
|
|
3210
|
+
opts: this.settings,
|
|
3140
3211
|
originalConfig: this.originalConfig,
|
|
3141
3212
|
config: this.config,
|
|
3142
3213
|
getDeeperValue: this.getDeeperValue.bind(this),
|
|
@@ -3294,7 +3365,7 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
3294
3365
|
})
|
|
3295
3366
|
}
|
|
3296
3367
|
runFunction(variableString) {
|
|
3297
|
-
|
|
3368
|
+
console.log('runFunction', variableString)
|
|
3298
3369
|
/* If json object value return it */
|
|
3299
3370
|
if (variableString.match(/^\s*{/) && variableString.match(/}\s*$/)) {
|
|
3300
3371
|
return variableString
|
|
@@ -3326,7 +3397,9 @@ Missing Value ${missingValue} - ${matchedString}
|
|
|
3326
3397
|
// TODO check for camelCase version. | toUpperCase messes with function name
|
|
3327
3398
|
const theFunction = this.functions[functionName] || this.functions[functionName.toLowerCase()]
|
|
3328
3399
|
|
|
3329
|
-
if (!theFunction)
|
|
3400
|
+
if (!theFunction) {
|
|
3401
|
+
throw new Error(`Function "${functionName}" not found`)
|
|
3402
|
+
}
|
|
3330
3403
|
|
|
3331
3404
|
const funcValue = theFunction(...argsToPass)
|
|
3332
3405
|
// console.log('funcValue', funcValue)
|
package/src/parsers/index.js
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} ParserFunction
|
|
3
|
+
* @property {Function} parse - Parse string content into object
|
|
4
|
+
* @property {Function} stringify - Convert object to string format
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
const json = require('./json5')
|
|
2
8
|
const toml = require('./toml')
|
|
3
9
|
const yaml = require('./yaml')
|
|
4
10
|
const ini = require('./ini')
|
|
5
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Collection of format parsers for different config file types
|
|
14
|
+
* @type {Object.<string, ParserFunction>}
|
|
15
|
+
*/
|
|
6
16
|
module.exports = {
|
|
7
17
|
json: json,
|
|
8
18
|
toml: toml,
|