configorama 0.9.13 → 0.9.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli.js CHANGED
@@ -225,7 +225,7 @@ configorama(inputFile, options)
225
225
  content: error.message,
226
226
  type: 'error',
227
227
  })
228
- console.log(errorMsg)
228
+ console.error(errorMsg)
229
229
  if (argv.debug) {
230
230
  console.error('error', error)
231
231
  }
package/index.d.ts CHANGED
@@ -124,6 +124,7 @@ declare namespace configorama {
124
124
  toml: any
125
125
  ini: any
126
126
  hcl: any
127
+ markdown: any
127
128
  }
128
129
 
129
130
  /** The Configorama class for advanced usage */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "configorama",
3
- "version": "0.9.13",
3
+ "version": "0.9.15",
4
4
  "description": "Variable support for configuration files",
5
5
  "main": "src/index.js",
6
6
  "types": "index.d.ts",
package/src/main.js CHANGED
@@ -94,15 +94,15 @@ const deepPrefixReplacePattern = /(?:^deep:)\d+\.?/g
94
94
  // TODO update file regex ^file\((~?[a-zA-Z0-9._\-\/, ]+?)\)
95
95
  // To match file(asyncValue.js, lol) input params
96
96
  const selfRefSyntax = RegExp(/^self:/g)
97
- const base64WrapperRegex = /\[_\[([A-Za-z0-9+/=\s]*)\]_\]/g
98
97
  const logLines = '─────────────────────────────────────────────────'
98
+ const evalIfPattern = /\b(eval|if)\s*\(/
99
+ const functionPrefixPattern = /^> function /
99
100
 
100
101
  let DEBUG = process.argv.includes('--debug') ? true : false
101
102
  let VERBOSE = process.argv.includes('--verbose') ? true : false
102
103
  let SETUP_MODE = process.argv.includes('--setup') ? true : false
103
104
  // DEBUG = true
104
105
  let DEBUG_TYPE = false
105
- const ENABLE_FUNCTIONS = true
106
106
 
107
107
  class Configorama {
108
108
  constructor(fileOrObject, opts) {
@@ -562,7 +562,6 @@ class Configorama {
562
562
  }
563
563
  return assign({}, value, otherValue)
564
564
  },
565
- math: () => {},
566
565
  upperKeys: (o) => {
567
566
  return Object.keys(o).reduce((c, k) => ((c[k.toUpperCase()] = o[k]), c), {}) // eslint-disable-line
568
567
  },
@@ -1235,8 +1234,7 @@ class Configorama {
1235
1234
 
1236
1235
  /* Exit early if list or info flag is set */
1237
1236
  if (showFoundVariables) {
1238
- // TODO re-enable this
1239
- // process.exit(0)
1237
+ return Promise.resolve(this.config)
1240
1238
  }
1241
1239
  }
1242
1240
 
@@ -1262,7 +1260,7 @@ class Configorama {
1262
1260
  }
1263
1261
  const stage = cliOpts.stage || providerStage || process.env.NODE_ENV || 'dev'
1264
1262
  /* Load env variables into process.env */
1265
- const values = require('env-stage-loader')({
1263
+ require('env-stage-loader')({
1266
1264
  // silent: true,
1267
1265
  // debug: true,
1268
1266
  env: stage,
@@ -1311,7 +1309,7 @@ class Configorama {
1311
1309
  if (typeof rawValue === 'string') {
1312
1310
  // console.log('rawValue', rawValue)
1313
1311
  /* Process inline functions like merge() */
1314
- if (ENABLE_FUNCTIONS && rawValue.match(/> function /)) {
1312
+ if (rawValue.match(functionPrefixPattern)) {
1315
1313
  // console.log('RAW FUNCTION', rawFunction)
1316
1314
  const funcString = rawValue.replace(/> function /g, '')
1317
1315
  // console.log('funcString', funcString)
@@ -2152,9 +2150,6 @@ class Configorama {
2152
2150
 
2153
2151
  historyEntry.match = matches[i].match
2154
2152
  historyEntry.variable = matches[i].variable
2155
- if (historyEntry.resultType === 'string' && historyEntry.result.match(/^>passthrough\[/)) {
2156
- historyEntry.variableType = 'encodedUnknown'
2157
- }
2158
2153
  if (resolverType) {
2159
2154
  historyEntry.variableType = resolverType
2160
2155
  }
@@ -2167,6 +2162,9 @@ class Configorama {
2167
2162
  }
2168
2163
 
2169
2164
  historyEntry.resultType = typeof finalResult
2165
+ if (historyEntry.resultType === 'string' && typeof cleanResult === 'string' && cleanResult.match(/^>passthrough\[/)) {
2166
+ historyEntry.variableType = 'encodedUnknown'
2167
+ }
2170
2168
  historyEntry.valueBeforeResolution = valueBeforeResolution
2171
2169
  historyEntry.from = 'renderMatches'
2172
2170
  if (isDeepResult) {
@@ -2383,7 +2381,7 @@ class Configorama {
2383
2381
  }
2384
2382
  }
2385
2383
 
2386
- const originalSrc = valueObject.originalSource || ''
2384
+ const originalSrc = (typeof valueObject.originalSource === 'string') ? valueObject.originalSource : ''
2387
2385
  const hasFilters = originalSrc.match(this.filterMatch)
2388
2386
  let foundFilters = []
2389
2387
  if (hasFilters) {
@@ -2485,7 +2483,7 @@ class Configorama {
2485
2483
 
2486
2484
  // For eval/if expressions, string values need quotes unless already quoted
2487
2485
  // BUT don't quote strings that contain variable refs (they need further resolution)
2488
- if (/\b(eval|if)\s*\(/.test(property) && !valueToPopulate.match(this.variableSyntax)) {
2486
+ if (evalIfPattern.test(property) && !valueToPopulate.match(this.variableSyntax)) {
2489
2487
  const matchIdx = property.indexOf(currentMatchedString)
2490
2488
  const charBefore = matchIdx > 0 ? property[matchIdx - 1] : ''
2491
2489
  // Always escape quotes in values for eval/if context
@@ -2513,7 +2511,7 @@ class Configorama {
2513
2511
  if (DEBUG_TYPE) console.log('DEBUG_TYPE isObject')
2514
2512
 
2515
2513
  // For eval/if expressions, encode objects to avoid {} breaking variable syntax
2516
- const isEvalOrIf = /\b(eval|if)\s*\(/.test(property)
2514
+ const isEvalOrIf = evalIfPattern.test(property)
2517
2515
  if (isEvalOrIf) {
2518
2516
  const encoded = encodeValueForEval(valueToPopulate)
2519
2517
  property = replaceAll(matchedString, encoded, property)
@@ -2550,12 +2548,12 @@ class Configorama {
2550
2548
  // console.log('other new prop', property)
2551
2549
 
2552
2550
  // partial replacement, boolean inside eval/if expressions
2553
- } else if (typeof valueToPopulate === 'boolean' && /\b(eval|if)\s*\(/.test(property)) {
2551
+ } else if (typeof valueToPopulate === 'boolean' && evalIfPattern.test(property)) {
2554
2552
  if (DEBUG_TYPE) console.log('DEBUG_TYPE isBoolean in eval/if')
2555
2553
  property = replaceAll(matchedString, String(valueToPopulate), property)
2556
2554
 
2557
2555
  // partial replacement, null inside eval/if expressions
2558
- } else if (valueToPopulate === null && /\b(eval|if)\s*\(/.test(property)) {
2556
+ } else if (valueToPopulate === null && evalIfPattern.test(property)) {
2559
2557
  if (DEBUG_TYPE) console.log('DEBUG_TYPE isNull in eval/if')
2560
2558
  property = replaceAll(matchedString, '__NULL__', property)
2561
2559
 
@@ -2655,13 +2653,13 @@ Missing Value ${missingValue} - ${matchedString}
2655
2653
  }
2656
2654
 
2657
2655
  // console.log('prop', prop)
2658
- if (property.match(/^> function /g) && prop) {
2656
+ if (property.match(functionPrefixPattern) && prop) {
2659
2657
  // console.log('func prop', property)
2660
2658
  // console.log('Prop', prop)
2661
2659
  }
2662
2660
  const func = funcRegex.exec(property)
2663
2661
  // console.log('func', func)
2664
- if (func && property.match(/^> function /g)) {
2662
+ if (func && property.match(functionPrefixPattern)) {
2665
2663
  /* IMPORTANT fix `finalProp` for nested function reference
2666
2664
  nestedOne: 'hi'
2667
2665
  nestedTwo: ${merge('nice', 'wow')}
@@ -2712,7 +2710,7 @@ Missing Value ${missingValue} - ${matchedString}
2712
2710
  /* if matches function signature like ${merge('foo', 'bar')}
2713
2711
  rewrite the variable to run the function after inputs resolved
2714
2712
  */
2715
- const rep = property.replace(/^> function /g, '')
2713
+ const rep = property.replace(functionPrefixPattern, '')
2716
2714
  property = `> function ${rep}`
2717
2715
  }
2718
2716
  // if (prop.match(/\s\|/)) {
@@ -3624,7 +3622,7 @@ Missing Value ${missingValue} - ${matchedString}
3624
3622
  return variableString
3625
3623
  }
3626
3624
  // console.log('runFunction', variableString)
3627
- var hasFunc = funcRegex.exec(variableString)
3625
+ const hasFunc = funcRegex.exec(variableString)
3628
3626
  // TODO finish Function handling. Need to move this down below resolver to resolve inner refs first
3629
3627
  // console.log('hasFunc', hasFunc)
3630
3628
  // Skip special expressions (cron, eval, if) - these aren't user functions
@@ -1,3 +1,5 @@
1
+ // Resolves values from process.env environment variables
2
+ // Matches ${env:VAR_NAME} syntax with optional fallback values
1
3
 
2
4
  const envRefSyntax = RegExp(/^env:/g)
3
5
 
@@ -13,12 +15,7 @@ Example: \${env:MY_ENV_VAR}
13
15
  `)
14
16
  }
15
17
 
16
- let valueToPopulate
17
- if (requestedEnvVar !== '' || '' in process.env) {
18
- valueToPopulate = process.env[requestedEnvVar]
19
- } else {
20
- valueToPopulate = process.env
21
- }
18
+ const valueToPopulate = process.env[requestedEnvVar]
22
19
  return Promise.resolve(valueToPopulate)
23
20
  }
24
21
 
@@ -121,9 +121,9 @@ async function getValueFromFile(ctx, variableString, options) {
121
121
 
122
122
  // Get function input params if any supplied https://regex101.com/r/qlNFVm/1
123
123
  // var funcParamsRegex = /(\w+)\s*\(((?:[^()]+)*)?\s*\)\s*/g
124
- var funcParamsRegex = /(\w+)\s*\(((?:[^()]+)*)?\s*\)/g
124
+ const funcParamsRegex = /(\w+)\s*\(((?:[^()]+)*)?\s*\)/g
125
125
  // tighter (?<![.\w-])\b(\w+)\s*\(((?:[^()]+)*)?\s*\)\s*
126
- var hasParams = funcParamsRegex.exec(matchedFileString)
126
+ const hasParams = funcParamsRegex.exec(matchedFileString)
127
127
 
128
128
  let argsToPass = []
129
129
  if (hasParams) {
@@ -257,8 +257,8 @@ ${JSON.stringify(options.context, null, 2)}`,
257
257
  const variableFileContents = fs.readFileSync(fullFilePath, 'utf-8')
258
258
 
259
259
  /* handle case for referencing raw JS files to inline them */
260
- if (argsToPass.length
261
- && (argsToPass && argsToPass[0] && typeof argsToPass[0] === 'string' && argsToPass[0].toLowerCase() === 'raw')
260
+ if ((argsToPass.length
261
+ && argsToPass[0] && typeof argsToPass[0] === 'string' && argsToPass[0].toLowerCase() === 'raw')
262
262
  || opts.asRawText
263
263
  ) {
264
264
  // Encode foo() to foo__PH_PAREN_OPEN__) to avoid function collisions
@@ -10,6 +10,21 @@ const { findProjectRoot } = require('../utils/paths/findProjectRoot')
10
10
  const GIT_PREFIX = 'git'
11
11
  const gitVariableSyntax = RegExp(/^git:/g)
12
12
 
13
+ /**
14
+ * Check if a directory is inside a git repository.
15
+ * @param {string} [dir] - Directory to check (defaults to process.cwd())
16
+ * @returns {boolean}
17
+ */
18
+ function isGitRepo(dir) {
19
+ const start = dir || process.cwd()
20
+ try {
21
+ if (!fs.existsSync(start)) return false
22
+ return findProjectRoot(start) !== null
23
+ } catch (err) {
24
+ return false
25
+ }
26
+ }
27
+
13
28
  /**
14
29
  * Execute a shell command
15
30
  * @param {string} cmd - Command to execute
@@ -45,6 +60,25 @@ async function _execFile(command, args, options = { timeout: 1000 }) {
45
60
  })
46
61
  }
47
62
 
63
+ /**
64
+ * Run a git command and return undefined on failure. This lets the variable
65
+ * resolver fall through to user-provided fallbacks (e.g. `${git:branch, "main"}`)
66
+ * when not in a git repo, without surfacing raw `fatal: not a git repository`
67
+ * errors. When no fallback is provided, the outer resolver in main.js still
68
+ * produces a clear "Unable to resolve config variable" error pointing at the
69
+ * exact config path.
70
+ *
71
+ * @param {() => Promise<string>} cmdFn - Function that runs the git command
72
+ * @returns {Promise<string|undefined>}
73
+ */
74
+ async function _safeGit(cmdFn) {
75
+ try {
76
+ return await cmdFn()
77
+ } catch (err) {
78
+ return undefined
79
+ }
80
+ }
81
+
48
82
  // TODO denote computed fields in metadata
49
83
  /*
50
84
  {
@@ -83,14 +117,21 @@ function createResolver(cwd) {
83
117
  const variable = variableString.split(`${GIT_PREFIX}:`)[1]
84
118
  let value = null
85
119
  // console.log('createResolver variableString', variableString)
120
+
121
+ // If we're not inside a git repository, every git: variable resolves to
122
+ // undefined. This lets fallbacks like `${git:branch, "main"}` work, and
123
+ // when there's no fallback the outer resolver throws a clear "Unable to
124
+ // resolve config variable" error pointing at the config path.
125
+ if (!isGitRepo(cwd)) {
126
+ return undefined
127
+ }
128
+
86
129
  if (variable.match(/^remote/i)) {
87
130
  const hasParams = functionRegex.exec(variableString)
88
131
  const remoteName = (hasParams && hasParams[2]) ? formatFunctionArgs(hasParams[2]) : 'origin'
89
- value = await getGitRemote(remoteName)
90
- return value
132
+ return _safeGit(() => getGitRemote(remoteName))
91
133
  }
92
134
 
93
- const verifyMsg = `Verify the cwd has a .git directory\n`
94
135
  const normalizedVar = (variable || '').toLowerCase()
95
136
  // console.log('normalizedVar', normalizedVar)
96
137
 
@@ -100,7 +141,7 @@ function createResolver(cwd) {
100
141
  const funcName = argsMatch[1]
101
142
  const args = argsMatch[2]
102
143
  if (funcName === 'timestamp' && args) {
103
- value = await getGitTimestamp(args, cwd)
144
+ value = await getGitTimestamp(args, cwd, false)
104
145
  }
105
146
  }
106
147
 
@@ -109,55 +150,61 @@ function createResolver(cwd) {
109
150
  case GIT_KEYS.repo:
110
151
  case 'repository':
111
152
  case 'reposlug':
112
- case 'repo-slug':
113
- const urla = await getGitRemote()
153
+ case 'repo-slug': {
154
+ const urla = await _safeGit(() => getGitRemote())
155
+ if (!urla) return undefined
114
156
  const parseda = GitUrlParse(urla)
115
157
  value = parseda.full_name
116
- break;
158
+ break
159
+ }
117
160
  // Repo name
118
161
  case GIT_KEYS.name:
119
162
  case 'reponame': // repoName
120
- case 'repo-name':
121
- value = await _exec('basename `git rev-parse --show-toplevel`')
122
- break;
163
+ case 'repo-name': {
164
+ const toplevel = await _safeGit(() => _execFile('git', ['rev-parse', '--show-toplevel']))
165
+ if (!toplevel) return undefined
166
+ value = path.basename(toplevel)
167
+ break
168
+ }
123
169
  // Repo org or owner
124
170
  case GIT_KEYS.org:
125
171
  case 'owner':
126
172
  case 'organization':
127
173
  case 'repoowner': // repoOwner
128
- case 'repo-owner':
129
- const url = await getGitRemote()
174
+ case 'repo-owner': {
175
+ const url = await _safeGit(() => getGitRemote())
176
+ if (!url) return undefined
130
177
  const parsed = GitUrlParse(url)
131
178
  value = parsed.organization || parsed.owner
132
- break;
179
+ break
180
+ }
133
181
  // Repo name
134
182
  case GIT_KEYS.dir:
135
183
  case 'directory':
136
184
  case 'dirpath': // dirPath
137
185
  case 'dir-path':
138
- case 'dir_path':
139
- const gitBasePath = await _exec('git rev-parse --show-toplevel')
186
+ case 'dir_path': {
187
+ const gitBasePath = await _safeGit(() => _execFile('git', ['rev-parse', '--show-toplevel']))
188
+ if (!gitBasePath) return undefined
140
189
  if (cwd) {
141
190
  const subPath = cwd.replace(gitBasePath, '')
142
- const branch = await _exec('git rev-parse --abbrev-ref HEAD')
143
- const url = await getGitRemote()
144
- value = (subPath) ? `${url}/tree/${branch}${subPath}` : url
191
+ const branch = await _safeGit(() => _execFile('git', ['rev-parse', '--abbrev-ref', 'HEAD']))
192
+ const url = await _safeGit(() => getGitRemote())
193
+ if (!url) return undefined
194
+ value = (subPath && branch) ? `${url}/tree/${branch}${subPath}` : url
145
195
  }
146
- break;
196
+ break
197
+ }
147
198
  // Repo url
148
199
  case GIT_KEYS.url:
149
200
  case 'repourl': // repoUrl
150
201
  case 'repo-url':
151
- value = await getGitRemote()
152
- break;
202
+ value = await _safeGit(() => getGitRemote())
203
+ break
153
204
  // Current commit sha
154
205
  case 'sha':
155
206
  case 'sha1':
156
- try {
157
- value = await _exec('git rev-parse --short HEAD')
158
- } catch (err) {
159
- throw new Error(`\${git:sha1} error ${verifyMsg}`)
160
- }
207
+ value = await _safeGit(() => _execFile('git', ['rev-parse', '--short', 'HEAD']))
161
208
  break
162
209
  // Current commit full sha
163
210
  case GIT_KEYS.commit:
@@ -165,11 +212,7 @@ function createResolver(cwd) {
165
212
  case 'commit-sha':
166
213
  case 'commithash':
167
214
  case 'commit-hash':
168
- try {
169
- value = await _exec('git rev-parse HEAD')
170
- } catch (err) {
171
- throw new Error(`\${git:commit} error. ${verifyMsg}`)
172
- }
215
+ value = await _safeGit(() => _execFile('git', ['rev-parse', 'HEAD']))
173
216
  break
174
217
  // Branches
175
218
  case GIT_KEYS.branch:
@@ -177,11 +220,7 @@ function createResolver(cwd) {
177
220
  case 'branch-name':
178
221
  case 'currentbranch': // currentBranch
179
222
  case 'current-branch':
180
- try {
181
- value = await _exec('git rev-parse --abbrev-ref HEAD')
182
- } catch (err) {
183
- throw new Error(`\${git:branch} error. ${verifyMsg}`)
184
- }
223
+ value = await _safeGit(() => _execFile('git', ['rev-parse', '--abbrev-ref', 'HEAD']))
185
224
  break
186
225
  // Commit msg
187
226
  case GIT_KEYS.message:
@@ -190,42 +229,36 @@ function createResolver(cwd) {
190
229
  case 'commit-message':
191
230
  case 'commitmsg': // commitMsg
192
231
  case 'commit-msg':
193
- try {
194
- value = await _exec('git log -1 --pretty=%B')
195
- } catch (err) {
196
- throw new Error(`\${git:message} error. ${verifyMsg}`)
197
- }
198
- break;
232
+ value = await _safeGit(() => _execFile('git', ['log', '-1', '--pretty=%B']))
233
+ break
199
234
  // Git tags
200
235
  case GIT_KEYS.tag:
201
236
  case 'describe':
202
- try {
203
- value = await _exec('git describe --always')
204
- } catch (err) {
205
- throw new Error(`\${git:describeLight} error. ${verifyMsg}`)
206
- }
207
- break;
237
+ value = await _safeGit(() => _execFile('git', ['describe', '--always']))
238
+ break
208
239
  // Git tags
209
240
  case 'describeLight':
210
241
  case 'describelight':
211
242
  case 'describe-light':
212
- try {
213
- value = await _exec('git describe --always --tags')
214
- } catch (err) {
215
- throw new Error(`\${git:describeLight} error. ${verifyMsg}`)
216
- }
217
- break;
243
+ value = await _safeGit(() => _execFile('git', ['describe', '--always', '--tags']))
244
+ break
218
245
  // Is branch dirty
219
246
  case 'isDirty':
220
247
  case 'isdirty':
221
- case 'is-dirty':
222
- const writeTree = await _exec('git write-tree')
223
- const changes = await _exec(`git diff-index ${writeTree} --`)
248
+ case 'is-dirty': {
249
+ const writeTree = await _safeGit(() => _execFile('git', ['write-tree']))
250
+ if (!writeTree) return undefined
251
+ const changes = await _safeGit(() => _execFile('git', ['diff-index', writeTree.trim(), '--']))
252
+ if (changes === undefined) return undefined
224
253
  value = `${changes.length > 0}`
225
254
  break
255
+ }
226
256
  default:
227
257
  if (!value) {
228
- throw new Error(`Git variable ${variable} is unknown. Candidates are 'describe', 'describeLight', 'sha1', 'commit', 'branch', 'message', 'repository'`)
258
+ // Unknown variable name (likely a typo). This is a config error,
259
+ // not an environment one, so throw a helpful message listing the
260
+ // valid keys.
261
+ throw new Error(`Git variable "${variable}" is unknown. Valid options: ${Object.values(GIT_KEYS).join(', ')}`)
229
262
  }
230
263
  }
231
264
  return value
@@ -299,14 +332,19 @@ async function getGitTimestamp(_file, cwd, throwOnMissing = true) {
299
332
  }
300
333
  }
301
334
 
335
+ const remoteCache = new Map()
336
+
302
337
  async function getGitRemote(name = 'origin') {
303
- const remoteValues = await _exec('git remote -v')
338
+ if (remoteCache.has(name)) {
339
+ return remoteCache.get(name)
340
+ }
341
+ const remoteValues = await _execFile('git', ['remote', '-v'])
304
342
  const remotes = remoteValues.toString().split(os.EOL)
305
343
  .filter(function filterOnlyFetchRows(remote) {
306
344
  return remote.match('(fetch)')
307
345
  })
308
346
  .map(function mapRemoteLineToObject(remote) {
309
- var parts = remote.split('\t')
347
+ const parts = remote.split('\t')
310
348
  if (parts.length < 2) {
311
349
  return
312
350
  }
@@ -326,7 +364,6 @@ async function getGitRemote(name = 'origin') {
326
364
 
327
365
  if (!originUrl) {
328
366
  throw new Error(`No git remote "${name}" found. Please double check your remote names`)
329
- return
330
367
  }
331
368
  // console.log('originUrl', originUrl)
332
369
  const parsed = GitUrlParse(originUrl)
@@ -334,7 +371,9 @@ async function getGitRemote(name = 'origin') {
334
371
  // @TODO finish git api
335
372
  // console.log('parsed', parsed)
336
373
  if (parsed && parsed.source && parsed.full_name) {
337
- return `https://${parsed.source}/${parsed.full_name}`
374
+ const result = `https://${parsed.source}/${parsed.full_name}`
375
+ remoteCache.set(name, result)
376
+ return result
338
377
  }
339
378
  }
340
379
 
@@ -1,14 +1,10 @@
1
-
1
+ // Resolves values from CLI option flags
2
+ // Matches ${opt:FLAG_NAME} syntax with optional fallback values
2
3
  const optRefSyntax = RegExp(/^opt:/g)
3
4
 
4
5
  function getValueFromOptions(variableString, options) {
5
6
  const requestedOption = variableString.split(':')[1]
6
- let valueToPopulate
7
- if (requestedOption !== '' || '' in options) {
8
- valueToPopulate = options[requestedOption]
9
- } else {
10
- valueToPopulate = options
11
- }
7
+ const valueToPopulate = options[requestedOption]
12
8
  return Promise.resolve(valueToPopulate)
13
9
  }
14
10
 
@@ -1,4 +1,5 @@
1
-
1
+ // Resolves values from named parameters
2
+ // Matches ${param:KEY} syntax with optional fallback values
2
3
  const paramRefSyntax = RegExp(/^param:/g)
3
4
 
4
5
  /**
@@ -67,34 +67,34 @@ function mapValues(obj, fn) {
67
67
  */
68
68
  function set(object, path, value) {
69
69
  if (object === null || typeof object !== 'object') {
70
- return object;
70
+ return object
71
71
  }
72
-
72
+
73
73
  const keys = Array.isArray(path) ? path : String(path)
74
74
  .split('.')
75
75
  .map(key => {
76
- const numKey = Number(key);
77
- return Number.isInteger(numKey) && numKey >= 0 ? numKey : key;
78
- });
79
-
80
- let current = object;
81
- const lastIndex = keys.length - 1;
82
-
76
+ const numKey = Number(key)
77
+ return Number.isInteger(numKey) && numKey >= 0 ? numKey : key
78
+ })
79
+
80
+ let current = object
81
+ const lastIndex = keys.length - 1
82
+
83
83
  for (let i = 0; i < lastIndex; i++) {
84
84
  const key = keys[i]
85
-
85
+
86
86
  // Check if value is undefined, null, or not an object (primitives can't have properties)
87
87
  if (current[key] == null || typeof current[key] !== 'object') {
88
88
  // Create appropriate container based on next key type
89
89
  const nextKey = keys[i + 1]
90
90
  current[key] = Number.isInteger(nextKey) && /** @type {number} */ (nextKey) >= 0 ? [] : {}
91
91
  }
92
-
92
+
93
93
  current = current[key]
94
94
  }
95
-
96
- current[keys[lastIndex]] = value;
97
- return object;
95
+
96
+ current[keys[lastIndex]] = value
97
+ return object
98
98
  }
99
99
 
100
100
  // Cache for trim regex patterns (perf: avoid recompilation)
@@ -107,18 +107,18 @@ const trimRegexCache = new Map()
107
107
  */
108
108
  function trim(string, chars) {
109
109
  if (string === null || string === undefined) {
110
- return '';
110
+ return ''
111
111
  }
112
112
 
113
- string = String(string);
113
+ string = String(string)
114
114
 
115
115
  if (!chars && String.prototype.trim) {
116
- return string.trim();
116
+ return string.trim()
117
117
  }
118
118
 
119
119
  if (!chars) {
120
120
  // Default characters to trim (whitespace)
121
- chars = ' \t\n\r\f\v\u00a0\u1680\u2000\u200a\u2028\u2029\u202f\u205f\u3000\ufeff';
121
+ chars = ' \t\n\r\f\v\u00a0\u1680\u2000\u200a\u2028\u2029\u202f\u205f\u3000\ufeff'
122
122
  }
123
123
 
124
124
  // Check cache first
@@ -132,7 +132,7 @@ function trim(string, chars) {
132
132
 
133
133
  // Reset lastIndex for global regex reuse
134
134
  pattern.lastIndex = 0
135
- return string.replace(pattern, '');
135
+ return string.replace(pattern, '')
136
136
  }
137
137
 
138
138
  module.exports = {
@@ -103,7 +103,7 @@ function parseFileContents({ contents, filePath, varRegex, dynamicArgs }) {
103
103
  configObject = jsFile(jsArgs)
104
104
  }
105
105
  } catch (err) {
106
- throw new Error(err)
106
+ throw err
107
107
  }
108
108
  } else if (fileType.match(/\.(ts|tsx|mts|cts)/i)) {
109
109
  try {