configorama 0.4.7 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/main.js CHANGED
@@ -77,6 +77,18 @@ class Configorama {
77
77
  allowUndefinedValues: false,
78
78
  }, options)
79
79
 
80
+
81
+ const defaultSyntax = '\\${((?!AWS)[ ~:a-zA-Z0-9=+!@#%*<>?._\'",|\\-\\/\\(\\)\\\\]+?)}'
82
+ const variableSyntax = options.syntax || defaultSyntax
83
+ let varRegex
84
+ if (typeof variableSyntax === 'string') {
85
+ varRegex = RegExp(variableSyntax, 'g')
86
+ // this.variableSyntax = /\${((?!AWS)([ ~:a-zA-Z0-9=+!@#%*<>?._'",|\-\/\(\)\\]+?|(\w+)\s*\(((?:[^()]+)*)?\s*\)\s*))}/
87
+ } else if (variableSyntax instanceof RegExp) {
88
+ varRegex = variableSyntax
89
+ }
90
+ this.variableSyntax = varRegex
91
+
80
92
  // Set initial config object to populate
81
93
  if (typeof fileOrObject === 'object') {
82
94
  // set config objects
@@ -94,11 +106,14 @@ class Configorama {
94
106
  let configObject
95
107
  if (fileType.match(/\.(yml|yaml)/)) {
96
108
  try {
97
- configObject = YAML.parse(fileContents)
109
+ const ymlText = YAML.preProcess(fileContents, varRegex)
110
+ // console.log('ymlText', ymlText)
111
+ configObject = YAML.parse(ymlText)
98
112
  } catch (err) {
99
113
  // Attempt to fix cloudformation refs
100
114
  if (err.message.match(/YAMLException/)) {
101
- const result = YAML.load(fileContents, {
115
+ const ymlText = YAML.preProcess(fileContents, varRegex)
116
+ const result = YAML.load(ymlText, {
102
117
  filename: fileOrObject,
103
118
  schema: cloudFormationSchema.schema
104
119
  })
@@ -140,16 +155,6 @@ class Configorama {
140
155
  // Track promise resolution
141
156
  this.tracker = new PromiseTracker()
142
157
 
143
- const defaultSyntax = '\\${((?!AWS)[ ~:a-zA-Z0-9=+!@#%*<>?._\'",|\\-\\/\\(\\)\\\\]+?)}'
144
- const variableSyntax = options.syntax || defaultSyntax
145
-
146
- if (typeof variableSyntax === 'string') {
147
- this.variableSyntax = RegExp(variableSyntax, 'g')
148
- // this.variableSyntax = /\${((?!AWS)([ ~:a-zA-Z0-9=+!@#%*<>?._'",|\-\/\(\)\\]+?|(\w+)\s*\(((?:[^()]+)*)?\s*\)\s*))}/
149
- } else if (variableSyntax instanceof RegExp) {
150
- this.variableSyntax = variableSyntax
151
- }
152
-
153
158
  // Variable Sources
154
159
  this.variableTypes = [
155
160
  /**
@@ -433,6 +438,10 @@ class Configorama {
433
438
  })
434
439
  }
435
440
  runFunction(variableString) {
441
+ /* If json object value return it */
442
+ if (variableString.match(/^\s*{/) && variableString.match(/}\s*$/)) {
443
+ return variableString
444
+ }
436
445
  // console.log('runFunction', variableString)
437
446
  var hasFunc = funcRegex.exec(variableString)
438
447
  // TODO finish Function handling. Need to move this down below resolver to resolve inner refs first
@@ -57,7 +57,131 @@ function toJson(ymlContents) {
57
57
  return json
58
58
  }
59
59
 
60
+ // TODO only works for default var syntax ${}. Maybe fix?
61
+ function findOutermostVariables(text) {
62
+ let matches = [];
63
+ let depth = 0;
64
+ let startIndex = -1;
65
+
66
+ for (let i = 0; i < text.length; i++) {
67
+ if (text[i] === '$' && text[i + 1] === '{') {
68
+ if (depth === 0) {
69
+ startIndex = i;
70
+ }
71
+ depth++;
72
+ i++; // Skip '{'
73
+ } else if (text[i] === '}') {
74
+ depth--;
75
+ if (depth === 0 && startIndex !== -1) {
76
+ matches.push(text.substring(startIndex, i + 1));
77
+ startIndex = -1;
78
+ }
79
+ }
80
+ }
81
+ return matches;
82
+ }
83
+
84
+
85
+ function matchOutermostBraces(text) {
86
+ let depth = 0;
87
+ let startIndex = -1;
88
+ let results = [];
89
+
90
+ for (let i = 0; i < text.length; i++) {
91
+ if (text[i] === '{') {
92
+ if (depth === 0) {
93
+ startIndex = i;
94
+ }
95
+ depth++;
96
+ } else if (text[i] === '}') {
97
+ depth--;
98
+ if (depth === 0 && startIndex !== -1) {
99
+ results.push(text.substring(startIndex, i + 1));
100
+ startIndex = -1;
101
+ }
102
+ }
103
+ }
104
+
105
+ return results;
106
+ }
107
+
108
+ // https://regex101.com/r/XIltbc/1
109
+ const KEY_OBJECT = /^[ \t]*[^":\s]*:\s+\{/gm
110
+
111
+ const INNER_ARRAY = /\[(?:[^\[\]])*\]/g
112
+
113
+ function preProcess(ymlStr = '') {
114
+ /*
115
+ return ymlStr
116
+ /** */
117
+
118
+ // Fix nested variables in array brackets
119
+ // in -> y: !Not [!Equals [!Join ['', ${param:xyz}]]]
120
+ // out -> y: !Not [!Equals [!Join ['', "${param:xyz}"]]]
121
+ const arrayBracketMatches = ymlStr && ymlStr.match(
122
+ // /\[(?:[^\[\]]+|)*\]/gm
123
+ INNER_ARRAY
124
+ )
125
+ if (arrayBracketMatches) {
126
+ // console.log('arrayBracketMatches', arrayBracketMatches)
127
+ arrayBracketMatches.forEach((txt) => {
128
+ // console.log('txt', txt)
129
+ const hasNestedVars = txt && findOutermostVariables(txt)
130
+ /*
131
+ console.log(varRegex)
132
+ console.log('findOutermostVariables(txt)', findOutermostVariables(txt))
133
+ console.log('hasNested', hasNested)
134
+ /** */
135
+ if (hasNestedVars && hasNestedVars.length) {
136
+ let fixedText = txt
137
+ hasNestedVars.forEach((nested) => {
138
+ // console.log('nested', nested)
139
+ if (txt.indexOf(`"${nested}"`) > -1) {
140
+ return
141
+ }
142
+ if (txt.indexOf(`'${nested}'`) > -1) {
143
+ return
144
+ }
145
+ /* Replace variable wrapped in quotes */
146
+ fixedText = fixedText.replace(nested, `"${nested}"`)
147
+ })
148
+ ymlStr = ymlStr.replace(txt, fixedText)
149
+ }
150
+ })
151
+ }
152
+
153
+ /* If have yaml object and vars not wrapped in quotes, wrap them */
154
+ if (ymlStr.match(KEY_OBJECT)) {
155
+ const hasObjects = matchOutermostBraces(ymlStr)
156
+ // console.log('hasObjects', hasObjects)
157
+ if (hasObjects && hasObjects.length) {
158
+ hasObjects.forEach((txt) => {
159
+ // console.log('obj text', txt)
160
+ const hasNestedVars = txt && findOutermostVariables(txt)
161
+ if (hasNestedVars && hasNestedVars.length) {
162
+ let fixedText = txt
163
+ hasNestedVars.forEach((nested) => {
164
+ // console.log('nested', nested)
165
+ if (txt.indexOf(`"${nested}"`) > -1) {
166
+ return
167
+ }
168
+ if (txt.indexOf(`'${nested}'`) > -1) {
169
+ return
170
+ }
171
+ /* Replace variable wrapped in quotes */
172
+ fixedText = fixedText.replace(nested, `"${nested}"`)
173
+ })
174
+ ymlStr = ymlStr.replace(txt, fixedText)
175
+ }
176
+ })
177
+ }
178
+ }
179
+ // console.log('ymlStr', ymlStr)
180
+ return ymlStr
181
+ }
182
+
60
183
  module.exports = {
184
+ preProcess: preProcess,
61
185
  parse: parse,
62
186
  load: load,
63
187
  dump: dump,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "configorama",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "description": "Variable support for configuration files",
5
5
  "main": "lib/index.js",
6
6
  "files": [