configorama 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/main.js CHANGED
@@ -1,6 +1,11 @@
1
1
  const os = require('os')
2
2
  const path = require('path')
3
3
  const fs = require('fs')
4
+ /*
5
+ console.log = () => {}
6
+ // process.exit(1)
7
+ /** */
8
+
4
9
  const promiseFinallyShim = require('promise.prototype.finally').shim()
5
10
  // @TODO only import lodash we need
6
11
 
@@ -42,7 +47,7 @@ const { getFallbackString, verifyVariable } = require('./utils/variableUtils')
42
47
  const { encodeUnknown, decodeUnknown } = require('./utils/unknownValues')
43
48
  const { mergeByKeys } = require('./utils/mergeByKeys')
44
49
  const { arrayToJsonPath } = require('./utils/arrayToJsonPath')
45
-
50
+ const { findNestedVariables } = require('./utils/find-nested-variables')
46
51
  /**
47
52
  * Maintainer's notes:
48
53
  *
@@ -105,6 +110,7 @@ class Configorama {
105
110
  } else if (variableSyntax instanceof RegExp) {
106
111
  varRegex = variableSyntax
107
112
  }
113
+ // console.log('varRegex', varRegex)
108
114
  this.variableSyntax = varRegex
109
115
 
110
116
  // Set initial config object to populate
@@ -130,8 +136,11 @@ class Configorama {
130
136
  this.opts
131
137
  )
132
138
 
139
+ this.configFilePath = fileOrObject
133
140
  // set config objects
134
141
  this.config = configObject
142
+ // Keep a copy of the original file contents
143
+ this.originalString = fileContents
135
144
  // Keep a copy
136
145
  this.originalConfig = cloneDeep(configObject)
137
146
  // Set configPath for file references
@@ -165,6 +174,8 @@ class Configorama {
165
174
  * // or ${self:otherKeyInConfig}
166
175
  */
167
176
  {
177
+ type: 'self',
178
+ prefix: 'self',
168
179
  match: selfRefSyntax,
169
180
  resolver: (varString, o, x, pathValue) => {
170
181
  return this.getValueFromSelf(varString, o, x, pathValue)
@@ -177,6 +188,8 @@ class Configorama {
177
188
  * ${file(pathToFile.yml), "fallbackValue"}
178
189
  */
179
190
  {
191
+ type: 'file',
192
+ prefix: 'file',
180
193
  match: fileRefSyntax,
181
194
  resolver: (varString, o, x, pathValue) => {
182
195
  // console.log('pathValue getValueFromFile', pathValue)
@@ -197,8 +210,10 @@ class Configorama {
197
210
  getValueFromString,
198
211
  /* Resolve deep references */
199
212
  {
213
+ type: 'deep',
200
214
  match: deepRefSyntax,
201
- resolver: (varString) => {
215
+ resolver: (varString, o, x, pathValue) => {
216
+ // console.log('>>>>>getValueFromDeep', varString)
202
217
  return this.getValueFromDeep(varString)
203
218
  },
204
219
  },
@@ -208,10 +223,13 @@ class Configorama {
208
223
 
209
224
  /* Nicer self: references. Match key in object */
210
225
  const fallThroughSelfMatcher = {
226
+ type: 'fallthrough',
211
227
  match: (varString, fullObject, valueObject) => {
212
- // console.log('fallthrough varString', varString)
213
- // console.log('fallthrough valueObject', valueObject)
214
- // console.log('fullObject', fullObject)
228
+ /*
229
+ console.log('fallthrough varString', varString)
230
+ console.log('fallthrough valueObject', valueObject)
231
+ console.log('fullObject', fullObject)
232
+ /** */
215
233
  /* its file ref so we need to shift lookup for self in nested files */
216
234
  if (valueObject.isFileRef) {
217
235
  const exists = dotProp.get(fullObject, varString)
@@ -229,8 +247,14 @@ class Configorama {
229
247
  const startOf = varString.split('.')
230
248
  return fullObject[startOf[0]]
231
249
  },
232
- resolver: (varString, o, x, pathValue) => {
233
- return this.getValueFromSelf(varString, o, x, pathValue)
250
+ resolver: (varString, options, config, pathValue) => {
251
+ /*
252
+ console.log('fallthrough resolver', varString)
253
+ console.log('fallthrough options', options)
254
+ console.log('fallthrough config', config)
255
+ console.log('fallthrough pathValue', pathValue)
256
+ /** */
257
+ return this.getValueFromSelf(varString, options, config, pathValue)
234
258
  },
235
259
  }
236
260
 
@@ -242,6 +266,9 @@ class Configorama {
242
266
  /* attach self matcher last */
243
267
  this.variableTypes = this.variableTypes.concat(fallThroughSelfMatcher)
244
268
 
269
+ this.variablesKnownTypes = new RegExp(`^(${this.variableTypes.map((v) => v.prefix || v.type).join('|')}):`)
270
+ // console.log('this.variablesKnownTypes', this.variablesKnownTypes)
271
+ // process.exit(1)
245
272
  // Additional filters on values. ${thing | filterFunction}
246
273
  this.filters = {
247
274
  capitalize: (val) => {
@@ -345,6 +372,10 @@ class Configorama {
345
372
  return Object.keys(o).reduce((c, k) => ((c[k.toUpperCase()] = o[k]), c), {}) // eslint-disable-line
346
373
  },
347
374
  md5: md5Function,
375
+ // ServiceName@${replace(${ self : version }, /\\./gi, - )}
376
+ // replace: (value, search, replace) => {
377
+ // return value.replace(search, replace)
378
+ // },
348
379
  }
349
380
 
350
381
  // Apply user defined functions
@@ -375,6 +406,13 @@ class Configorama {
375
406
  this.options = cliOpts || {}
376
407
  const configoramaOpts = this.opts
377
408
  const originalConfig = this.originalConfig
409
+
410
+ /* If no variables found just return early */
411
+ if (this.originalString && !this.originalString.match(this.variableSyntax)) {
412
+ return Promise.resolve(originalConfig)
413
+ }
414
+
415
+ /* Parse variables */
378
416
  return this.initialCall(() => {
379
417
  return Promise.resolve()
380
418
  .then(() => {
@@ -403,7 +441,7 @@ class Configorama {
403
441
  // console.log('RAW FUNCTION', rawFunction)
404
442
  const funcString = rawValue.replace(/> function /g, '')
405
443
  // console.log('funcString', funcString)
406
- const func = cleanVariable(funcString, varSyntax, true)
444
+ const func = cleanVariable(funcString, varSyntax, true, `init ${this.callCount}`)
407
445
  const funcVal = transform(func)
408
446
  const hasObjectRef = rawValue.match(/\.\S*$/)
409
447
  if (hasObjectRef && typeof funcVal === 'object') {
@@ -484,7 +522,7 @@ class Configorama {
484
522
  let replaceVal = funcValue
485
523
  if (typeof funcValue === 'string') {
486
524
  const replaceIt = variableString.replace(hasFunc[0], funcValue)
487
- replaceVal = cleanVariable(replaceIt, this.variableSyntax, true)
525
+ replaceVal = cleanVariable(replaceIt, this.variableSyntax, true, `runFunction ${this.callCount}`)
488
526
  }
489
527
 
490
528
  // If wrapped in outer function, recurse
@@ -560,7 +598,7 @@ class Configorama {
560
598
  }
561
599
  leaf.originalSource = originalValue
562
600
  if (originalValue && isString(originalValue)) {
563
- const varString = cleanVariable(originalValue, this.variableSyntax)
601
+ const varString = cleanVariable(originalValue, this.variableSyntax, true, `getProperties ${this.callCount}`)
564
602
  if (varString.match(fileRefSyntax)) {
565
603
  leaf.isFileRef = true
566
604
  }
@@ -664,7 +702,7 @@ class Configorama {
664
702
  // console.log('match', match)
665
703
  return {
666
704
  match: match,
667
- variable: cleanVariable(match, this.variableSyntax),
705
+ variable: cleanVariable(match, this.variableSyntax, true, `getMatches ${this.callCount}`),
668
706
  }
669
707
  })
670
708
  }
@@ -675,9 +713,9 @@ class Configorama {
675
713
  * @returns {Promise[]} Promises for the eventual populated values of the given matches
676
714
  */
677
715
  populateMatches(matches, valueObject, root) {
678
- // console.log('matches', matches)
716
+ // console.log('populateMatches matches', matches)
679
717
  return map(matches, (match) => {
680
- return this.splitAndGet(match.variable, valueObject, root)
718
+ return this.splitAndGet(match.variable, valueObject, root, match.match)
681
719
  })
682
720
  }
683
721
  /**
@@ -735,7 +773,10 @@ class Configorama {
735
773
  }
736
774
  const populations = this.populateMatches(matches, valueObject, root)
737
775
  return Promise.all(populations)
738
- .then((results) => this.renderMatches(valueObject, matches, results))
776
+ .then((results) => {
777
+ // console.log('populateMatches results', results)
778
+ return this.renderMatches(valueObject, matches, results)
779
+ })
739
780
  .then((result) => {
740
781
  // console.log('renderMatches result', result)
741
782
  if (root && isArray(matches)) {
@@ -762,7 +803,7 @@ class Configorama {
762
803
  * @param property The original property string the given variable was extracted from
763
804
  * @returns {Promise} A promise resolving to the final value of the given variable
764
805
  */
765
- splitAndGet(variable, valueObject, root) {
806
+ splitAndGet(variable, valueObject, root, originalVar) {
766
807
  if (DEBUG) {
767
808
  console.log('>>>>>>>> Split and Get', variable)
768
809
  console.log('valueObject', valueObject)
@@ -775,19 +816,20 @@ class Configorama {
775
816
  // valueObject.value = `> function ${valueObject.value}`
776
817
  }*/
777
818
 
778
- const parts = splitByComma(variable)
819
+ const parts = splitByComma(variable, this.variableSyntax)
779
820
  if (DEBUG) {
780
821
  console.log('parts', parts)
781
822
  console.log('parts variable:', variable)
782
- console.log('parts property:', valueObject.value)
823
+ console.log('parts originalVar:', originalVar)
824
+ console.log('parts property:', valueObject)
783
825
  console.log('All parts:', parts)
784
826
  console.log('-----')
785
827
  }
786
828
  if (parts.length <= 1) {
787
- return this.getValueFromSource(parts[0], valueObject, 'splitAndGet')
829
+ return this.getValueFromSource(parts[0], valueObject, 'splitAndGet', originalVar)
788
830
  }
789
831
  // More than 2 parts, so we need to overwrite
790
- return this.overwrite(parts, valueObject)
832
+ return this.overwrite(parts, valueObject, originalVar)
791
833
  }
792
834
  /**
793
835
  * Populate a given property, given the matched string to replace and the value to replace the
@@ -934,7 +976,7 @@ class Configorama {
934
976
  missingValue = this.deep[i]
935
977
  }
936
978
 
937
- const cleanVar = cleanVariable(property, this.variableSyntax)
979
+ const cleanVar = cleanVariable(property, this.variableSyntax, true, `populateVariable fallback ${this.callCount}`)
938
980
  const cleanVarNoFilters = cleanVar.split('|')[0]
939
981
  const splitVars = splitByComma(cleanVarNoFilters)
940
982
  const nestedVar = findNestedVariable(splitVars, valueObject.originalSource)
@@ -966,7 +1008,7 @@ Missing Value ${missingValue} - ${matchedString}
966
1008
 
967
1009
  if (property && typeof property === 'string') {
968
1010
  // console.log('property', property)
969
- const prop = cleanVariable(property, this.variableSyntax)
1011
+ const prop = cleanVariable(property, this.variableSyntax, true, `populateVariable string ${this.callCount}`)
970
1012
  // console.log('prop', prop)
971
1013
  if (property.match(/^> function /g) && prop) {
972
1014
  // console.log('func prop', property)
@@ -1070,25 +1112,49 @@ Missing Value ${missingValue} - ${matchedString}
1070
1112
  * @returns {Promise.<TResult>|*} A promise resolving to the first validly populating variable
1071
1113
  * in the given variable strings string.
1072
1114
  */
1073
- overwrite(variableStrings, valueObject) {
1115
+ overwrite(variableStrings, valueObject, originalVar) {
1074
1116
  const propertyString = valueObject.value
1075
- // console.log('variableStrings', variableStrings)
1117
+ /*
1118
+ console.log('overwrite variableStrings', variableStrings)
1119
+ console.log('overwrite valueObject', valueObject)
1120
+ console.log('overwrite originalVar', originalVar)
1121
+ // process.exit(1)
1122
+ /** */
1123
+
1124
+ if (variableStrings.length === 2) {
1125
+ const firstValue = variableStrings[0]
1126
+ const secondValue = variableStrings[1]
1127
+ if (
1128
+ isString(firstValue) && firstValue.match(this.variablesKnownTypes)
1129
+ && isString(secondValue) && !secondValue.match(this.variablesKnownTypes) && !secondValue.match(this.variableSyntax)
1130
+ ) {
1131
+ if (!isSurroundedByQuotes(secondValue) && !/^-?\d+(\.\d+)?$/.test(secondValue) && !startsWithQuotedPipe(secondValue)) {
1132
+ variableStrings = [firstValue, ensureQuote(secondValue)]
1133
+ }
1134
+ // console.log('new overwrite variableStrings', variableStrings)
1135
+ }
1136
+ }
1137
+
1076
1138
  // console.log('propertyString', typeof propertyString)
1077
1139
  const variableValues = variableStrings.map((variableString) => {
1078
1140
  // This runs on nested variable resolution
1079
1141
  return this.getValueFromSource(variableString, valueObject, 'overwrite')
1080
1142
  })
1143
+
1081
1144
  // console.log('variableValues', variableValues)
1082
1145
  return Promise.all(variableValues).then((values) => {
1083
1146
  let deepPropertyStr = propertyString
1084
1147
  let deepProperties = 0
1148
+ // console.log('overwrite values', valuesToUse)
1085
1149
  values.forEach((value, index) => {
1086
1150
  // console.log('───────────────────────────────> value', value)
1087
1151
  if (isString(value) && value.match(this.variableSyntax)) {
1088
1152
  deepProperties += 1
1089
1153
  // console.log('makeDeepVariable overwrite', value)
1090
- const deepVariable = this.makeDeepVariable(value)
1091
- const newValue = cleanVariable(deepVariable, this.variableSyntax)
1154
+ const deepVariable = this.makeDeepVariable(value, 'via overwrite')
1155
+ // console.log('deepVariable', deepVariable)
1156
+ const newValue = cleanVariable(deepVariable, this.variableSyntax, true, `overwrite ${this.callCount}`)
1157
+ // console.log(`overwrite newValue ${variableStrings[index]}`, newValue)
1092
1158
  // console.log('variableStrings', variableStrings)
1093
1159
  deepPropertyStr = deepPropertyStr.replace(variableStrings[index], newValue)
1094
1160
  // console.log('deepPropertyString', deepPropertyStr)
@@ -1104,11 +1170,11 @@ Missing Value ${missingValue} - ${matchedString}
1104
1170
  * @param variableString The variable string to retrieve a value for.
1105
1171
  * @returns {Promise.<TResult>|*} A promise resolving to the given variables value.
1106
1172
  */
1107
- getValueFromSource(variableString, valueObject, caller) {
1108
- // console.log('getValueFromSource caller', caller)
1173
+ getValueFromSource(variableString, valueObject, caller, originalVar) {
1174
+ // console.log('getValueFromSrc caller', caller)
1109
1175
  const propertyString = valueObject.value
1110
1176
  const pathValue = valueObject.path
1111
- // console.log('getValueFromSource propertyString', propertyString)
1177
+ // console.log('getValueFromSrc propertyString', propertyString)
1112
1178
  // console.log(`tracker contains ${variableString}`, this.tracker.contains(variableString))
1113
1179
  if (this.tracker.contains(variableString)) {
1114
1180
  // console.log('try to get', variableString)
@@ -1118,7 +1184,7 @@ Missing Value ${missingValue} - ${matchedString}
1118
1184
  let newHasFilter
1119
1185
  // Else lookup value from various sources
1120
1186
  if (DEBUG) {
1121
- console.log(`>>>>> getValueFromSource() call - ${caller}`)
1187
+ console.log(`>>>>> getValueFromSrc() call - ${caller}`)
1122
1188
  console.log('variableString:', variableString)
1123
1189
  console.log('propertyString:', propertyString)
1124
1190
  console.log('pathValue:', pathValue)
@@ -1130,7 +1196,7 @@ Missing Value ${missingValue} - ${matchedString}
1130
1196
  let promiseKey
1131
1197
  // TODO match () or pipes |
1132
1198
  if (filters) {
1133
- const string = cleanVariable(propertyString, this.variableSyntax, true)
1199
+ const string = cleanVariable(propertyString, this.variableSyntax, true, `getValueFromSrc filter ${this.callCount}`)
1134
1200
  // console.log('string', string)
1135
1201
  const deeperValue = getTextAfterOccurance(string, variableString)
1136
1202
  // console.log('deeperValue', deeperValue)
@@ -1163,27 +1229,49 @@ Missing Value ${missingValue} - ${matchedString}
1163
1229
  }
1164
1230
 
1165
1231
  let resolverFunction
1232
+ let resolverType
1166
1233
  /* Loop over variables and set getterFunction when match found. */
1167
1234
  const found = this.variableTypes.some((r, i) => {
1168
1235
  if (r.match instanceof RegExp && variableString.match(r.match)) {
1169
1236
  // set resolver function
1170
1237
  resolverFunction = r.resolver
1238
+ resolverType = r.type || 'unknown'
1171
1239
  return true
1172
1240
  } else if (typeof r.match === 'function') {
1173
1241
  // TODO finalize match API
1174
1242
  if (r.match(variableString, this.config, valueObject)) {
1175
1243
  // set resolver function
1176
1244
  resolverFunction = r.resolver
1245
+ resolverType = r.type || 'unknown'
1177
1246
  return true
1178
1247
  }
1179
1248
  }
1180
1249
  return false
1181
1250
  })
1182
- // console.log('found', found)
1251
+ /*
1252
+ // console.log('found variable resolver', found)
1253
+ // console.log('resolverFunction', resolverFunction)
1254
+ /** */
1183
1255
 
1184
1256
  if (found && resolverFunction) {
1257
+ /*
1258
+ console.log(`----------Resolver [${resolverType}]----------------------`)
1259
+ console.log(`Resolver TYPE [${resolverType}]`, caller)
1260
+ console.log('WITH INPUTS ▼')
1261
+ console.log('variableString: ', variableString)
1262
+ console.log('this.options: ', this.options)
1263
+ console.log('this.config: ', this.config)
1264
+ console.log('valueObject: ', valueObject)
1265
+ // process.exit(1)
1266
+ /** */
1185
1267
  // TODO finalize resolverFunction API
1186
- const valuePromise = resolverFunction(variableString, this.options, this.config, valueObject).then((val) => {
1268
+ const valuePromise = resolverFunction(
1269
+ variableString,
1270
+ this.options,
1271
+ this.config,
1272
+ valueObject,
1273
+
1274
+ ).then((val) => {
1187
1275
  // console.log('VALUE', val)
1188
1276
  if (
1189
1277
  val === null ||
@@ -1191,8 +1279,11 @@ Missing Value ${missingValue} - ${matchedString}
1191
1279
  /* match deep refs as empty {}, they need resolving via functions */
1192
1280
  (typeof val === 'object' && isEmpty(val) && variableString.match(/deep\:/))
1193
1281
  ) {
1282
+
1283
+ const cleanV = cleanVariable(propertyString, this.variableSyntax, true, `getValueFromSrc resolverFunction ${this.callCount}`)
1194
1284
  // console.log('variableString', variableString)
1195
- const cleanV = cleanVariable(propertyString, this.variableSyntax)
1285
+ // console.log('cleanV', cleanV)
1286
+ // console.log('nestedVars', nestedVars)
1196
1287
  const valueCount = splitByComma(cleanV)
1197
1288
 
1198
1289
  if (variableString.match(/deep\:/)) {
@@ -1206,18 +1297,29 @@ Missing Value ${missingValue} - ${matchedString}
1206
1297
  // console.log('deepIndexValue', deepIndexValue)
1207
1298
  // console.log('FINAL', `${deepIndexValue}.${deepRef}`)
1208
1299
  if (deepIndexValue) {
1300
+ // console.log('> RESOLVER RETURN newValue 1', `${deepIndexValue}.${deepRef}`)
1209
1301
  return Promise.resolve(`${deepIndexValue}.${deepRef}`)
1210
1302
  }
1211
1303
  }
1212
1304
  }
1305
+ // console.log('valueCount', valueCount)
1213
1306
  // TODO throw on empty values?
1214
1307
  // No fallback value found AND this is undefined, throw error
1215
- if (valueCount.length === 1) {
1308
+ const nestedVars = findNestedVariables(propertyString, this.variableSyntax)
1309
+ // console.log('nestedVars', nestedVars)
1310
+ const noNestedVars = nestedVars.length < 2
1311
+ if (valueCount.length === 1 && noNestedVars) {
1312
+ const configFilePath = (this.configFilePath) ? ` in ${this.configFilePath}` : ''
1216
1313
  throw new Error(`
1217
- Unable to resolve variable ${propertyString} from "${valueObject.originalSource}" at path ${valueObject.path ? `"${arrayToJsonPath(valueObject.path)}"` : 'na'}
1314
+ Unable to resolve configuration variable
1315
+
1316
+ Value "${propertyString}"
1317
+ From "${valueObject.originalSource}"
1318
+ At location ${valueObject.path ? `"${arrayToJsonPath(valueObject.path)}"` : 'na'}${configFilePath}
1218
1319
  \nFix this reference, your inputs and/or provide a valid fallback value.
1219
1320
  \nExample of setting a fallback value: \${${variableString}, "fallbackValue"\}\n`)
1220
1321
  }
1322
+ // console.log('> RESOLVER RETURN newValue 2', val)
1221
1323
  // no value resolved but fallback value exists, keep moving on
1222
1324
  return Promise.resolve(val)
1223
1325
  }
@@ -1230,6 +1332,8 @@ Unable to resolve variable ${propertyString} from "${valueObject.originalSource}
1230
1332
  /** */
1231
1333
  // No filters found. return value
1232
1334
  if (!newHasFilter) {
1335
+ // console.log('no newHasFilter', val, valueObject)
1336
+ // console.log('> RESOLVER RETURN newValue 3', val, originalVar)
1233
1337
  return Promise.resolve(val)
1234
1338
  }
1235
1339
 
@@ -1260,6 +1364,7 @@ Unable to resolve variable ${propertyString} from "${valueObject.originalSource}
1260
1364
  // add filters to deep references if filter is used
1261
1365
  const deepValueWithFilters = newHasFilter[1] ? val.replace(/}$/, ` ${allFilters}}`) : val
1262
1366
  // console.log('deepValueWithFilters', deepValueWithFilters)
1367
+ // console.log('RESOLVER RETURN newValue 4', deepValueWithFilters)
1263
1368
  return Promise.resolve(deepValueWithFilters)
1264
1369
  }
1265
1370
  /* Loop over filters used and produce new value */
@@ -1271,15 +1376,18 @@ Unable to resolve variable ${propertyString} from "${valueObject.originalSource}
1271
1376
  }
1272
1377
  if (c.args) {
1273
1378
  this.filterCache[pathValue] = (this.filterCache[pathValue] || []).concat(c.filterName)
1274
- return c.filter(theValue, ...c.args, 'from getValueFromSource with args')
1379
+ return c.filter(theValue, ...c.args, 'from getValueFromSrc with args')
1275
1380
  }
1276
1381
  this.filterCache[pathValue] = (this.filterCache[pathValue] || []).concat(c.filterName)
1277
- return c.filter(theValue, 'from getValueFromSource')
1382
+ return c.filter(theValue, 'from getValueFromSrc')
1278
1383
  }, val)
1279
- // console.log('newValue', newValue)
1280
-
1384
+ // console.log('> RESOLVER RETURN newValue', newValue)
1385
+ // console.log('> RESOLVER RETURN newValue 5', newValue)
1281
1386
  return Promise.resolve(newValue)
1282
1387
  })
1388
+
1389
+ // console.log('valuePromise', valuePromise)
1390
+ // console.log(`----------End Resolver [${resolverType}]-------------------`)
1283
1391
  // console.log('newHasFilter', newHasFilter)
1284
1392
  // TODO do something with func here?
1285
1393
  return this.tracker.add(variableString, valuePromise, propertyString, newHasFilter, promiseKey)
@@ -1288,9 +1396,9 @@ Unable to resolve variable ${propertyString} from "${valueObject.originalSource}
1288
1396
  /* fall through case with self refs */
1289
1397
  if (variableString) {
1290
1398
  // console.log('before clean propertyString', propertyString, variableString)
1291
- const clean = cleanVariable(propertyString, this.variableSyntax)
1399
+ const clean = cleanVariable(propertyString, this.variableSyntax, true, `getValueFromSrc self ${this.callCount}`)
1292
1400
  // TODO @DWELLS cleanVariable makes fallback values with spaces have no spaces
1293
- // console.log('cleanVariable', clean)
1401
+ // console.log('AFTER cleanVariable', clean)
1294
1402
  const cleanClean = clean.split('|')[0]
1295
1403
  // console.log('cleanCleanVariable', cleanClean)
1296
1404
  if (funcRegex.exec(cleanClean)) {
@@ -1342,7 +1450,7 @@ Unable to resolve variable ${propertyString} from "${valueObject.originalSource}
1342
1450
  return this.tracker.add(fallbackValue, valuePromise, propertyString, newHasFilter)
1343
1451
  }
1344
1452
 
1345
- // has fallback but needs deeper lookup. Call getValueFromSource again
1453
+ // has fallback but needs deeper lookup. Call getValueFromSrc again
1346
1454
  if (fallbackValue) {
1347
1455
  if (DEBUG) console.log('fallbackValue', fallbackValue)
1348
1456
  // console.log('fallbackValue', fallbackValue)
@@ -1587,7 +1695,7 @@ Please use ":" to reference sub properties`
1587
1695
  // const index = this.getDeepIndex(variableString)
1588
1696
  /*
1589
1697
  console.log('FIND INDEX', index)
1590
- console.log(this.deep)
1698
+ console.log(this.deep, this.deep[index])
1591
1699
  /** */
1592
1700
  return this.deep[index]
1593
1701
  }
@@ -1600,14 +1708,13 @@ Please use ":" to reference sub properties`
1600
1708
  console.log('getValueFromDeep variable', variable)
1601
1709
  /** */
1602
1710
  let ret = this.populateValue({ value: variable }, undefined, 'getValueFromDeep')
1603
- // console.log('variable ret', ret)
1604
1711
  if (deepRef.length) {
1605
1712
  // if there is a deep reference remaining
1606
1713
  ret = ret.then((result) => {
1607
1714
  // console.log('DEEP RESULT', result)
1608
1715
  if (isString(result.value) && result.value.match(this.variableSyntax)) {
1609
1716
  // console.log('makeDeepVariable getValueFromDeep', result.value)
1610
- const deepVariable = this.makeDeepVariable(result.value)
1717
+ const deepVariable = this.makeDeepVariable(result.value, 'via getValueFromDeep')
1611
1718
  return Promise.resolve(appendDeepVariable(deepVariable, deepRef))
1612
1719
  }
1613
1720
  return this.getDeeperValue(deepRef.split('.'), result.value)
@@ -1615,8 +1722,8 @@ Please use ":" to reference sub properties`
1615
1722
  }
1616
1723
  return ret
1617
1724
  }
1618
- makeDeepVariable(variable) {
1619
- // console.log('MAKE DEEP', variable)
1725
+ makeDeepVariable(variable, caller) {
1726
+ // variable = variable.replace("dev", '"dev"')
1620
1727
  let index = this.deep.findIndex((item) => variable === item)
1621
1728
  if (index < 0) {
1622
1729
  // console.log('this.deep.push', variable)
@@ -1624,11 +1731,18 @@ Please use ":" to reference sub properties`
1624
1731
  }
1625
1732
  // console.log("makeDeepVariable SET INDEX", index)
1626
1733
  const variableContainer = variable.match(this.variableSyntax)[0]
1627
- const variableString = cleanVariable(variableContainer, this.variableSyntax)
1734
+ const variableString = cleanVariable(variableContainer, this.variableSyntax, true, `makeDeepVariable ${this.callCount}`)
1628
1735
  const deepVar = variableContainer.replace(variableString, `deep:${index}`)
1736
+ /*
1737
+ console.log('MAKE DEEP', variable, caller)
1738
+ console.log('this.deep', this.deep)
1739
+ console.log('variableContainer', variable)
1740
+ console.log('variableString', variableString)
1741
+ console.log('deepVar', deepVar)
1742
+ // process.exit(1)
1743
+ /** */
1629
1744
  // TODO debugging space removal. Seems like this helps
1630
1745
  // const deepVar = variableContainer.replace(/\s/g, '').replace(variableString, `deep:${index}`)
1631
-
1632
1746
  return deepVar
1633
1747
  }
1634
1748
  /**
@@ -1689,7 +1803,7 @@ Please use ":" to reference sub properties`
1689
1803
  }
1690
1804
  if (typeof reducedValue === 'string' && reducedValue.match(this.variableSyntax)) {
1691
1805
  // console.log('makeDeepVariable reducedValue', reducedValue)
1692
- reducedValue = this.makeDeepVariable(reducedValue)
1806
+ reducedValue = this.makeDeepVariable(reducedValue, 'via getDeeperValue')
1693
1807
  }
1694
1808
  }
1695
1809
  // console.log('fin', reducedValue)
@@ -1726,4 +1840,37 @@ Please use ":" to reference sub properties`
1726
1840
  }
1727
1841
  }
1728
1842
 
1843
+ function ensureQuote(value, open = '"', close) {
1844
+ let i = -1
1845
+ const result = []
1846
+ const end = close || open
1847
+ if (typeof value === 'string') {
1848
+ return startChar(value, open) + value + endChar(value, end)
1849
+ }
1850
+ while (++i < value.length) {
1851
+ result[i] = startChar(value[i], open) + value[i] + endChar(value[i], end)
1852
+ }
1853
+ return result
1854
+ }
1855
+
1856
+ function startChar(str, char) {
1857
+ return (str[0] === char) ? '' : char
1858
+ }
1859
+
1860
+ function endChar(str, char) {
1861
+ return (str[str.length -1] === char) ? '' : char
1862
+ }
1863
+
1864
+ function isSurroundedByQuotes(str) {
1865
+ if (!str || str.length < 2) return false
1866
+ const firstChar = str[0]
1867
+ const lastChar = str[str.length - 1]
1868
+ return (firstChar === "'" && lastChar === "'") || (firstChar === '"' && lastChar === '"')
1869
+ }
1870
+
1871
+ function startsWithQuotedPipe(str) {
1872
+ // Matches either 'xyz' | or "xyz" |
1873
+ return /^(['"])(.*?)\1\s*\|/.test(str)
1874
+ }
1875
+
1729
1876
  module.exports = Configorama
@@ -23,6 +23,7 @@ Example: \${env:MY_ENV_VAR}
23
23
  }
24
24
 
25
25
  module.exports = {
26
+ type: 'env',
26
27
  match: envRefSyntax,
27
28
  resolver: getValueFromEnv
28
29
  }
@@ -294,6 +294,8 @@ async function getGitRemote(name = 'origin') {
294
294
 
295
295
  module.exports = function createGitResolver(cwd) {
296
296
  return {
297
+ type: 'git',
298
+ prefix: 'git',
297
299
  match: gitVariableSyntax,
298
300
  resolver: createResolver(cwd)
299
301
  }
@@ -10,6 +10,7 @@ function getValueFromNumber(variableString) {
10
10
  }
11
11
 
12
12
  module.exports = {
13
+ type: 'number',
13
14
  match: isNumberVariable,
14
15
  resolver: getValueFromNumber
15
16
  }
@@ -13,6 +13,8 @@ function getValueFromOptions(variableString, options) {
13
13
  }
14
14
 
15
15
  module.exports = {
16
+ type: 'options',
17
+ prefix: 'opt',
16
18
  match: optRefSyntax,
17
19
  resolver: getValueFromOptions
18
20
  }
@@ -61,11 +61,12 @@ class PromiseTracker {
61
61
  }
62
62
  // console.log('SET PROMISE', nameSpacedVariable)
63
63
 
64
- promise.waitList = `${variable} waited on by: ${specifier} ${nameSpacedVariable}`
64
+ promise.waitList = `Var [${variable}] waited on by: ${specifier}. key: ${nameSpacedVariable}`
65
65
  promise.state = 'pending'
66
66
  promise.then( // creates a promise with the following effects but that we otherwise ignore
67
67
  () => { promise.state = 'resolved' },
68
- () => { promise.state = 'rejected' })
68
+ () => { promise.state = 'rejected' }
69
+ )
69
70
 
70
71
  this.promiseList.push(promise)
71
72