configorama 0.6.19 → 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.
Files changed (139) hide show
  1. package/README.md +78 -2
  2. package/cli.js +1 -0
  3. package/index.d.ts +90 -37
  4. package/package.json +8 -2
  5. package/src/index.js +42 -14
  6. package/src/main.js +72 -51
  7. package/src/parsers/index.js +10 -0
  8. package/src/parsers/typescript.js +20 -43
  9. package/src/parsers/yaml.js +35 -2
  10. package/src/resolvers/valueFromFile.js +87 -24
  11. package/src/resolvers/valueFromGit.js +11 -3
  12. package/src/utils/encoders/js-fixes.js +44 -0
  13. package/src/utils/parsing/mergeByKeys.js +4 -3
  14. package/src/utils/parsing/parse.js +4 -2
  15. package/src/utils/paths/getFullFilePath.js +1 -1
  16. package/src/utils/resolution/preResolveVariable.js +1 -0
  17. package/src/utils/strings/quoteUtils.js +2 -2
  18. package/src/utils/strings/splitCsv.js +1 -1
  19. package/src/utils/ui/logs.js +4 -4
  20. package/src/utils/validation/warnIfNotFound.js +3 -3
  21. package/src/utils/variables/findNestedVariables.js +2 -2
  22. package/types/cli.d.ts +3 -0
  23. package/types/cli.d.ts.map +1 -0
  24. package/types/src/functions/md5.d.ts +3 -0
  25. package/types/src/functions/md5.d.ts.map +1 -0
  26. package/types/src/index.d.ts +100 -0
  27. package/types/src/index.d.ts.map +1 -0
  28. package/types/src/main.d.ts +275 -0
  29. package/types/src/main.d.ts.map +1 -0
  30. package/types/src/parsers/esm.d.ts +15 -0
  31. package/types/src/parsers/esm.d.ts.map +1 -0
  32. package/types/src/parsers/hcl.d.ts +1 -0
  33. package/types/src/parsers/hcl.d.ts.map +1 -0
  34. package/types/src/parsers/index.d.ts +18 -0
  35. package/types/src/parsers/index.d.ts.map +1 -0
  36. package/types/src/parsers/ini.d.ts +6 -0
  37. package/types/src/parsers/ini.d.ts.map +1 -0
  38. package/types/src/parsers/json5.d.ts +10 -0
  39. package/types/src/parsers/json5.d.ts.map +1 -0
  40. package/types/src/parsers/toml.d.ts +7 -0
  41. package/types/src/parsers/toml.d.ts.map +1 -0
  42. package/types/src/parsers/typescript.d.ts +15 -0
  43. package/types/src/parsers/typescript.d.ts.map +1 -0
  44. package/types/src/parsers/yaml.d.ts +45 -0
  45. package/types/src/parsers/yaml.d.ts.map +1 -0
  46. package/types/src/resolvers/valueFromCron.d.ts +14 -0
  47. package/types/src/resolvers/valueFromCron.d.ts.map +1 -0
  48. package/types/src/resolvers/valueFromEnv.d.ts +8 -0
  49. package/types/src/resolvers/valueFromEnv.d.ts.map +1 -0
  50. package/types/src/resolvers/valueFromEval.d.ts +7 -0
  51. package/types/src/resolvers/valueFromEval.d.ts.map +1 -0
  52. package/types/src/resolvers/valueFromFile.d.ts +58 -0
  53. package/types/src/resolvers/valueFromFile.d.ts.map +1 -0
  54. package/types/src/resolvers/valueFromGit.d.ts +11 -0
  55. package/types/src/resolvers/valueFromGit.d.ts.map +1 -0
  56. package/types/src/resolvers/valueFromNumber.d.ts +6 -0
  57. package/types/src/resolvers/valueFromNumber.d.ts.map +1 -0
  58. package/types/src/resolvers/valueFromOptions.d.ts +9 -0
  59. package/types/src/resolvers/valueFromOptions.d.ts.map +1 -0
  60. package/types/src/resolvers/valueFromSelf.d.ts +1 -0
  61. package/types/src/resolvers/valueFromSelf.d.ts.map +1 -0
  62. package/types/src/resolvers/valueFromString.d.ts +6 -0
  63. package/types/src/resolvers/valueFromString.d.ts.map +1 -0
  64. package/types/src/sync.d.ts +3 -0
  65. package/types/src/sync.d.ts.map +1 -0
  66. package/types/src/utils/PromiseTracker.d.ts +19 -0
  67. package/types/src/utils/PromiseTracker.d.ts.map +1 -0
  68. package/types/src/utils/encoders/index.d.ts +2 -0
  69. package/types/src/utils/encoders/index.d.ts.map +1 -0
  70. package/types/src/utils/encoders/js-fixes.d.ts +23 -0
  71. package/types/src/utils/encoders/js-fixes.d.ts.map +1 -0
  72. package/types/src/utils/encoders/unknown-values.d.ts +18 -0
  73. package/types/src/utils/encoders/unknown-values.d.ts.map +1 -0
  74. package/types/src/utils/handleSignalEvents.d.ts +3 -0
  75. package/types/src/utils/handleSignalEvents.d.ts.map +1 -0
  76. package/types/src/utils/lodash.d.ts +4 -0
  77. package/types/src/utils/lodash.d.ts.map +1 -0
  78. package/types/src/utils/parsing/arrayToJsonPath.d.ts +5 -0
  79. package/types/src/utils/parsing/arrayToJsonPath.d.ts.map +1 -0
  80. package/types/src/utils/parsing/cloudformationSchema.d.ts +2 -0
  81. package/types/src/utils/parsing/cloudformationSchema.d.ts.map +1 -0
  82. package/types/src/utils/parsing/enrichMetadata.d.ts +17 -0
  83. package/types/src/utils/parsing/enrichMetadata.d.ts.map +1 -0
  84. package/types/src/utils/parsing/mergeByKeys.d.ts +5 -0
  85. package/types/src/utils/parsing/mergeByKeys.d.ts.map +1 -0
  86. package/types/src/utils/parsing/parse.d.ts +54 -0
  87. package/types/src/utils/parsing/parse.d.ts.map +1 -0
  88. package/types/src/utils/parsing/preProcess.d.ts +10 -0
  89. package/types/src/utils/parsing/preProcess.d.ts.map +1 -0
  90. package/types/src/utils/paths/filePathUtils.d.ts +32 -0
  91. package/types/src/utils/paths/filePathUtils.d.ts.map +1 -0
  92. package/types/src/utils/paths/findLineForKey.d.ts +12 -0
  93. package/types/src/utils/paths/findLineForKey.d.ts.map +1 -0
  94. package/types/src/utils/paths/findProjectRoot.d.ts +2 -0
  95. package/types/src/utils/paths/findProjectRoot.d.ts.map +1 -0
  96. package/types/src/utils/paths/getFullFilePath.d.ts +25 -0
  97. package/types/src/utils/paths/getFullFilePath.d.ts.map +1 -0
  98. package/types/src/utils/paths/resolveAlias.d.ts +14 -0
  99. package/types/src/utils/paths/resolveAlias.d.ts.map +1 -0
  100. package/types/src/utils/regex/index.d.ts +14 -0
  101. package/types/src/utils/regex/index.d.ts.map +1 -0
  102. package/types/src/utils/resolution/preResolveVariable.d.ts +51 -0
  103. package/types/src/utils/resolution/preResolveVariable.d.ts.map +1 -0
  104. package/types/src/utils/strings/bracketMatcher.d.ts +25 -0
  105. package/types/src/utils/strings/bracketMatcher.d.ts.map +1 -0
  106. package/types/src/utils/strings/formatFunctionArgs.d.ts +3 -0
  107. package/types/src/utils/strings/formatFunctionArgs.d.ts.map +1 -0
  108. package/types/src/utils/strings/quoteUtils.d.ts +31 -0
  109. package/types/src/utils/strings/quoteUtils.d.ts.map +1 -0
  110. package/types/src/utils/strings/replaceAll.d.ts +9 -0
  111. package/types/src/utils/strings/replaceAll.d.ts.map +1 -0
  112. package/types/src/utils/strings/splitByComma.d.ts +2 -0
  113. package/types/src/utils/strings/splitByComma.d.ts.map +1 -0
  114. package/types/src/utils/strings/splitCsv.d.ts +10 -0
  115. package/types/src/utils/strings/splitCsv.d.ts.map +1 -0
  116. package/types/src/utils/strings/textUtils.d.ts +15 -0
  117. package/types/src/utils/strings/textUtils.d.ts.map +1 -0
  118. package/types/src/utils/ui/chalk.d.ts +70 -0
  119. package/types/src/utils/ui/chalk.d.ts.map +1 -0
  120. package/types/src/utils/ui/configWizard.d.ts +67 -0
  121. package/types/src/utils/ui/configWizard.d.ts.map +1 -0
  122. package/types/src/utils/ui/createEditorLink.d.ts +11 -0
  123. package/types/src/utils/ui/createEditorLink.d.ts.map +1 -0
  124. package/types/src/utils/ui/deep-log.d.ts +3 -0
  125. package/types/src/utils/ui/deep-log.d.ts.map +1 -0
  126. package/types/src/utils/ui/logs.d.ts +2 -0
  127. package/types/src/utils/ui/logs.d.ts.map +1 -0
  128. package/types/src/utils/validation/warnIfNotFound.d.ts +15 -0
  129. package/types/src/utils/validation/warnIfNotFound.d.ts.map +1 -0
  130. package/types/src/utils/variables/appendDeepVariable.d.ts +3 -0
  131. package/types/src/utils/variables/appendDeepVariable.d.ts.map +1 -0
  132. package/types/src/utils/variables/cleanVariable.d.ts +3 -0
  133. package/types/src/utils/variables/cleanVariable.d.ts.map +1 -0
  134. package/types/src/utils/variables/findNestedVariables.d.ts +23 -0
  135. package/types/src/utils/variables/findNestedVariables.d.ts.map +1 -0
  136. package/types/src/utils/variables/getVariableType.d.ts +8 -0
  137. package/types/src/utils/variables/getVariableType.d.ts.map +1 -0
  138. package/types/src/utils/variables/variableUtils.d.ts +21 -0
  139. package/types/src/utils/variables/variableUtils.d.ts.map +1 -0
@@ -7,7 +7,7 @@ const { splitCsv } = require('../utils/strings/splitCsv')
7
7
  const { resolveFilePathFromMatch, resolveFilePath } = require('../utils/paths/getFullFilePath')
8
8
  const { findNestedVariables } = require('../utils/variables/findNestedVariables')
9
9
  const { makeBox } = require('@davidwells/box-logger')
10
- const { encodeJsSyntax } = require('../utils/encoders/js-fixes')
10
+ const { encodeJsSyntax, decodeJsonInVariable, hasEncodedJson } = require('../utils/encoders/js-fixes')
11
11
 
12
12
  /* File Parsers */
13
13
  const YAML = require('../parsers/yaml')
@@ -15,6 +15,29 @@ const TOML = require('../parsers/toml')
15
15
  const INI = require('../parsers/ini')
16
16
  const JSON5 = require('../parsers/json5')
17
17
 
18
+ /**
19
+ * Recursively clean encoded JSON from an object
20
+ * @param {*} obj - Object to clean
21
+ * @returns {*} Cleaned object
22
+ */
23
+ function cleanEncodedJson(obj) {
24
+ if (!obj) return obj
25
+ if (typeof obj === 'string') {
26
+ return decodeJsonInVariable(obj)
27
+ }
28
+ if (Array.isArray(obj)) {
29
+ return obj.map(cleanEncodedJson)
30
+ }
31
+ if (typeof obj === 'object') {
32
+ const cleaned = {}
33
+ for (const key of Object.keys(obj)) {
34
+ cleaned[key] = cleanEncodedJson(obj[key])
35
+ }
36
+ return cleaned
37
+ }
38
+ return obj
39
+ }
40
+
18
41
  /**
19
42
  * Parse file contents based on file extension
20
43
  * @param {string} content - Raw file contents
@@ -86,6 +109,17 @@ async function getValueFromFile(ctx, variableString, options) {
86
109
  matchedFileString = argsFound[0]
87
110
  argsToPass = argsFound.filter((arg, i) => {
88
111
  return i !== 0
112
+ }).map((arg) => {
113
+ // Decode base64-encoded JSON objects passed as args
114
+ if (hasEncodedJson(arg)) {
115
+ const decoded = decodeJsonInVariable(arg)
116
+ try {
117
+ return JSON.parse(decoded)
118
+ } catch (e) {
119
+ return decoded
120
+ }
121
+ }
122
+ return arg
89
123
  })
90
124
  }
91
125
  }
@@ -137,9 +171,8 @@ async function getValueFromFile(ctx, variableString, options) {
137
171
 
138
172
  ctx.fileRefsFound.push(fileRefEntry)
139
173
 
140
- let fileExtension = resolvedPath.split('.')
141
-
142
- fileExtension = fileExtension[fileExtension.length - 1].toLowerCase()
174
+ const fileExtParts = resolvedPath.split('.')
175
+ const fileExtension = fileExtParts[fileExtParts.length - 1].toLowerCase()
143
176
 
144
177
  // Validate file exists
145
178
  if (!exists) {
@@ -168,14 +201,14 @@ async function getValueFromFile(ctx, variableString, options) {
168
201
  const errorMsg = makeBox({
169
202
  title: `File Not Found in ${originalVar}`,
170
203
  minWidth: '100%',
171
- text: `Variable ${variableString} cannot resolve due to missing file.
204
+ content: `Variable ${variableString} cannot resolve due to missing file.
172
205
 
173
206
  File not found ${fullFilePath}
174
207
 
175
208
  Default fallback value will be used if provided.
176
209
 
177
210
  ${JSON.stringify(options.context, null, 2)}`,
178
- })
211
+ })
179
212
  console.log(errorMsg)
180
213
  }
181
214
  // TODO maybe reject. YAML does not allow for null/undefined values
@@ -197,11 +230,17 @@ ${JSON.stringify(options.context, null, 2)}`,
197
230
  return Promise.resolve(valueToPopulate)
198
231
  }
199
232
 
233
+ // Clean encoded JSON from currentConfig for cleaner context
234
+ const cleanedCurrentConfig = cleanEncodedJson(ctx.config)
235
+
200
236
  // Build context for executable files
201
237
  const valueForFunction = {
238
+ options: ctx.opts.options || {},
202
239
  originalConfig: ctx.originalConfig,
203
- config: ctx.config,
204
- opts: ctx.opts,
240
+ currentConfig: cleanedCurrentConfig,
241
+ argsToPass,
242
+ // maybe helper fns
243
+ // maybe the lib instance itself for nested lookups
205
244
  }
206
245
 
207
246
  // Process JS files
@@ -230,8 +269,14 @@ ${JSON.stringify(options.context, null, 2)}`,
230
269
  try {
231
270
  const tsFile = await executeTypeScriptFile(fullFilePath, { dynamicArgs: () => argsToPass })
232
271
  let returnValueFunction = tsFile.config || tsFile.default || tsFile
233
- if (moduleName) {
272
+ // For default export functions with :property syntax, keep the function and use deep properties
273
+ // For named exports (non-function module), look up the named export
274
+ let includeFirstProperty = false
275
+ if (moduleName && typeof returnValueFunction !== 'function') {
234
276
  returnValueFunction = tsFile[moduleName]
277
+ } else if (moduleName && typeof returnValueFunction === 'function') {
278
+ // Default export function with property access - include first property in path
279
+ includeFirstProperty = true
235
280
  }
236
281
 
237
282
  return processExecutableFile({
@@ -243,7 +288,8 @@ ${JSON.stringify(options.context, null, 2)}`,
243
288
  matchedFileString,
244
289
  relativePath,
245
290
  fileType: 'TypeScript',
246
- getDeeperValue: ctx.getDeeperValue
291
+ getDeeperValue: ctx.getDeeperValue,
292
+ includeFirstProperty
247
293
  })
248
294
  } catch (err) {
249
295
  return Promise.reject(new Error(`Error processing TypeScript file: ${err.message}`))
@@ -257,8 +303,14 @@ ${JSON.stringify(options.context, null, 2)}`,
257
303
  try {
258
304
  const esmFile = await executeESMFile(fullFilePath, { dynamicArgs: () => argsToPass })
259
305
  let returnValueFunction = esmFile.config || esmFile.default || esmFile
260
- if (moduleName) {
306
+ // For default export functions with :property syntax, keep the function and use deep properties
307
+ // For named exports (non-function module), look up the named export
308
+ let includeFirstProperty = false
309
+ if (moduleName && typeof returnValueFunction !== 'function') {
261
310
  returnValueFunction = esmFile[moduleName]
311
+ } else if (moduleName && typeof returnValueFunction === 'function') {
312
+ // Default export function with property access - include first property in path
313
+ includeFirstProperty = true
262
314
  }
263
315
 
264
316
  return processExecutableFile({
@@ -270,7 +322,8 @@ ${JSON.stringify(options.context, null, 2)}`,
270
322
  matchedFileString,
271
323
  relativePath,
272
324
  fileType: 'ESM',
273
- getDeeperValue: ctx.getDeeperValue
325
+ getDeeperValue: ctx.getDeeperValue,
326
+ includeFirstProperty
274
327
  })
275
328
  } catch (err) {
276
329
  return Promise.reject(new Error(`Error processing ESM file: ${err.message}`))
@@ -295,15 +348,15 @@ ${JSON.stringify(options.context, null, 2)}`,
295
348
  }
296
349
  // console.log('deep', variableString)
297
350
  // console.log('matchedFileString', matchedFileString)
298
- let deepProperties = variableString.replace(matchedFileString, '')
351
+ const deepPropertiesStr = variableString.replace(matchedFileString, '')
299
352
  // Support both : and . as the separator for sub properties
300
- const firstChar = deepProperties.substring(0, 1)
353
+ const firstChar = deepPropertiesStr.substring(0, 1)
301
354
  if (firstChar !== ':' && firstChar !== '.') {
302
355
  const errorMessage = `Invalid variable syntax when referencing file "${relativePath}" sub properties
303
- Please use ":" or "." to reference sub properties. ${deepProperties}`
356
+ Please use ":" or "." to reference sub properties. ${deepPropertiesStr}`
304
357
  return Promise.reject(new Error(errorMessage))
305
358
  }
306
- deepProperties = deepProperties.slice(1).split('.')
359
+ const deepProperties = deepPropertiesStr.slice(1).split('.')
307
360
  return ctx.getDeeperValue(deepProperties, valueToPopulate)
308
361
  }
309
362
 
@@ -360,13 +413,21 @@ function parseModuleReference(variableString, matchedFileString) {
360
413
  * Extracts deep properties from variable string after file match
361
414
  * @param {string} variableString - The full variable string
362
415
  * @param {string} matchedFileString - The matched file path portion
416
+ * @param {boolean} [includeFirstProperty=false] - Include first property (for default exports)
363
417
  * @returns {string[]} Array of property keys to traverse
364
418
  */
365
- function extractDeepProperties(variableString, matchedFileString) {
366
- let deepProperties = variableString.replace(matchedFileString, '')
367
- deepProperties = deepProperties.slice(1).split('.')
368
- deepProperties.splice(0, 1)
369
- return deepProperties.map((prop) => trim(prop))
419
+ function extractDeepProperties(variableString, matchedFileString, includeFirstProperty = false) {
420
+ const deepPropertiesStr = variableString.replace(matchedFileString, '')
421
+ if (!deepPropertiesStr || deepPropertiesStr === '') {
422
+ return []
423
+ }
424
+ const deepProperties = deepPropertiesStr.slice(1).split('.')
425
+ // For named exports, skip first property (it's the module name)
426
+ // For default exports, keep all properties
427
+ if (!includeFirstProperty) {
428
+ deepProperties.splice(0, 1)
429
+ }
430
+ return deepProperties.map((prop) => trim(prop)).filter(Boolean)
370
431
  }
371
432
 
372
433
  /**
@@ -381,6 +442,7 @@ function extractDeepProperties(variableString, matchedFileString) {
381
442
  * @param {string} params.relativePath - Relative file path for errors
382
443
  * @param {string} params.fileType - Type of file (javascript/TypeScript/ESM)
383
444
  * @param {Function} params.getDeeperValue - Function to resolve nested values
445
+ * @param {boolean} [params.includeFirstProperty=false] - Include first property in path (for default exports)
384
446
  * @returns {Promise<any>}
385
447
  */
386
448
  async function processExecutableFile({
@@ -392,7 +454,8 @@ async function processExecutableFile({
392
454
  matchedFileString,
393
455
  relativePath,
394
456
  fileType,
395
- getDeeperValue
457
+ getDeeperValue,
458
+ includeFirstProperty = false
396
459
  }) {
397
460
  if (typeof returnValueFunction !== 'function') {
398
461
  const errorMessage = `Invalid variable syntax when referencing file "${relativePath}".
@@ -400,10 +463,10 @@ Check if your ${fileType} is exporting a function that returns a value.`
400
463
  return Promise.reject(new Error(errorMessage))
401
464
  }
402
465
 
403
- const valueToPopulate = returnValueFunction.call(fileModule, valueForFunction, ...argsToPass)
466
+ const valueToPopulate = returnValueFunction.call(fileModule, ...argsToPass, valueForFunction)
404
467
 
405
468
  return Promise.resolve(valueToPopulate).then((valueToPopulateResolved) => {
406
- const deepProperties = extractDeepProperties(variableString, matchedFileString)
469
+ const deepProperties = extractDeepProperties(variableString, matchedFileString, includeFirstProperty)
407
470
  return getDeeperValue(deepProperties, valueToPopulateResolved).then((deepValueToPopulateResolved) => {
408
471
  if (typeof deepValueToPopulateResolved === 'undefined') {
409
472
  const errorMessage = `Invalid variable syntax when referencing file "${relativePath}".
@@ -10,13 +10,19 @@ const { findProjectRoot } = require('../utils/paths/findProjectRoot')
10
10
  const GIT_PREFIX = 'git'
11
11
  const gitVariableSyntax = RegExp(/^git:/g)
12
12
 
13
+ /**
14
+ * Execute a shell command
15
+ * @param {string} cmd - Command to execute
16
+ * @param {import('child_process').ExecOptions} [options] - Exec options
17
+ * @returns {Promise<string>}
18
+ */
13
19
  async function _exec(cmd, options = { timeout: 1000 }) {
14
20
  return new Promise((resolve, reject) => {
15
21
  childProcess.exec(cmd, options, (err, stdout) => {
16
22
  if (err) {
17
23
  return reject(err)
18
24
  }
19
- return resolve(stdout.trim())
25
+ return resolve(String(stdout).trim())
20
26
  })
21
27
  })
22
28
  }
@@ -213,8 +219,10 @@ const cache = new Map()
213
219
 
214
220
  /**
215
221
  * Gets the last Git commit timestamp for a file
216
- * @param {string} file - Path to the file to check
217
- * @returns {Promise<Date|undefined>} The commit timestamp or undefined if not in Git
222
+ * @param {string} _file - Path to the file to check
223
+ * @param {string} cwd - Working directory
224
+ * @param {boolean} [throwOnMissing] - Whether to throw on missing file
225
+ * @returns {Promise<string|undefined>} The commit timestamp ISO string or undefined if not in Git
218
226
  */
219
227
  async function getGitTimestamp(_file, cwd, throwOnMissing = true) {
220
228
  // Validate file path to prevent command injection
@@ -1,6 +1,9 @@
1
1
  const PAREN_OPEN_PLACEHOLDER = '__PH_PAREN_OPEN__'
2
2
  const OPEN_PAREN_PLACEHOLDER_PATTERN = /__PH_PAREN_OPEN__/g
3
3
 
4
+ const JSON_ENCODED_PREFIX = '__JSON_B64__'
5
+ const JSON_ENCODED_PATTERN = /__JSON_B64__([A-Za-z0-9+/=]+)__/g
6
+
4
7
  function encodeJsSyntax(value = '') {
5
8
  return value.replace(/\(/g, PAREN_OPEN_PLACEHOLDER)
6
9
  }
@@ -14,9 +17,50 @@ function hasParenthesesPlaceholder(value = '') {
14
17
  return OPEN_PAREN_PLACEHOLDER_PATTERN.test(value)
15
18
  }
16
19
 
20
+ /**
21
+ * Encode a JSON object to base64 for safe embedding in variable strings
22
+ * @param {object} obj - Object to encode
23
+ * @returns {string} Encoded string like __JSON_B64__eyJmb28iOiJiYXIifQ==__
24
+ */
25
+ function encodeJsonForVariable(obj) {
26
+ const jsonStr = JSON.stringify(obj)
27
+ const b64 = Buffer.from(jsonStr).toString('base64')
28
+ return `${JSON_ENCODED_PREFIX}${b64}__`
29
+ }
30
+
31
+ /**
32
+ * Decode base64-encoded JSON from variable strings
33
+ * @param {string} value - String potentially containing encoded JSON
34
+ * @returns {string} String with encoded JSON decoded back to JSON strings
35
+ */
36
+ function decodeJsonInVariable(value) {
37
+ if (!value || typeof value !== 'string') return value
38
+ return value.replace(JSON_ENCODED_PATTERN, (match, b64) => {
39
+ try {
40
+ const jsonStr = Buffer.from(b64, 'base64').toString('utf8')
41
+ return jsonStr
42
+ } catch (e) {
43
+ return match
44
+ }
45
+ })
46
+ }
47
+
48
+ /**
49
+ * Check if string contains encoded JSON
50
+ * @param {string} value - String to check
51
+ * @returns {boolean}
52
+ */
53
+ function hasEncodedJson(value) {
54
+ if (!value || typeof value !== 'string') return false
55
+ return value.includes(JSON_ENCODED_PREFIX)
56
+ }
57
+
17
58
  module.exports = {
18
59
  OPEN_PAREN_PLACEHOLDER_PATTERN,
19
60
  hasParenthesesPlaceholder,
20
61
  encodeJsSyntax,
21
62
  decodeJsSyntax,
63
+ encodeJsonForVariable,
64
+ decodeJsonInVariable,
65
+ hasEncodedJson,
22
66
  }
@@ -3,9 +3,10 @@
3
3
  */
4
4
  function mergeByKeys(data, path, keysToMerge) {
5
5
  if (!data) return {}
6
-
7
- const items = path.split('.').reduce((obj, key) => obj?.[key], data)
8
- if (!Array.isArray(items)) return {}
6
+
7
+ // Handle empty path - operate on root data
8
+ const items = path ? path.split('.').reduce((obj, key) => obj?.[key], data) : data
9
+ if (!Array.isArray(items)) return data
9
10
 
10
11
  const result = {}
11
12
  const mergeAll = !keysToMerge || !Array.isArray(keysToMerge) || keysToMerge.length === 0
@@ -31,12 +31,12 @@ function parseFileContents({ contents, filePath, varRegex, dynamicArgs }) {
31
31
 
32
32
  if (fileType.match(/\.(yml|yaml)/i)) {
33
33
  try {
34
- const ymlText = YAML.preProcess(contents, regex)
34
+ const ymlText = YAML.preProcess(contents)
35
35
  configObject = YAML.parse(ymlText)
36
36
  } catch (err) {
37
37
  // Attempt to fix cloudformation refs
38
38
  if (err.message.match(/YAMLException/)) {
39
- const ymlText = YAML.preProcess(contents, regex)
39
+ const ymlText = YAML.preProcess(contents)
40
40
  const result = YAML.load(ymlText, {
41
41
  filename: filePath,
42
42
  schema: cloudFormationSchema.schema,
@@ -82,6 +82,8 @@ function parseFileContents({ contents, filePath, varRegex, dynamicArgs }) {
82
82
  configObject = (typeof configObject.config === 'function') ? configObject.config(jsArgs) : configObject.config
83
83
  } else if (configObject.default) {
84
84
  configObject = (typeof configObject.default === 'function') ? configObject.default(jsArgs) : configObject.default
85
+ } else if (typeof configObject === 'function') {
86
+ configObject = configObject(jsArgs)
85
87
  }
86
88
  // console.log('parseFileContents configObject', configObject)
87
89
  } catch (err) {
@@ -40,7 +40,7 @@ function getFullPath(fileString, cwd) {
40
40
  * @param {string} matchedFileString - The matched file string (e.g., "file(path/to/file.js)")
41
41
  * @param {RegExp} syntax - The regex pattern used to match the file string (e.g., fileRefSyntax or textRefSyntax)
42
42
  * @param {string} configPath - The base directory path for resolving relative paths
43
- * @returns {{fullFilePath: string|null, resolvedPath: string}} - Object containing the resolved full file path and the resolved path (after alias resolution)
43
+ * @returns {{fullFilePath: string, resolvedPath: string, relativePath: string}} - Object containing the resolved full file path, resolved path (after alias resolution), and relative path
44
44
  */
45
45
  function resolveFilePathFromMatch(matchedFileString, syntax, configPath) {
46
46
  const relativePath = trimSurroundingQuotes(
@@ -36,6 +36,7 @@ function hasUnresolvedVars(str, variableSyntax) {
36
36
  * @param {object} context.config - Original config object
37
37
  * @param {string} context.configDir - Config file directory
38
38
  * @param {RegExp} context.variableSyntax - Variable syntax regex
39
+ * @param {object} [context.options] - CLI options
39
40
  * @returns {Promise<*>} Resolved value or undefined if can't pre-resolve
40
41
  */
41
42
  async function preResolveSingle(varString, context) {
@@ -43,8 +43,8 @@ function endChar(str, char) {
43
43
  /**
44
44
  * Ensures a value (string or array of strings) has quotes around it
45
45
  * @param {string|string[]} value - The value to quote
46
- * @param {string} open - Opening quote character (default: '"')
47
- * @param {string} close - Closing quote character (default: same as open)
46
+ * @param {string} [open] - Opening quote character (default: '"')
47
+ * @param {string} [close] - Closing quote character (default: same as open)
48
48
  * @returns {string|string[]} The quoted value(s)
49
49
  */
50
50
  function ensureQuote(value, open = '"', close) {
@@ -5,7 +5,7 @@ const { splitByComma } = require('./splitByComma')
5
5
  * NOTE: This is a simpler version that delegates to splitByComma for consistency.
6
6
  * For advanced use cases with bracket depth tracking and regex protection, use splitByComma directly.
7
7
  * @param {string} str - String to split
8
- * @param {string} splitter - Optional custom splitter (defaults to ',')
8
+ * @param {string} [splitter] - Optional custom splitter (defaults to ',')
9
9
  * @returns {string[]} Array of split strings
10
10
  */
11
11
  function splitCsv(str, splitter) {
@@ -2,10 +2,10 @@ const { makeHeader, logHeader : logHeaderBox } = require('@davidwells/box-logger
2
2
 
3
3
  function logHeader(message) {
4
4
  logHeaderBox({
5
- content: message,
6
- rightBorder: true,
7
- minWidth: 80,
8
- textStyle: 'bold',
5
+ content: message,
6
+ borderRight: true,
7
+ minWidth: 80,
8
+ fontStyle: 'bold',
9
9
  borderStyle: 'bold',
10
10
  borderColor: 'cyanBright',
11
11
  })
@@ -14,9 +14,9 @@ function isValidValue(val) {
14
14
  * Check if variable resolved to valid value, log warning if not
15
15
  * @param {string} variableString - The variable being resolved
16
16
  * @param {*} valueToPopulate - The resolved value
17
- * @param {object} options - Configuration options
18
- * @param {object} options.patterns - Regex patterns for variable types
19
- * @param {boolean} options.debug - Whether to log warnings
17
+ * @param {object} [options] - Configuration options
18
+ * @param {object} [options.patterns] - Regex patterns for variable types
19
+ * @param {boolean} [options.debug] - Whether to log warnings
20
20
  * @returns {*} The valueToPopulate unchanged
21
21
  */
22
22
  function warnIfNotFound(variableString, valueToPopulate, options = {}) {
@@ -338,10 +338,10 @@ function findNestedVariablesOld(input, regex, variablesKnownTypes, debug = false
338
338
 
339
339
  // Replace the `__REPLACED_${iteration - 1}__` with the original match
340
340
  matches = matches.map((match, index) => {
341
- const indexOfReplaced = match.varMatch.match(/__REPLACED_(\d+)__/)
341
+ const indexOfReplaced = match.fullMatch.match(/__REPLACED_(\d+)__/)
342
342
  if (indexOfReplaced) {
343
343
  const replacedIndex = parseInt(indexOfReplaced[1])
344
- match.varMatch = match.varMatch.replace(`__REPLACED_${replacedIndex}__`, matches[replacedIndex].variable)
344
+ match.fullMatch = match.fullMatch.replace(`__REPLACED_${replacedIndex}__`, matches[replacedIndex].variable)
345
345
  match.variable = match.variable.replace(`__REPLACED_${replacedIndex}__`, matches[replacedIndex].variable)
346
346
  }
347
347
  return match
package/types/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../cli.js"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ declare function _exports(string: string): string;
2
+ export = _exports;
3
+ //# sourceMappingURL=md5.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"md5.d.ts","sourceRoot":"","sources":["../../../src/functions/md5.js"],"names":[],"mappings":"AAOiB,kCAHL,MAAM,GACN,MAAM,CAOjB"}
@@ -0,0 +1,100 @@
1
+ declare namespace _exports {
2
+ export { ConfigoramaSettings, ConfigoramaResult };
3
+ }
4
+ declare function _exports<T = any>(configPathOrObject: string | any, settings?: ConfigoramaSettings): Promise<T | ConfigoramaResult<T>>;
5
+ declare namespace _exports {
6
+ export { Configorama };
7
+ export function sync<T = any>(configPathOrObject: string | any, settings?: ConfigoramaSettings): T;
8
+ export function analyze(configPathOrObject: string | object, settings?: object): Promise<any>;
9
+ export { parsers as format };
10
+ }
11
+ export = _exports;
12
+ type ConfigoramaSettings = {
13
+ /**
14
+ * - options to populate for ${opt:xyz}. These could be CLI flags
15
+ */
16
+ options?: {
17
+ [x: string]: any;
18
+ };
19
+ /**
20
+ * - Regex of variable syntax
21
+ */
22
+ syntax?: string;
23
+ /**
24
+ * - cwd of config. Needed if raw object passed in instead of file path
25
+ */
26
+ configDir?: string;
27
+ /**
28
+ * - array of custom variable sources
29
+ */
30
+ variableSources?: any[];
31
+ /**
32
+ * - Object of custom filters
33
+ */
34
+ filters?: {
35
+ [x: string]: Function;
36
+ };
37
+ /**
38
+ * - Object of custom functions
39
+ */
40
+ functions?: {
41
+ [x: string]: Function;
42
+ };
43
+ /**
44
+ * - allow unknown variables to pass through without throwing errors
45
+ */
46
+ allowUnknownVars?: boolean;
47
+ /**
48
+ * - allow undefined values to pass through without throwing errors
49
+ */
50
+ allowUndefinedValues?: boolean;
51
+ /**
52
+ * - values passed into .js config files if user using javascript config
53
+ */
54
+ dynamicArgs?: any | Function;
55
+ /**
56
+ * - return both config and metadata about variables found
57
+ */
58
+ returnMetadata?: boolean;
59
+ /**
60
+ * - keys to merge in arrays of objects
61
+ */
62
+ mergeKeys?: string[];
63
+ /**
64
+ * - map of file paths to override
65
+ */
66
+ filePathOverrides?: {
67
+ [x: string]: string;
68
+ };
69
+ };
70
+ type ConfigoramaResult<T = any> = {
71
+ /**
72
+ * - The variable syntax pattern used
73
+ */
74
+ variableSyntax: RegExp;
75
+ /**
76
+ * - Map of variable types found
77
+ */
78
+ variableTypes: {
79
+ [x: string]: any;
80
+ };
81
+ /**
82
+ * - The resolved configuration object
83
+ */
84
+ config: T;
85
+ /**
86
+ * - The original unresolved configuration
87
+ */
88
+ originalConfig: any;
89
+ /**
90
+ * - Metadata about variables found and resolved
91
+ */
92
+ metadata: any;
93
+ /**
94
+ * - Resolution history per path for debugging
95
+ */
96
+ resolutionHistory: any;
97
+ };
98
+ import Configorama = require("./main");
99
+ import parsers = require("./parsers");
100
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":";;;AAwCiB,0BALH,CAAC,4BACJ,MAAM,MAAO,aACb,mBAAmB,GACjB,OAAO,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAiD7C;;;IASqB,qBALR,CAAC,4BACJ,MAAM,MAAO,aACb,mBAAmB,GACjB,CAAC,CAgBb;IAQwB,4CAJb,MAAM,GAAC,MAAM,aACd,MAAM,gBAUhB;;;;;;;;;;;;;;aApHa,MAAM;;;;gBACN,MAAM;;;;;;;;;;;;;;;;;;;;uBAIN,OAAO;;;;2BACP,OAAO;;;;kBACP,cAAe;;;;qBACf,OAAO;;;;gBACP,MAAM,EAAE;;;;;;;;uBAKR,CAAC;;;;oBAED,MAAM;;;;;;;;;;YAEN,CAAC"}