configorama 0.10.2 → 0.10.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/README.md CHANGED
@@ -1667,7 +1667,7 @@ const config = await configorama('config.yml', { syntax })
1667
1667
  |---|---|---|---|
1668
1668
  | `prefix` | `string` | `'${'` | Opening delimiter |
1669
1669
  | `suffix` | `string` | `'}'` | Closing delimiter |
1670
- | `excludePatterns` | `string[]` | `['AWS', 'stageVariables']` | Patterns to exclude via negative lookahead (so e.g. `${AWS::Region}` is left untouched by CloudFormation users) |
1670
+ | `excludePatterns` | `string[]` | `['AWS', 'aws:', 'stageVariables']` | Patterns to exclude via negative lookahead (so e.g. `${AWS::Region}` and `${aws:username}` are left untouched by CloudFormation users) |
1671
1671
 
1672
1672
  ---
1673
1673
 
@@ -1762,7 +1762,7 @@ buildVariableSyntax('<', '>') // <env:FOO>
1762
1762
  function buildVariableSyntax(
1763
1763
  prefix: string = '${',
1764
1764
  suffix: string = '}',
1765
- excludePatterns: string[] = ['AWS', 'stageVariables']
1765
+ excludePatterns: string[] = ['AWS', 'aws:', 'stageVariables']
1766
1766
  ): string
1767
1767
  ```
1768
1768
 
@@ -1891,6 +1891,9 @@ const config = await configorama(configFile, {
1891
1891
  | `allowUnknownVariableTypes` | `boolean \| string[]` | `false` | Allow unknown variable types to pass through |
1892
1892
  | `allowUnresolvedVariables` | `boolean \| string[]` | `false` | Allow known types that can't resolve to pass through |
1893
1893
  | `allowUndefinedValues` | `boolean` | `false` | Allow undefined as a valid end result |
1894
+ | `ignorePaths` | `string[]` | Built-in CloudFormation/code paths | Glob-like config paths whose values should be left verbatim |
1895
+ | `skipResolutionPaths` | `string[]` | `[]` | Alias for `ignorePaths` |
1896
+ | `disableDefaultIgnorePaths` | `boolean` | `false` | Disable the built-in CloudFormation/code ignore paths |
1894
1897
  | `returnMetadata` | `boolean` | `false` | Return `{ config, metadata }` instead of just the resolved config |
1895
1898
  | `returnPreResolvedVariableDetails` | `boolean` | `false` | Return metadata about variables *without* resolving them (used by `analyze()`) |
1896
1899
  | `useDotEnvFiles` | `boolean` | `false` | Auto-load `.env`, `.env.{stage}`, etc. into `process.env` before resolution (via [env-stage-loader](https://www.npmjs.com/package/env-stage-loader)) |
@@ -2084,8 +2087,14 @@ configorama config.yml --info
2084
2087
  # Verify config (check for errors without resolving)
2085
2088
  configorama config.yml --verify
2086
2089
 
2087
- # Extract specific path from config
2088
- configorama config.yml database.host
2090
+ # Extract a specific path from config
2091
+ configorama config.yml .database.host
2092
+
2093
+ # Print an extracted scalar without JSON quotes
2094
+ configorama config.yml .database.host --raw
2095
+
2096
+ # Copy the formatted output to your clipboard
2097
+ configorama config.yml .database.host --raw --copy
2089
2098
 
2090
2099
  # Output as YAML
2091
2100
  configorama config.yml --format yaml
@@ -2102,6 +2111,8 @@ Options:
2102
2111
  -v, --version Show version number
2103
2112
  -o, --output <file> Write output to file instead of stdout
2104
2113
  -f, --format <format> Output format: json, yaml, or js (default: json)
2114
+ -r, --raw Print extracted scalar values without JSON quoting
2115
+ -c, --copy Copy the formatted output to the clipboard
2105
2116
  -d, --debug Enable debug mode
2106
2117
  -i, --info Show info about the config
2107
2118
  -V, --verify Verify the config
@@ -2110,10 +2121,24 @@ Options:
2110
2121
  --allow-undefined Allow undefined values in the final output
2111
2122
 
2112
2123
  Path Extraction:
2113
- configorama config.yml database.host Extract specific value
2114
- configorama config.yml functions[0] Extract from array
2124
+ configorama config.yml .database.host Extract a nested value
2125
+ configorama config.yml '.functions[0]' Extract from an array
2126
+ configorama -r config.yml .stage Print raw scalar output
2127
+ configorama -r -c config.yml .stage Print and copy raw scalar output
2115
2128
  ```
2116
2129
 
2130
+ Path extraction uses jq-style paths. JSON remains the default output format, so extracted strings are quoted by default:
2131
+
2132
+ ```bash
2133
+ configorama config.yml .stage
2134
+ # "prod"
2135
+
2136
+ configorama config.yml .stage --raw
2137
+ # prod
2138
+ ```
2139
+
2140
+ `--copy` copies exactly the formatted value that the CLI prints. It uses native clipboard commands where available: `pbcopy` on macOS, `clip` on Windows, and `wl-copy`, `xclip`, or `xsel` on Linux.
2141
+
2117
2142
  ### CLI Examples
2118
2143
 
2119
2144
  **Basic resolution:**
@@ -2151,12 +2176,20 @@ database:
2151
2176
  host: localhost
2152
2177
  port: 5432
2153
2178
 
2154
- # Extract database.host
2155
- configorama config.yml database.host
2179
+ # Extract database.host as JSON
2180
+ configorama config.yml .database.host
2181
+ # Output: "localhost"
2182
+
2183
+ # Extract database.host as a raw scalar
2184
+ configorama config.yml .database.host --raw
2185
+ # Output: localhost
2186
+
2187
+ # Extract and copy the raw scalar
2188
+ configorama config.yml .database.host --raw --copy
2156
2189
  # Output: localhost
2157
2190
 
2158
2191
  # Extract database config as JSON
2159
- configorama config.yml database --format json
2192
+ configorama config.yml .database --format json
2160
2193
  # Output: {"host":"localhost","port":5432}
2161
2194
  ```
2162
2195
 
package/cli.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  const fs = require('fs')
4
4
  const minimist = require('minimist')
5
+ const { spawnSync } = require('child_process')
5
6
  const Configorama = require('./src/main')
6
7
  const deepLog = require('./src/utils/ui/deep-log')
7
8
  const { logHeader } = require('./src/utils/ui/logs')
@@ -12,13 +13,15 @@ const getValueAtPath = require('./src/utils/parsing/getValueAtPath')
12
13
  // Parse command line arguments
13
14
  const argv = minimist(process.argv.slice(2), {
14
15
  string: ['output', 'o', 'format', 'f', 'param'],
15
- boolean: ['help', 'h', 'version', 'v', 'V', 'debug', 'allow-unknown', 'allow-undefined', 'list', 'info', 'verify'],
16
+ boolean: ['help', 'h', 'version', 'v', 'V', 'debug', 'allow-unknown', 'allow-undefined', 'list', 'info', 'verify', 'raw', 'r', 'copy', 'c'],
16
17
  alias: {
17
18
  h: 'help',
18
19
  v: 'version',
19
20
  V: 'verify',
20
21
  o: 'output',
21
22
  f: 'format',
23
+ r: 'raw',
24
+ c: 'copy',
22
25
  l: 'list',
23
26
  i: 'info',
24
27
  },
@@ -40,6 +43,8 @@ Options:
40
43
  -v, --version Show version number
41
44
  -o, --output <file> Write output to file instead of stdout
42
45
  -f, --format <format> Output format: json, yaml, or js (default: json)
46
+ -r, --raw Print extracted scalar values without JSON quoting
47
+ -c, --copy Copy the formatted output to the clipboard
43
48
  -d, --debug Enable debug mode
44
49
  -i, --info Show info about the config
45
50
  -V, --verify Verify the config
@@ -62,6 +67,8 @@ Path Extraction:
62
67
  Examples:
63
68
  configorama config.yml
64
69
  configorama config.yml .database.host
70
+ configorama -r config.yml .database.host
71
+ configorama -r --copy config.yml .database.host
65
72
  configorama '.servers[0].port' config.yml
66
73
  configorama --info config.yml
67
74
  configorama --format yaml config.json
@@ -84,11 +91,53 @@ if (argv.version) {
84
91
  let inputFile = null
85
92
  let extractPath = null
86
93
 
94
+ function isFileArg(arg) {
95
+ if (fs.existsSync(arg) && fs.statSync(arg).isFile()) return true
96
+ return arg.startsWith('./') || arg.startsWith('../')
97
+ }
98
+
99
+ function getClipboardCommands() {
100
+ if (process.env.CONFIGORAMA_CLIPBOARD_COMMAND) {
101
+ return [{ command: process.env.CONFIGORAMA_CLIPBOARD_COMMAND, shell: true }]
102
+ }
103
+
104
+ if (process.platform === 'darwin') return [{ command: 'pbcopy', args: [] }]
105
+ if (process.platform === 'win32') return [{ command: 'clip', args: [] }]
106
+
107
+ return [
108
+ { command: 'wl-copy', args: [] },
109
+ { command: 'xclip', args: ['-selection', 'clipboard'] },
110
+ { command: 'xsel', args: ['--clipboard', '--input'] }
111
+ ]
112
+ }
113
+
114
+ function copyToClipboard(value) {
115
+ let lastError = ''
116
+ for (const candidate of getClipboardCommands()) {
117
+ const result = spawnSync(candidate.command, candidate.args || [], {
118
+ input: String(value),
119
+ encoding: 'utf8',
120
+ shell: !!candidate.shell,
121
+ stdio: ['pipe', 'ignore', 'pipe']
122
+ })
123
+
124
+ if (!result.error && result.status === 0) return { ok: true }
125
+ lastError = result.error ? result.error.message : (result.stderr || '').trim()
126
+ }
127
+
128
+ return {
129
+ ok: false,
130
+ error: lastError || 'No supported clipboard command found'
131
+ }
132
+ }
133
+
87
134
  for (const arg of argv._) {
88
135
  if (arg === 'setup') continue
89
136
 
90
137
  // jq-style paths start with '.' or '['
91
- if (arg.startsWith('.') || arg.startsWith('[')) {
138
+ if (!inputFile && isFileArg(arg)) {
139
+ inputFile = arg
140
+ } else if (arg.startsWith('.') || arg.startsWith('[')) {
92
141
  extractPath = arg
93
142
  } else if (!inputFile) {
94
143
  inputFile = arg
@@ -134,6 +183,10 @@ const {
134
183
  l,
135
184
  info,
136
185
  i,
186
+ r,
187
+ raw,
188
+ c,
189
+ copy,
137
190
  'allow-unknown': allowUnknown,
138
191
  'allow-undefined': allowUndefined,
139
192
  'allow-unknown-file-refs': allowUnknownFileRefs,
@@ -177,7 +230,9 @@ configorama(inputFile, options)
177
230
  let output
178
231
 
179
232
  // Format the output
180
- switch (argv.format.toLowerCase()) {
233
+ if (argv.raw && extractPath && (config === null || ['string', 'number', 'boolean'].includes(typeof config))) {
234
+ output = config === null ? 'null' : String(config)
235
+ } else switch (argv.format.toLowerCase()) {
181
236
  case 'yaml':
182
237
  case 'yml':
183
238
  const YAML = require('./src/parsers/yaml')
@@ -204,6 +259,14 @@ configorama(inputFile, options)
204
259
  output = JSON.stringify(config, null, 2)
205
260
  }
206
261
 
262
+ if (argv.copy) {
263
+ const copyResult = copyToClipboard(output)
264
+ if (!copyResult.ok) {
265
+ console.error(`Error: Unable to copy to clipboard: ${copyResult.error}`)
266
+ process.exit(1)
267
+ }
268
+ }
269
+
207
270
  // Write to file or stdout
208
271
  if (argv.output) {
209
272
  fs.writeFileSync(argv.output, output)
@@ -230,4 +293,4 @@ configorama(inputFile, options)
230
293
  console.error('error', error)
231
294
  }
232
295
  process.exit(1)
233
- })
296
+ })
package/index.d.ts CHANGED
@@ -38,6 +38,18 @@ interface ConfigoramaSettings {
38
38
  /** Allow undefined values as final results */
39
39
  allowUndefinedValues?: boolean
40
40
 
41
+ /**
42
+ * Glob-like config paths whose values should be left verbatim.
43
+ * Useful for embedded languages that also use ${...}.
44
+ */
45
+ ignorePaths?: string[]
46
+
47
+ /** Alias for ignorePaths */
48
+ skipResolutionPaths?: string[]
49
+
50
+ /** Disable the built-in CloudFormation and embedded-code ignore paths */
51
+ disableDefaultIgnorePaths?: boolean
52
+
41
53
  // === Legacy Options (deprecated, use above instead) ===
42
54
 
43
55
  /** @deprecated Use allowUnknownVariableTypes instead */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "configorama",
3
- "version": "0.10.2",
3
+ "version": "0.10.3",
4
4
  "description": "Variable support for configuration files",
5
5
  "main": "src/index.js",
6
6
  "types": "index.d.ts",
package/src/index.js CHANGED
@@ -13,6 +13,9 @@ const { buildVariableSyntax } = require('./utils/variables/variableUtils')
13
13
  * @property {Object.<string, Function>} [functions] - Object of custom functions
14
14
  * @property {boolean} [allowUnknownVars] - allow unknown variables to pass through without throwing errors
15
15
  * @property {boolean} [allowUndefinedValues] - allow undefined values to pass through without throwing errors
16
+ * @property {string[]} [ignorePaths] - glob-like config paths whose values should be left verbatim
17
+ * @property {string[]} [skipResolutionPaths] - alias for ignorePaths
18
+ * @property {boolean} [disableDefaultIgnorePaths] - disable built-in CloudFormation and embedded-code ignore paths
16
19
  * @property {Object|Function} [dynamicArgs] - values passed into .js config files if user using javascript config
17
20
  * @property {boolean} [returnMetadata] - return both config and metadata about variables found
18
21
  * @property {boolean} [dotEnvSilent] - suppress env-stage-loader logs when useDotenv/useDotEnv is enabled
package/src/main.js CHANGED
@@ -60,6 +60,7 @@ const { mergeByKeys } = require('./utils/parsing/mergeByKeys')
60
60
  const { arrayToJsonPath } = require('./utils/parsing/arrayToJsonPath')
61
61
  /* Utils - paths */
62
62
  const { findLineByPath } = require('./utils/paths/findLineForKey')
63
+ const { normalizeIgnorePaths, compileIgnorePaths, shouldIgnorePath } = require('./utils/paths/ignorePaths')
63
64
  /* Utils - regex */
64
65
  const { combineRegexes, funcRegex, fileRefSyntax, textRefSyntax } = require('./utils/regex')
65
66
  /* Utils - strings */
@@ -162,6 +163,11 @@ class Configorama {
162
163
  // CLI users can still see them with --verbose or dotEnvSilent: false.
163
164
  dotEnvSilent: !VERBOSE,
164
165
  dotEnvDebug: false,
166
+ // Glob-like path patterns whose values should be left verbatim.
167
+ // Useful for embedded languages that also use ${...}, such as
168
+ // CloudFormation Fn::Sub, inline Lambda code, and CloudFront functions.
169
+ ignorePaths: [],
170
+ skipResolutionPaths: [],
165
171
  }, options)
166
172
 
167
173
  // Backward compat: allowUnknownVars -> allowUnknownVariableTypes
@@ -221,9 +227,10 @@ class Configorama {
221
227
 
222
228
  // Use $[...] syntax for HCL/Terraform files to avoid conflicts with Terraform's ${} syntax
223
229
  const isHclFile = detectedFileType === '.tf' || detectedFileType === '.hcl'
230
+ const defaultExcludedPatterns = ['AWS', 'aws:', 'stageVariables']
224
231
  const defaultSyntax = isHclFile
225
- ? buildVariableSyntax('$[', ']', ['AWS', 'stageVariables'])
226
- : buildVariableSyntax('${', '}', ['AWS', 'stageVariables'])
232
+ ? buildVariableSyntax('$[', ']', defaultExcludedPatterns)
233
+ : buildVariableSyntax('${', '}', defaultExcludedPatterns)
227
234
 
228
235
  const varSyntax = options.syntax || defaultSyntax
229
236
  let varRegex
@@ -247,6 +254,7 @@ class Configorama {
247
254
  this.varPrefixPattern = new RegExp('^' + this.varPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
248
255
  this.varSuffixPattern = new RegExp(escapedSuffix + '$')
249
256
  this.varSuffixWithSpacePattern = new RegExp('\\s+' + escapedSuffix + '$')
257
+ this.ignorePathPatterns = compileIgnorePaths(normalizeIgnorePaths(this.settings))
250
258
 
251
259
  // Set initial config object to populate
252
260
  if (typeof fileOrObject === 'object') {
@@ -1063,6 +1071,7 @@ class Configorama {
1063
1071
  originalConfig: this.originalConfig,
1064
1072
  varSuffix: this.varSuffix,
1065
1073
  varSuffixWithSpacePattern: this.varSuffixWithSpacePattern,
1074
+ ignorePathPatterns: this.ignorePathPatterns,
1066
1075
  })
1067
1076
 
1068
1077
  return this._cachedMetadata
@@ -1102,9 +1111,8 @@ class Configorama {
1102
1111
  // #######################
1103
1112
  // ## PROPERTY HANDLING ##
1104
1113
  // #######################
1105
- isCloudFormationSubPath(pathValue) {
1106
- if (!pathValue || !pathValue.length) return false
1107
- return pathValue[pathValue.length - 1] === 'Fn::Sub'
1114
+ shouldSkipResolution(pathValue) {
1115
+ return shouldIgnorePath(pathValue, this.ignorePathPatterns)
1108
1116
  }
1109
1117
 
1110
1118
  /**
@@ -1264,10 +1272,10 @@ class Configorama {
1264
1272
  }
1265
1273
  return false
1266
1274
  })
1267
- /* Leave CloudFormation Fn::Sub bodies verbatim. ${...} inside a !Sub is a
1268
- CloudFormation reference, not a configorama variable. */
1275
+ /* Leave opaque paths verbatim. These often contain non-configorama
1276
+ `${...}` syntax from CloudFormation, JavaScript, shell, VTL, etc. */
1269
1277
  variables = variables.filter((property) => {
1270
- return !this.isCloudFormationSubPath(property.path)
1278
+ return !this.shouldSkipResolution(property.path)
1271
1279
  })
1272
1280
  /*
1273
1281
  console.log(`variables at call count ${this.callCount}`, variables)
@@ -1555,7 +1563,7 @@ class Configorama {
1555
1563
  console.log(valueObject)
1556
1564
  }
1557
1565
  const property = valueObject.value
1558
- if (this.isCloudFormationSubPath(valueObject.path)) {
1566
+ if (this.shouldSkipResolution(valueObject.path)) {
1559
1567
  return Promise.resolve(property)
1560
1568
  }
1561
1569
  const matches = this.getMatches(property)
package/src/metadata.js CHANGED
@@ -6,6 +6,7 @@ const fs = require('fs')
6
6
  const traverse = require('traverse')
7
7
  const dotProp = require('dot-prop')
8
8
  const { normalizePath, extractFilePath, resolveInnerVariables } = require('./utils/paths/filePathUtils')
9
+ const { shouldIgnorePath } = require('./utils/paths/ignorePaths')
9
10
  const { findNestedVariables } = require('./utils/variables/findNestedVariables')
10
11
  const { splitOnPipe } = require('./utils/strings/splitOnPipe')
11
12
 
@@ -21,6 +22,7 @@ const { splitOnPipe } = require('./utils/strings/splitOnPipe')
21
22
  * @param {Object} params.originalConfig - this.originalConfig, used for dotProp.get checks
22
23
  * @param {string} params.varSuffix
23
24
  * @param {RegExp} params.varSuffixWithSpacePattern
25
+ * @param {string[][]} [params.ignorePathPatterns]
24
26
  * @returns {Object} Metadata object containing variables, fileDependencies, and summary
25
27
  */
26
28
  function collectVariableMetadata({
@@ -33,6 +35,7 @@ function collectVariableMetadata({
33
35
  originalConfig,
34
36
  varSuffix,
35
37
  varSuffixWithSpacePattern,
38
+ ignorePathPatterns,
36
39
  }) {
37
40
  const foundVariables = []
38
41
  const variableData = {}
@@ -46,8 +49,8 @@ function collectVariableMetadata({
46
49
  traverse(displayConfig).forEach(function (rawValue) {
47
50
  if (typeof rawValue === 'string' && rawValue.match(variableSyntax)) {
48
51
  const configValuePath = this.path.join('.')
49
- /* Skip Fn::Sub variables */
50
- if (configValuePath.endsWith('Fn::Sub')) {
52
+ /* Skip opaque paths that contain non-configorama ${...} syntax. */
53
+ if (shouldIgnorePath(this.path, ignorePathPatterns)) {
51
54
  return
52
55
  }
53
56
 
@@ -10,7 +10,7 @@ const { executeTypeScriptFileSync } = require('../../parsers/typescript')
10
10
  const { executeESMFileSync } = require('../../parsers/esm')
11
11
  const cloudFormationSchema = require('./cloudformationSchema')
12
12
 
13
- const DEFAULT_VAR_SYNTAX = '\\${((?!AWS|stageVariables)[ ~:a-zA-Z0-9=+!@#%*<>?._\'",|\\-\\/\\(\\)\\\\]+?)}'
13
+ const DEFAULT_VAR_SYNTAX = '\\${((?!AWS|aws:|stageVariables)[ ~:a-zA-Z0-9=+!@#%*<>?._\'",|\\-\\/\\(\\)\\\\]+?)}'
14
14
 
15
15
  const KNOWN_EXTENSIONS = new Set([
16
16
  '.yml', '.yaml', '.json', '.json5', '.jsonc',
@@ -0,0 +1,69 @@
1
+ const DEFAULT_IGNORE_PATHS = [
2
+ '**.Fn::Sub',
3
+ '**.Properties.Code.ZipFile',
4
+ '**.Properties.FunctionCode',
5
+ '**.Properties.UserData',
6
+ '**.Properties.BuildSpec',
7
+ '**.Properties.DefinitionString',
8
+ '**.Properties.DefinitionBody',
9
+ '**.Properties.RequestMappingTemplate',
10
+ '**.Properties.ResponseMappingTemplate',
11
+ '**.Properties.RequestTemplates.*',
12
+ '**.Properties.ResponseTemplates.*',
13
+ '**.Metadata.AWS::CloudFormation::Init.*.files.*.content',
14
+ '**.Metadata.AWS::CloudFormation::Init.*.commands.*.command'
15
+ ]
16
+
17
+ function toArray(value) {
18
+ if (!value) return []
19
+ return Array.isArray(value) ? value : [value]
20
+ }
21
+
22
+ function pathToSegments(pathValue) {
23
+ if (!pathValue) return []
24
+ return Array.isArray(pathValue) ? pathValue.map(String) : String(pathValue).split('.')
25
+ }
26
+
27
+ function patternToSegments(pattern) {
28
+ return String(pattern).split('.')
29
+ }
30
+
31
+ function matchSegments(patternSegments, pathSegments) {
32
+ if (!patternSegments.length) return pathSegments.length === 0
33
+
34
+ const [head, ...tail] = patternSegments
35
+ if (head === '**') {
36
+ if (matchSegments(tail, pathSegments)) return true
37
+ return pathSegments.length > 0 && matchSegments(patternSegments, pathSegments.slice(1))
38
+ }
39
+
40
+ if (!pathSegments.length) return false
41
+ if (head !== '*' && head !== pathSegments[0]) return false
42
+ return matchSegments(tail, pathSegments.slice(1))
43
+ }
44
+
45
+ function normalizeIgnorePaths(options = {}) {
46
+ const defaults = options.disableDefaultIgnorePaths ? [] : DEFAULT_IGNORE_PATHS
47
+ return Array.from(new Set([
48
+ ...defaults,
49
+ ...toArray(options.ignorePaths),
50
+ ...toArray(options.skipResolutionPaths)
51
+ ]))
52
+ }
53
+
54
+ function compileIgnorePaths(patterns) {
55
+ return toArray(patterns).map(patternToSegments)
56
+ }
57
+
58
+ function shouldIgnorePath(pathValue, compiledPatterns) {
59
+ if (!compiledPatterns || !compiledPatterns.length) return false
60
+ const pathSegments = pathToSegments(pathValue)
61
+ return compiledPatterns.some((patternSegments) => matchSegments(patternSegments, pathSegments))
62
+ }
63
+
64
+ module.exports = {
65
+ DEFAULT_IGNORE_PATHS,
66
+ normalizeIgnorePaths,
67
+ compileIgnorePaths,
68
+ shouldIgnorePath
69
+ }
@@ -2,7 +2,7 @@ const { test } = require('uvu')
2
2
  const assert = require('uvu/assert')
3
3
  const { splitByComma } = require('./splitByComma')
4
4
 
5
- const variableSyntax = /\${((?!AWS|stageVariables)[ ~:a-zA-Z0-9=+!@#%*<>?._'",|\-\/\(\)\\]+?)}/g
5
+ const variableSyntax = /\${((?!AWS|aws:|stageVariables)[ ~:a-zA-Z0-9=+!@#%*<>?._'",|\-\/\(\)\\]+?)}/g
6
6
 
7
7
  test('splitByComma - should return array with original string when no commas present', () => {
8
8
  const result = splitByComma('singleString')
@@ -145,4 +145,4 @@ test('splitByComma - should handle odd backslashes (escaped quote)', () => {
145
145
  })
146
146
 
147
147
  // Run all tests
148
- test.run()
148
+ test.run()
@@ -358,7 +358,7 @@ function findNestedVariablesOld(input, regex, variablesKnownTypes, debug = false
358
358
  }
359
359
 
360
360
  // // Test with the example
361
- // const regex = /\${((?!AWS|stageVariables)[ ~:a-zA-Z0-9=+!@#%*<>?._'",|\-\/\(\)\\]+?)}/g
361
+ // const regex = /\${((?!AWS|aws:|stageVariables)[ ~:a-zA-Z0-9=+!@#%*<>?._'",|\-\/\(\)\\]+?)}/g
362
362
  // const input = '${file(./config.${opt:stage, ${defaultStage}}.json):CREDS}'
363
363
 
364
364
  // // Run the function with debug output
@@ -374,4 +374,4 @@ function findNestedVariablesOld(input, regex, variablesKnownTypes, debug = false
374
374
 
375
375
  module.exports = {
376
376
  findNestedVariables
377
- }
377
+ }
@@ -9,7 +9,7 @@ const getValueFromOptions = require('../../resolvers/valueFromOptions')
9
9
  const getValueFromGit = require('../../resolvers/valueFromGit')
10
10
 
11
11
  // Define the regex pattern as used in the main function
12
- const regex = /\${((?!AWS|stageVariables)[ ~:a-zA-Z0-9=+!@#%*<>?._'",|\-\/\(\)\\]+?)}/g;
12
+ const regex = /\${((?!AWS|aws:|stageVariables)[ ~:a-zA-Z0-9=+!@#%*<>?._'",|\-\/\(\)\\]+?)}/g;
13
13
  const variablesKnownTypes = /(^env:|^opt:|^self:|^file\((~?[\{\}\:\$a-zA-Z0-9._\-\/,'" ]+?)\)|^git:|(\${)?deep:\d+(\.[^}]+)*()}?)/
14
14
 
15
15
  const fileRefSyntax = RegExp(/^file\((~?[@\{\}\:\$a-zA-Z0-9._\-\/,'" ]+?)\)/g)
@@ -239,4 +239,4 @@ test('findNestedVariables - deep - no var types passed', () => {
239
239
 
240
240
 
241
241
  // Run all tests
242
- test.run();
242
+ test.run();
@@ -93,10 +93,10 @@ Remove or update the \${${variableString}} to fix
93
93
  * Excludes suffix characters from the allowed set to prevent parsing issues
94
94
  * @param {string} [prefix='${'] - Variable prefix
95
95
  * @param {string} [suffix='}'] - Variable suffix
96
- * @param {string[]} [excludePatterns=['AWS', 'stageVariables']] - Patterns to exclude via negative lookahead
96
+ * @param {string[]} [excludePatterns=['AWS', 'aws:', 'stageVariables']] - Patterns to exclude via negative lookahead
97
97
  * @returns {string} Regex source string
98
98
  */
99
- function buildVariableSyntax(prefix = '${', suffix = '}', excludePatterns = ['AWS', 'stageVariables']) {
99
+ function buildVariableSyntax(prefix = '${', suffix = '}', excludePatterns = ['AWS', 'aws:', 'stageVariables']) {
100
100
  // All allowed characters, stored as individual escaped entries for regex character class
101
101
  // Each entry is how it appears in a regex character class
102
102
  // NOTE: { and } are intentionally excluded - they break nested variable matching
@@ -145,4 +145,4 @@ module.exports = {
145
145
  getFallbackString,
146
146
  verifyVariable,
147
147
  buildVariableSyntax
148
- }
148
+ }
@@ -172,6 +172,15 @@ test('buildVariableSyntax - supports backslash in values', () => {
172
172
  assert.is(match[0], "${env:FOO, 'path\\to\\file'}")
173
173
  })
174
174
 
175
+ test('buildVariableSyntax - default ${} syntax excludes IAM aws variables', () => {
176
+ const syntax = buildVariableSyntax('${', '}')
177
+ const regex = new RegExp(syntax, 'g')
178
+
179
+ assert.not.ok('${aws:username}'.match(regex))
180
+ assert.not.ok('arn:aws:s3:::bucket/${aws:PrincipalTag/team}/*'.match(regex))
181
+ assert.ok('${self:custom.value}'.match(regex))
182
+ })
183
+
175
184
  test('buildVariableSyntax - double brace ${{}} syntax excludes }', () => {
176
185
  const syntax = buildVariableSyntax('${{', '}}')
177
186
  const regex = new RegExp(syntax, 'g')