configorama 0.4.8 → 0.4.10
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/lib/main.js +81 -59
- package/lib/parsers/yaml.js +7 -4
- package/lib/resolvers/valueFromNumber.js +2 -2
- package/lib/utils/PromiseTracker.js +5 -6
- package/lib/utils/cloudformationSchema.js +10 -6
- package/lib/utils/formatFunctionArgs.js +2 -2
- package/lib/utils/handleSignalEvents.js +17 -14
- package/lib/utils/isValidValue.js +2 -2
- package/package.json +27 -18
package/lib/main.js
CHANGED
|
@@ -3,9 +3,26 @@ 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
|
-
const
|
|
6
|
+
const isArray = require('lodash.isarray')
|
|
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')
|
|
7
24
|
const findUp = require('find-up')
|
|
8
|
-
const
|
|
25
|
+
const replaceAll = require('replaceall')
|
|
9
26
|
const traverse = require('traverse')
|
|
10
27
|
const dotProp = require('dot-prop')
|
|
11
28
|
/* Default Value resolvers */
|
|
@@ -78,7 +95,7 @@ class Configorama {
|
|
|
78
95
|
}, options)
|
|
79
96
|
|
|
80
97
|
|
|
81
|
-
const defaultSyntax = '\\${((?!AWS)[ ~:a-zA-Z0-9=+!@#%*<>?._\'",|\\-\\/\\(\\)\\\\]+?)}'
|
|
98
|
+
const defaultSyntax = '\\${((?!AWS|stageVariables)[ ~:a-zA-Z0-9=+!@#%*<>?._\'",|\\-\\/\\(\\)\\\\]+?)}'
|
|
82
99
|
const variableSyntax = options.syntax || defaultSyntax
|
|
83
100
|
let varRegex
|
|
84
101
|
if (typeof variableSyntax === 'string') {
|
|
@@ -87,6 +104,7 @@ class Configorama {
|
|
|
87
104
|
} else if (variableSyntax instanceof RegExp) {
|
|
88
105
|
varRegex = variableSyntax
|
|
89
106
|
}
|
|
107
|
+
// console.log('varRegex', varRegex)
|
|
90
108
|
this.variableSyntax = varRegex
|
|
91
109
|
|
|
92
110
|
// Set initial config object to populate
|
|
@@ -94,7 +112,7 @@ class Configorama {
|
|
|
94
112
|
// set config objects
|
|
95
113
|
this.config = fileOrObject
|
|
96
114
|
// Keep a copy
|
|
97
|
-
this.originalConfig =
|
|
115
|
+
this.originalConfig = cloneDeep(fileOrObject)
|
|
98
116
|
// Set configPath for file references
|
|
99
117
|
this.configPath = options.configDir || process.cwd()
|
|
100
118
|
} else if (typeof fileOrObject === 'string') {
|
|
@@ -147,7 +165,7 @@ class Configorama {
|
|
|
147
165
|
// set config objects
|
|
148
166
|
this.config = configObject
|
|
149
167
|
// Keep a copy
|
|
150
|
-
this.originalConfig =
|
|
168
|
+
this.originalConfig = cloneDeep(configObject)
|
|
151
169
|
// Set configPath for file references
|
|
152
170
|
this.configPath = fileDirectory
|
|
153
171
|
}
|
|
@@ -283,13 +301,13 @@ class Configorama {
|
|
|
283
301
|
}
|
|
284
302
|
},
|
|
285
303
|
toCamelCase: (val) => {
|
|
286
|
-
return
|
|
304
|
+
return camelCase(val)
|
|
287
305
|
},
|
|
288
306
|
toKebabCase: (val) => {
|
|
289
|
-
return
|
|
307
|
+
return kebabCase(val)
|
|
290
308
|
},
|
|
291
309
|
capitalize: (val) => {
|
|
292
|
-
return
|
|
310
|
+
return capitalize(val)
|
|
293
311
|
}
|
|
294
312
|
}
|
|
295
313
|
|
|
@@ -301,14 +319,14 @@ class Configorama {
|
|
|
301
319
|
this.functions = {
|
|
302
320
|
split: (value, delimiter, limit) => {
|
|
303
321
|
const delimit = delimiter || ','
|
|
304
|
-
const splitVal =
|
|
322
|
+
const splitVal = split(value, delimit)
|
|
305
323
|
return splitVal
|
|
306
324
|
},
|
|
307
325
|
join: (value, delimiter) => {
|
|
308
|
-
if (
|
|
326
|
+
if (isString(value)) {
|
|
309
327
|
value = [value]
|
|
310
328
|
}
|
|
311
|
-
if (!
|
|
329
|
+
if (!isArray(value)) {
|
|
312
330
|
throw new Error('value must be array for join() function')
|
|
313
331
|
}
|
|
314
332
|
const delimit = delimiter || ','
|
|
@@ -334,10 +352,10 @@ class Configorama {
|
|
|
334
352
|
if (typeof value === 'string' && typeof otherValue === 'string') {
|
|
335
353
|
return value + otherValue
|
|
336
354
|
}
|
|
337
|
-
if (
|
|
355
|
+
if (isArray(value) && isArray(otherValue)) {
|
|
338
356
|
return otherValue.concat(value)
|
|
339
357
|
}
|
|
340
|
-
return
|
|
358
|
+
return assign({}, value, otherValue)
|
|
341
359
|
},
|
|
342
360
|
math: () => {},
|
|
343
361
|
upperKeys: (o) => {
|
|
@@ -365,7 +383,7 @@ class Configorama {
|
|
|
365
383
|
}
|
|
366
384
|
|
|
367
385
|
/**
|
|
368
|
-
* Populate all variables in the service,
|
|
386
|
+
* Populate all variables in the service, conveniently remove and restore the service attributes
|
|
369
387
|
* that confuse the population methods.
|
|
370
388
|
* @param cliOpts An options hive to use for ${opt:...} variables.
|
|
371
389
|
* @returns {Promise.<TResult>|*} A promise resolving to the populated service.
|
|
@@ -438,6 +456,10 @@ class Configorama {
|
|
|
438
456
|
})
|
|
439
457
|
}
|
|
440
458
|
runFunction(variableString) {
|
|
459
|
+
/* If json object value return it */
|
|
460
|
+
if (variableString.match(/^\s*{/) && variableString.match(/}\s*$/)) {
|
|
461
|
+
return variableString
|
|
462
|
+
}
|
|
441
463
|
// console.log('runFunction', variableString)
|
|
442
464
|
var hasFunc = funcRegex.exec(variableString)
|
|
443
465
|
// TODO finish Function handling. Need to move this down below resolver to resolve inner refs first
|
|
@@ -458,7 +480,7 @@ class Configorama {
|
|
|
458
480
|
} else {
|
|
459
481
|
// TODO fix how commas + spaces are ned
|
|
460
482
|
const splitter = splitCsv(rawArgs, ', ')
|
|
461
|
-
// console.log('
|
|
483
|
+
// console.log('splitter', splitter)
|
|
462
484
|
argsToPass = formatFunctionArgs(splitter)
|
|
463
485
|
}
|
|
464
486
|
// console.log('argsToPass runFunction', argsToPass)
|
|
@@ -471,7 +493,7 @@ class Configorama {
|
|
|
471
493
|
}
|
|
472
494
|
|
|
473
495
|
const funcValue = theFunction(...argsToPass)
|
|
474
|
-
// console.log('
|
|
496
|
+
// console.log('funcValue', funcValue)
|
|
475
497
|
// console.log('typeof funcValue', typeof funcValue)
|
|
476
498
|
let replaceVal = funcValue
|
|
477
499
|
if (typeof funcValue === 'string') {
|
|
@@ -521,23 +543,23 @@ class Configorama {
|
|
|
521
543
|
* @returns {TerminalProperty[]} The terminal properties of the given root object, with the path
|
|
522
544
|
* and value of each
|
|
523
545
|
*/
|
|
524
|
-
getProperties(root, atRoot, current,
|
|
525
|
-
let context =
|
|
546
|
+
getProperties(root, atRoot, current, _context, _results) {
|
|
547
|
+
let context = _context
|
|
526
548
|
if (!context) {
|
|
527
549
|
context = []
|
|
528
550
|
}
|
|
529
|
-
let results =
|
|
551
|
+
let results = _results
|
|
530
552
|
if (!results) {
|
|
531
553
|
results = []
|
|
532
554
|
}
|
|
533
555
|
const addContext = (value, key) => {
|
|
534
556
|
return this.getProperties(root, false, value, context.concat(key), results)
|
|
535
557
|
}
|
|
536
|
-
if (
|
|
537
|
-
|
|
538
|
-
} else if (
|
|
558
|
+
if (isArray(current)) {
|
|
559
|
+
map(current, addContext)
|
|
560
|
+
} else if (isObject(current) && !isDate(current) && !isRegExp(current) && !isFunction(current)) {
|
|
539
561
|
if (atRoot || current !== root) {
|
|
540
|
-
|
|
562
|
+
mapValues(current, addContext)
|
|
541
563
|
}
|
|
542
564
|
} else {
|
|
543
565
|
// TODO Add values to leaves here
|
|
@@ -555,7 +577,7 @@ class Configorama {
|
|
|
555
577
|
originalValue = dotProp.get(this.originalConfig, parentPath)
|
|
556
578
|
}
|
|
557
579
|
leaf.originalSource = originalValue
|
|
558
|
-
if (originalValue &&
|
|
580
|
+
if (originalValue && isString(originalValue)) {
|
|
559
581
|
const varString = cleanVariable(originalValue, this.variableSyntax)
|
|
560
582
|
if (varString.match(fileRefSyntax)) {
|
|
561
583
|
leaf.isFileRef = true
|
|
@@ -581,13 +603,13 @@ class Configorama {
|
|
|
581
603
|
// console.log('properties', properties)
|
|
582
604
|
const variables = properties.filter((property) => {
|
|
583
605
|
// Initial check if value has variable string in it
|
|
584
|
-
return
|
|
606
|
+
return isString(property.value) && property.value.match(this.variableSyntax)
|
|
585
607
|
})
|
|
586
|
-
return
|
|
608
|
+
return map(variables, (valueObject) => {
|
|
587
609
|
// console.log('valueObject', valueObject)
|
|
588
610
|
return this.populateValue(valueObject, false)
|
|
589
611
|
.then((populated) => {
|
|
590
|
-
return
|
|
612
|
+
return assign({}, valueObject, { populated: populated.value })
|
|
591
613
|
})
|
|
592
614
|
})
|
|
593
615
|
}
|
|
@@ -602,7 +624,7 @@ class Configorama {
|
|
|
602
624
|
return Promise.all(populations)
|
|
603
625
|
.then((results) => results.forEach((result) => {
|
|
604
626
|
if (result.value !== result.populated) {
|
|
605
|
-
|
|
627
|
+
set(target, result.path, result.populated)
|
|
606
628
|
}
|
|
607
629
|
}))
|
|
608
630
|
}
|
|
@@ -660,7 +682,7 @@ class Configorama {
|
|
|
660
682
|
if (!matches || !matches.length) {
|
|
661
683
|
return property
|
|
662
684
|
}
|
|
663
|
-
return
|
|
685
|
+
return map(matches, match => {
|
|
664
686
|
// console.log('match', match)
|
|
665
687
|
return ({
|
|
666
688
|
match: match,
|
|
@@ -676,7 +698,7 @@ class Configorama {
|
|
|
676
698
|
*/
|
|
677
699
|
populateMatches(matches, valueObject, root) {
|
|
678
700
|
// console.log('matches', matches)
|
|
679
|
-
return
|
|
701
|
+
return map(matches, (match) => {
|
|
680
702
|
return this.splitAndGet(match.variable, valueObject, root)
|
|
681
703
|
})
|
|
682
704
|
}
|
|
@@ -695,7 +717,7 @@ class Configorama {
|
|
|
695
717
|
let result = valueObject.value
|
|
696
718
|
for (let i = 0; i < matches.length; i += 1) {
|
|
697
719
|
this.warnIfNotFound(matches[i].variable, results[i])
|
|
698
|
-
// console.log('
|
|
720
|
+
// console.log('Render MATCHES', results[i])
|
|
699
721
|
let valueToPop = results[i]
|
|
700
722
|
// TODO refactor this. __internal_only_flag needed to stop clash with sync/async file resolution
|
|
701
723
|
if (results[i] && typeof results[i] === 'object' && results[i].__internal_only_flag) {
|
|
@@ -715,7 +737,7 @@ class Configorama {
|
|
|
715
737
|
/**
|
|
716
738
|
* Populate the given value, recursively if root is true
|
|
717
739
|
* @param valueObject The value to populate variables within
|
|
718
|
-
* @param root Whether the caller is the root
|
|
740
|
+
* @param root Whether the caller is the root populater and thereby whether to recursively
|
|
719
741
|
* populate
|
|
720
742
|
* @returns {PromiseLike<T>} A promise that resolves to the populated value, recursively if root
|
|
721
743
|
* is true
|
|
@@ -731,7 +753,7 @@ class Configorama {
|
|
|
731
753
|
/*
|
|
732
754
|
console.log('matchesmatches', matches)
|
|
733
755
|
/** */
|
|
734
|
-
if (!
|
|
756
|
+
if (!isArray(matches)) {
|
|
735
757
|
return Promise.resolve(property)
|
|
736
758
|
}
|
|
737
759
|
const populations = this.populateMatches(matches, valueObject, root)
|
|
@@ -742,7 +764,7 @@ class Configorama {
|
|
|
742
764
|
console.log('renderMatches result', result)
|
|
743
765
|
/** */
|
|
744
766
|
|
|
745
|
-
if (root && matches
|
|
767
|
+
if (root && isArray(matches)) {
|
|
746
768
|
return this.populateValue({ value: result.value }, root)
|
|
747
769
|
}
|
|
748
770
|
return result
|
|
@@ -762,7 +784,7 @@ class Configorama {
|
|
|
762
784
|
/**
|
|
763
785
|
* Split the cleaned variable string containing one or more comma delimited variables and get a
|
|
764
786
|
* final value for the entirety of the string
|
|
765
|
-
* @param
|
|
787
|
+
* @param variable The variable string to split and get a final value for
|
|
766
788
|
* @param property The original property string the given variable was extracted from
|
|
767
789
|
* @returns {Promise} A promise resolving to the final value of the given variable
|
|
768
790
|
*/
|
|
@@ -822,7 +844,7 @@ class Configorama {
|
|
|
822
844
|
property = valueToPopulate
|
|
823
845
|
/* Handle ${self:custom.ref, ''} with deep values */
|
|
824
846
|
if (v.match(deepRefSyntax) && originalSrc.match(this.variableSyntax) && !v.match(/deep\:(\d*)\..*}$/)) {
|
|
825
|
-
// console.log('
|
|
847
|
+
// console.log('deep var', this.deep)
|
|
826
848
|
// console.log('originalSrc', originalSrc)
|
|
827
849
|
// console.log('value', v)
|
|
828
850
|
let deepIndex = Number(v.match(/deep\:(\d*)/)[1])
|
|
@@ -835,7 +857,7 @@ class Configorama {
|
|
|
835
857
|
property = this.deep[deepIndex]
|
|
836
858
|
}
|
|
837
859
|
// partial replacement, string
|
|
838
|
-
} else if (
|
|
860
|
+
} else if (isString(valueToPopulate)) {
|
|
839
861
|
// if (property.match(/^> function /g)) {
|
|
840
862
|
//
|
|
841
863
|
// const innerFunc = /> function (\w+)\s*\(((?:[^()]+)*)?\s*\)\s*/
|
|
@@ -868,7 +890,7 @@ class Configorama {
|
|
|
868
890
|
/** */
|
|
869
891
|
|
|
870
892
|
// (replaceThis, withThis, inThis)
|
|
871
|
-
property =
|
|
893
|
+
property = replaceAll(currentMatchedString, valueToPopulate, property)
|
|
872
894
|
// console.log('property', property)
|
|
873
895
|
|
|
874
896
|
// if (property.match(/^> function /g)) {
|
|
@@ -876,17 +898,17 @@ class Configorama {
|
|
|
876
898
|
// }
|
|
877
899
|
|
|
878
900
|
// partial replacement, number
|
|
879
|
-
} else if (
|
|
880
|
-
property =
|
|
901
|
+
} else if (isNumber(valueToPopulate)) {
|
|
902
|
+
property = replaceAll(matchedString, String(valueToPopulate), property)
|
|
881
903
|
// TODO This was temp fix for array value mismatch from filters. This fixes filterInner: ${commas | split(${self:inner}, 2) }
|
|
882
|
-
// } else if (
|
|
883
|
-
// property =
|
|
884
|
-
} else if (
|
|
904
|
+
// } else if (isArray(valueToPopulate) && valueToPopulate.length === 1) {
|
|
905
|
+
// property = replaceAll(matchedString, String(valueToPopulate[0]), property)
|
|
906
|
+
} else if (isObject(valueToPopulate)) {
|
|
885
907
|
// console.log('OBJECT MATCH', valueToPopulate)
|
|
886
|
-
property =
|
|
908
|
+
property = replaceAll(matchedString, JSON.stringify(valueToPopulate), property)// .replace(/}$/, '').replace(/^\$\{/, '')
|
|
887
909
|
// console.log('property', property)
|
|
888
910
|
// TODO run functions here
|
|
889
|
-
// console.log('
|
|
911
|
+
// console.log('other new prop', property)
|
|
890
912
|
} else {
|
|
891
913
|
let missingValue = matchedString
|
|
892
914
|
|
|
@@ -934,7 +956,7 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
934
956
|
const prop = cleanVariable(property, this.variableSyntax)
|
|
935
957
|
// console.log('prop', prop)
|
|
936
958
|
if (property.match(/^> function /g) && prop) {
|
|
937
|
-
// console.log('
|
|
959
|
+
// console.log('func prop', property)
|
|
938
960
|
// console.log('Prop', prop)
|
|
939
961
|
}
|
|
940
962
|
const func = funcRegex.exec(property)
|
|
@@ -1024,8 +1046,8 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
1024
1046
|
let deepPropertyStr = propertyString
|
|
1025
1047
|
let deepProperties = 0
|
|
1026
1048
|
values.forEach((value, index) => {
|
|
1027
|
-
// console.log('
|
|
1028
|
-
if (
|
|
1049
|
+
// console.log('───────────────────────────────> value', value)
|
|
1050
|
+
if (isString(value) && value.match(this.variableSyntax)) {
|
|
1029
1051
|
deepProperties += 1
|
|
1030
1052
|
// console.log('makeDeepVariable overwrite', value)
|
|
1031
1053
|
const deepVariable = this.makeDeepVariable(value)
|
|
@@ -1078,7 +1100,7 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
1078
1100
|
const filterz = string.split('|').filter((value, index, arr) => {
|
|
1079
1101
|
return index > 0
|
|
1080
1102
|
}).map((f) => {
|
|
1081
|
-
return
|
|
1103
|
+
return trim(f)
|
|
1082
1104
|
})
|
|
1083
1105
|
// console.log('filters to run', filterz)
|
|
1084
1106
|
|
|
@@ -1089,7 +1111,7 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
1089
1111
|
}
|
|
1090
1112
|
// console.log('HAS FILTERS', filters)
|
|
1091
1113
|
// console.log('t', t)
|
|
1092
|
-
variableString =
|
|
1114
|
+
variableString = trim(t[0])
|
|
1093
1115
|
}
|
|
1094
1116
|
|
|
1095
1117
|
let resolverFunction
|
|
@@ -1123,7 +1145,7 @@ ${valueObject.path}: ${valueObject.originalSource}
|
|
|
1123
1145
|
// console.log('VALUE', val)
|
|
1124
1146
|
if (val === null || typeof val === 'undefined' ||
|
|
1125
1147
|
/* match deep refs as empty {}, they need resolving via functions */
|
|
1126
|
-
(typeof val === 'object' &&
|
|
1148
|
+
(typeof val === 'object' && isEmpty(val) && variableString.match(/deep\:/))
|
|
1127
1149
|
) {
|
|
1128
1150
|
// console.log('variableString', variableString)
|
|
1129
1151
|
const cleanV = cleanVariable(propertyString, this.variableSyntax)
|
|
@@ -1185,7 +1207,7 @@ Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
|
1185
1207
|
if (i === 0) {
|
|
1186
1208
|
return acc
|
|
1187
1209
|
}
|
|
1188
|
-
acc += `| ${
|
|
1210
|
+
acc += `| ${trim(currentFilter)}`
|
|
1189
1211
|
return acc
|
|
1190
1212
|
}, '')
|
|
1191
1213
|
|
|
@@ -1265,7 +1287,7 @@ Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
|
1265
1287
|
}, 'cleanClean.match(fileRefSyntax)')
|
|
1266
1288
|
}
|
|
1267
1289
|
}
|
|
1268
|
-
// const fallbackValue = split[1]
|
|
1290
|
+
// const fallbackValue = split[1]
|
|
1269
1291
|
// console.log('variableString', variableString)
|
|
1270
1292
|
// console.log('propertyString', propertyString)
|
|
1271
1293
|
// console.log('fallbackValue', fallbackValue)
|
|
@@ -1374,7 +1396,7 @@ Like so: \${${variableString}, "fallbackValue"\}.`)
|
|
|
1374
1396
|
if (hasParams) {
|
|
1375
1397
|
const splitter = splitCsv(hasParams[2])
|
|
1376
1398
|
const argsFound = splitter.map((arg) => {
|
|
1377
|
-
const cleanArg =
|
|
1399
|
+
const cleanArg = trim(arg).replace(/^'|"/, '').replace(/'|"$/, '')
|
|
1378
1400
|
return cleanArg
|
|
1379
1401
|
})
|
|
1380
1402
|
|
|
@@ -1467,7 +1489,7 @@ Check if your javascript is exporting a function that returns a value.`
|
|
|
1467
1489
|
deepProperties.splice(0, 1)
|
|
1468
1490
|
// Trim prop keys for starting/trailing spaces
|
|
1469
1491
|
deepProperties = deepProperties.map((prop) => {
|
|
1470
|
-
return
|
|
1492
|
+
return trim(prop)
|
|
1471
1493
|
})
|
|
1472
1494
|
return this.getDeeperValue(deepProperties, valueToPopulateResolved)
|
|
1473
1495
|
.then((deepValueToPopulateResolved) => {
|
|
@@ -1543,14 +1565,14 @@ Please use ":" to reference sub properties`
|
|
|
1543
1565
|
/*
|
|
1544
1566
|
console.log("GET getValueFromDeep", variableString)
|
|
1545
1567
|
console.log('deepRef', deepRef)
|
|
1546
|
-
console.log('
|
|
1568
|
+
console.log('getValueFromDeep variable', variable)
|
|
1547
1569
|
/** */
|
|
1548
1570
|
let ret = this.populateValue({ value: variable })
|
|
1549
1571
|
// console.log('variable ret', ret)
|
|
1550
1572
|
if (deepRef.length) { // if there is a deep reference remaining
|
|
1551
1573
|
ret = ret.then((result) => {
|
|
1552
1574
|
// console.log('DEEP RESULT', result)
|
|
1553
|
-
if (
|
|
1575
|
+
if (isString(result.value) && result.value.match(this.variableSyntax)) {
|
|
1554
1576
|
// console.log('makeDeepVariable getValueFromDeep', result.value)
|
|
1555
1577
|
const deepVariable = this.makeDeepVariable(result.value)
|
|
1556
1578
|
return Promise.resolve(appendDeepVariable(deepVariable, deepRef))
|
|
@@ -1604,7 +1626,7 @@ Please use ":" to reference sub properties`
|
|
|
1604
1626
|
// console.log(typeof reducedValue)
|
|
1605
1627
|
// console.log('subProperty', `"${subProperty}"`)
|
|
1606
1628
|
|
|
1607
|
-
if (
|
|
1629
|
+
if (isString(reducedValue) && reducedValue.match(deepRefSyntax)) { // build mode
|
|
1608
1630
|
reducedValue = appendDeepVariable(reducedValue, subProperty)
|
|
1609
1631
|
} else { // get mode
|
|
1610
1632
|
if (typeof reducedValue === 'undefined') {
|
|
@@ -1625,7 +1647,7 @@ Please use ":" to reference sub properties`
|
|
|
1625
1647
|
} catch (e) {}
|
|
1626
1648
|
|
|
1627
1649
|
reducedValue = reducedValue[subProperty]
|
|
1628
|
-
} else if (
|
|
1650
|
+
} else if (isString(reducedValue)) {
|
|
1629
1651
|
try {
|
|
1630
1652
|
// if JSON parse it
|
|
1631
1653
|
reducedValue = JSON.parse(reducedValue)
|
package/lib/parsers/yaml.js
CHANGED
|
@@ -105,6 +105,11 @@ function matchOutermostBraces(text) {
|
|
|
105
105
|
return results;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
// https://regex101.com/r/XIltbc/1
|
|
109
|
+
const KEY_OBJECT = /^[ \t]*[^":\s]*:\s+\{/gm
|
|
110
|
+
|
|
111
|
+
const INNER_ARRAY = /\[(?:[^\[\]])*\]/g
|
|
112
|
+
|
|
108
113
|
function preProcess(ymlStr = '') {
|
|
109
114
|
/*
|
|
110
115
|
return ymlStr
|
|
@@ -115,7 +120,7 @@ function preProcess(ymlStr = '') {
|
|
|
115
120
|
// out -> y: !Not [!Equals [!Join ['', "${param:xyz}"]]]
|
|
116
121
|
const arrayBracketMatches = ymlStr && ymlStr.match(
|
|
117
122
|
// /\[(?:[^\[\]]+|)*\]/gm
|
|
118
|
-
|
|
123
|
+
INNER_ARRAY
|
|
119
124
|
)
|
|
120
125
|
if (arrayBracketMatches) {
|
|
121
126
|
// console.log('arrayBracketMatches', arrayBracketMatches)
|
|
@@ -146,7 +151,7 @@ function preProcess(ymlStr = '') {
|
|
|
146
151
|
}
|
|
147
152
|
|
|
148
153
|
/* If have yaml object and vars not wrapped in quotes, wrap them */
|
|
149
|
-
if (ymlStr.match(
|
|
154
|
+
if (ymlStr.match(KEY_OBJECT)) {
|
|
150
155
|
const hasObjects = matchOutermostBraces(ymlStr)
|
|
151
156
|
// console.log('hasObjects', hasObjects)
|
|
152
157
|
if (hasObjects && hasObjects.length) {
|
|
@@ -171,9 +176,7 @@ function preProcess(ymlStr = '') {
|
|
|
171
176
|
})
|
|
172
177
|
}
|
|
173
178
|
}
|
|
174
|
-
|
|
175
179
|
// console.log('ymlStr', ymlStr)
|
|
176
|
-
|
|
177
180
|
return ymlStr
|
|
178
181
|
}
|
|
179
182
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const
|
|
1
|
+
const isNumber = require('lodash.isnumber')
|
|
2
2
|
|
|
3
3
|
function isNumberVariable(variableString) {
|
|
4
4
|
const num = Number(variableString)
|
|
5
|
-
return !isNaN(num) &&
|
|
5
|
+
return !isNaN(num) && isNumber(num)
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
function getValueFromNumber(variableString) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const trim = require('lodash.trim')
|
|
2
2
|
|
|
3
3
|
// Track promise resolution
|
|
4
4
|
class PromiseTracker {
|
|
@@ -18,7 +18,7 @@ class PromiseTracker {
|
|
|
18
18
|
report() {
|
|
19
19
|
const delta = Date.now() - this.startTime
|
|
20
20
|
const pending = this.getPending()
|
|
21
|
-
const dots =
|
|
21
|
+
const dots = dotDotDot(this.cursor++, 100, '...')
|
|
22
22
|
console.log([
|
|
23
23
|
`Fetching Async values${dots}`,
|
|
24
24
|
].concat(
|
|
@@ -41,8 +41,7 @@ class PromiseTracker {
|
|
|
41
41
|
clearInterval(this.interval)
|
|
42
42
|
this.reset()
|
|
43
43
|
}
|
|
44
|
-
add(variable,
|
|
45
|
-
const promise = prms
|
|
44
|
+
add(variable, promise, specifier, hasFilter) {
|
|
46
45
|
// Refactor promise tracker to account for multiple instances of a given variable
|
|
47
46
|
|
|
48
47
|
// console.log(`${specifier} hasFilter`, hasFilter)
|
|
@@ -51,7 +50,7 @@ class PromiseTracker {
|
|
|
51
50
|
let uniqueId = ''
|
|
52
51
|
if (hasFilter) {
|
|
53
52
|
uniqueId = hasFilter.reduce((acc, currentFilter, i) => {
|
|
54
|
-
acc += `|${
|
|
53
|
+
acc += `|${trim(currentFilter)}`
|
|
55
54
|
return acc
|
|
56
55
|
}, '')
|
|
57
56
|
}
|
|
@@ -89,7 +88,7 @@ class PromiseTracker {
|
|
|
89
88
|
}
|
|
90
89
|
}
|
|
91
90
|
|
|
92
|
-
function
|
|
91
|
+
function dotDotDot(cursor, times, string) {
|
|
93
92
|
return Array(times - Math.abs(cursor % (times * 2) - times) + 1).join(string)
|
|
94
93
|
}
|
|
95
94
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
const YAML = require('js-yaml');
|
|
2
|
-
const
|
|
2
|
+
const includes = require('lodash.includes');
|
|
3
|
+
const isString = require('lodash.isstring');
|
|
4
|
+
const split = require('lodash.split');
|
|
5
|
+
const flatten = require('lodash.flatten');
|
|
6
|
+
const map = require('lodash.map');
|
|
3
7
|
|
|
4
8
|
const functionNames = [
|
|
5
9
|
'And',
|
|
@@ -22,13 +26,13 @@ const functionNames = [
|
|
|
22
26
|
];
|
|
23
27
|
|
|
24
28
|
const yamlType = (name, kind) => {
|
|
25
|
-
const functionName =
|
|
29
|
+
const functionName = includes(['Ref', 'Condition'], name) ? name : `Fn::${name}`;
|
|
26
30
|
return new YAML.Type(`!${name}`, {
|
|
27
31
|
kind,
|
|
28
32
|
construct: data => {
|
|
29
33
|
if (name === 'GetAtt') {
|
|
30
34
|
// special GetAtt dot syntax
|
|
31
|
-
return { [functionName]:
|
|
35
|
+
return { [functionName]: isString(data) ? split(data, '.', 2) : data };
|
|
32
36
|
}
|
|
33
37
|
return { [functionName]: data };
|
|
34
38
|
},
|
|
@@ -36,9 +40,9 @@ const yamlType = (name, kind) => {
|
|
|
36
40
|
};
|
|
37
41
|
|
|
38
42
|
const createSchema = () => {
|
|
39
|
-
const types =
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
const types = flatten(
|
|
44
|
+
map(functionNames, functionName =>
|
|
45
|
+
map(['mapping', 'scalar', 'sequence'], kind => yamlType(functionName, kind))
|
|
42
46
|
)
|
|
43
47
|
);
|
|
44
48
|
return YAML.Schema.create(types);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const
|
|
1
|
+
const trim = require('lodash.trim')
|
|
2
2
|
|
|
3
3
|
function formatArg(arg) {
|
|
4
|
-
const cleanArg =
|
|
4
|
+
const cleanArg = trim(arg).replace(/^('|")/, '').replace(/('|")$/, '')
|
|
5
5
|
if (cleanArg.match(/^{([^}]+)}$/)) {
|
|
6
6
|
return JSON.parse(cleanArg)
|
|
7
7
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const readline = require('readline')
|
|
2
2
|
|
|
3
3
|
function handleSignalEvents() {
|
|
4
|
+
if (global.signalEventHandling) return // Only set up handlers once
|
|
4
5
|
// NOTE: instantiating this global variable here to keep track of the state
|
|
5
6
|
// usually global variables should be "considered harmful" but are a good fit in this case
|
|
6
7
|
global.signalEventHandling = {
|
|
@@ -8,7 +9,7 @@ function handleSignalEvents() {
|
|
|
8
9
|
shouldExitGracefully: false
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
const msg = `
|
|
12
13
|
───────────────────────────────────────────────────────────
|
|
13
14
|
Exit received. Waiting for current operation to finish...
|
|
14
15
|
───────────────────────────────────────────────────────────
|
|
@@ -20,23 +21,25 @@ Exit received. Waiting for current operation to finish...
|
|
|
20
21
|
output: process.stdout
|
|
21
22
|
})
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
rl.
|
|
30
|
-
process.emit('SIGBREAK')
|
|
31
|
-
})
|
|
24
|
+
// Clean up readline interface when done
|
|
25
|
+
process.once('exit', () => rl.close())
|
|
26
|
+
|
|
27
|
+
// Use once() instead of on()
|
|
28
|
+
rl.once('SIGINT', () => process.emit('SIGINT'))
|
|
29
|
+
rl.once('SIGTERM', () => process.emit('SIGTERM'))
|
|
30
|
+
rl.once('SIGBREAK', () => process.emit('SIGBREAK'))
|
|
32
31
|
}
|
|
33
32
|
|
|
33
|
+
// Remove any existing listeners before adding new ones
|
|
34
|
+
process.removeAllListeners('SIGINT')
|
|
35
|
+
process.removeAllListeners('SIGTERM')
|
|
36
|
+
process.removeAllListeners('SIGBREAK')
|
|
37
|
+
|
|
34
38
|
process.on('SIGINT', () => {
|
|
35
39
|
global.signalEventHandling.SIGINTCount += 1
|
|
36
40
|
global.signalEventHandling.shouldExitGracefully = true
|
|
37
41
|
if (global.signalEventHandling.SIGINTCount < 2) {
|
|
38
|
-
|
|
39
|
-
console.log(msg) // eslint-disable-line no-console
|
|
42
|
+
console.log(`${msg} Press CTRL + C again to force an exit\nNOTE: Doing so might corrupt the applications state information!`)
|
|
40
43
|
} else {
|
|
41
44
|
process.exit(1)
|
|
42
45
|
}
|
|
@@ -44,12 +47,12 @@ Exit received. Waiting for current operation to finish...
|
|
|
44
47
|
|
|
45
48
|
process.on('SIGTERM', () => {
|
|
46
49
|
global.signalEventHandling.shouldExitGracefully = true
|
|
47
|
-
console.log(msg)
|
|
50
|
+
console.log(msg)
|
|
48
51
|
})
|
|
49
52
|
|
|
50
53
|
process.on('SIGBREAK', () => {
|
|
51
54
|
global.signalEventHandling.shouldExitGracefully = true
|
|
52
|
-
console.log(msg)
|
|
55
|
+
console.log(msg)
|
|
53
56
|
})
|
|
54
57
|
}
|
|
55
58
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const
|
|
1
|
+
const isEmpty = require('lodash.isempty')
|
|
2
2
|
|
|
3
3
|
module.exports = function isValidValue(val) {
|
|
4
4
|
if (typeof val === 'object' && val.hasOwnProperty('__internal_only_flag')) {
|
|
5
5
|
return false
|
|
6
6
|
}
|
|
7
|
-
return val !== null && typeof val !== 'undefined' && !(typeof val === 'object' &&
|
|
7
|
+
return val !== null && typeof val !== 'undefined' && !(typeof val === 'object' && isEmpty(val))
|
|
8
8
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "configorama",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10",
|
|
4
4
|
"description": "Variable support for configuration files",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"files": [
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
],
|
|
12
12
|
"scripts": {
|
|
13
13
|
"docs": "node ./scripts/docs.js",
|
|
14
|
-
"test": "
|
|
15
|
-
"test:api": "
|
|
16
|
-
"watch": "
|
|
14
|
+
"test": "uvu tests \".*\\.test.js$\"",
|
|
15
|
+
"test:api": "uvu tests/api api.test.js",
|
|
16
|
+
"watch": "watchlist tests -- npm test",
|
|
17
17
|
"publish": "git push origin && git push origin --tags",
|
|
18
18
|
"release:patch": "npm version patch && npm publish",
|
|
19
19
|
"release:minor": "npm version minor && npm publish",
|
|
@@ -33,26 +33,35 @@
|
|
|
33
33
|
"git-url-parse": "^14.0.0",
|
|
34
34
|
"js-yaml": "^3.14.1",
|
|
35
35
|
"json5": "^2.2.3",
|
|
36
|
-
"lodash": "^4.
|
|
36
|
+
"lodash.isarray": "^4.0.0",
|
|
37
|
+
"lodash.isstring": "^4.0.1",
|
|
38
|
+
"lodash.isnumber": "^3.0.3",
|
|
39
|
+
"lodash.isobject": "^3.0.2",
|
|
40
|
+
"lodash.isdate": "^4.0.1",
|
|
41
|
+
"lodash.isregexp": "^4.0.1",
|
|
42
|
+
"lodash.isfunction": "^3.0.9",
|
|
43
|
+
"lodash.isempty": "^4.4.0",
|
|
44
|
+
"lodash.trim": "^4.5.1",
|
|
45
|
+
"lodash.camelcase": "^4.3.0",
|
|
46
|
+
"lodash.kebabcase": "^4.1.1",
|
|
47
|
+
"lodash.capitalize": "^4.2.1",
|
|
48
|
+
"lodash.split": "^4.4.2",
|
|
49
|
+
"lodash.map": "^4.6.0",
|
|
50
|
+
"lodash.mapvalues": "^4.6.0",
|
|
51
|
+
"lodash.assign": "^4.2.0",
|
|
52
|
+
"lodash.set": "^4.3.2",
|
|
53
|
+
"lodash.clonedeep": "^4.5.0",
|
|
54
|
+
"lodash.includes": "^4.3.0",
|
|
55
|
+
"lodash.flatten": "^4.4.0",
|
|
37
56
|
"promise.prototype.finally": "^3.1.8",
|
|
38
57
|
"replaceall": "^0.1.6",
|
|
39
58
|
"sync-rpc": "^1.3.6",
|
|
40
59
|
"traverse": "^0.6.8"
|
|
41
60
|
},
|
|
42
61
|
"devDependencies": {
|
|
43
|
-
"ava": "^2.4.0",
|
|
44
62
|
"markdown-magic": "^2.6.1",
|
|
45
|
-
"minimist": "^1.2.8"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"files": [
|
|
49
|
-
"tests/**/*.test.js"
|
|
50
|
-
],
|
|
51
|
-
"sources": [
|
|
52
|
-
"**/*.{js,jsx}",
|
|
53
|
-
"*.yml",
|
|
54
|
-
"**/*.yml"
|
|
55
|
-
],
|
|
56
|
-
"verbose": true
|
|
63
|
+
"minimist": "^1.2.8",
|
|
64
|
+
"uvu": "^0.5.6",
|
|
65
|
+
"watchlist": "^0.3.1"
|
|
57
66
|
}
|
|
58
67
|
}
|