@znemz/cfn-include 2.1.20 → 2.1.21
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/index.js +20 -14
- package/lib/scope.js +58 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -26,6 +26,7 @@ const { lowerCamelCase, upperCamelCase } = require('./lib/utils');
|
|
|
26
26
|
const { isOurExplicitFunction } = require('./lib/schema');
|
|
27
27
|
const { getAwsPseudoParameters, buildResourceArn } = require('./lib/internals');
|
|
28
28
|
const { cachedReadFile } = require('./lib/cache');
|
|
29
|
+
const { createChildScope } = require('./lib/scope');
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* @param {object} options
|
|
@@ -109,7 +110,8 @@ async function recurse({ base, scope, cft, rootTemplate, caller, ...opts }) {
|
|
|
109
110
|
if (opts.doLog) {
|
|
110
111
|
console.log({ base, scope, cft, rootTemplate, caller, ...opts });
|
|
111
112
|
}
|
|
112
|
-
|
|
113
|
+
// Use Object.create() for O(1) child scope creation instead of O(n) clone
|
|
114
|
+
scope = createChildScope(scope);
|
|
113
115
|
if (Array.isArray(cft)) {
|
|
114
116
|
return Promise.all(cft.map((o) => recurse({ base, scope, cft: o, rootTemplate, caller: 'recurse:isArray', ...opts })));
|
|
115
117
|
}
|
|
@@ -137,13 +139,14 @@ async function recurse({ base, scope, cft, rootTemplate, caller, ...opts }) {
|
|
|
137
139
|
placeholder = '_';
|
|
138
140
|
}
|
|
139
141
|
return PromiseExt.mapX(recurse({ base, scope, cft: list, rootTemplate, caller: 'Fn::Map', ...opts }), (replace, key) => {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
+
// Use Object.create() for O(1) child scope creation instead of O(n) clone
|
|
143
|
+
const additions = { [placeholder]: replace };
|
|
142
144
|
if (hasindex) {
|
|
143
|
-
|
|
145
|
+
additions[idx] = key;
|
|
144
146
|
}
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
+
const childScope = createChildScope(scope, additions);
|
|
148
|
+
const replaced = findAndReplace(childScope, _.cloneDeep(body));
|
|
149
|
+
return recurse({ base, scope: childScope, cft: replaced, rootTemplate, caller: 'Fn::Map', ...opts });
|
|
147
150
|
}).then((_cft) => {
|
|
148
151
|
if (hassize) {
|
|
149
152
|
_cft = findAndReplace({ [sz]: _cft.length }, _cft);
|
|
@@ -594,20 +597,23 @@ async function recurse({ base, scope, cft, rootTemplate, caller, ...opts }) {
|
|
|
594
597
|
}
|
|
595
598
|
|
|
596
599
|
function findAndReplace(scope, object) {
|
|
597
|
-
if (
|
|
598
|
-
|
|
600
|
+
if (typeof object === 'string') {
|
|
601
|
+
// Use for...in to walk prototype chain (Object.create() based scopes)
|
|
602
|
+
for (const find in scope) {
|
|
599
603
|
if (object === find) {
|
|
600
|
-
object =
|
|
604
|
+
object = scope[find];
|
|
601
605
|
}
|
|
602
|
-
}
|
|
606
|
+
}
|
|
603
607
|
}
|
|
604
|
-
if (
|
|
605
|
-
|
|
608
|
+
if (typeof object === 'string') {
|
|
609
|
+
// Use for...in to walk prototype chain (Object.create() based scopes)
|
|
610
|
+
for (const find in scope) {
|
|
611
|
+
const replace = scope[find];
|
|
606
612
|
const regex = new RegExp(`\\\${${find}}`, 'g');
|
|
607
613
|
if (find !== '_' && object.match(regex)) {
|
|
608
614
|
object = object.replace(regex, replace);
|
|
609
615
|
}
|
|
610
|
-
}
|
|
616
|
+
}
|
|
611
617
|
}
|
|
612
618
|
if (Array.isArray(object)) {
|
|
613
619
|
object = object.map(_.bind(findAndReplace, this, scope));
|
|
@@ -615,7 +621,7 @@ function findAndReplace(scope, object) {
|
|
|
615
621
|
object = _.mapKeys(object, function (value, key) {
|
|
616
622
|
return findAndReplace(scope, key);
|
|
617
623
|
});
|
|
618
|
-
|
|
624
|
+
Object.keys(object).forEach(function (key) {
|
|
619
625
|
if (key === 'Fn::Map') return;
|
|
620
626
|
object[key] = findAndReplace(scope, object[key]);
|
|
621
627
|
});
|
package/lib/scope.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scope helper functions for lazy prototype-chain based scope management.
|
|
3
|
+
*
|
|
4
|
+
* Instead of _.clone(scope) which copies O(n) properties each time,
|
|
5
|
+
* we use Object.create(scope) which creates a child scope in O(1) time
|
|
6
|
+
* that inherits from the parent via the prototype chain.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Create a child scope that inherits from the parent.
|
|
11
|
+
* Uses Object.create() for O(1) creation instead of cloning.
|
|
12
|
+
*
|
|
13
|
+
* @param {Object} parent - The parent scope to inherit from
|
|
14
|
+
* @param {Object} [additions={}] - Properties to add to the child scope
|
|
15
|
+
* @returns {Object} A new child scope with prototype chain to parent
|
|
16
|
+
*/
|
|
17
|
+
function createChildScope(parent, additions = {}) {
|
|
18
|
+
const child = Object.create(parent);
|
|
19
|
+
Object.assign(child, additions);
|
|
20
|
+
return child;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Convert a prototype-chain scope to a plain object.
|
|
25
|
+
* Uses for...in to walk the entire prototype chain.
|
|
26
|
+
*
|
|
27
|
+
* Useful when we need to pass scope to functions that don't
|
|
28
|
+
* walk the prototype chain (e.g., Object.keys, _.forEach).
|
|
29
|
+
*
|
|
30
|
+
* @param {Object} scope - The scope to flatten
|
|
31
|
+
* @returns {Object} A plain object with all inherited properties
|
|
32
|
+
*/
|
|
33
|
+
function scopeToObject(scope) {
|
|
34
|
+
const result = {};
|
|
35
|
+
for (const key in scope) {
|
|
36
|
+
result[key] = scope[key];
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Iterate over all properties in a scope, including inherited ones.
|
|
43
|
+
* This is a replacement for _.forEach that walks the prototype chain.
|
|
44
|
+
*
|
|
45
|
+
* @param {Object} scope - The scope to iterate over
|
|
46
|
+
* @param {Function} callback - Function to call with (value, key)
|
|
47
|
+
*/
|
|
48
|
+
function forEachInScope(scope, callback) {
|
|
49
|
+
for (const key in scope) {
|
|
50
|
+
callback(scope[key], key);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = {
|
|
55
|
+
createChildScope,
|
|
56
|
+
scopeToObject,
|
|
57
|
+
forEachInScope,
|
|
58
|
+
};
|