@znemz/cfn-include 4.2.2 → 4.3.1
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/dist/cli.js +44 -1
- package/dist/cli.js.map +1 -1
- package/dist/lib/graph.d.ts +54 -0
- package/dist/lib/graph.d.ts.map +1 -0
- package/dist/lib/graph.js +149 -0
- package/dist/lib/graph.js.map +1 -0
- package/dist/lib/split.d.ts +82 -0
- package/dist/lib/split.d.ts.map +1 -0
- package/dist/lib/split.js +557 -0
- package/dist/lib/split.js.map +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { readFileSync } from 'node:fs';
|
|
5
|
+
import { readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
6
6
|
import _ from 'lodash';
|
|
7
7
|
import include from './index.js';
|
|
8
8
|
import * as yaml from './lib/yaml.js';
|
|
9
9
|
import Client from './lib/cfnclient.js';
|
|
10
10
|
import replaceEnv from './lib/replaceEnv.js';
|
|
11
11
|
import { computeStats, checkThresholds, formatStatsReport } from './lib/stats.js';
|
|
12
|
+
import { buildDependencyGraph } from './lib/graph.js';
|
|
13
|
+
import { suggestSplit, autoSplit, formatSplitReport } from './lib/split.js';
|
|
12
14
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
15
|
const __dirname = path.dirname(__filename);
|
|
14
16
|
// Read package.json using fs instead of import assertion
|
|
@@ -86,6 +88,15 @@ const opts = yargs(hideBin(process.argv))
|
|
|
86
88
|
default: false,
|
|
87
89
|
boolean: true,
|
|
88
90
|
},
|
|
91
|
+
'suggest-split': {
|
|
92
|
+
desc: 'analyze template and suggest how to split into multiple stacks',
|
|
93
|
+
default: false,
|
|
94
|
+
boolean: true,
|
|
95
|
+
},
|
|
96
|
+
'auto-split': {
|
|
97
|
+
desc: 'split template into multiple stacks and write to the specified output directory',
|
|
98
|
+
string: true,
|
|
99
|
+
},
|
|
89
100
|
'ref-now-ignore-missing': {
|
|
90
101
|
boolean: true,
|
|
91
102
|
desc: 'do not fail if Fn::RefNow reference cannot be resolved',
|
|
@@ -203,6 +214,38 @@ promise
|
|
|
203
214
|
}
|
|
204
215
|
console.error('');
|
|
205
216
|
}
|
|
217
|
+
// Suggest split
|
|
218
|
+
if (opts['suggest-split'] || opts['auto-split']) {
|
|
219
|
+
const graph = buildDependencyGraph(template);
|
|
220
|
+
const suggestion = suggestSplit(template, graph);
|
|
221
|
+
if (opts['suggest-split']) {
|
|
222
|
+
console.error(formatSplitReport(suggestion));
|
|
223
|
+
console.error('');
|
|
224
|
+
}
|
|
225
|
+
if (opts['auto-split']) {
|
|
226
|
+
const outputDir = path.resolve(opts['auto-split']);
|
|
227
|
+
mkdirSync(outputDir, { recursive: true });
|
|
228
|
+
const result = autoSplit(template, graph, suggestion);
|
|
229
|
+
for (const stack of result.stacks) {
|
|
230
|
+
const filename = `${stack.name}${opts.yaml ? '.yaml' : '.json'}`;
|
|
231
|
+
const content = opts.yaml
|
|
232
|
+
? yaml.dump(stack.template, { lineWidth: opts.lineWidth })
|
|
233
|
+
: JSON.stringify(stack.template, null, 2);
|
|
234
|
+
writeFileSync(path.join(outputDir, filename), content);
|
|
235
|
+
console.error(` ✅ ${filename} (${stack.resourceIds.length} resources)`);
|
|
236
|
+
}
|
|
237
|
+
if (result.parent) {
|
|
238
|
+
const filename = `Parent${opts.yaml ? '.yaml' : '.json'}`;
|
|
239
|
+
const content = opts.yaml
|
|
240
|
+
? yaml.dump(result.parent.template, { lineWidth: opts.lineWidth })
|
|
241
|
+
: JSON.stringify(result.parent.template, null, 2);
|
|
242
|
+
writeFileSync(path.join(outputDir, filename), content);
|
|
243
|
+
console.error(` ✅ ${filename} (orchestrator)`);
|
|
244
|
+
}
|
|
245
|
+
console.error(`\nWrote ${result.stacks.length + (result.parent ? 1 : 0)} templates to ${outputDir}`);
|
|
246
|
+
console.error('');
|
|
247
|
+
}
|
|
248
|
+
}
|
|
206
249
|
console.log(opts.yaml ? yaml.dump(template, { lineWidth: opts.lineWidth }) : JSON.stringify(template, null, opts.minimize ? null : 2));
|
|
207
250
|
})
|
|
208
251
|
.catch(function (err) {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency Graph Builder for CloudFormation templates (Phase 2 of #90)
|
|
3
|
+
*
|
|
4
|
+
* Scans a resolved CloudFormation template and builds a directed dependency graph
|
|
5
|
+
* by detecting inter-resource references via Ref, Fn::GetAtt, DependsOn, and Conditions.
|
|
6
|
+
*
|
|
7
|
+
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
|
|
8
|
+
*/
|
|
9
|
+
import type { TemplateDocument } from '../types/template.js';
|
|
10
|
+
/** A single directed edge in the dependency graph. */
|
|
11
|
+
export interface DependencyEdge {
|
|
12
|
+
/** The resource that depends on `target`. */
|
|
13
|
+
source: string;
|
|
14
|
+
/** The resource being depended upon. */
|
|
15
|
+
target: string;
|
|
16
|
+
/** How the dependency was discovered. */
|
|
17
|
+
type: 'Ref' | 'Fn::GetAtt' | 'DependsOn' | 'Condition';
|
|
18
|
+
/** For Fn::GetAtt edges, the attribute name. */
|
|
19
|
+
attribute?: string;
|
|
20
|
+
}
|
|
21
|
+
/** Metadata for a single resource node in the graph. */
|
|
22
|
+
export interface ResourceNode {
|
|
23
|
+
logicalId: string;
|
|
24
|
+
resourceType: string;
|
|
25
|
+
/** Conditions this resource is gated on. */
|
|
26
|
+
conditions: string[];
|
|
27
|
+
/** Logical IDs this resource directly depends on (union of all edge types). */
|
|
28
|
+
dependsOn: Set<string>;
|
|
29
|
+
/** Logical IDs that directly depend on this resource. */
|
|
30
|
+
dependedOnBy: Set<string>;
|
|
31
|
+
}
|
|
32
|
+
/** The complete dependency graph for a template. */
|
|
33
|
+
export interface DependencyGraph {
|
|
34
|
+
/** Map of logicalId → ResourceNode. */
|
|
35
|
+
nodes: Map<string, ResourceNode>;
|
|
36
|
+
/** All discovered edges. */
|
|
37
|
+
edges: DependencyEdge[];
|
|
38
|
+
/** Set of all resource logical IDs. */
|
|
39
|
+
resourceIds: Set<string>;
|
|
40
|
+
/** Set of all parameter names (used to exclude Ref targets that are params). */
|
|
41
|
+
parameterIds: Set<string>;
|
|
42
|
+
/** Map of condition name → resource logical IDs that use it. */
|
|
43
|
+
conditionUsage: Map<string, Set<string>>;
|
|
44
|
+
}
|
|
45
|
+
/** AWS pseudo-parameters that should not be treated as resource refs. */
|
|
46
|
+
export declare const PSEUDO_PARAMETERS: Set<string>;
|
|
47
|
+
/**
|
|
48
|
+
* Build a directed dependency graph from a resolved CloudFormation template.
|
|
49
|
+
*
|
|
50
|
+
* @param template - A fully resolved CloudFormation template document.
|
|
51
|
+
* @returns The dependency graph.
|
|
52
|
+
*/
|
|
53
|
+
export declare function buildDependencyGraph(template: TemplateDocument): DependencyGraph;
|
|
54
|
+
//# sourceMappingURL=graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/lib/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,sBAAsB,CAAC;AAI5E,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,IAAI,EAAE,KAAK,GAAG,YAAY,GAAG,WAAW,GAAG,WAAW,CAAC;IACvD,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wDAAwD;AACxD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,+EAA+E;IAC/E,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,yDAAyD;IACzD,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC3B;AAED,oDAAoD;AACpD,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjC,4BAA4B;IAC5B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,uCAAuC;IACvC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,gFAAgF;IAChF,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,gEAAgE;IAChE,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;CAC1C;AAID,yEAAyE;AACzE,eAAO,MAAM,iBAAiB,aAS5B,CAAC;AAwDH;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,eAAe,CAoFhF"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency Graph Builder for CloudFormation templates (Phase 2 of #90)
|
|
3
|
+
*
|
|
4
|
+
* Scans a resolved CloudFormation template and builds a directed dependency graph
|
|
5
|
+
* by detecting inter-resource references via Ref, Fn::GetAtt, DependsOn, and Conditions.
|
|
6
|
+
*
|
|
7
|
+
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
|
|
8
|
+
*/
|
|
9
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
10
|
+
/** AWS pseudo-parameters that should not be treated as resource refs. */
|
|
11
|
+
export const PSEUDO_PARAMETERS = new Set([
|
|
12
|
+
'AWS::AccountId',
|
|
13
|
+
'AWS::NotificationARNs',
|
|
14
|
+
'AWS::NoValue',
|
|
15
|
+
'AWS::Partition',
|
|
16
|
+
'AWS::Region',
|
|
17
|
+
'AWS::StackId',
|
|
18
|
+
'AWS::StackName',
|
|
19
|
+
'AWS::URLSuffix',
|
|
20
|
+
]);
|
|
21
|
+
/**
|
|
22
|
+
* Deep-walk a template value and collect all resource references.
|
|
23
|
+
* Mutates `refs` in place for performance.
|
|
24
|
+
*/
|
|
25
|
+
function collectRefs(value, resourceIds, parameterIds, refs, source) {
|
|
26
|
+
if (value == null || typeof value !== 'object')
|
|
27
|
+
return;
|
|
28
|
+
if (Array.isArray(value)) {
|
|
29
|
+
for (const item of value)
|
|
30
|
+
collectRefs(item, resourceIds, parameterIds, refs, source);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const obj = value;
|
|
34
|
+
// Ref
|
|
35
|
+
if ('Ref' in obj && typeof obj.Ref === 'string') {
|
|
36
|
+
const target = obj.Ref;
|
|
37
|
+
if (resourceIds.has(target) && !PSEUDO_PARAMETERS.has(target) && !parameterIds.has(target)) {
|
|
38
|
+
refs.push({ source, target, type: 'Ref' });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Fn::GetAtt
|
|
42
|
+
if ('Fn::GetAtt' in obj) {
|
|
43
|
+
const getAtt = obj['Fn::GetAtt'];
|
|
44
|
+
let target;
|
|
45
|
+
let attribute;
|
|
46
|
+
if (Array.isArray(getAtt) && getAtt.length >= 2 && typeof getAtt[0] === 'string') {
|
|
47
|
+
target = getAtt[0];
|
|
48
|
+
attribute = String(getAtt[1]);
|
|
49
|
+
}
|
|
50
|
+
else if (typeof getAtt === 'string' && getAtt.includes('.')) {
|
|
51
|
+
const dot = getAtt.indexOf('.');
|
|
52
|
+
target = getAtt.substring(0, dot);
|
|
53
|
+
attribute = getAtt.substring(dot + 1);
|
|
54
|
+
}
|
|
55
|
+
if (target && resourceIds.has(target)) {
|
|
56
|
+
refs.push({ source, target, type: 'Fn::GetAtt', attribute });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Recurse into all values
|
|
60
|
+
for (const val of Object.values(obj)) {
|
|
61
|
+
collectRefs(val, resourceIds, parameterIds, refs, source);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
65
|
+
/**
|
|
66
|
+
* Build a directed dependency graph from a resolved CloudFormation template.
|
|
67
|
+
*
|
|
68
|
+
* @param template - A fully resolved CloudFormation template document.
|
|
69
|
+
* @returns The dependency graph.
|
|
70
|
+
*/
|
|
71
|
+
export function buildDependencyGraph(template) {
|
|
72
|
+
const resources = template.Resources ?? {};
|
|
73
|
+
const resourceIds = new Set(Object.keys(resources));
|
|
74
|
+
const parameterIds = new Set(Object.keys(template.Parameters ?? {}));
|
|
75
|
+
const nodes = new Map();
|
|
76
|
+
const edges = [];
|
|
77
|
+
const conditionUsage = new Map();
|
|
78
|
+
// Initialize nodes
|
|
79
|
+
for (const [logicalId, resource] of Object.entries(resources)) {
|
|
80
|
+
nodes.set(logicalId, {
|
|
81
|
+
logicalId,
|
|
82
|
+
resourceType: resource.Type ?? 'Unknown',
|
|
83
|
+
conditions: [],
|
|
84
|
+
dependsOn: new Set(),
|
|
85
|
+
dependedOnBy: new Set(),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// Collect edges
|
|
89
|
+
for (const [logicalId, resource] of Object.entries(resources)) {
|
|
90
|
+
const node = nodes.get(logicalId);
|
|
91
|
+
// DependsOn
|
|
92
|
+
if (resource.DependsOn) {
|
|
93
|
+
const deps = Array.isArray(resource.DependsOn) ? resource.DependsOn : [resource.DependsOn];
|
|
94
|
+
for (const dep of deps) {
|
|
95
|
+
if (resourceIds.has(dep)) {
|
|
96
|
+
edges.push({ source: logicalId, target: dep, type: 'DependsOn' });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Condition
|
|
101
|
+
if (resource.Condition) {
|
|
102
|
+
node.conditions.push(resource.Condition);
|
|
103
|
+
let set = conditionUsage.get(resource.Condition);
|
|
104
|
+
if (!set) {
|
|
105
|
+
set = new Set();
|
|
106
|
+
conditionUsage.set(resource.Condition, set);
|
|
107
|
+
}
|
|
108
|
+
set.add(logicalId);
|
|
109
|
+
// If another resource also uses this condition, they share a dependency via condition
|
|
110
|
+
// but we don't add edges for that — it's tracked separately.
|
|
111
|
+
}
|
|
112
|
+
// Deep-walk Properties, Metadata, CreationPolicy, UpdatePolicy for Ref/GetAtt
|
|
113
|
+
const walkTargets = [
|
|
114
|
+
resource.Properties,
|
|
115
|
+
resource.Metadata,
|
|
116
|
+
resource.CreationPolicy,
|
|
117
|
+
resource.UpdatePolicy,
|
|
118
|
+
];
|
|
119
|
+
for (const target of walkTargets) {
|
|
120
|
+
if (target != null) {
|
|
121
|
+
collectRefs(target, resourceIds, parameterIds, edges, logicalId);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Deduplicate edges and build adjacency
|
|
126
|
+
const edgeSet = new Set();
|
|
127
|
+
const dedupedEdges = [];
|
|
128
|
+
for (const edge of edges) {
|
|
129
|
+
const key = `${edge.source}|${edge.target}|${edge.type}|${edge.attribute ?? ''}`;
|
|
130
|
+
if (!edgeSet.has(key)) {
|
|
131
|
+
edgeSet.add(key);
|
|
132
|
+
dedupedEdges.push(edge);
|
|
133
|
+
const sourceNode = nodes.get(edge.source);
|
|
134
|
+
const targetNode = nodes.get(edge.target);
|
|
135
|
+
if (sourceNode)
|
|
136
|
+
sourceNode.dependsOn.add(edge.target);
|
|
137
|
+
if (targetNode)
|
|
138
|
+
targetNode.dependedOnBy.add(edge.source);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
nodes,
|
|
143
|
+
edges: dedupedEdges,
|
|
144
|
+
resourceIds,
|
|
145
|
+
parameterIds,
|
|
146
|
+
conditionUsage,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../../src/lib/graph.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Split Strategy & Execution (Phases 2 & 3 of #90)
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - `suggestSplit()` — analyze a template and suggest how to break it into stacks
|
|
6
|
+
* - `autoSplit()` — generate the actual child + parent stack templates
|
|
7
|
+
*
|
|
8
|
+
* Cross-stack references are wired via CloudFormation Exports / Fn::ImportValue,
|
|
9
|
+
* similar to how AWS CDK handles cross-stack references.
|
|
10
|
+
*
|
|
11
|
+
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-exports.html
|
|
12
|
+
*/
|
|
13
|
+
import type { TemplateDocument } from '../types/template.js';
|
|
14
|
+
import type { DependencyGraph, DependencyEdge } from './graph.js';
|
|
15
|
+
/**
|
|
16
|
+
* Resource type prefix → category mapping.
|
|
17
|
+
* Order matters: more specific prefixes should come first.
|
|
18
|
+
*/
|
|
19
|
+
export declare const CATEGORY_RULES: Array<{
|
|
20
|
+
prefixes: string[];
|
|
21
|
+
category: string;
|
|
22
|
+
}>;
|
|
23
|
+
/** Fallback category for unmatched resource types. */
|
|
24
|
+
export declare const DEFAULT_CATEGORY = "Other";
|
|
25
|
+
/** Classify a CloudFormation resource type into a category. */
|
|
26
|
+
export declare function categorizeResource(resourceType: string): string;
|
|
27
|
+
/** A group of resources proposed to live in one stack. */
|
|
28
|
+
export interface ResourceGroup {
|
|
29
|
+
name: string;
|
|
30
|
+
category: string;
|
|
31
|
+
resourceIds: string[];
|
|
32
|
+
/** Resource types summary. */
|
|
33
|
+
resourceTypes: Record<string, number>;
|
|
34
|
+
}
|
|
35
|
+
/** A dependency that crosses stack boundaries. */
|
|
36
|
+
export interface CrossStackDependency {
|
|
37
|
+
sourceStack: string;
|
|
38
|
+
targetStack: string;
|
|
39
|
+
sourceResource: string;
|
|
40
|
+
targetResource: string;
|
|
41
|
+
edge: DependencyEdge;
|
|
42
|
+
}
|
|
43
|
+
/** Output of `suggestSplit`. */
|
|
44
|
+
export interface SplitSuggestion {
|
|
45
|
+
groups: ResourceGroup[];
|
|
46
|
+
crossStackDependencies: CrossStackDependency[];
|
|
47
|
+
/** Topological deployment order (group names). */
|
|
48
|
+
deploymentOrder: string[];
|
|
49
|
+
}
|
|
50
|
+
/** Options for suggestSplit / autoSplit. */
|
|
51
|
+
export interface SplitOptions {
|
|
52
|
+
/** Whether to generate a parent orchestrator stack. Default: true. */
|
|
53
|
+
generateParent?: boolean;
|
|
54
|
+
/** Stack name prefix for exports. Default: template description or 'Stack'. */
|
|
55
|
+
stackPrefix?: string;
|
|
56
|
+
}
|
|
57
|
+
/** A generated child stack template + metadata. */
|
|
58
|
+
export interface GeneratedStack {
|
|
59
|
+
name: string;
|
|
60
|
+
template: TemplateDocument;
|
|
61
|
+
/** Resources in this stack. */
|
|
62
|
+
resourceIds: string[];
|
|
63
|
+
}
|
|
64
|
+
/** Output of `autoSplit`. */
|
|
65
|
+
export interface SplitResult {
|
|
66
|
+
stacks: GeneratedStack[];
|
|
67
|
+
parent?: GeneratedStack;
|
|
68
|
+
suggestion: SplitSuggestion;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Analyze a template's dependency graph and suggest how to split it into stacks.
|
|
72
|
+
*/
|
|
73
|
+
export declare function suggestSplit(template: TemplateDocument, graph: DependencyGraph, options?: SplitOptions): SplitSuggestion;
|
|
74
|
+
/**
|
|
75
|
+
* Format a split suggestion as a human-readable report.
|
|
76
|
+
*/
|
|
77
|
+
export declare function formatSplitReport(suggestion: SplitSuggestion): string;
|
|
78
|
+
/**
|
|
79
|
+
* Generate actual split stack templates from a suggestion.
|
|
80
|
+
*/
|
|
81
|
+
export declare function autoSplit(template: TemplateDocument, graph: DependencyGraph, suggestion?: SplitSuggestion, options?: SplitOptions): SplitResult;
|
|
82
|
+
//# sourceMappingURL=split.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../../src/lib/split.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAmC,MAAM,sBAAsB,CAAC;AAC9F,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIlE;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAiD1E,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAExC,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAO/D;AAID,0DAA0D;AAC1D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,8BAA8B;IAC9B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,kDAAkD;AAClD,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,cAAc,CAAC;CACtB;AAED,gCAAgC;AAChC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,sBAAsB,EAAE,oBAAoB,EAAE,CAAC;IAC/C,kDAAkD;IAClD,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,4CAA4C;AAC5C,MAAM,WAAW,YAAY;IAC3B,sEAAsE;IACtE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,mDAAmD;AACnD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,+BAA+B;IAC/B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,6BAA6B;AAC7B,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE,eAAe,CAAC;CAC7B;AAID;;GAEG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,eAAe,EACtB,OAAO,CAAC,EAAE,YAAY,GACrB,eAAe,CA0DjB;AAwDD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,eAAe,GAAG,MAAM,CAkCrE;AAID;;GAEG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,eAAe,EACtB,UAAU,CAAC,EAAE,eAAe,EAC5B,OAAO,CAAC,EAAE,YAAY,GACrB,WAAW,CAsHb"}
|
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Split Strategy & Execution (Phases 2 & 3 of #90)
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - `suggestSplit()` — analyze a template and suggest how to break it into stacks
|
|
6
|
+
* - `autoSplit()` — generate the actual child + parent stack templates
|
|
7
|
+
*
|
|
8
|
+
* Cross-stack references are wired via CloudFormation Exports / Fn::ImportValue,
|
|
9
|
+
* similar to how AWS CDK handles cross-stack references.
|
|
10
|
+
*
|
|
11
|
+
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-exports.html
|
|
12
|
+
*/
|
|
13
|
+
// ── Category Heuristics ──────────────────────────────────────────────────────
|
|
14
|
+
/**
|
|
15
|
+
* Resource type prefix → category mapping.
|
|
16
|
+
* Order matters: more specific prefixes should come first.
|
|
17
|
+
*/
|
|
18
|
+
export const CATEGORY_RULES = [
|
|
19
|
+
{
|
|
20
|
+
category: 'Networking',
|
|
21
|
+
prefixes: [
|
|
22
|
+
'AWS::EC2::VPC', 'AWS::EC2::Subnet', 'AWS::EC2::SecurityGroup',
|
|
23
|
+
'AWS::EC2::RouteTable', 'AWS::EC2::Route', 'AWS::EC2::NatGateway',
|
|
24
|
+
'AWS::EC2::InternetGateway', 'AWS::EC2::VPCGatewayAttachment',
|
|
25
|
+
'AWS::EC2::EIP', 'AWS::EC2::NetworkInterface', 'AWS::EC2::NetworkAcl',
|
|
26
|
+
'AWS::EC2::SubnetRouteTableAssociation', 'AWS::EC2::SubnetNetworkAclAssociation',
|
|
27
|
+
'AWS::EC2::VPCEndpoint', 'AWS::EC2::VPNGateway', 'AWS::EC2::DHCPOptions',
|
|
28
|
+
'AWS::EC2::TransitGateway', 'AWS::EC2::PrefixList',
|
|
29
|
+
'AWS::ElasticLoadBalancing::', 'AWS::ElasticLoadBalancingV2::',
|
|
30
|
+
'AWS::Route53::', 'AWS::CloudFront::',
|
|
31
|
+
'AWS::ApiGateway::', 'AWS::ApiGatewayV2::',
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
category: 'Compute',
|
|
36
|
+
prefixes: [
|
|
37
|
+
'AWS::Lambda::', 'AWS::EC2::Instance', 'AWS::EC2::LaunchTemplate',
|
|
38
|
+
'AWS::ECS::', 'AWS::EKS::', 'AWS::AutoScaling::',
|
|
39
|
+
'AWS::Batch::', 'AWS::StepFunctions::', 'AWS::AppRunner::',
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
category: 'Data',
|
|
44
|
+
prefixes: [
|
|
45
|
+
'AWS::DynamoDB::', 'AWS::RDS::', 'AWS::S3::', 'AWS::ElastiCache::',
|
|
46
|
+
'AWS::Redshift::', 'AWS::Neptune::', 'AWS::DocumentDB::',
|
|
47
|
+
'AWS::Kinesis::', 'AWS::OpenSearchService::', 'AWS::Elasticsearch::',
|
|
48
|
+
'AWS::DAX::', 'AWS::Athena::',
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
category: 'IAM',
|
|
53
|
+
prefixes: [
|
|
54
|
+
'AWS::IAM::Role', 'AWS::IAM::Policy', 'AWS::IAM::InstanceProfile',
|
|
55
|
+
'AWS::IAM::ManagedPolicy', 'AWS::IAM::User', 'AWS::IAM::Group',
|
|
56
|
+
'AWS::IAM::AccessKey', 'AWS::IAM::ServiceLinkedRole',
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
category: 'Monitoring',
|
|
61
|
+
prefixes: [
|
|
62
|
+
'AWS::CloudWatch::', 'AWS::SNS::', 'AWS::SQS::',
|
|
63
|
+
'AWS::Logs::', 'AWS::Events::', 'AWS::ApplicationAutoScaling::',
|
|
64
|
+
'AWS::CloudTrail::', 'AWS::Config::',
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
/** Fallback category for unmatched resource types. */
|
|
69
|
+
export const DEFAULT_CATEGORY = 'Other';
|
|
70
|
+
/** Classify a CloudFormation resource type into a category. */
|
|
71
|
+
export function categorizeResource(resourceType) {
|
|
72
|
+
for (const rule of CATEGORY_RULES) {
|
|
73
|
+
for (const prefix of rule.prefixes) {
|
|
74
|
+
if (resourceType.startsWith(prefix))
|
|
75
|
+
return rule.category;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return DEFAULT_CATEGORY;
|
|
79
|
+
}
|
|
80
|
+
// ── Phase 2: suggestSplit ────────────────────────────────────────────────────
|
|
81
|
+
/**
|
|
82
|
+
* Analyze a template's dependency graph and suggest how to split it into stacks.
|
|
83
|
+
*/
|
|
84
|
+
export function suggestSplit(template, graph, options) {
|
|
85
|
+
const resources = template.Resources ?? {};
|
|
86
|
+
// Group resources by category
|
|
87
|
+
const categoryMap = new Map();
|
|
88
|
+
for (const [logicalId, resource] of Object.entries(resources)) {
|
|
89
|
+
const cat = categorizeResource(resource.Type ?? 'Unknown');
|
|
90
|
+
let arr = categoryMap.get(cat);
|
|
91
|
+
if (!arr) {
|
|
92
|
+
arr = [];
|
|
93
|
+
categoryMap.set(cat, arr);
|
|
94
|
+
}
|
|
95
|
+
arr.push(logicalId);
|
|
96
|
+
}
|
|
97
|
+
// Build groups
|
|
98
|
+
const groups = [];
|
|
99
|
+
for (const [category, ids] of categoryMap) {
|
|
100
|
+
const types = {};
|
|
101
|
+
for (const id of ids) {
|
|
102
|
+
const t = resources[id]?.Type ?? 'Unknown';
|
|
103
|
+
types[t] = (types[t] ?? 0) + 1;
|
|
104
|
+
}
|
|
105
|
+
groups.push({
|
|
106
|
+
name: category,
|
|
107
|
+
category,
|
|
108
|
+
resourceIds: ids.sort(),
|
|
109
|
+
resourceTypes: types,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
groups.sort((a, b) => a.name.localeCompare(b.name));
|
|
113
|
+
// Build resource → group mapping
|
|
114
|
+
const resourceToGroup = new Map();
|
|
115
|
+
for (const g of groups) {
|
|
116
|
+
for (const id of g.resourceIds)
|
|
117
|
+
resourceToGroup.set(id, g.name);
|
|
118
|
+
}
|
|
119
|
+
// Find cross-stack dependencies
|
|
120
|
+
const crossStackDependencies = [];
|
|
121
|
+
for (const edge of graph.edges) {
|
|
122
|
+
const sg = resourceToGroup.get(edge.source);
|
|
123
|
+
const tg = resourceToGroup.get(edge.target);
|
|
124
|
+
if (sg && tg && sg !== tg) {
|
|
125
|
+
crossStackDependencies.push({
|
|
126
|
+
sourceStack: sg,
|
|
127
|
+
targetStack: tg,
|
|
128
|
+
sourceResource: edge.source,
|
|
129
|
+
targetResource: edge.target,
|
|
130
|
+
edge,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Compute deployment order via topological sort of group dependency DAG
|
|
135
|
+
const deploymentOrder = topoSortGroups(groups, crossStackDependencies);
|
|
136
|
+
return { groups, crossStackDependencies, deploymentOrder };
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Topological sort of groups based on cross-stack deps.
|
|
140
|
+
* Groups that are depended upon deploy first.
|
|
141
|
+
*/
|
|
142
|
+
function topoSortGroups(groups, deps) {
|
|
143
|
+
const names = groups.map((g) => g.name);
|
|
144
|
+
const inDegree = new Map();
|
|
145
|
+
const adj = new Map();
|
|
146
|
+
for (const n of names) {
|
|
147
|
+
inDegree.set(n, 0);
|
|
148
|
+
adj.set(n, new Set());
|
|
149
|
+
}
|
|
150
|
+
// edge: sourceStack depends on targetStack → targetStack must deploy first
|
|
151
|
+
const edgeSet = new Set();
|
|
152
|
+
for (const dep of deps) {
|
|
153
|
+
const key = `${dep.targetStack}→${dep.sourceStack}`;
|
|
154
|
+
if (!edgeSet.has(key)) {
|
|
155
|
+
edgeSet.add(key);
|
|
156
|
+
adj.get(dep.targetStack).add(dep.sourceStack);
|
|
157
|
+
inDegree.set(dep.sourceStack, (inDegree.get(dep.sourceStack) ?? 0) + 1);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const queue = [];
|
|
161
|
+
for (const [n, d] of inDegree) {
|
|
162
|
+
if (d === 0)
|
|
163
|
+
queue.push(n);
|
|
164
|
+
}
|
|
165
|
+
queue.sort();
|
|
166
|
+
const order = [];
|
|
167
|
+
while (queue.length > 0) {
|
|
168
|
+
const node = queue.shift();
|
|
169
|
+
order.push(node);
|
|
170
|
+
for (const neighbor of adj.get(node) ?? []) {
|
|
171
|
+
const newDeg = (inDegree.get(neighbor) ?? 1) - 1;
|
|
172
|
+
inDegree.set(neighbor, newDeg);
|
|
173
|
+
if (newDeg === 0) {
|
|
174
|
+
// Insert sorted for deterministic output
|
|
175
|
+
const idx = queue.findIndex((q) => q.localeCompare(neighbor) > 0);
|
|
176
|
+
if (idx === -1)
|
|
177
|
+
queue.push(neighbor);
|
|
178
|
+
else
|
|
179
|
+
queue.splice(idx, 0, neighbor);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// If there are cycles, append remaining groups
|
|
184
|
+
for (const n of names) {
|
|
185
|
+
if (!order.includes(n))
|
|
186
|
+
order.push(n);
|
|
187
|
+
}
|
|
188
|
+
return order;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Format a split suggestion as a human-readable report.
|
|
192
|
+
*/
|
|
193
|
+
export function formatSplitReport(suggestion) {
|
|
194
|
+
const lines = [
|
|
195
|
+
'Stack Split Suggestion',
|
|
196
|
+
'======================',
|
|
197
|
+
'',
|
|
198
|
+
];
|
|
199
|
+
lines.push(`Deployment Order: ${suggestion.deploymentOrder.join(' → ')}`);
|
|
200
|
+
lines.push('');
|
|
201
|
+
for (const group of suggestion.groups) {
|
|
202
|
+
lines.push(`📦 ${group.name} (${group.resourceIds.length} resources)`);
|
|
203
|
+
const types = Object.entries(group.resourceTypes).sort((a, b) => b[1] - a[1]);
|
|
204
|
+
for (const [type, count] of types) {
|
|
205
|
+
lines.push(` ${type}: ${count}`);
|
|
206
|
+
}
|
|
207
|
+
lines.push(` Resources: ${group.resourceIds.join(', ')}`);
|
|
208
|
+
lines.push('');
|
|
209
|
+
}
|
|
210
|
+
if (suggestion.crossStackDependencies.length > 0) {
|
|
211
|
+
lines.push('Cross-Stack Dependencies:');
|
|
212
|
+
const seen = new Set();
|
|
213
|
+
for (const dep of suggestion.crossStackDependencies) {
|
|
214
|
+
const key = `${dep.sourceResource}→${dep.targetResource}`;
|
|
215
|
+
if (seen.has(key))
|
|
216
|
+
continue;
|
|
217
|
+
seen.add(key);
|
|
218
|
+
lines.push(` ${dep.sourceStack}::${dep.sourceResource} → ${dep.targetStack}::${dep.targetResource} (${dep.edge.type}${dep.edge.attribute ? `:${dep.edge.attribute}` : ''})`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
lines.push('No cross-stack dependencies detected.');
|
|
223
|
+
}
|
|
224
|
+
return lines.join('\n');
|
|
225
|
+
}
|
|
226
|
+
// ── Phase 3: autoSplit ───────────────────────────────────────────────────────
|
|
227
|
+
/**
|
|
228
|
+
* Generate actual split stack templates from a suggestion.
|
|
229
|
+
*/
|
|
230
|
+
export function autoSplit(template, graph, suggestion, options) {
|
|
231
|
+
const opts = {
|
|
232
|
+
generateParent: options?.generateParent ?? true,
|
|
233
|
+
stackPrefix: options?.stackPrefix ?? 'Stack',
|
|
234
|
+
};
|
|
235
|
+
const sug = suggestion ?? suggestSplit(template, graph, options);
|
|
236
|
+
const resources = template.Resources ?? {};
|
|
237
|
+
// Build resource → group mapping
|
|
238
|
+
const resourceToGroup = new Map();
|
|
239
|
+
for (const g of sug.groups) {
|
|
240
|
+
for (const id of g.resourceIds)
|
|
241
|
+
resourceToGroup.set(id, g.name);
|
|
242
|
+
}
|
|
243
|
+
// Determine which resources need to be exported (referenced from another stack)
|
|
244
|
+
// Key: `logicalId` or `logicalId.attribute` → set of target stacks
|
|
245
|
+
const exportsNeeded = new Map();
|
|
246
|
+
for (const dep of sug.crossStackDependencies) {
|
|
247
|
+
const key = dep.edge.type === 'Fn::GetAtt' && dep.edge.attribute
|
|
248
|
+
? `${dep.targetResource}.${dep.edge.attribute}`
|
|
249
|
+
: dep.targetResource;
|
|
250
|
+
let entry = exportsNeeded.get(key);
|
|
251
|
+
if (!entry) {
|
|
252
|
+
entry = {
|
|
253
|
+
logicalId: dep.targetResource,
|
|
254
|
+
attribute: dep.edge.type === 'Fn::GetAtt' ? dep.edge.attribute : undefined,
|
|
255
|
+
targetStacks: new Set(),
|
|
256
|
+
};
|
|
257
|
+
exportsNeeded.set(key, entry);
|
|
258
|
+
}
|
|
259
|
+
entry.targetStacks.add(dep.sourceStack);
|
|
260
|
+
}
|
|
261
|
+
// Generate child stacks
|
|
262
|
+
const stacks = [];
|
|
263
|
+
for (const group of sug.groups) {
|
|
264
|
+
const resourceIdsInGroup = new Set(group.resourceIds);
|
|
265
|
+
const childResources = {};
|
|
266
|
+
for (const id of group.resourceIds) {
|
|
267
|
+
childResources[id] = resources[id];
|
|
268
|
+
}
|
|
269
|
+
// Determine which parameters are used by this group's resources
|
|
270
|
+
const usedParams = findUsedParameters(childResources, template.Parameters ?? {});
|
|
271
|
+
const usedMappings = findUsedMappings(childResources, template.Mappings ?? {});
|
|
272
|
+
const usedConditions = findUsedConditions(childResources, template.Conditions ?? {});
|
|
273
|
+
// Build the child template
|
|
274
|
+
const childTemplate = {};
|
|
275
|
+
if (template.AWSTemplateFormatVersion) {
|
|
276
|
+
childTemplate.AWSTemplateFormatVersion = template.AWSTemplateFormatVersion;
|
|
277
|
+
}
|
|
278
|
+
childTemplate.Description = `${template.Description ?? 'CloudFormation Stack'} - ${group.name}`;
|
|
279
|
+
if (Object.keys(usedParams).length > 0)
|
|
280
|
+
childTemplate.Parameters = usedParams;
|
|
281
|
+
if (Object.keys(usedMappings).length > 0)
|
|
282
|
+
childTemplate.Mappings = usedMappings;
|
|
283
|
+
if (Object.keys(usedConditions).length > 0)
|
|
284
|
+
childTemplate.Conditions = usedConditions;
|
|
285
|
+
// Rewrite resources: replace cross-stack Ref/GetAtt with Fn::ImportValue
|
|
286
|
+
const rewrittenResources = {};
|
|
287
|
+
for (const [id, resource] of Object.entries(childResources)) {
|
|
288
|
+
rewrittenResources[id] = rewriteResource(resource, resourceToGroup, group.name, opts.stackPrefix);
|
|
289
|
+
}
|
|
290
|
+
childTemplate.Resources = rewrittenResources;
|
|
291
|
+
// Add exports for resources that other stacks reference
|
|
292
|
+
const childOutputs = {};
|
|
293
|
+
// Carry over existing outputs that reference resources in this group
|
|
294
|
+
if (template.Outputs) {
|
|
295
|
+
for (const [outId, output] of Object.entries(template.Outputs)) {
|
|
296
|
+
const refs = findRefsInValue(output.Value, new Set(Object.keys(resources)));
|
|
297
|
+
if (refs.some((r) => resourceIdsInGroup.has(r))) {
|
|
298
|
+
childOutputs[outId] = output;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// Add cross-stack exports
|
|
303
|
+
for (const [key, entry] of exportsNeeded) {
|
|
304
|
+
if (!resourceIdsInGroup.has(entry.logicalId))
|
|
305
|
+
continue;
|
|
306
|
+
const exportName = makeExportName(opts.stackPrefix, group.name, entry.logicalId, entry.attribute);
|
|
307
|
+
const outputLogicalId = makeOutputLogicalId(entry.logicalId, entry.attribute);
|
|
308
|
+
const outputValue = entry.attribute
|
|
309
|
+
? { 'Fn::GetAtt': [entry.logicalId, entry.attribute] }
|
|
310
|
+
: { Ref: entry.logicalId };
|
|
311
|
+
childOutputs[outputLogicalId] = {
|
|
312
|
+
Description: `Cross-stack export for ${key}`,
|
|
313
|
+
Value: outputValue,
|
|
314
|
+
Export: {
|
|
315
|
+
Name: { 'Fn::Sub': `\${AWS::StackName}-${exportName}` },
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
if (Object.keys(childOutputs).length > 0)
|
|
320
|
+
childTemplate.Outputs = childOutputs;
|
|
321
|
+
stacks.push({
|
|
322
|
+
name: group.name,
|
|
323
|
+
template: childTemplate,
|
|
324
|
+
resourceIds: group.resourceIds,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
// Generate parent orchestrator stack
|
|
328
|
+
let parent;
|
|
329
|
+
if (opts.generateParent) {
|
|
330
|
+
parent = generateParentStack(template, sug, stacks, opts);
|
|
331
|
+
}
|
|
332
|
+
return { stacks, parent, suggestion: sug };
|
|
333
|
+
}
|
|
334
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
335
|
+
function makeExportName(prefix, groupName, logicalId, attribute) {
|
|
336
|
+
const base = `${groupName}-${logicalId}`;
|
|
337
|
+
return attribute ? `${base}-${attribute}` : base;
|
|
338
|
+
}
|
|
339
|
+
function makeOutputLogicalId(logicalId, attribute) {
|
|
340
|
+
const base = `Export${logicalId}`;
|
|
341
|
+
return attribute ? `${base}${attribute.replace(/[^a-zA-Z0-9]/g, '')}` : base;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Deep-rewrite a resource, replacing cross-stack Ref/GetAtt with Fn::ImportValue.
|
|
345
|
+
*/
|
|
346
|
+
function rewriteResource(resource, resourceToGroup, currentGroup, stackPrefix) {
|
|
347
|
+
return JSON.parse(JSON.stringify(resource), (_key, value) => {
|
|
348
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
349
|
+
// Ref to another stack's resource
|
|
350
|
+
if ('Ref' in value && typeof value.Ref === 'string') {
|
|
351
|
+
const targetGroup = resourceToGroup.get(value.Ref);
|
|
352
|
+
if (targetGroup && targetGroup !== currentGroup) {
|
|
353
|
+
const exportName = makeExportName(stackPrefix, targetGroup, value.Ref);
|
|
354
|
+
return {
|
|
355
|
+
'Fn::ImportValue': { 'Fn::Sub': `\${AWS::StackName}-${exportName}` },
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// Fn::GetAtt to another stack's resource
|
|
360
|
+
if ('Fn::GetAtt' in value) {
|
|
361
|
+
let target;
|
|
362
|
+
let attr;
|
|
363
|
+
const getAtt = value['Fn::GetAtt'];
|
|
364
|
+
if (Array.isArray(getAtt) && getAtt.length >= 2) {
|
|
365
|
+
target = getAtt[0];
|
|
366
|
+
attr = String(getAtt[1]);
|
|
367
|
+
}
|
|
368
|
+
else if (typeof getAtt === 'string' && getAtt.includes('.')) {
|
|
369
|
+
const dot = getAtt.indexOf('.');
|
|
370
|
+
target = getAtt.substring(0, dot);
|
|
371
|
+
attr = getAtt.substring(dot + 1);
|
|
372
|
+
}
|
|
373
|
+
if (target && attr) {
|
|
374
|
+
const targetGroup = resourceToGroup.get(target);
|
|
375
|
+
if (targetGroup && targetGroup !== currentGroup) {
|
|
376
|
+
const exportName = makeExportName(stackPrefix, targetGroup, target, attr);
|
|
377
|
+
return {
|
|
378
|
+
'Fn::ImportValue': { 'Fn::Sub': `\${AWS::StackName}-${exportName}` },
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return value;
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
/** Find all resource logical IDs referenced (via Ref) in a template value. */
|
|
388
|
+
function findRefsInValue(value, resourceIds) {
|
|
389
|
+
const refs = [];
|
|
390
|
+
const walk = (v) => {
|
|
391
|
+
if (v == null || typeof v !== 'object')
|
|
392
|
+
return;
|
|
393
|
+
if (Array.isArray(v)) {
|
|
394
|
+
v.forEach(walk);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const obj = v;
|
|
398
|
+
if ('Ref' in obj && typeof obj.Ref === 'string' && resourceIds.has(obj.Ref)) {
|
|
399
|
+
refs.push(obj.Ref);
|
|
400
|
+
}
|
|
401
|
+
if ('Fn::GetAtt' in obj) {
|
|
402
|
+
const ga = obj['Fn::GetAtt'];
|
|
403
|
+
if (Array.isArray(ga) && typeof ga[0] === 'string' && resourceIds.has(ga[0])) {
|
|
404
|
+
refs.push(ga[0]);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
Object.values(obj).forEach(walk);
|
|
408
|
+
};
|
|
409
|
+
walk(value);
|
|
410
|
+
return refs;
|
|
411
|
+
}
|
|
412
|
+
/** Find parameters actually referenced by the given resources. */
|
|
413
|
+
function findUsedParameters(resources, allParams) {
|
|
414
|
+
const paramNames = new Set(Object.keys(allParams));
|
|
415
|
+
const used = new Set();
|
|
416
|
+
const walk = (v) => {
|
|
417
|
+
if (v == null || typeof v !== 'object')
|
|
418
|
+
return;
|
|
419
|
+
if (Array.isArray(v)) {
|
|
420
|
+
v.forEach(walk);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
const obj = v;
|
|
424
|
+
if ('Ref' in obj && typeof obj.Ref === 'string' && paramNames.has(obj.Ref)) {
|
|
425
|
+
used.add(obj.Ref);
|
|
426
|
+
}
|
|
427
|
+
// Also check Fn::Sub for ${ParamName} references
|
|
428
|
+
if ('Fn::Sub' in obj) {
|
|
429
|
+
const sub = obj['Fn::Sub'];
|
|
430
|
+
const str = typeof sub === 'string' ? sub : Array.isArray(sub) ? sub[0] : '';
|
|
431
|
+
if (typeof str === 'string') {
|
|
432
|
+
for (const match of str.matchAll(/\$\{([^!}]+)\}/g)) {
|
|
433
|
+
if (paramNames.has(match[1]))
|
|
434
|
+
used.add(match[1]);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
Object.values(obj).forEach(walk);
|
|
439
|
+
};
|
|
440
|
+
for (const r of Object.values(resources))
|
|
441
|
+
walk(r);
|
|
442
|
+
const result = {};
|
|
443
|
+
for (const p of used)
|
|
444
|
+
result[p] = allParams[p];
|
|
445
|
+
return result;
|
|
446
|
+
}
|
|
447
|
+
/** Find mappings referenced by FindInMap in the given resources. */
|
|
448
|
+
function findUsedMappings(resources, allMappings) {
|
|
449
|
+
const used = new Set();
|
|
450
|
+
const walk = (v) => {
|
|
451
|
+
if (v == null || typeof v !== 'object')
|
|
452
|
+
return;
|
|
453
|
+
if (Array.isArray(v)) {
|
|
454
|
+
v.forEach(walk);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
const obj = v;
|
|
458
|
+
if ('Fn::FindInMap' in obj) {
|
|
459
|
+
const fim = obj['Fn::FindInMap'];
|
|
460
|
+
if (Array.isArray(fim) && typeof fim[0] === 'string')
|
|
461
|
+
used.add(fim[0]);
|
|
462
|
+
}
|
|
463
|
+
Object.values(obj).forEach(walk);
|
|
464
|
+
};
|
|
465
|
+
for (const r of Object.values(resources))
|
|
466
|
+
walk(r);
|
|
467
|
+
const result = {};
|
|
468
|
+
for (const m of used)
|
|
469
|
+
if (allMappings[m])
|
|
470
|
+
result[m] = allMappings[m];
|
|
471
|
+
return result;
|
|
472
|
+
}
|
|
473
|
+
/** Find conditions referenced by resources (Condition key or Fn::If). */
|
|
474
|
+
function findUsedConditions(resources, allConditions) {
|
|
475
|
+
const used = new Set();
|
|
476
|
+
for (const r of Object.values(resources)) {
|
|
477
|
+
if (r.Condition)
|
|
478
|
+
used.add(r.Condition);
|
|
479
|
+
}
|
|
480
|
+
const walk = (v) => {
|
|
481
|
+
if (v == null || typeof v !== 'object')
|
|
482
|
+
return;
|
|
483
|
+
if (Array.isArray(v)) {
|
|
484
|
+
v.forEach(walk);
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const obj = v;
|
|
488
|
+
if ('Fn::If' in obj && Array.isArray(obj['Fn::If']) && typeof obj['Fn::If'][0] === 'string') {
|
|
489
|
+
used.add(obj['Fn::If'][0]);
|
|
490
|
+
}
|
|
491
|
+
if ('Condition' in obj && typeof obj.Condition === 'string' && allConditions[obj.Condition]) {
|
|
492
|
+
used.add(obj.Condition);
|
|
493
|
+
}
|
|
494
|
+
Object.values(obj).forEach(walk);
|
|
495
|
+
};
|
|
496
|
+
for (const r of Object.values(resources))
|
|
497
|
+
walk(r);
|
|
498
|
+
const result = {};
|
|
499
|
+
for (const c of used)
|
|
500
|
+
if (allConditions[c])
|
|
501
|
+
result[c] = allConditions[c];
|
|
502
|
+
return result;
|
|
503
|
+
}
|
|
504
|
+
/** Generate the parent orchestrator stack with nested stack resources. */
|
|
505
|
+
function generateParentStack(template, suggestion, childStacks, opts) {
|
|
506
|
+
const parentTemplate = {};
|
|
507
|
+
if (template.AWSTemplateFormatVersion) {
|
|
508
|
+
parentTemplate.AWSTemplateFormatVersion = template.AWSTemplateFormatVersion;
|
|
509
|
+
}
|
|
510
|
+
parentTemplate.Description = `${template.Description ?? 'CloudFormation Stack'} - Parent Orchestrator`;
|
|
511
|
+
// Forward all parameters
|
|
512
|
+
if (template.Parameters && Object.keys(template.Parameters).length > 0) {
|
|
513
|
+
parentTemplate.Parameters = { ...template.Parameters };
|
|
514
|
+
}
|
|
515
|
+
// Add a TemplateURLBase parameter for S3 location
|
|
516
|
+
parentTemplate.Parameters = {
|
|
517
|
+
...parentTemplate.Parameters,
|
|
518
|
+
TemplateURLBase: {
|
|
519
|
+
Type: 'String',
|
|
520
|
+
Description: 'S3 URL base where child stack templates are uploaded',
|
|
521
|
+
},
|
|
522
|
+
};
|
|
523
|
+
const parentResources = {};
|
|
524
|
+
const stackNameMap = new Map();
|
|
525
|
+
for (const group of suggestion.deploymentOrder) {
|
|
526
|
+
const child = childStacks.find((s) => s.name === group);
|
|
527
|
+
if (!child)
|
|
528
|
+
continue;
|
|
529
|
+
const stackLogicalId = `${group.replace(/[^a-zA-Z0-9]/g, '')}Stack`;
|
|
530
|
+
stackNameMap.set(group, stackLogicalId);
|
|
531
|
+
// Determine DependsOn from cross-stack deps
|
|
532
|
+
const dependsOn = new Set();
|
|
533
|
+
for (const dep of suggestion.crossStackDependencies) {
|
|
534
|
+
if (dep.sourceStack === group && dep.targetStack !== group) {
|
|
535
|
+
const depStackId = `${dep.targetStack.replace(/[^a-zA-Z0-9]/g, '')}Stack`;
|
|
536
|
+
dependsOn.add(depStackId);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
const nestedResource = {
|
|
540
|
+
Type: 'AWS::CloudFormation::Stack',
|
|
541
|
+
Properties: {
|
|
542
|
+
TemplateURL: { 'Fn::Sub': `\${TemplateURLBase}/${group}.json` },
|
|
543
|
+
},
|
|
544
|
+
};
|
|
545
|
+
if (dependsOn.size > 0) {
|
|
546
|
+
nestedResource.DependsOn = [...dependsOn].sort();
|
|
547
|
+
}
|
|
548
|
+
parentResources[stackLogicalId] = nestedResource;
|
|
549
|
+
}
|
|
550
|
+
parentTemplate.Resources = parentResources;
|
|
551
|
+
return {
|
|
552
|
+
name: 'Parent',
|
|
553
|
+
template: parentTemplate,
|
|
554
|
+
resourceIds: [],
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
//# sourceMappingURL=split.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split.js","sourceRoot":"","sources":["../../src/lib/split.ts"],"names":[],"mappings":"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"}
|