@suss/contract-terraform 0.32.0 → 0.33.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/README.md +66 -4
- package/dist/index.cjs +876 -155
- package/dist/index.d.cts +199 -36
- package/dist/index.d.ts +199 -36
- package/dist/index.js +882 -156
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -33,6 +33,7 @@ __export(index_exports, {
|
|
|
33
33
|
filterCalls: () => filterCalls,
|
|
34
34
|
filterTerms: () => filterTerms,
|
|
35
35
|
filterValuesFor: () => filterValuesFor,
|
|
36
|
+
jsonAttributeValue: () => jsonAttributeValue,
|
|
36
37
|
parseFilterQuery: () => parseFilterQuery,
|
|
37
38
|
terraformFileToSummaries: () => terraformFileToSummaries,
|
|
38
39
|
terraformToSummaries: () => terraformToSummaries
|
|
@@ -40,10 +41,360 @@ __export(index_exports, {
|
|
|
40
41
|
module.exports = __toCommonJS(index_exports);
|
|
41
42
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
42
43
|
var import_node_path = __toESM(require("path"), 1);
|
|
43
|
-
var import_hcl2_parser = __toESM(require("hcl2-parser"), 1);
|
|
44
44
|
var import_semver = __toESM(require("semver"), 1);
|
|
45
45
|
var import_behavioral_ir = require("@suss/behavioral-ir");
|
|
46
46
|
|
|
47
|
+
// src/hclDocument.ts
|
|
48
|
+
var import_hcl2_parser = __toESM(require("hcl2-parser"), 1);
|
|
49
|
+
var WRAPPER = "value";
|
|
50
|
+
function parseHclDocument(source) {
|
|
51
|
+
let read;
|
|
52
|
+
try {
|
|
53
|
+
const [parsed] = import_hcl2_parser.default.parseToObject(source);
|
|
54
|
+
read = parsed;
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return typeof read === "object" && read !== null && !Array.isArray(read) ? read : null;
|
|
59
|
+
}
|
|
60
|
+
function parseHclExpression(expression) {
|
|
61
|
+
return parseHclDocument(`${WRAPPER} = ${expression}`)?.[WRAPPER] ?? null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/hclValue.ts
|
|
65
|
+
function arrayOf(value) {
|
|
66
|
+
if (value === void 0 || value === null) {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
return Array.isArray(value) ? value : [value];
|
|
70
|
+
}
|
|
71
|
+
function asRecord(value) {
|
|
72
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
73
|
+
}
|
|
74
|
+
function stringOf(value) {
|
|
75
|
+
return typeof value === "string" ? value : null;
|
|
76
|
+
}
|
|
77
|
+
function recordsIn(value) {
|
|
78
|
+
return arrayOf(value).map(asRecord).filter((record) => record !== null);
|
|
79
|
+
}
|
|
80
|
+
function mapStrings(value, leaf) {
|
|
81
|
+
if (typeof value === "string") {
|
|
82
|
+
return leaf(value);
|
|
83
|
+
}
|
|
84
|
+
if (Array.isArray(value)) {
|
|
85
|
+
return value.map((entry) => mapStrings(entry, leaf));
|
|
86
|
+
}
|
|
87
|
+
const record = asRecord(value);
|
|
88
|
+
if (record === null) {
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
return Object.fromEntries(
|
|
92
|
+
Object.entries(record).map(([name, entry]) => [
|
|
93
|
+
name,
|
|
94
|
+
mapStrings(entry, leaf)
|
|
95
|
+
])
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
function someString(value, test) {
|
|
99
|
+
if (typeof value === "string") {
|
|
100
|
+
return test(value);
|
|
101
|
+
}
|
|
102
|
+
if (Array.isArray(value)) {
|
|
103
|
+
return value.some((entry) => someString(entry, test));
|
|
104
|
+
}
|
|
105
|
+
return Object.values(asRecord(value) ?? {}).some(
|
|
106
|
+
(entry) => someString(entry, test)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/mapValue.ts
|
|
111
|
+
var WHOLE_INTERPOLATION = /^\$\{([\s\S]*)\}$/;
|
|
112
|
+
var MERGE_CALL = /^merge\(([\s\S]*)\)$/;
|
|
113
|
+
var LOCAL_MAP = /^local\.([A-Za-z_][\w-]*)$/;
|
|
114
|
+
var VARIABLE_MAP = /^var\.([A-Za-z_][\w-]*)$/;
|
|
115
|
+
var CHAIN_LIMIT = 4;
|
|
116
|
+
var OPENERS = "([{";
|
|
117
|
+
var CLOSERS = ")]}";
|
|
118
|
+
function statedMap(value, scope) {
|
|
119
|
+
return mapFrom(value, scope, 0);
|
|
120
|
+
}
|
|
121
|
+
function mapFrom(value, scope, depth) {
|
|
122
|
+
if (depth > CHAIN_LIMIT) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
const record = asRecord(value);
|
|
126
|
+
if (record !== null) {
|
|
127
|
+
return record;
|
|
128
|
+
}
|
|
129
|
+
if (typeof value !== "string") {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const inner = WHOLE_INTERPOLATION.exec(value.trim());
|
|
133
|
+
return inner === null ? null : mapFromExpression(inner[1].trim(), scope, depth);
|
|
134
|
+
}
|
|
135
|
+
function mapFromExpression(expression, scope, depth) {
|
|
136
|
+
const merged = MERGE_CALL.exec(expression);
|
|
137
|
+
if (merged !== null) {
|
|
138
|
+
return mergedMaps(splitArguments(merged[1]), scope, depth);
|
|
139
|
+
}
|
|
140
|
+
const local = LOCAL_MAP.exec(expression);
|
|
141
|
+
if (local !== null) {
|
|
142
|
+
return mapFrom(scope.locals[local[1]], scope, depth + 1);
|
|
143
|
+
}
|
|
144
|
+
const variable = VARIABLE_MAP.exec(expression);
|
|
145
|
+
if (variable !== null) {
|
|
146
|
+
const name = variable[1];
|
|
147
|
+
return mapFrom(scope.arguments[name], scope, depth + 1) ?? mapFrom(scope.defaults[name], scope, depth + 1);
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
function mergedMaps(argumentTexts, scope, depth) {
|
|
152
|
+
const merged = {};
|
|
153
|
+
for (const text of argumentTexts) {
|
|
154
|
+
const stated = mapFrom(parseHclExpression(text), scope, depth + 1);
|
|
155
|
+
if (stated === null) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
Object.assign(merged, stated);
|
|
159
|
+
}
|
|
160
|
+
return merged;
|
|
161
|
+
}
|
|
162
|
+
function splitArguments(text) {
|
|
163
|
+
const found = [];
|
|
164
|
+
let depth = 0;
|
|
165
|
+
let quoted = false;
|
|
166
|
+
let start = 0;
|
|
167
|
+
for (let at = 0; at < text.length; at += 1) {
|
|
168
|
+
const character = text[at];
|
|
169
|
+
if (quoted) {
|
|
170
|
+
quoted = character !== '"' || text[at - 1] === "\\";
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (character === '"') {
|
|
174
|
+
quoted = true;
|
|
175
|
+
} else if (OPENERS.includes(character)) {
|
|
176
|
+
depth += 1;
|
|
177
|
+
} else if (CLOSERS.includes(character)) {
|
|
178
|
+
depth -= 1;
|
|
179
|
+
} else if (character === "," && depth === 0) {
|
|
180
|
+
found.push(text.slice(start, at));
|
|
181
|
+
start = at + 1;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
found.push(text.slice(start));
|
|
185
|
+
return found.map((argument) => argument.trim()).filter((argument) => argument.length > 0);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/references.ts
|
|
189
|
+
var SUB_TOKEN = /\$\{([^}]*)\}/g;
|
|
190
|
+
function replaceInterpolations(text, settle) {
|
|
191
|
+
return text.replace(
|
|
192
|
+
SUB_TOKEN,
|
|
193
|
+
(written, inner) => settle(inner.trim()) ?? written
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
function interpolatedReferences(text) {
|
|
197
|
+
return [...text.matchAll(SUB_TOKEN)].map(
|
|
198
|
+
(match) => match[1].trim()
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
var RESOURCE_ATTRIBUTE = /^([A-Za-z][\w-]*)\.([A-Za-z_][\w-]*)\.([A-Za-z_][\w-]*)$/;
|
|
202
|
+
var WHOLE_REFERENCE = /^\$\{([^}]*)\}$/;
|
|
203
|
+
var LOCAL_VALUE = /^local\.([A-Za-z_][\w-]*)$/;
|
|
204
|
+
var VARIABLE_VALUE = /^var\.([A-Za-z_][\w-]*)$/;
|
|
205
|
+
var CHAIN_LIMIT2 = 4;
|
|
206
|
+
function referenceScope(opts) {
|
|
207
|
+
const resources = /* @__PURE__ */ new Map();
|
|
208
|
+
for (const [resourceType, label, body] of opts.resources) {
|
|
209
|
+
const address = `${resourceType}.${label}`;
|
|
210
|
+
if (!resources.has(address)) {
|
|
211
|
+
resources.set(address, body);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
resources,
|
|
216
|
+
locals: firstOfEach(opts.locals ?? []),
|
|
217
|
+
arguments: opts.arguments ?? {},
|
|
218
|
+
defaults: opts.defaults ?? {},
|
|
219
|
+
namePrefix: opts.namePrefix ?? ""
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function firstOfEach(blocks) {
|
|
223
|
+
const stated = {};
|
|
224
|
+
for (const block of blocks) {
|
|
225
|
+
for (const [name, value] of Object.entries(block)) {
|
|
226
|
+
if (!(name in stated)) {
|
|
227
|
+
stated[name] = value;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return stated;
|
|
232
|
+
}
|
|
233
|
+
function referencedResource(value, scope) {
|
|
234
|
+
const whole = WHOLE_REFERENCE.exec(value.trim());
|
|
235
|
+
if (whole === null) {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
const parsed = RESOURCE_ATTRIBUTE.exec(whole[1].trim());
|
|
239
|
+
if (parsed === null) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
const [, resourceType, label] = parsed;
|
|
243
|
+
return scope.resources.has(`${resourceType}.${label}`) ? `${scope.namePrefix}${label}` : null;
|
|
244
|
+
}
|
|
245
|
+
function resolveReferences(value, scope) {
|
|
246
|
+
return expand(value, scope, []) ?? value;
|
|
247
|
+
}
|
|
248
|
+
function expand(value, scope, resolving) {
|
|
249
|
+
let cycled = false;
|
|
250
|
+
const expandOne = (reference) => {
|
|
251
|
+
if (resolving.includes(reference)) {
|
|
252
|
+
cycled = true;
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
const stated = statedValue(reference, scope);
|
|
256
|
+
if (stated === null || resolving.length >= CHAIN_LIMIT2) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
const nested = expand(stated, scope, [...resolving, reference]);
|
|
260
|
+
if (nested === null) {
|
|
261
|
+
cycled = true;
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
return nested;
|
|
265
|
+
};
|
|
266
|
+
const expanded = replaceInterpolations(value, expandOne);
|
|
267
|
+
return cycled ? null : expanded;
|
|
268
|
+
}
|
|
269
|
+
function statedValue(reference, scope) {
|
|
270
|
+
const local = LOCAL_VALUE.exec(reference);
|
|
271
|
+
if (local !== null) {
|
|
272
|
+
return stringOrNull(scope.locals[local[1]]);
|
|
273
|
+
}
|
|
274
|
+
const variable = VARIABLE_VALUE.exec(reference);
|
|
275
|
+
if (variable !== null) {
|
|
276
|
+
return stringOrNull(scope.arguments[variable[1]]);
|
|
277
|
+
}
|
|
278
|
+
const parsed = RESOURCE_ATTRIBUTE.exec(reference);
|
|
279
|
+
if (parsed === null) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
const [, resourceType, label, attribute] = parsed;
|
|
283
|
+
return stringOrNull(
|
|
284
|
+
scope.resources.get(`${resourceType}.${label}`)?.[attribute]
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
function stringOrNull(value) {
|
|
288
|
+
return typeof value === "string" ? value : null;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/blockExpansion.ts
|
|
292
|
+
var DYNAMIC = "dynamic";
|
|
293
|
+
var BARE_NAME = /^\$\{([A-Za-z_][\w-]*)\}$/;
|
|
294
|
+
var FOR_EXPRESSION = /^\$\{\s*\[\s*for\s+([A-Za-z_]\w*)\s*,\s*([A-Za-z_]\w*)\s+in\s+([^:]+):([\s\S]*)\]\s*\}$/;
|
|
295
|
+
function dynamicBlocks(body, block, scope) {
|
|
296
|
+
const written = [];
|
|
297
|
+
const labelled = arrayOf(body[DYNAMIC]).flatMap(
|
|
298
|
+
(entry) => recordsIn(asRecord(entry)?.[block])
|
|
299
|
+
);
|
|
300
|
+
for (const declared of labelled) {
|
|
301
|
+
const stated = statedMap(declared.for_each, scope);
|
|
302
|
+
if (stated === null) {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
const iterator = iteratorName(declared, block);
|
|
306
|
+
for (const [key, value] of Object.entries(stated)) {
|
|
307
|
+
const settle = entrySettle(iterator, key, value);
|
|
308
|
+
for (const content of recordsIn(declared.content)) {
|
|
309
|
+
written.push(...filledBlock(content, settle, [iterator]));
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return written;
|
|
314
|
+
}
|
|
315
|
+
function filledBlock(content, settle, iterators) {
|
|
316
|
+
const filled = substituted(content, settle);
|
|
317
|
+
return mentions(filled, iterators) ? [] : [filled];
|
|
318
|
+
}
|
|
319
|
+
function iteratedRecords(value, scope) {
|
|
320
|
+
if (typeof value !== "string") {
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
const parsed = FOR_EXPRESSION.exec(value.trim());
|
|
324
|
+
if (parsed === null) {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
const [, keyName, valueName, collection, body] = parsed;
|
|
328
|
+
const stated = statedMap(`\${${collection.trim()}}`, scope);
|
|
329
|
+
if (stated === null) {
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
const template = parseBody(body);
|
|
333
|
+
if (template === null) {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
return Object.entries(stated).flatMap(
|
|
337
|
+
([key, entry]) => filledBlock(
|
|
338
|
+
template,
|
|
339
|
+
pairSettle(keyName, valueName, key, entry),
|
|
340
|
+
[keyName, valueName]
|
|
341
|
+
)
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
function parseBody(body) {
|
|
345
|
+
const trimmed = body.trim();
|
|
346
|
+
return trimmed.startsWith("{") ? asRecord(parseHclExpression(trimmed)) : null;
|
|
347
|
+
}
|
|
348
|
+
function iteratorName(declared, block) {
|
|
349
|
+
const stated = declared.iterator;
|
|
350
|
+
if (typeof stated !== "string") {
|
|
351
|
+
return block;
|
|
352
|
+
}
|
|
353
|
+
const bare = BARE_NAME.exec(stated.trim());
|
|
354
|
+
return bare === null ? block : bare[1];
|
|
355
|
+
}
|
|
356
|
+
function entrySettle(iterator, key, value) {
|
|
357
|
+
return (reference) => {
|
|
358
|
+
const steps = reference.split(".");
|
|
359
|
+
if (steps[0] !== iterator) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
if (steps.length === 2 && steps[1] === "key") {
|
|
363
|
+
return key;
|
|
364
|
+
}
|
|
365
|
+
return steps[1] === "value" ? fieldOf(value, steps.slice(2)) : null;
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function pairSettle(keyName, valueName, key, value) {
|
|
369
|
+
return (reference) => {
|
|
370
|
+
const steps = reference.split(".");
|
|
371
|
+
if (steps.length === 1 && steps[0] === keyName) {
|
|
372
|
+
return key;
|
|
373
|
+
}
|
|
374
|
+
return steps[0] === valueName ? fieldOf(value, steps.slice(1)) : null;
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
function fieldOf(value, steps) {
|
|
378
|
+
if (steps.length === 0) {
|
|
379
|
+
return typeof value === "string" ? value : null;
|
|
380
|
+
}
|
|
381
|
+
if (steps.length > 1) {
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
const field = asRecord(value)?.[steps[0]];
|
|
385
|
+
return typeof field === "string" ? field : null;
|
|
386
|
+
}
|
|
387
|
+
function substituted(value, settle) {
|
|
388
|
+
const fill = (text) => replaceInterpolations(text, settle);
|
|
389
|
+
return mapStrings(value, fill);
|
|
390
|
+
}
|
|
391
|
+
function mentions(value, iterators) {
|
|
392
|
+
const mentionsOne = (text) => interpolatedReferences(text).some(
|
|
393
|
+
(reference) => iterators.includes(reference.split(".")[0] ?? "")
|
|
394
|
+
);
|
|
395
|
+
return someString(value, mentionsOne);
|
|
396
|
+
}
|
|
397
|
+
|
|
47
398
|
// src/filterQuery.ts
|
|
48
399
|
var OPERATORS = ["!=", ">=", "<=", "=", ">", "<", ":"];
|
|
49
400
|
var KEYWORDS = /* @__PURE__ */ new Set(["AND", "OR", "NOT"]);
|
|
@@ -305,96 +656,147 @@ var TokenReader = class {
|
|
|
305
656
|
}
|
|
306
657
|
};
|
|
307
658
|
|
|
308
|
-
// src/
|
|
309
|
-
var
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
var CHAIN_LIMIT = 4;
|
|
314
|
-
function referenceScope(resources, locals = []) {
|
|
315
|
-
const scope = /* @__PURE__ */ new Map();
|
|
316
|
-
for (const [resourceType, label, body] of resources) {
|
|
317
|
-
const address = `${resourceType}.${label}`;
|
|
318
|
-
if (!scope.has(address)) {
|
|
319
|
-
scope.set(address, body);
|
|
320
|
-
}
|
|
659
|
+
// src/jsonAttribute.ts
|
|
660
|
+
var JSON_ENCODE = /^\$\{\s*jsonencode\((.*)\)\s*\}$/s;
|
|
661
|
+
function jsonAttributeValue(value) {
|
|
662
|
+
if (typeof value !== "string") {
|
|
663
|
+
return null;
|
|
321
664
|
}
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
if (!(name in stated)) {
|
|
326
|
-
stated[name] = value;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
665
|
+
const literal = parseJson(value);
|
|
666
|
+
if (literal !== null) {
|
|
667
|
+
return literal;
|
|
329
668
|
}
|
|
330
|
-
|
|
331
|
-
return
|
|
332
|
-
}
|
|
333
|
-
function resolveReferences(value, scope) {
|
|
334
|
-
return expand(value, scope, []) ?? value;
|
|
335
|
-
}
|
|
336
|
-
function expand(value, scope, resolving) {
|
|
337
|
-
let cycled = false;
|
|
338
|
-
const expanded = value.replace(SUB_TOKEN, (written, inner) => {
|
|
339
|
-
const reference = inner.trim();
|
|
340
|
-
if (resolving.includes(reference)) {
|
|
341
|
-
cycled = true;
|
|
342
|
-
return written;
|
|
343
|
-
}
|
|
344
|
-
const stated = statedValue(reference, scope);
|
|
345
|
-
if (stated === null || resolving.length >= CHAIN_LIMIT) {
|
|
346
|
-
return written;
|
|
347
|
-
}
|
|
348
|
-
const nested = expand(stated, scope, [...resolving, reference]);
|
|
349
|
-
if (nested === null) {
|
|
350
|
-
cycled = true;
|
|
351
|
-
return written;
|
|
352
|
-
}
|
|
353
|
-
return nested;
|
|
354
|
-
});
|
|
355
|
-
return cycled ? null : expanded;
|
|
669
|
+
const encoded = JSON_ENCODE.exec(value);
|
|
670
|
+
return encoded === null ? null : parseHclExpression(encoded[1]);
|
|
356
671
|
}
|
|
357
|
-
function
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
return typeof stated2 === "string" ? stated2 : null;
|
|
362
|
-
}
|
|
363
|
-
const parsed = RESOURCE_ATTRIBUTE.exec(reference);
|
|
364
|
-
if (parsed === null) {
|
|
672
|
+
function parseJson(text) {
|
|
673
|
+
try {
|
|
674
|
+
return JSON.parse(text);
|
|
675
|
+
} catch {
|
|
365
676
|
return null;
|
|
366
677
|
}
|
|
367
|
-
const [, resourceType, label, attribute] = parsed;
|
|
368
|
-
const stated = scope.get(`${resourceType}.${label}`)?.[attribute];
|
|
369
|
-
return typeof stated === "string" ? stated : null;
|
|
370
678
|
}
|
|
371
679
|
|
|
372
680
|
// src/index.ts
|
|
373
681
|
function terraformToSummaries(source, sourceFile, options) {
|
|
374
|
-
return
|
|
682
|
+
return moduleSummaries(
|
|
683
|
+
moduleOf({
|
|
684
|
+
files: [{ source, sourceFile }],
|
|
685
|
+
directory: import_node_path.default.dirname(sourceFile),
|
|
686
|
+
namePrefix: "",
|
|
687
|
+
arguments: {},
|
|
688
|
+
ancestors: []
|
|
689
|
+
}),
|
|
690
|
+
options
|
|
691
|
+
);
|
|
375
692
|
}
|
|
376
693
|
function terraformFileToSummaries(target, options) {
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
694
|
+
const directory = import_node_fs.default.statSync(target).isDirectory() ? target : import_node_path.default.dirname(target);
|
|
695
|
+
const files = import_node_fs.default.statSync(target).isDirectory() ? sourceFilesIn(target) : [readSourceFile(target)];
|
|
696
|
+
return moduleSummaries(
|
|
697
|
+
moduleOf({
|
|
698
|
+
files,
|
|
699
|
+
directory,
|
|
700
|
+
namePrefix: "",
|
|
701
|
+
arguments: {},
|
|
702
|
+
ancestors: [directory]
|
|
703
|
+
}),
|
|
383
704
|
options
|
|
384
705
|
);
|
|
385
706
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
707
|
+
var LOCAL_SOURCE = /^\.\.?[/\\]/;
|
|
708
|
+
var MODULE_SOURCE = "source";
|
|
709
|
+
var MODULE_DEPTH_LIMIT = 8;
|
|
710
|
+
function sourceFilesIn(directory) {
|
|
711
|
+
return import_node_fs.default.readdirSync(directory).filter((name) => name.endsWith(".tf")).map((name) => readSourceFile(import_node_path.default.join(directory, name)));
|
|
712
|
+
}
|
|
713
|
+
function readSourceFile(file) {
|
|
714
|
+
return { source: import_node_fs.default.readFileSync(file, "utf8"), sourceFile: file };
|
|
715
|
+
}
|
|
716
|
+
function moduleOf(opts) {
|
|
717
|
+
const files = opts.files.map((file) => parseSource(file)).filter((file) => file !== null);
|
|
718
|
+
const scope = referenceScope({
|
|
719
|
+
resources: files.flatMap((file) => file.resources),
|
|
720
|
+
locals: files.flatMap((file) => file.locals),
|
|
721
|
+
defaults: Object.assign({}, ...files.map((file) => file.defaults)),
|
|
722
|
+
arguments: opts.arguments,
|
|
723
|
+
namePrefix: opts.namePrefix
|
|
724
|
+
});
|
|
725
|
+
const children = [];
|
|
726
|
+
for (const [label, call] of files.flatMap((file) => file.modules)) {
|
|
727
|
+
const child = childModule({ ...opts, scope, label, call });
|
|
728
|
+
if (child === null) {
|
|
729
|
+
continue;
|
|
730
|
+
}
|
|
731
|
+
children.push(child);
|
|
732
|
+
scope.resources.set(`module.${label}`, outputValues(child));
|
|
733
|
+
}
|
|
734
|
+
return { files, scope, children };
|
|
735
|
+
}
|
|
736
|
+
function childModule(opts) {
|
|
737
|
+
const source = stringOf(opts.call[MODULE_SOURCE]);
|
|
738
|
+
if (source === null || !LOCAL_SOURCE.test(source)) {
|
|
739
|
+
return null;
|
|
740
|
+
}
|
|
741
|
+
const directory = import_node_path.default.resolve(opts.directory, source);
|
|
742
|
+
if (opts.ancestors.includes(directory) || opts.ancestors.length >= MODULE_DEPTH_LIMIT || !isDirectory(directory)) {
|
|
743
|
+
return null;
|
|
744
|
+
}
|
|
745
|
+
return moduleOf({
|
|
746
|
+
files: sourceFilesIn(directory),
|
|
747
|
+
directory,
|
|
748
|
+
namePrefix: `${opts.namePrefix}module.${opts.label}.`,
|
|
749
|
+
arguments: passedArguments(opts.call, opts.scope),
|
|
750
|
+
ancestors: [...opts.ancestors, directory]
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
function isDirectory(target) {
|
|
754
|
+
return import_node_fs.default.existsSync(target) && import_node_fs.default.statSync(target).isDirectory();
|
|
755
|
+
}
|
|
756
|
+
function passedArguments(call, parent) {
|
|
757
|
+
const passed = {};
|
|
758
|
+
for (const [name, value] of Object.entries(call)) {
|
|
759
|
+
if (name === MODULE_SOURCE) {
|
|
760
|
+
continue;
|
|
761
|
+
}
|
|
762
|
+
const stated = asRecord(value);
|
|
763
|
+
if (stated !== null) {
|
|
764
|
+
passed[name] = resolvedThroughout(stated, parent);
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
const written = stringOf(value);
|
|
768
|
+
const settled = written === null ? null : resolveReferences(written, parent);
|
|
769
|
+
if (settled !== null && !settled.includes("${")) {
|
|
770
|
+
passed[name] = settled;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
return passed;
|
|
774
|
+
}
|
|
775
|
+
function resolvedThroughout(value, scope) {
|
|
776
|
+
const resolveHere = (text) => resolveReferences(text, scope);
|
|
777
|
+
return mapStrings(value, resolveHere);
|
|
778
|
+
}
|
|
779
|
+
function outputValues(child) {
|
|
780
|
+
const stated = {};
|
|
781
|
+
for (const [name, value] of child.files.flatMap((file) => file.outputs)) {
|
|
782
|
+
const written = stringOf(value);
|
|
783
|
+
if (written === null || name in stated) {
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
const settled = resolveReferences(written, child.scope);
|
|
787
|
+
if (!settled.includes("${")) {
|
|
788
|
+
stated[name] = settled;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
return stated;
|
|
792
|
+
}
|
|
793
|
+
function moduleSummaries(module2, options) {
|
|
392
794
|
const summaries = [];
|
|
393
|
-
for (const file of
|
|
795
|
+
for (const file of module2.files) {
|
|
394
796
|
for (const [resourceType, label, body] of file.resources) {
|
|
395
797
|
for (const pack of options.packs) {
|
|
396
|
-
const pattern = patternFor(pack, resourceType, file.constraints);
|
|
397
|
-
if (pattern === void 0
|
|
798
|
+
const pattern = patternFor(pack, resourceType, file.constraints, body);
|
|
799
|
+
if (pattern === void 0) {
|
|
398
800
|
continue;
|
|
399
801
|
}
|
|
400
802
|
summaries.push(
|
|
@@ -404,23 +806,20 @@ function summariesForFiles(files, options) {
|
|
|
404
806
|
body,
|
|
405
807
|
sourceFile: file.sourceFile,
|
|
406
808
|
resourceType,
|
|
407
|
-
scope
|
|
809
|
+
scope: module2.scope,
|
|
810
|
+
options
|
|
408
811
|
})
|
|
409
812
|
);
|
|
410
813
|
}
|
|
411
814
|
}
|
|
412
815
|
}
|
|
816
|
+
for (const child of module2.children) {
|
|
817
|
+
summaries.push(...moduleSummaries(child, options));
|
|
818
|
+
}
|
|
413
819
|
return summaries;
|
|
414
820
|
}
|
|
415
821
|
function parseSource(file) {
|
|
416
|
-
|
|
417
|
-
try {
|
|
418
|
-
const [parsed] = import_hcl2_parser.default.parseToObject(file.source);
|
|
419
|
-
read = parsed;
|
|
420
|
-
} catch {
|
|
421
|
-
return null;
|
|
422
|
-
}
|
|
423
|
-
const document = asRecord(read);
|
|
822
|
+
const document = parseHclDocument(file.source);
|
|
424
823
|
if (document === null) {
|
|
425
824
|
return null;
|
|
426
825
|
}
|
|
@@ -428,9 +827,43 @@ function parseSource(file) {
|
|
|
428
827
|
sourceFile: file.sourceFile,
|
|
429
828
|
constraints: providerConstraints(document),
|
|
430
829
|
resources: resourcesIn(document),
|
|
431
|
-
locals: localsIn(document)
|
|
830
|
+
locals: localsIn(document),
|
|
831
|
+
defaults: variableDefaults(document),
|
|
832
|
+
modules: labelledBlocks(document.module),
|
|
833
|
+
outputs: labelledBlocks(document.output).map(([name, block]) => [
|
|
834
|
+
name,
|
|
835
|
+
block.value
|
|
836
|
+
])
|
|
432
837
|
};
|
|
433
838
|
}
|
|
839
|
+
function labelledBlocks(declared) {
|
|
840
|
+
const found = [];
|
|
841
|
+
for (const group of arrayOf(declared)) {
|
|
842
|
+
for (const [label, bodies] of Object.entries(asRecord(group) ?? {})) {
|
|
843
|
+
for (const body of arrayOf(bodies)) {
|
|
844
|
+
const read = asRecord(body);
|
|
845
|
+
if (read !== null) {
|
|
846
|
+
found.push([label, read]);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
return found;
|
|
852
|
+
}
|
|
853
|
+
function variableDefaults(document) {
|
|
854
|
+
const defaults = {};
|
|
855
|
+
for (const group of arrayOf(document.variable)) {
|
|
856
|
+
for (const [name, declared] of Object.entries(asRecord(group) ?? {})) {
|
|
857
|
+
for (const block of arrayOf(declared)) {
|
|
858
|
+
const stated = asRecord(block)?.default;
|
|
859
|
+
if (stated !== void 0 && !(name in defaults)) {
|
|
860
|
+
defaults[name] = stated;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
return defaults;
|
|
866
|
+
}
|
|
434
867
|
function providerConstraints(document) {
|
|
435
868
|
const constraints = /* @__PURE__ */ new Map();
|
|
436
869
|
for (const block of arrayOf(document.terraform)) {
|
|
@@ -451,23 +884,21 @@ function providerConstraints(document) {
|
|
|
451
884
|
}
|
|
452
885
|
return constraints;
|
|
453
886
|
}
|
|
454
|
-
function patternFor(pack, resourceType, constraints) {
|
|
887
|
+
function patternFor(pack, resourceType, constraints, body) {
|
|
455
888
|
const pinned = constraints.get(pack.provider);
|
|
456
|
-
return pack.resources.find(
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
});
|
|
889
|
+
return pack.resources.find(
|
|
890
|
+
(pattern) => pattern.resource === resourceType && versionAllows(pinned, pattern.providerVersions) && entryApplies(pattern, body)
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
function versionAllows(pinned, providerVersions) {
|
|
894
|
+
if (pinned === void 0) {
|
|
895
|
+
return true;
|
|
896
|
+
}
|
|
897
|
+
try {
|
|
898
|
+
return import_semver.default.intersects(pinned, providerVersions, { loose: true });
|
|
899
|
+
} catch {
|
|
900
|
+
return true;
|
|
901
|
+
}
|
|
471
902
|
}
|
|
472
903
|
function entryApplies(pattern, body) {
|
|
473
904
|
const gate = pattern.appliesWhen;
|
|
@@ -479,7 +910,7 @@ function entryApplies(pattern, body) {
|
|
|
479
910
|
return gate.whenUnset === "read";
|
|
480
911
|
}
|
|
481
912
|
const text = stringOf(value);
|
|
482
|
-
return text !== null && gate.equals.includes(text);
|
|
913
|
+
return text !== null && (gate.equals ?? []).includes(text);
|
|
483
914
|
}
|
|
484
915
|
var READERS = {
|
|
485
916
|
storage: (site, boundary) => {
|
|
@@ -490,7 +921,8 @@ var READERS = {
|
|
|
490
921
|
},
|
|
491
922
|
"message-bus": (site, boundary) => [busSummary({ ...site, boundary })],
|
|
492
923
|
metric: (site, boundary) => [metricSummary({ ...site, boundary })],
|
|
493
|
-
"metric-reading": (site, boundary) => readingSummaries({ ...site, boundary })
|
|
924
|
+
"metric-reading": (site, boundary) => readingSummaries({ ...site, boundary }),
|
|
925
|
+
deployable: (site, boundary) => deployableSummaries({ ...site, boundary })
|
|
494
926
|
};
|
|
495
927
|
function summariesFor(opts) {
|
|
496
928
|
const { pattern, ...site } = opts;
|
|
@@ -499,9 +931,11 @@ function summariesFor(opts) {
|
|
|
499
931
|
}
|
|
500
932
|
function storageSummary(opts) {
|
|
501
933
|
const { boundary, label, shape, types } = opts;
|
|
502
|
-
const address = `${opts.resourceType}.${label}`;
|
|
934
|
+
const address = `${opts.scope.namePrefix}${opts.resourceType}.${label}`;
|
|
935
|
+
const storageSystem = storageSystemOf(opts.body, boundary, opts.scope);
|
|
503
936
|
const declaresContainer = boundary.declares !== "store";
|
|
504
937
|
const physicalTable = !declaresContainer || boundary.nameAttribute === void 0 ? null : namePattern(opts.body[boundary.nameAttribute], opts.scope);
|
|
938
|
+
const listedFields = jsonFields(opts.body, boundary);
|
|
505
939
|
return {
|
|
506
940
|
kind: "library",
|
|
507
941
|
location: {
|
|
@@ -514,35 +948,102 @@ function storageSummary(opts) {
|
|
|
514
948
|
exportPath: null,
|
|
515
949
|
boundaryBinding: (0, import_behavioral_ir.storageBinding)({
|
|
516
950
|
recognition: "terraform",
|
|
517
|
-
storageSystem
|
|
951
|
+
storageSystem,
|
|
518
952
|
...boundary.transport !== void 0 ? { transport: boundary.transport } : {},
|
|
519
|
-
scope:
|
|
953
|
+
scope: containerScope(opts.body, boundary, opts.scope),
|
|
520
954
|
container: declaresContainer ? label : null,
|
|
521
955
|
accessPath: shape.accessPath
|
|
522
956
|
})
|
|
523
957
|
},
|
|
524
958
|
inputs: [],
|
|
525
959
|
transitions: [],
|
|
526
|
-
gaps:
|
|
960
|
+
gaps: unknownEngineGaps(storageSystem, boundary),
|
|
527
961
|
confidence: { source: "declared", level: "high" },
|
|
528
962
|
metadata: {
|
|
529
963
|
storageContract: {
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
fieldSet: shape.serves === null ? boundary.fieldSet : "exhaustive",
|
|
533
|
-
...boundary.identifies === void 0 ? {} : {
|
|
534
|
-
identifies: { kind: "keyFields", fields: shape.keyFields },
|
|
535
|
-
fields: (shape.serves ?? shape.keyFields).map((field) => ({
|
|
536
|
-
name: field,
|
|
537
|
-
...types.has(field) ? { type: types.get(field) } : {},
|
|
538
|
-
...shape.keyFields.includes(field) ? { primary: true } : {}
|
|
539
|
-
}))
|
|
540
|
-
},
|
|
964
|
+
fieldSet: declaredFieldSet(boundary, shape, listedFields),
|
|
965
|
+
...contractFields(boundary, shape, types, listedFields),
|
|
541
966
|
...physicalTable !== null ? { physicalTable } : {}
|
|
542
967
|
}
|
|
543
968
|
}
|
|
544
969
|
};
|
|
545
970
|
}
|
|
971
|
+
function storageSystemOf(body, boundary, scope) {
|
|
972
|
+
const spec = boundary.storageSystem;
|
|
973
|
+
if (typeof spec === "string") {
|
|
974
|
+
return spec;
|
|
975
|
+
}
|
|
976
|
+
return meaningOf(body, spec, scope) ?? null;
|
|
977
|
+
}
|
|
978
|
+
function unknownEngineGaps(storageSystem, boundary) {
|
|
979
|
+
const spec = boundary.storageSystem;
|
|
980
|
+
if (storageSystem !== null || typeof spec === "string") {
|
|
981
|
+
return [];
|
|
982
|
+
}
|
|
983
|
+
return [
|
|
984
|
+
{
|
|
985
|
+
type: "unreadOutcome",
|
|
986
|
+
conditions: [],
|
|
987
|
+
consequence: "unknown",
|
|
988
|
+
description: `"${spec.attribute}" states an engine this run could not settle, so which store this is stays unknown and it pairs with an access on any engine.`
|
|
989
|
+
}
|
|
990
|
+
];
|
|
991
|
+
}
|
|
992
|
+
function contractFields(boundary, shape, types, listedFields) {
|
|
993
|
+
if (boundary.identifies !== void 0) {
|
|
994
|
+
return {
|
|
995
|
+
identifies: { kind: "keyFields", fields: shape.keyFields },
|
|
996
|
+
fields: (shape.serves ?? shape.keyFields).map((field) => ({
|
|
997
|
+
name: field,
|
|
998
|
+
...types.has(field) ? { type: types.get(field) } : {},
|
|
999
|
+
...shape.keyFields.includes(field) ? { primary: true } : {}
|
|
1000
|
+
}))
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
return listedFields === null ? {} : { fields: listedFields };
|
|
1004
|
+
}
|
|
1005
|
+
function declaredFieldSet(boundary, shape, listedFields) {
|
|
1006
|
+
if (shape.serves !== null) {
|
|
1007
|
+
return "exhaustive";
|
|
1008
|
+
}
|
|
1009
|
+
return listedFields === null ? boundary.fieldSet : "exhaustive";
|
|
1010
|
+
}
|
|
1011
|
+
function jsonFields(body, boundary) {
|
|
1012
|
+
const spec = boundary.fieldsFromJson;
|
|
1013
|
+
if (spec === void 0) {
|
|
1014
|
+
return null;
|
|
1015
|
+
}
|
|
1016
|
+
const stated = jsonAttributeValue(valueAt(body, spec.attribute));
|
|
1017
|
+
if (!Array.isArray(stated)) {
|
|
1018
|
+
return null;
|
|
1019
|
+
}
|
|
1020
|
+
const fields = stated.flatMap((entry) => {
|
|
1021
|
+
const field = asRecord(entry);
|
|
1022
|
+
const name = field === null ? null : stringOf(field[spec.nameKey]);
|
|
1023
|
+
if (field === null || name === null) {
|
|
1024
|
+
return [];
|
|
1025
|
+
}
|
|
1026
|
+
const type = spec.typeKey === void 0 ? null : stringOf(field[spec.typeKey]);
|
|
1027
|
+
return [
|
|
1028
|
+
{
|
|
1029
|
+
name,
|
|
1030
|
+
...type !== null ? { type } : {},
|
|
1031
|
+
...spec.requires === void 0 ? {} : { nullable: !alwaysSet(field, spec.requires) }
|
|
1032
|
+
}
|
|
1033
|
+
];
|
|
1034
|
+
});
|
|
1035
|
+
return fields.length === 0 ? null : fields;
|
|
1036
|
+
}
|
|
1037
|
+
function alwaysSet(field, requires) {
|
|
1038
|
+
const stated = stringOf(field[requires.key]);
|
|
1039
|
+
return stated !== null && requires.values.includes(stated);
|
|
1040
|
+
}
|
|
1041
|
+
function containerScope(body, boundary, scope) {
|
|
1042
|
+
if (boundary.scopeAttribute === void 0) {
|
|
1043
|
+
return "default";
|
|
1044
|
+
}
|
|
1045
|
+
return namePattern(valueAt(body, boundary.scopeAttribute), scope) ?? "default";
|
|
1046
|
+
}
|
|
546
1047
|
function busSummary(opts) {
|
|
547
1048
|
const { boundary, label } = opts;
|
|
548
1049
|
const physicalName = boundary.nameAttribute === void 0 ? null : namePattern(opts.body[boundary.nameAttribute], opts.scope);
|
|
@@ -554,7 +1055,7 @@ function busSummary(opts) {
|
|
|
554
1055
|
exportName: null
|
|
555
1056
|
},
|
|
556
1057
|
identity: {
|
|
557
|
-
name: `${opts.resourceType}.${label}`,
|
|
1058
|
+
name: `${opts.scope.namePrefix}${opts.resourceType}.${label}`,
|
|
558
1059
|
exportPath: null,
|
|
559
1060
|
boundaryBinding: (0, import_behavioral_ir.messageBusBinding)({
|
|
560
1061
|
recognition: "terraform",
|
|
@@ -575,14 +1076,26 @@ function busSummary(opts) {
|
|
|
575
1076
|
}
|
|
576
1077
|
};
|
|
577
1078
|
}
|
|
578
|
-
var
|
|
1079
|
+
var TEMPLATE_HOLE = /\{([^{}]+)\}/g;
|
|
1080
|
+
function metricTypeFrom(template, body, scope) {
|
|
1081
|
+
let missing = false;
|
|
1082
|
+
const spelled = template.replace(TEMPLATE_HOLE, (_whole, path2) => {
|
|
1083
|
+
const stated = namePattern(valueAt(body, path2), scope);
|
|
1084
|
+
if (stated === null) {
|
|
1085
|
+
missing = true;
|
|
1086
|
+
return "";
|
|
1087
|
+
}
|
|
1088
|
+
return stated;
|
|
1089
|
+
});
|
|
1090
|
+
return missing ? null : spelled;
|
|
1091
|
+
}
|
|
579
1092
|
function metricSummary(opts) {
|
|
580
1093
|
const { boundary } = opts;
|
|
581
|
-
const
|
|
582
|
-
|
|
1094
|
+
const metricType = metricTypeFrom(
|
|
1095
|
+
boundary.metricTypeTemplate,
|
|
1096
|
+
opts.body,
|
|
583
1097
|
opts.scope
|
|
584
1098
|
);
|
|
585
|
-
const metricType = declaredName === null ? null : boundary.metricTypeTemplate.replace(NAME_HOLE, declaredName);
|
|
586
1099
|
return {
|
|
587
1100
|
kind: "library",
|
|
588
1101
|
location: {
|
|
@@ -591,7 +1104,7 @@ function metricSummary(opts) {
|
|
|
591
1104
|
exportName: null
|
|
592
1105
|
},
|
|
593
1106
|
identity: {
|
|
594
|
-
name: `${opts.resourceType}.${opts.label}`,
|
|
1107
|
+
name: `${opts.scope.namePrefix}${opts.resourceType}.${opts.label}`,
|
|
595
1108
|
exportPath: null,
|
|
596
1109
|
boundaryBinding: (0, import_behavioral_ir.metricBinding)({
|
|
597
1110
|
recognition: "terraform",
|
|
@@ -603,12 +1116,14 @@ function metricSummary(opts) {
|
|
|
603
1116
|
transitions: [],
|
|
604
1117
|
gaps: [],
|
|
605
1118
|
confidence: { source: "declared", level: "high" },
|
|
606
|
-
metadata: {
|
|
1119
|
+
metadata: {
|
|
1120
|
+
metricContract: metricContract(opts.body, boundary, opts.scope)
|
|
1121
|
+
}
|
|
607
1122
|
};
|
|
608
1123
|
}
|
|
609
|
-
function metricContract(body, boundary) {
|
|
610
|
-
const values = meaningOf(body, boundary.values);
|
|
611
|
-
const accumulates = meaningOf(body, boundary.accumulates);
|
|
1124
|
+
function metricContract(body, boundary, scope) {
|
|
1125
|
+
const values = meaningOf(body, boundary.values, scope);
|
|
1126
|
+
const accumulates = meaningOf(body, boundary.accumulates, scope);
|
|
612
1127
|
return {
|
|
613
1128
|
...values !== void 0 ? { values } : {},
|
|
614
1129
|
...accumulates !== void 0 ? { accumulates } : {}
|
|
@@ -617,11 +1132,14 @@ function metricContract(body, boundary) {
|
|
|
617
1132
|
function readingSummaries(opts) {
|
|
618
1133
|
const { boundary } = opts;
|
|
619
1134
|
const summaries = [];
|
|
620
|
-
for (const reading of blocksAt(
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
1135
|
+
for (const reading of blocksAt(
|
|
1136
|
+
opts.body,
|
|
1137
|
+
boundary.readingBlocks,
|
|
1138
|
+
opts.scope
|
|
1139
|
+
)) {
|
|
1140
|
+
for (const metricType of metricsRead(
|
|
1141
|
+
reading,
|
|
1142
|
+
boundary.identifies,
|
|
625
1143
|
opts.scope
|
|
626
1144
|
)) {
|
|
627
1145
|
summaries.push({
|
|
@@ -632,7 +1150,7 @@ function readingSummaries(opts) {
|
|
|
632
1150
|
exportName: null
|
|
633
1151
|
},
|
|
634
1152
|
identity: {
|
|
635
|
-
name: `${opts.resourceType}.${opts.label}#${summaries.length}`,
|
|
1153
|
+
name: `${opts.scope.namePrefix}${opts.resourceType}.${opts.label}#${summaries.length}`,
|
|
636
1154
|
exportPath: null,
|
|
637
1155
|
boundaryBinding: (0, import_behavioral_ir.metricBinding)({
|
|
638
1156
|
recognition: "terraform",
|
|
@@ -644,12 +1162,28 @@ function readingSummaries(opts) {
|
|
|
644
1162
|
transitions: [],
|
|
645
1163
|
gaps: [],
|
|
646
1164
|
confidence: { source: "declared", level: "high" },
|
|
647
|
-
metadata: {
|
|
1165
|
+
metadata: {
|
|
1166
|
+
metricReading: metricReading(reading, boundary, opts.scope)
|
|
1167
|
+
}
|
|
648
1168
|
});
|
|
649
1169
|
}
|
|
650
1170
|
}
|
|
651
1171
|
return summaries;
|
|
652
1172
|
}
|
|
1173
|
+
var READING_IDENTITIES = {
|
|
1174
|
+
attributes: (reading, identity, scope) => [
|
|
1175
|
+
metricTypeFrom(identity.template, reading, scope)
|
|
1176
|
+
],
|
|
1177
|
+
query: (reading, identity, scope) => metricTypesIn(
|
|
1178
|
+
stringOf(valueAt(reading, identity.attribute)),
|
|
1179
|
+
identity.key,
|
|
1180
|
+
scope
|
|
1181
|
+
)
|
|
1182
|
+
};
|
|
1183
|
+
function metricsRead(reading, identity, scope) {
|
|
1184
|
+
const read = READING_IDENTITIES[identity.from];
|
|
1185
|
+
return read(reading, identity, scope);
|
|
1186
|
+
}
|
|
653
1187
|
function metricTypesIn(query, identityKey, scope) {
|
|
654
1188
|
if (query === null) {
|
|
655
1189
|
return [null];
|
|
@@ -661,23 +1195,212 @@ function metricTypesIn(query, identityKey, scope) {
|
|
|
661
1195
|
const found = filterValuesFor(parsed.query, identityKey).map((value) => namePattern(value, scope)).filter((value) => value !== null);
|
|
662
1196
|
return found.length === 0 ? [null] : found;
|
|
663
1197
|
}
|
|
664
|
-
function metricReading(reading, boundary) {
|
|
1198
|
+
function metricReading(reading, boundary, scope) {
|
|
665
1199
|
const compares = boundary.comparesTo;
|
|
666
1200
|
const comparesTo = compares !== void 0 && valueAt(reading, compares.attribute) !== void 0 ? compares.whenSet : void 0;
|
|
667
1201
|
const reduces = boundary.reducesTo;
|
|
668
|
-
const reducesTo = meaningOf(reading, reduces);
|
|
1202
|
+
const reducesTo = meaningOf(reading, reduces, scope);
|
|
669
1203
|
return {
|
|
670
1204
|
...comparesTo !== void 0 ? { comparesTo } : {},
|
|
671
1205
|
...reducesTo !== void 0 ? { reducesTo } : {},
|
|
672
1206
|
...reduces === void 0 ? {} : { reduction: { setting: reduces.attribute, leaves: reduces.means } }
|
|
673
1207
|
};
|
|
674
1208
|
}
|
|
675
|
-
function
|
|
1209
|
+
function deployableSummaries(opts) {
|
|
1210
|
+
const { boundary, label } = opts;
|
|
1211
|
+
return deployedProcesses(opts.body, boundary, opts.scope).map(
|
|
1212
|
+
(process) => deployableSummary({
|
|
1213
|
+
...opts,
|
|
1214
|
+
boundary,
|
|
1215
|
+
process,
|
|
1216
|
+
instanceName: process.containerName === null ? label : (0, import_behavioral_ir.ecsContainerInstanceName)(label, process.containerName)
|
|
1217
|
+
})
|
|
1218
|
+
);
|
|
1219
|
+
}
|
|
1220
|
+
function deployableSummary(opts) {
|
|
1221
|
+
const { boundary, instanceName, process } = opts;
|
|
1222
|
+
const declared = declaredEnv(process.body, boundary.env ?? [], opts.scope);
|
|
1223
|
+
const platform = boundary.platformEnvVars ?? import_behavioral_ir.PLATFORM_INJECTED_ENV_VARS[boundary.deploymentTarget];
|
|
1224
|
+
const code = codePointer(process.body, boundary, opts.scope);
|
|
1225
|
+
const image = attributePattern(
|
|
1226
|
+
process.body,
|
|
1227
|
+
boundary.code?.imageAttribute,
|
|
1228
|
+
opts.scope
|
|
1229
|
+
);
|
|
1230
|
+
const runtime = attributePattern(
|
|
1231
|
+
process.body,
|
|
1232
|
+
boundary.runtimeAttribute,
|
|
1233
|
+
opts.scope
|
|
1234
|
+
);
|
|
1235
|
+
const prefix = opts.scope.namePrefix;
|
|
1236
|
+
const deployableUnit = {
|
|
1237
|
+
deploymentTarget: boundary.deploymentTarget,
|
|
1238
|
+
instanceName: `${prefix}${instanceName}`
|
|
1239
|
+
};
|
|
1240
|
+
return {
|
|
1241
|
+
kind: "library",
|
|
1242
|
+
location: {
|
|
1243
|
+
file: opts.sourceFile,
|
|
1244
|
+
range: { start: 1, end: 1 },
|
|
1245
|
+
exportName: null
|
|
1246
|
+
},
|
|
1247
|
+
identity: {
|
|
1248
|
+
name: `${prefix}${opts.resourceType}.${instanceName.replace("/", "#")}`,
|
|
1249
|
+
exportPath: null,
|
|
1250
|
+
boundaryBinding: (0, import_behavioral_ir.runtimeConfigBinding)({
|
|
1251
|
+
recognition: "terraform",
|
|
1252
|
+
...deployableUnit
|
|
1253
|
+
}),
|
|
1254
|
+
deployableUnit
|
|
1255
|
+
},
|
|
1256
|
+
inputs: [],
|
|
1257
|
+
transitions: [],
|
|
1258
|
+
gaps: [],
|
|
1259
|
+
confidence: { source: "declared", level: "high" },
|
|
1260
|
+
metadata: (0, import_behavioral_ir.withRuntimeContractMetadata)(
|
|
1261
|
+
{
|
|
1262
|
+
codeScope: declaredCodeScope(
|
|
1263
|
+
opts.options.codeScopes?.[deployableUnit.instanceName],
|
|
1264
|
+
code.entry
|
|
1265
|
+
)
|
|
1266
|
+
},
|
|
1267
|
+
{
|
|
1268
|
+
envVars: [.../* @__PURE__ */ new Set([...declared.names, ...platform])].sort(),
|
|
1269
|
+
envVarSources: envVarSources(declared.names, platform),
|
|
1270
|
+
...Object.keys(declared.targets).length > 0 ? { envVarTargets: declared.targets } : {},
|
|
1271
|
+
...Object.keys(declared.values).length > 0 ? { envVarValues: declared.values } : {},
|
|
1272
|
+
...code.entryPoint !== null ? { entryPoint: code.entryPoint } : {},
|
|
1273
|
+
...image !== null ? { image } : {},
|
|
1274
|
+
...runtime !== null ? { runtime } : {}
|
|
1275
|
+
}
|
|
1276
|
+
)
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
function declaredCodeScope(directory, entry) {
|
|
1280
|
+
const written = entry !== null ? { entry } : {};
|
|
1281
|
+
if (directory !== void 0) {
|
|
1282
|
+
return { kind: "codeUri", path: directory, ...written };
|
|
1283
|
+
}
|
|
1284
|
+
return { kind: "unknown", ...written };
|
|
1285
|
+
}
|
|
1286
|
+
function envVarSources(declared, platform) {
|
|
1287
|
+
const sources = {};
|
|
1288
|
+
for (const name of declared) {
|
|
1289
|
+
sources[name] = "template";
|
|
1290
|
+
}
|
|
1291
|
+
for (const name of platform) {
|
|
1292
|
+
sources[name] ??= "platform";
|
|
1293
|
+
}
|
|
1294
|
+
return sources;
|
|
1295
|
+
}
|
|
1296
|
+
function deployedProcesses(body, boundary, scope) {
|
|
1297
|
+
const containers = boundary.containers;
|
|
1298
|
+
if (containers === void 0) {
|
|
1299
|
+
return [{ body, containerName: null }];
|
|
1300
|
+
}
|
|
1301
|
+
return blocksAt(body, containers.blocks, scope).map((container) => ({
|
|
1302
|
+
body: container,
|
|
1303
|
+
containerName: containers.nameAttribute === void 0 ? null : stringOf(container[containers.nameAttribute])
|
|
1304
|
+
}));
|
|
1305
|
+
}
|
|
1306
|
+
var HANDLER_MODULE = {
|
|
1307
|
+
"module.export": (written) => (0, import_behavioral_ir.parseHandler)(written)?.modulePath ?? null,
|
|
1308
|
+
name: () => null
|
|
1309
|
+
};
|
|
1310
|
+
function codePointer(body, boundary, scope) {
|
|
1311
|
+
const spec = boundary.code?.handler;
|
|
1312
|
+
const written = attributePattern(body, spec?.attribute, scope);
|
|
1313
|
+
if (spec === void 0 || written === null) {
|
|
1314
|
+
return { entryPoint: null, entry: null };
|
|
1315
|
+
}
|
|
1316
|
+
return {
|
|
1317
|
+
entryPoint: written,
|
|
1318
|
+
entry: (0, import_behavioral_ir.hasNameHole)(written) ? null : HANDLER_MODULE[spec.spelling](written)
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
var ENV_READERS = {
|
|
1322
|
+
map: (body, declaration, into, scope) => {
|
|
1323
|
+
const stated = asRecord(valueAt(body, declaration.attribute)) ?? {};
|
|
1324
|
+
for (const [name, value] of Object.entries(stated)) {
|
|
1325
|
+
setVariable(into, name, stringOf(value), scope);
|
|
1326
|
+
}
|
|
1327
|
+
},
|
|
1328
|
+
entries: (body, declaration, into, scope) => {
|
|
1329
|
+
for (const entry of blocksAt(body, declaration.block.split("."), scope)) {
|
|
1330
|
+
const name = stringOf(entry[declaration.nameAttribute]);
|
|
1331
|
+
if (name === null) {
|
|
1332
|
+
continue;
|
|
1333
|
+
}
|
|
1334
|
+
setVariable(
|
|
1335
|
+
into,
|
|
1336
|
+
name,
|
|
1337
|
+
attributeText(entry, declaration.valueAttribute),
|
|
1338
|
+
scope
|
|
1339
|
+
);
|
|
1340
|
+
setTarget(
|
|
1341
|
+
into,
|
|
1342
|
+
name,
|
|
1343
|
+
attributeText(entry, declaration.secretAttribute),
|
|
1344
|
+
scope
|
|
1345
|
+
);
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1349
|
+
function declaredEnv(body, declarations, scope) {
|
|
1350
|
+
const declared = { names: [], values: {}, targets: {} };
|
|
1351
|
+
for (const declaration of declarations) {
|
|
1352
|
+
const read = ENV_READERS[declaration.style];
|
|
1353
|
+
read(body, declaration, declared, scope);
|
|
1354
|
+
}
|
|
1355
|
+
return declared;
|
|
1356
|
+
}
|
|
1357
|
+
function setVariable(into, name, written, scope) {
|
|
1358
|
+
if (!into.names.includes(name)) {
|
|
1359
|
+
into.names.push(name);
|
|
1360
|
+
}
|
|
1361
|
+
if (written === null) {
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
const pattern = namePattern(written, scope);
|
|
1365
|
+
if (pattern !== null) {
|
|
1366
|
+
into.values[name] = pattern;
|
|
1367
|
+
}
|
|
1368
|
+
setTarget(into, name, written, scope);
|
|
1369
|
+
}
|
|
1370
|
+
function setTarget(into, name, written, scope) {
|
|
1371
|
+
const target = written === null ? null : referencedResource(written, scope);
|
|
1372
|
+
if (target !== null) {
|
|
1373
|
+
into.targets[name] = { kind: "ref", logicalId: target };
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
function attributeText(body, attribute) {
|
|
1377
|
+
return attribute === void 0 ? null : stringOf(valueAt(body, attribute));
|
|
1378
|
+
}
|
|
1379
|
+
function attributePattern(body, attribute, scope) {
|
|
1380
|
+
return attribute === void 0 ? null : namePattern(valueAt(body, attribute), scope);
|
|
1381
|
+
}
|
|
1382
|
+
var MEANING_KEYS = {
|
|
1383
|
+
value: (stated, keys) => keys.find((key) => key === stated),
|
|
1384
|
+
prefix: (stated, keys) => keys.find((key) => stated.startsWith(key))
|
|
1385
|
+
};
|
|
1386
|
+
function meaningOf(body, spec, scope) {
|
|
676
1387
|
if (spec === void 0) {
|
|
677
1388
|
return void 0;
|
|
678
1389
|
}
|
|
679
|
-
const
|
|
680
|
-
|
|
1390
|
+
const value = valueAt(body, spec.attribute);
|
|
1391
|
+
if (value === void 0) {
|
|
1392
|
+
return spec.whenUnset;
|
|
1393
|
+
}
|
|
1394
|
+
const written = stringOf(value);
|
|
1395
|
+
const stated = written === null ? null : resolveReferences(written, scope);
|
|
1396
|
+
if (stated === null || stated.includes("${")) {
|
|
1397
|
+
return void 0;
|
|
1398
|
+
}
|
|
1399
|
+
const key = MEANING_KEYS[spec.matches ?? "value"](
|
|
1400
|
+
stated,
|
|
1401
|
+
Object.keys(spec.means)
|
|
1402
|
+
);
|
|
1403
|
+
return key === void 0 ? void 0 : spec.means[key];
|
|
681
1404
|
}
|
|
682
1405
|
function valueAt(body, path2) {
|
|
683
1406
|
const steps = path2.split(".");
|
|
@@ -692,15 +1415,24 @@ function valueAt(body, path2) {
|
|
|
692
1415
|
}
|
|
693
1416
|
return current[last];
|
|
694
1417
|
}
|
|
695
|
-
function blocksAt(body, blocks) {
|
|
1418
|
+
function blocksAt(body, blocks, scope) {
|
|
696
1419
|
let found = [body];
|
|
697
1420
|
for (const block of blocks) {
|
|
698
|
-
found = found.flatMap(
|
|
699
|
-
(record
|
|
700
|
-
|
|
1421
|
+
found = found.flatMap((record) => [
|
|
1422
|
+
...nestedRecords(record[block], scope),
|
|
1423
|
+
...dynamicBlocks(record, block, scope)
|
|
1424
|
+
]);
|
|
701
1425
|
}
|
|
702
1426
|
return found;
|
|
703
1427
|
}
|
|
1428
|
+
function nestedRecords(value, scope) {
|
|
1429
|
+
const iterated = iteratedRecords(value, scope);
|
|
1430
|
+
if (iterated !== null) {
|
|
1431
|
+
return iterated;
|
|
1432
|
+
}
|
|
1433
|
+
const stated = typeof value === "string" ? jsonAttributeValue(value) : value;
|
|
1434
|
+
return arrayOf(stated).map(asRecord).filter((nested) => nested !== null);
|
|
1435
|
+
}
|
|
704
1436
|
function keyedShapes(body, boundary) {
|
|
705
1437
|
if (boundary.identifies === void 0) {
|
|
706
1438
|
return [{ accessPath: null, keyFields: [], serves: null }];
|
|
@@ -806,23 +1538,12 @@ function namePattern(value, scope) {
|
|
|
806
1538
|
typeof value === "string" ? resolveReferences(value, scope) : value
|
|
807
1539
|
);
|
|
808
1540
|
}
|
|
809
|
-
function arrayOf(value) {
|
|
810
|
-
if (value === void 0 || value === null) {
|
|
811
|
-
return [];
|
|
812
|
-
}
|
|
813
|
-
return Array.isArray(value) ? value : [value];
|
|
814
|
-
}
|
|
815
|
-
function asRecord(value) {
|
|
816
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
817
|
-
}
|
|
818
|
-
function stringOf(value) {
|
|
819
|
-
return typeof value === "string" ? value : null;
|
|
820
|
-
}
|
|
821
1541
|
// Annotate the CommonJS export names for ESM import in node:
|
|
822
1542
|
0 && (module.exports = {
|
|
823
1543
|
filterCalls,
|
|
824
1544
|
filterTerms,
|
|
825
1545
|
filterValuesFor,
|
|
1546
|
+
jsonAttributeValue,
|
|
826
1547
|
parseFilterQuery,
|
|
827
1548
|
terraformFileToSummaries,
|
|
828
1549
|
terraformToSummaries
|