@fjall/generator 0.89.5 → 0.89.6

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.
Files changed (168) hide show
  1. package/LICENSE +50 -21
  2. package/README.md +28 -0
  3. package/dist/.minified +1 -0
  4. package/dist/src/ast/astCdnParser.d.ts +5 -0
  5. package/dist/src/ast/astCdnParser.js +1 -114
  6. package/dist/src/ast/astCommonParser.d.ts +6 -17
  7. package/dist/src/ast/astCommonParser.js +1 -351
  8. package/dist/src/ast/astComputeConnectionParser.d.ts +18 -0
  9. package/dist/src/ast/astComputeConnectionParser.js +1 -0
  10. package/dist/src/ast/astComputeParser.d.ts +6 -0
  11. package/dist/src/ast/astComputeParser.js +1 -473
  12. package/dist/src/ast/astComputeParserHelpers.d.ts +21 -0
  13. package/dist/src/ast/astComputeParserHelpers.js +1 -0
  14. package/dist/src/ast/astDatabaseParser.d.ts +9 -24
  15. package/dist/src/ast/astDatabaseParser.js +1 -275
  16. package/dist/src/ast/astDomainParser.d.ts +139 -0
  17. package/dist/src/ast/astDomainParser.js +1 -0
  18. package/dist/src/ast/astDynamoDBParser.d.ts +35 -0
  19. package/dist/src/ast/astDynamoDBParser.js +1 -0
  20. package/dist/src/ast/astExpressionEvaluator.d.ts +23 -0
  21. package/dist/src/ast/astExpressionEvaluator.js +1 -0
  22. package/dist/src/ast/astInfrastructureParser.d.ts +12 -49
  23. package/dist/src/ast/astInfrastructureParser.js +1 -552
  24. package/dist/src/ast/astMessagingParser.d.ts +5 -0
  25. package/dist/src/ast/astMessagingParser.js +1 -78
  26. package/dist/src/ast/astNetworkParser.d.ts +6 -0
  27. package/dist/src/ast/astNetworkParser.js +1 -219
  28. package/dist/src/ast/astPatternParser.d.ts +6 -0
  29. package/dist/src/ast/astPatternParser.js +1 -155
  30. package/dist/src/ast/astPlanConverter.d.ts +11 -0
  31. package/dist/src/ast/astPlanConverter.js +2 -0
  32. package/dist/src/ast/astStatementClassifier.d.ts +24 -0
  33. package/dist/src/ast/astStatementClassifier.js +1 -0
  34. package/dist/src/ast/astStatementQueries.d.ts +21 -0
  35. package/dist/src/ast/astStatementQueries.js +3 -0
  36. package/dist/src/ast/astStorageParser.d.ts +5 -0
  37. package/dist/src/ast/astStorageParser.js +1 -164
  38. package/dist/src/ast/astSurgicalModification.js +19 -400
  39. package/dist/src/ast/astTestHelpers.d.ts +635 -0
  40. package/dist/src/ast/astTestHelpers.js +1 -0
  41. package/dist/src/ast/index.d.ts +1 -0
  42. package/dist/src/ast/index.js +1 -6
  43. package/dist/src/aws/regions.js +1 -254
  44. package/dist/src/codemod/_internal.d.ts +12 -0
  45. package/dist/src/codemod/_internal.js +1 -0
  46. package/dist/src/codemod/edits/addResource/bodyIndex.d.ts +34 -0
  47. package/dist/src/codemod/edits/addResource/bodyIndex.js +1 -0
  48. package/dist/src/codemod/edits/addResource/propertyBuilder.d.ts +7 -0
  49. package/dist/src/codemod/edits/addResource/propertyBuilder.js +1 -0
  50. package/dist/src/codemod/edits/addResource.d.ts +9 -0
  51. package/dist/src/codemod/edits/addResource.js +1 -0
  52. package/dist/src/codemod/edits/ensureImports.d.ts +26 -0
  53. package/dist/src/codemod/edits/ensureImports.js +1 -0
  54. package/dist/src/codemod/edits/findInsertionPosition.d.ts +39 -0
  55. package/dist/src/codemod/edits/findInsertionPosition.js +1 -0
  56. package/dist/src/codemod/edits/index.d.ts +6 -0
  57. package/dist/src/codemod/edits/index.js +1 -0
  58. package/dist/src/codemod/edits/modifyResource/literalConversion.d.ts +37 -0
  59. package/dist/src/codemod/edits/modifyResource/literalConversion.js +1 -0
  60. package/dist/src/codemod/edits/modifyResource.d.ts +9 -0
  61. package/dist/src/codemod/edits/modifyResource.js +1 -0
  62. package/dist/src/codemod/edits/removeResource/commentHeuristic.d.ts +31 -0
  63. package/dist/src/codemod/edits/removeResource/commentHeuristic.js +1 -0
  64. package/dist/src/codemod/edits/removeResource/importPruning.d.ts +8 -0
  65. package/dist/src/codemod/edits/removeResource/importPruning.js +1 -0
  66. package/dist/src/codemod/edits/removeResource.d.ts +10 -0
  67. package/dist/src/codemod/edits/removeResource.js +1 -0
  68. package/dist/src/codemod/edits/schemaFragments.d.ts +9 -0
  69. package/dist/src/codemod/edits/schemaFragments.js +1 -0
  70. package/dist/src/codemod/fileRewriter/builders.d.ts +57 -0
  71. package/dist/src/codemod/fileRewriter/builders.js +1 -0
  72. package/dist/src/codemod/fileRewriter/index.d.ts +4 -0
  73. package/dist/src/codemod/fileRewriter/index.js +1 -0
  74. package/dist/src/codemod/fileRewriter/locateByRange.d.ts +65 -0
  75. package/dist/src/codemod/fileRewriter/locateByRange.js +1 -0
  76. package/dist/src/codemod/fileRewriter/parse.d.ts +18 -0
  77. package/dist/src/codemod/fileRewriter/parse.js +2 -0
  78. package/dist/src/codemod/fileRewriter/print.d.ts +46 -0
  79. package/dist/src/codemod/fileRewriter/print.js +4 -0
  80. package/dist/src/codemod/historyPaths.d.ts +2 -0
  81. package/dist/src/codemod/historyPaths.js +1 -0
  82. package/dist/src/codemod/index.d.ts +7 -0
  83. package/dist/src/codemod/index.js +1 -0
  84. package/dist/src/codemod/listResources.d.ts +4 -0
  85. package/dist/src/codemod/listResources.js +1 -0
  86. package/dist/src/codemod/semanticIndex/findReferences.d.ts +15 -0
  87. package/dist/src/codemod/semanticIndex/findReferences.js +2 -0
  88. package/dist/src/codemod/semanticIndex/index.d.ts +4 -0
  89. package/dist/src/codemod/semanticIndex/index.js +1 -0
  90. package/dist/src/codemod/semanticIndex/listImports.d.ts +24 -0
  91. package/dist/src/codemod/semanticIndex/listImports.js +1 -0
  92. package/dist/src/codemod/semanticIndex/locateByShape.d.ts +28 -0
  93. package/dist/src/codemod/semanticIndex/locateByShape.js +1 -0
  94. package/dist/src/codemod/semanticIndex/projectCache.d.ts +14 -0
  95. package/dist/src/codemod/semanticIndex/projectCache.js +1 -0
  96. package/dist/src/codemod/types.d.ts +172 -0
  97. package/dist/src/codemod/types.js +1 -0
  98. package/dist/src/dns/bindParser.js +2 -224
  99. package/dist/src/dns/bindWriter.js +3 -52
  100. package/dist/src/dns/domainFileGenerator.d.ts +20 -0
  101. package/dist/src/dns/domainFileGenerator.js +207 -0
  102. package/dist/src/dns/domainRecords.d.ts +164 -0
  103. package/dist/src/dns/domainRecords.js +1 -0
  104. package/dist/src/dns/index.d.ts +2 -1
  105. package/dist/src/dns/index.js +1 -4
  106. package/dist/src/dns/types.js +1 -52
  107. package/dist/src/generation/common.js +6 -161
  108. package/dist/src/generation/compute.js +82 -590
  109. package/dist/src/generation/database.js +12 -198
  110. package/dist/src/generation/generatePatternCode.d.ts +58 -0
  111. package/dist/src/generation/generatePatternCode.js +33 -0
  112. package/dist/src/generation/index.js +1 -20
  113. package/dist/src/generation/infrastructure.d.ts +1 -5
  114. package/dist/src/generation/infrastructure.js +35 -377
  115. package/dist/src/generation/messagingConnections.js +1 -73
  116. package/dist/src/generation/storage.d.ts +0 -15
  117. package/dist/src/generation/storage.js +35 -168
  118. package/dist/src/generation/storageConnections.js +1 -75
  119. package/dist/src/planning/generateResourceChange.d.ts +21 -0
  120. package/dist/src/planning/generateResourceChange.js +1 -0
  121. package/dist/src/planning/index.d.ts +3 -0
  122. package/dist/src/planning/index.js +1 -1
  123. package/dist/src/planning/resourceAddition.d.ts +154 -0
  124. package/dist/src/planning/resourceAddition.js +1 -0
  125. package/dist/src/planning/resourceConnections.d.ts +19 -0
  126. package/dist/src/planning/resourceConnections.js +1 -0
  127. package/dist/src/planning/resourcePlanning.js +1 -214
  128. package/dist/src/presets/index.js +1 -3
  129. package/dist/src/presets/patternTierPresets.js +1 -131
  130. package/dist/src/presets/storagePresets.js +1 -36
  131. package/dist/src/presets/tierPresets.d.ts +5 -8
  132. package/dist/src/presets/tierPresets.js +1 -384
  133. package/dist/src/presets/tierTypes.d.ts +1 -1
  134. package/dist/src/presets/tierTypes.js +0 -7
  135. package/dist/src/schemas/alarmSchemas.d.ts +19 -0
  136. package/dist/src/schemas/alarmSchemas.js +1 -0
  137. package/dist/src/schemas/applicationSchemas.d.ts +22 -6
  138. package/dist/src/schemas/applicationSchemas.js +1 -80
  139. package/dist/src/schemas/baseSchemas.d.ts +8 -3
  140. package/dist/src/schemas/baseSchemas.js +2 -248
  141. package/dist/src/schemas/cdnSchemas.js +1 -62
  142. package/dist/src/schemas/computeSchemas.d.ts +25 -3
  143. package/dist/src/schemas/computeSchemas.js +1 -727
  144. package/dist/src/schemas/constants.d.ts +5 -7
  145. package/dist/src/schemas/constants.js +1 -218
  146. package/dist/src/schemas/databaseSchemas.d.ts +6 -1
  147. package/dist/src/schemas/databaseSchemas.js +1 -366
  148. package/dist/src/schemas/index.js +1 -3
  149. package/dist/src/schemas/instanceTypeArchitecture.js +1 -75
  150. package/dist/src/schemas/messagingSchemas.js +1 -29
  151. package/dist/src/schemas/networkSchemas.js +1 -125
  152. package/dist/src/schemas/patternSchemas.d.ts +1 -1
  153. package/dist/src/schemas/patternSchemas.js +1 -294
  154. package/dist/src/schemas/resourceSchemas.d.ts +1 -0
  155. package/dist/src/schemas/resourceSchemas.js +1 -28
  156. package/dist/src/schemas/sharedTypes.d.ts +18 -0
  157. package/dist/src/schemas/sharedTypes.js +1 -0
  158. package/dist/src/schemas/storageSchemas.d.ts +1 -0
  159. package/dist/src/schemas/storageSchemas.js +1 -119
  160. package/dist/src/types/Result.js +1 -31
  161. package/dist/src/util/errorUtils.js +1 -1
  162. package/dist/src/validation/patterns.d.ts +9 -0
  163. package/dist/src/validation/patterns.js +1 -369
  164. package/dist/src/version.d.ts +1 -1
  165. package/dist/src/version.js +1 -1
  166. package/package.json +29 -9
  167. package/dist/src/dns/infrastructureWriter.d.ts +0 -2
  168. package/dist/src/dns/infrastructureWriter.js +0 -58
@@ -1,275 +1 @@
1
- import * as ts from "typescript";
2
- import { constIncludes } from "../schemas/constants.js";
3
- import { asBoolean, asNumber, asString, asStringArray, asStringUnion, captureExtraProperties, collectFromAst, extractVariableName, isCallRef, isFactoryBuildCall, isFactoryMethodCall, isParsedObject, omitUndefined, parseObjectLiteral, parseOptionalConfig, parseBooleanOrConfig, resolveTemplateLiteral, typed, } from "./astCommonParser.js";
4
- const DYNAMODB_KEY_TYPES = ["S", "N", "B"];
5
- // ---- Extraction helpers ----
6
- /** Derive database engine from parsed config */
7
- function extractDatabaseEngine(config) {
8
- const directEngine = asString(config.databaseEngine);
9
- if (directEngine === "postgresql" || directEngine === "mysql")
10
- return directEngine;
11
- const engine = config.engine;
12
- if (isCallRef(engine)) {
13
- const callText = String(engine.__call);
14
- if (callText.includes("postgres") || callText.includes("auroraPostgres")) {
15
- return "postgresql";
16
- }
17
- if (callText.includes("mysql") || callText.includes("auroraMysql")) {
18
- return "mysql";
19
- }
20
- }
21
- return undefined;
22
- }
23
- /** Extract raw engine expression text */
24
- function extractEngineExpression(config) {
25
- const engine = config.engine;
26
- if (isCallRef(engine)) {
27
- return String(engine.__call);
28
- }
29
- return undefined;
30
- }
31
- const DATABASE_KNOWN_KEYS = new Set([
32
- "type",
33
- "databaseName",
34
- "databaseEngine",
35
- "engine",
36
- "vpc",
37
- "port",
38
- "deletionProtection",
39
- "instanceType",
40
- "multiAz",
41
- "publiclyAccessible",
42
- "enableSecretRotation",
43
- "encryption",
44
- "databaseInsights",
45
- "proxy",
46
- "readReplica",
47
- "credentials",
48
- "writer",
49
- "readers",
50
- "backupRetention",
51
- "preferredMaintenanceWindow",
52
- "primaryRegion",
53
- "secondaryRegions",
54
- "globalClusterIdentifier",
55
- "enableGlobalWriteForwarding",
56
- "snapshotIdentifier",
57
- "allocatedStorage",
58
- "monitoringInterval",
59
- "snapshotUsername",
60
- ]);
61
- function extractDatabaseResource(sourceFile, addDatabaseCall, buildCall) {
62
- if (buildCall.arguments.length < 2)
63
- return null;
64
- const nameArg = buildCall.arguments[0];
65
- const configArg = buildCall.arguments[1];
66
- if (!ts.isStringLiteral(nameArg) && !ts.isTemplateExpression(nameArg)) {
67
- return null;
68
- }
69
- const resourceName = ts.isStringLiteral(nameArg)
70
- ? nameArg.text
71
- : resolveTemplateLiteral(sourceFile, nameArg);
72
- if (!ts.isObjectLiteralExpression(configArg)) {
73
- return null;
74
- }
75
- const config = parseObjectLiteral(configArg);
76
- const resource = {
77
- resourceName,
78
- type: asString(config.type) ?? "",
79
- databaseName: asString(config.databaseName) ?? "",
80
- databaseEngine: extractDatabaseEngine(config),
81
- engineExpression: extractEngineExpression(config),
82
- port: asNumber(config.port),
83
- deletionProtection: asBoolean(config.deletionProtection),
84
- instanceType: asString(config.instanceType),
85
- multiAz: asBoolean(config.multiAz),
86
- publiclyAccessible: asBoolean(config.publiclyAccessible),
87
- enableSecretRotation: asBoolean(config.enableSecretRotation),
88
- encryption: parseOptionalConfig(config.encryption, typed()),
89
- databaseInsights: parseBooleanOrConfig(config.databaseInsights, typed()),
90
- proxy: parseBooleanOrConfig(config.proxy, typed()),
91
- readReplica: parseBooleanOrConfig(config.readReplica, typed()),
92
- credentials: parseOptionalConfig(config.credentials, typed()),
93
- writer: parseOptionalConfig(config.writer, typed()),
94
- readers: parseBooleanOrConfig(config.readers, typed()),
95
- backupRetention: asNumber(config.backupRetention),
96
- preferredMaintenanceWindow: asString(config.preferredMaintenanceWindow),
97
- primaryRegion: asString(config.primaryRegion),
98
- secondaryRegions: asStringArray(config.secondaryRegions),
99
- globalClusterIdentifier: asString(config.globalClusterIdentifier),
100
- enableGlobalWriteForwarding: asBoolean(config.enableGlobalWriteForwarding),
101
- allocatedStorage: asNumber(config.allocatedStorage),
102
- monitoringInterval: asNumber(config.monitoringInterval),
103
- snapshotIdentifier: asString(config.snapshotIdentifier),
104
- snapshotUsername: asString(config.snapshotUsername),
105
- node: addDatabaseCall,
106
- };
107
- const varName = extractVariableName(addDatabaseCall);
108
- if (varName)
109
- resource.variableName = varName;
110
- const extras = captureExtraProperties(config, DATABASE_KNOWN_KEYS);
111
- if (extras.length > 0)
112
- resource.extraProperties = extras;
113
- return resource;
114
- }
115
- // ---- DynamoDB helpers ----
116
- /** Parse a DynamoDB key schema from parsed AST object */
117
- function parseDynamoDBKey(value) {
118
- if (!isParsedObject(value))
119
- return undefined;
120
- const name = asString(value.name);
121
- const type = asStringUnion(value.type, DYNAMODB_KEY_TYPES);
122
- if (!name || !type)
123
- return undefined;
124
- return { name, type };
125
- }
126
- /** Extract DynamoDB-specific fields from a parsed database resource */
127
- function extractDynamoDBFields(resource) {
128
- const node = resource.node;
129
- if (!ts.isCallExpression(node))
130
- return null;
131
- const buildCallArg = node.arguments[0];
132
- if (!ts.isCallExpression(buildCallArg) || buildCallArg.arguments.length < 2)
133
- return null;
134
- const configArg = buildCallArg.arguments[1];
135
- if (!ts.isObjectLiteralExpression(configArg))
136
- return null;
137
- const config = parseObjectLiteral(configArg);
138
- const partitionKey = parseDynamoDBKey(config.partitionKey);
139
- if (!partitionKey)
140
- return null;
141
- const result = {
142
- resourceName: resource.resourceName,
143
- partitionKey,
144
- node: resource.node,
145
- };
146
- if (resource.variableName)
147
- result.variableName = resource.variableName;
148
- const sortKey = parseDynamoDBKey(config.sortKey);
149
- if (sortKey)
150
- result.sortKey = sortKey;
151
- if (Array.isArray(config.globalSecondaryIndexes)) {
152
- const gsis = config.globalSecondaryIndexes
153
- .filter(isParsedObject)
154
- .map((gsi) => {
155
- const pk = parseDynamoDBKey(gsi.partitionKey);
156
- if (!pk)
157
- return null;
158
- const indexName = asString(gsi.indexName);
159
- if (!indexName)
160
- return null;
161
- const entry = { indexName, partitionKey: pk };
162
- const sk = parseDynamoDBKey(gsi.sortKey);
163
- if (sk)
164
- entry.sortKey = sk;
165
- return entry;
166
- })
167
- .filter((g) => g !== null);
168
- if (gsis.length > 0)
169
- result.globalSecondaryIndexes = gsis;
170
- }
171
- const ttlAttribute = asString(config.ttlAttribute);
172
- if (ttlAttribute)
173
- result.ttlAttribute = ttlAttribute;
174
- const stream = asBoolean(config.stream);
175
- if (stream !== undefined)
176
- result.stream = stream;
177
- const DYNAMODB_KNOWN_KEYS = new Set([
178
- "type",
179
- "databaseName",
180
- "partitionKey",
181
- "sortKey",
182
- "globalSecondaryIndexes",
183
- "ttlAttribute",
184
- "stream",
185
- ]);
186
- const extras = captureExtraProperties(config, DYNAMODB_KNOWN_KEYS);
187
- if (extras.length > 0)
188
- result.extraProperties = extras;
189
- return result;
190
- }
191
- // ---- Public API ----
192
- /** Find all database resources (including DynamoDB) from addDatabase calls */
193
- export function findDatabaseResources(sourceFile) {
194
- return collectFromAst(sourceFile, (node) => {
195
- if (!ts.isCallExpression(node) || !isFactoryMethodCall(node, "addDatabase"))
196
- return null;
197
- const databaseArg = node.arguments[0];
198
- if (!isFactoryBuildCall(databaseArg, "DatabaseFactory"))
199
- return null;
200
- return extractDatabaseResource(sourceFile, node, databaseArg);
201
- });
202
- }
203
- /** Split DynamoDB resources (type: "DynamoDB") from regular database resources */
204
- export function splitDynamoDBFromDatabases(allResources) {
205
- const databases = [];
206
- const dynamodb = [];
207
- for (const resource of allResources) {
208
- if (resource.type === "DynamoDB") {
209
- const dynamo = extractDynamoDBFields(resource);
210
- if (dynamo)
211
- dynamodb.push(dynamo);
212
- }
213
- else {
214
- databases.push(resource);
215
- }
216
- }
217
- return { databases, dynamodb };
218
- }
219
- const VALID_DB_TYPES = ["Instance", "Aurora", "GlobalAurora"];
220
- /** Convert parsed database resources to plan format */
221
- export function convertDatabaseResources(databaseResources) {
222
- return databaseResources
223
- .filter((db) => db.type !== "DynamoDB")
224
- .map((database) => ({
225
- name: database.resourceName,
226
- type: constIncludes(VALID_DB_TYPES, database.type)
227
- ? database.type
228
- : "Instance",
229
- databaseName: database.databaseName,
230
- ...omitUndefined({
231
- port: database.port,
232
- deletionProtection: database.deletionProtection,
233
- instanceType: database.instanceType,
234
- multiAz: database.multiAz,
235
- publiclyAccessible: database.publiclyAccessible,
236
- enableSecretRotation: database.enableSecretRotation,
237
- encryption: database.encryption,
238
- databaseInsights: database.databaseInsights,
239
- proxy: database.proxy,
240
- readReplica: database.readReplica,
241
- credentials: database.credentials,
242
- writer: database.writer,
243
- readers: database.readers,
244
- backupRetention: database.backupRetention,
245
- preferredMaintenanceWindow: database.preferredMaintenanceWindow,
246
- primaryRegion: database.primaryRegion,
247
- secondaryRegions: database.secondaryRegions,
248
- globalClusterIdentifier: database.globalClusterIdentifier,
249
- enableGlobalWriteForwarding: database.enableGlobalWriteForwarding,
250
- allocatedStorage: database.allocatedStorage,
251
- monitoringInterval: database.monitoringInterval,
252
- variableName: database.variableName,
253
- databaseEngine: database.databaseEngine,
254
- engineExpression: database.engineExpression,
255
- extraProperties: database.extraProperties,
256
- }),
257
- }));
258
- }
259
- /** Convert parsed DynamoDB resources to plan format */
260
- export function convertDynamoDBResources(dynamodbResources) {
261
- if (dynamodbResources.length === 0)
262
- return undefined;
263
- return dynamodbResources.map((table) => ({
264
- name: table.resourceName,
265
- partitionKey: table.partitionKey,
266
- ...omitUndefined({
267
- sortKey: table.sortKey,
268
- globalSecondaryIndexes: table.globalSecondaryIndexes,
269
- ttlAttribute: table.ttlAttribute,
270
- stream: table.stream,
271
- variableName: table.variableName,
272
- extraProperties: table.extraProperties,
273
- }),
274
- }));
275
- }
1
+ import*as l from"typescript";import{constIncludes as R}from"../schemas/constants.js";import{asBoolean as c,asNumber as p,asString as o,asStringArray as x,captureExtraProperties as I,collectFromAst as A,extractVariableName as S,isCallRef as f,isFactoryBuildCall as D,isFactoryMethodCall as E,omitUndefined as h,parseObjectLiteral as w,parseOptionalConfig as m,parseBooleanOrConfig as g,resolveTemplateLiteral as N,typed as a}from"./astCommonParser.js";import{extractDynamoDBFields as v}from"./astDynamoDBParser.js";import{convertDynamoDBResources as O}from"./astDynamoDBParser.js";function P(t){const e=o(t.databaseEngine);if(e==="postgresql"||e==="mysql")return e;const i=t.engine;if(f(i)){const r=String(i.__call);if(r.includes("postgres")||r.includes("auroraPostgres"))return"postgresql";if(r.includes("mysql")||r.includes("auroraMysql"))return"mysql"}}function W(t){const e=t.engine;if(f(e))return String(e.__call)}const B=new Set(["type","databaseName","databaseEngine","engine","vpc","port","deletionProtection","instanceType","multiAz","publiclyAccessible","enableSecretRotation","encryption","databaseInsights","proxy","readReplica","credentials","writer","readers","backupRetention","preferredMaintenanceWindow","primaryRegion","secondaryRegions","globalClusterIdentifier","enableGlobalWriteForwarding","snapshotIdentifier","allocatedStorage","monitoringInterval","snapshotUsername"]);function F(t,e,i){if(i.arguments.length<2)return null;const r=i.arguments[0],s=i.arguments[1];if(!l.isStringLiteral(r)&&!l.isTemplateExpression(r))return null;const b=l.isStringLiteral(r)?r.text:N(t,r);if(!l.isObjectLiteralExpression(s))return null;const n=w(s),u={resourceName:b,type:o(n.type)??"",databaseName:o(n.databaseName)??"",databaseEngine:P(n),engineExpression:W(n),port:p(n.port),deletionProtection:c(n.deletionProtection),instanceType:o(n.instanceType),multiAz:c(n.multiAz),publiclyAccessible:c(n.publiclyAccessible),enableSecretRotation:c(n.enableSecretRotation),encryption:m(n.encryption,a()),databaseInsights:g(n.databaseInsights,a()),proxy:g(n.proxy,a()),readReplica:g(n.readReplica,a()),credentials:m(n.credentials,a()),writer:m(n.writer,a()),readers:g(n.readers,a()),backupRetention:p(n.backupRetention),preferredMaintenanceWindow:o(n.preferredMaintenanceWindow),primaryRegion:o(n.primaryRegion),secondaryRegions:x(n.secondaryRegions),globalClusterIdentifier:o(n.globalClusterIdentifier),enableGlobalWriteForwarding:c(n.enableGlobalWriteForwarding),allocatedStorage:p(n.allocatedStorage),monitoringInterval:p(n.monitoringInterval),snapshotIdentifier:o(n.snapshotIdentifier),snapshotUsername:o(n.snapshotUsername),node:e},d=S(e);d&&(u.variableName=d);const y=I(n,B);return y.length>0&&(u.extraProperties=y),u}function q(t){return A(t,e=>{if(!l.isCallExpression(e)||!E(e,"addDatabase"))return null;const i=e.arguments[0];return D(i,"DatabaseFactory")?F(t,e,i):null})}function G(t){const e=[],i=[];for(const r of t)if(r.type==="DynamoDB"){const s=v(r);s&&i.push(s)}else e.push(r);return{databases:e,dynamodb:i}}const T=["Instance","Aurora","GlobalAurora"];function L(t){return t.filter(e=>e.type!=="DynamoDB").map(e=>({name:e.resourceName,type:R(T,e.type)?e.type:"Instance",databaseName:e.databaseName,...h({port:e.port,deletionProtection:e.deletionProtection,instanceType:e.instanceType,multiAz:e.multiAz,publiclyAccessible:e.publiclyAccessible,enableSecretRotation:e.enableSecretRotation,encryption:e.encryption,databaseInsights:e.databaseInsights,proxy:e.proxy,readReplica:e.readReplica,credentials:e.credentials,writer:e.writer,readers:e.readers,backupRetention:e.backupRetention,preferredMaintenanceWindow:e.preferredMaintenanceWindow,primaryRegion:e.primaryRegion,secondaryRegions:e.secondaryRegions,globalClusterIdentifier:e.globalClusterIdentifier,enableGlobalWriteForwarding:e.enableGlobalWriteForwarding,allocatedStorage:e.allocatedStorage,monitoringInterval:e.monitoringInterval,variableName:e.variableName,databaseEngine:e.databaseEngine,engineExpression:e.engineExpression,extraProperties:e.extraProperties})}))}export{L as convertDatabaseResources,O as convertDynamoDBResources,q as findDatabaseResources,G as splitDynamoDBFromDatabases};
@@ -0,0 +1,139 @@
1
+ import * as ts from "typescript";
2
+ import { type Result } from "../types/Result.js";
3
+ /** One-of match for a single `new Domain(...)` call in an infrastructure file. */
4
+ export interface DomainCallMatch {
5
+ readonly callExpression: ts.NewExpression;
6
+ /**
7
+ * Top-level statement containing the `new Domain(...)` call — either the
8
+ * bare `ExpressionStatement` (`new Domain(...);`) or the `VariableStatement`
9
+ * (`const domain = new Domain(...);`). Eject replaces this statement with
10
+ * the expanded template.
11
+ */
12
+ readonly containingStatement: ts.Statement;
13
+ readonly propsObjectLiteral: ts.ObjectLiteralExpression;
14
+ /**
15
+ * Variable name the call is assigned to, if any:
16
+ * `const domain = new Domain(...);` → "domain"
17
+ * `new Domain(...);` → undefined (bare expression)
18
+ */
19
+ readonly domainVarId: string | undefined;
20
+ /** Raw source text of the first argument (scope expression — e.g. `app`). */
21
+ readonly scopeArgumentText: string;
22
+ /** The `id` argument — second arg — as a string literal if resolvable. */
23
+ readonly constructIdLiteral: string | undefined;
24
+ }
25
+ /** Parsed target expression for a single `AliasRecord.target`. */
26
+ export type ParsedFjallTarget = {
27
+ readonly kind: "ecs";
28
+ readonly appName: string;
29
+ } | {
30
+ readonly kind: "cdn";
31
+ readonly appName: string;
32
+ } | {
33
+ readonly kind: "bucket";
34
+ readonly bucketName: string;
35
+ } | {
36
+ readonly kind: "custom";
37
+ readonly dnsName: string;
38
+ readonly hostedZoneId: string;
39
+ } | {
40
+ readonly kind: "unresolved";
41
+ readonly sourceText: string;
42
+ } | {
43
+ readonly kind: "dynamic";
44
+ readonly sourceText: string;
45
+ };
46
+ export interface ParsedStandardRecord {
47
+ readonly kind: "standard";
48
+ readonly type: "A" | "AAAA" | "CNAME" | "MX" | "TXT" | "NS" | "SRV" | "CAA";
49
+ readonly name: string;
50
+ readonly value: string | string[];
51
+ readonly ttl?: number;
52
+ }
53
+ export interface ParsedAliasRecord {
54
+ readonly kind: "alias";
55
+ readonly type: "A" | "AAAA";
56
+ readonly name: string;
57
+ readonly target: ParsedFjallTarget;
58
+ }
59
+ export type ParsedDnsRecordFromAst = ParsedStandardRecord | ParsedAliasRecord;
60
+ export interface ParsedCertificateFromAst {
61
+ readonly domainName: string;
62
+ readonly subjectAlternativeNames?: string[];
63
+ readonly transparencyLogging?: boolean;
64
+ }
65
+ export interface ParsedDelegationFromAst {
66
+ readonly subdomain: string;
67
+ readonly toAccount: string;
68
+ readonly auto?: boolean;
69
+ }
70
+ interface ParsedDomainCommon {
71
+ readonly zoneName: string;
72
+ readonly description: string | undefined;
73
+ readonly costAllocationEnvironment: string | undefined;
74
+ readonly tags: Record<string, string> | undefined;
75
+ readonly records: ParsedDnsRecordFromAst[];
76
+ readonly certificates: ParsedCertificateFromAst[];
77
+ }
78
+ export interface ParsedRoute53ApexDomainProps extends ParsedDomainCommon {
79
+ readonly registrar: "route53";
80
+ readonly hostedZoneId: string | undefined;
81
+ readonly delegations: ParsedDelegationFromAst[];
82
+ }
83
+ export interface ParsedExternalDelegatedDomainProps extends ParsedDomainCommon {
84
+ readonly registrar: "external-delegated";
85
+ readonly delegatedSubdomain: string;
86
+ readonly delegations: ParsedDelegationFromAst[];
87
+ }
88
+ export interface ParsedExternalRecordsDomainProps extends ParsedDomainCommon {
89
+ readonly registrar: "external-records";
90
+ }
91
+ export type ParsedDomainProps = ParsedRoute53ApexDomainProps | ParsedExternalDelegatedDomainProps | ParsedExternalRecordsDomainProps;
92
+ /**
93
+ * Locate the single `new Domain(...)` call expression in a parsed source file.
94
+ * Returns:
95
+ * - success(match) when exactly one call is found
96
+ * - success(undefined) when no call is found (caller decides how to report)
97
+ * - failure(Error) when more than one call is found (invariant: one domain per file)
98
+ */
99
+ export declare function findDomainConstructCall(sourceFile: ts.SourceFile): Result<DomainCallMatch | undefined, Error>;
100
+ /**
101
+ * Structured error union for `parseDomainProps`. Callers `switch` on `.kind`
102
+ * rather than string-matching an error message.
103
+ *
104
+ * - `registrar_required` — `registrar` property absent entirely
105
+ * - `registrar_unsupported` — `registrar` present but not one of
106
+ * `route53`, `external-delegated`, `external-records`
107
+ * - `missing_field` — a required field (`zoneName`, `delegatedSubdomain`,
108
+ * record fields) is absent
109
+ * - `invalid_literal` — a field is present but its shape/value is wrong
110
+ * (array expected, type mismatch, unsupported enum value)
111
+ */
112
+ export type ParseDomainError = {
113
+ readonly kind: "registrar_required";
114
+ } | {
115
+ readonly kind: "registrar_unsupported";
116
+ readonly value: string;
117
+ } | {
118
+ readonly kind: "missing_field";
119
+ readonly field: string;
120
+ } | {
121
+ readonly kind: "invalid_literal";
122
+ readonly field: string;
123
+ readonly reason: string;
124
+ };
125
+ /**
126
+ * Parse the props object literal of a located `new Domain(...)` call into a
127
+ * discriminated union keyed on `registrar`. Returns a `Result<_, ParseDomainError>`
128
+ * so callers can `switch` on `.kind` structurally — see `ParseDomainError` above.
129
+ */
130
+ export declare function parseDomainProps(propsObjectLiteral: ts.ObjectLiteralExpression): Result<ParsedDomainProps, ParseDomainError>;
131
+ /** Human-readable single-line message for a `ParseDomainError`. */
132
+ export declare function parseDomainErrorMessage(err: ParseDomainError): string;
133
+ /**
134
+ * Split a comma-separated argument list into top-level args, respecting
135
+ * nested parens/braces/brackets and string literals. Does NOT attempt to
136
+ * evaluate the individual arg expressions — returns raw source slices.
137
+ */
138
+ export declare function splitTopLevelArgs(argsText: string): string[];
139
+ export {};
@@ -0,0 +1 @@
1
+ import*as l from"typescript";import{parseObjectLiteral as x,asString as c,asStringUnion as A,asStringArray as k,asBoolean as y,asNumber as N,isCallRef as $,isParsedObject as g}from"./astCommonParser.js";import{success as a,failure as u}from"../types/Result.js";const h=["route53","external-delegated","external-records"],T=["A","AAAA","CNAME","MX","TXT","NS","SRV","CAA"],I=["A","AAAA"];function J(e){const n=[],t=i=>{if(l.isNewExpression(i)&&E(i.expression)){const d=j(i);d!==void 0&&n.push(d)}l.forEachChild(i,t)};if(t(e),n.length===0)return a(void 0);if(n.length>1)return u(new Error(`Expected exactly one 'new Domain(...)' call per infrastructure file, found ${n.length}`));const r=n[0];return r?a(r):a(void 0)}function E(e){return l.isIdentifier(e)&&e.text==="Domain"}function j(e){const n=e.arguments;if(!n||n.length<3)return;const t=n[0],r=n[1],i=n[2];if(!t||!r||!i||!l.isObjectLiteralExpression(i))return;const d=v(e);if(d===void 0)return;const o=R(e),s=l.isStringLiteral(r)?r.text:void 0;return{callExpression:e,containingStatement:d,propsObjectLiteral:i,domainVarId:o,scopeArgumentText:t.getText(),constructIdLiteral:s}}function v(e){let n=e;for(;n!==void 0;){if(l.isExpressionStatement(n)||l.isVariableStatement(n))return n;n=n.parent}}function R(e){let n=e.parent;for(;n!==void 0;){if(l.isVariableDeclaration(n)&&l.isIdentifier(n.name)&&n.initializer===e)return n.name.text;n=n.parent}}function D(e){switch(e.kind){case"registrar_required":return"'registrar' property is required";case"registrar_unsupported":return`'registrar' must be one of ${h.join(", ")}, got ${JSON.stringify(e.value)}`;case"missing_field":return`'${e.field}' property is required`;case"invalid_literal":return`'${e.field}' ${e.reason}`}}function B(e){const n=x(e),t=A(n.registrar,h);if(t===void 0){const s=n.registrar;if(s===void 0)return u({kind:"registrar_required"});const f=typeof s=="string"?s:p(s);return u({kind:"registrar_unsupported",value:f})}const r=c(n.zoneName);if(r===void 0)return u({kind:"missing_field",field:"zoneName"});const i=L(n.records);if(!i.success)return i;const d=z(n.certificates);if(!d.success)return d;const o={zoneName:r,description:c(n.description),costAllocationEnvironment:c(n.costAllocationEnvironment),tags:M(n.tags),records:i.data,certificates:d.data};switch(t){case"route53":{const s=S(n.delegations);return s.success?a({...o,registrar:t,hostedZoneId:c(n.hostedZoneId),delegations:s.data}):s}case"external-delegated":{const s=c(n.delegatedSubdomain);if(s===void 0)return u({kind:"missing_field",field:"delegatedSubdomain"});const f=S(n.delegations);return f.success?a({...o,registrar:t,delegatedSubdomain:s,delegations:f.data}):f}case"external-records":return a({...o,registrar:t})}}function X(e){return D(e)}function L(e){if(e===void 0)return a([]);if(!Array.isArray(e))return u({kind:"invalid_literal",field:"records",reason:"must be an array"});const n=[];for(let t=0;t<e.length;t++){const r=e[t];if(!g(r))return u({kind:"invalid_literal",field:`records[${t}]`,reason:"must be an object literal"});const i=O(r,t);if(!i.success)return i;n.push(i.data)}return a(n)}function O(e,n){const t=c(e.type),r=c(e.name);if(t===void 0)return u({kind:"missing_field",field:`records[${n}].type`});if(r===void 0)return u({kind:"missing_field",field:`records[${n}].name`});if(e.target!==void 0){if(!I.some(f=>f===t))return u({kind:"invalid_literal",field:`records[${n}]`,reason:`alias records must have type 'A' or 'AAAA', got '${t}'`});const s=V(e.target);return a({kind:"alias",type:t,name:r,target:s})}if(!T.some(s=>s===t))return u({kind:"invalid_literal",field:`records[${n}]`,reason:`unsupported record type '${t}'`});const i=C(e.value);if(i===void 0)return u({kind:"invalid_literal",field:`records[${n}].value`,reason:`must be a string or array of strings (got ${JSON.stringify(e.value)})`});const d=N(e.ttl),o={kind:"standard",type:t,name:r,value:i,...d!==void 0?{ttl:d}:{}};return a(o)}function C(e){if(e===void 0)return;if(typeof e=="string")return e;const n=k(e);if(n!==void 0)return n}function V(e){if($(e))return Z(e);if(g(e)){const n=A(e.kind,["ecs","cdn","bucket","custom"]);if(n==="ecs"||n==="cdn"){const t=c(e.appName);if(t!==void 0)return{kind:n,appName:t}}if(n==="bucket"){const t=c(e.bucketName);if(t!==void 0)return{kind:n,bucketName:t}}if(n==="custom"){const t=c(e.dnsName),r=c(e.hostedZoneId);if(t!==void 0&&r!==void 0)return{kind:n,dnsName:t,hostedZoneId:r}}}return{kind:"unresolved",sourceText:p(e)}}function Z(e){const n=e.__call.trim(),t=n.match(/^([A-Za-z_][\w$]*)\s*\(([\s\S]*)\)\s*$/);if(!t)return{kind:"unresolved",sourceText:n};const r=t[1],i=t[2]??"",d=_(i);switch(r){case"fjallApp":{const o=m(d,0);return o===void 0?{kind:"dynamic",sourceText:n}:{kind:"ecs",appName:o}}case"fjallCdn":{const o=m(d,0);return o===void 0?{kind:"dynamic",sourceText:n}:{kind:"cdn",appName:o}}case"fjallBucket":{const o=m(d,0);return o===void 0?{kind:"dynamic",sourceText:n}:{kind:"bucket",bucketName:o}}case"aliasTo":{if(d.length>=2){const o=m(d,0),s=m(d,1);return o!==void 0&&s!==void 0?{kind:"custom",dnsName:o,hostedZoneId:s}:{kind:"dynamic",sourceText:n}}if(d.length===1){const o=d[0]?.trim()??"",s=b(o,"dnsName"),f=b(o,"hostedZoneId");return s!==void 0&&f!==void 0?{kind:"custom",dnsName:s,hostedZoneId:f}:{kind:"dynamic",sourceText:n}}return{kind:"unresolved",sourceText:n}}default:return{kind:"unresolved",sourceText:n}}}function _(e){const n=[];let t=0,r=null,i="";for(let o=0;o<e.length;o++){const s=e[o];if(r!==null){if(i+=s,s==="\\"&&o+1<e.length){const f=e[o+1];f!==void 0&&(i+=f,o+=1);continue}s===r&&(r=null);continue}if(s==='"'||s==="'"||s==="`"){r=s,i+=s;continue}if(s==="("||s==="{"||s==="["){t+=1,i+=s;continue}if(s===")"||s==="}"||s==="]"){t-=1,i+=s;continue}if(s===","&&t===0){n.push(i.trim()),i="";continue}i+=s}const d=i.trim();return d.length>0&&n.push(d),n}function m(e,n){const t=e[n];if(t===void 0)return;const r=t.trim();if(r.length<2)return;const i=r[0],d=r[r.length-1];if(i===d&&!(i!=='"'&&i!=="'"&&i!=="`"))return r.slice(1,-1)}function b(e,n){const t=e.trim().replace(/^\{|\}$/g,""),r=_(t);for(const i of r){const d=i.indexOf(":");if(d<0||i.slice(0,d).trim().replace(/["'`]/g,"")!==n)continue;const s=i.slice(d+1).trim();return m([s],0)}}function z(e){if(e===void 0)return a([]);if(!Array.isArray(e))return u({kind:"invalid_literal",field:"certificates",reason:"must be an array"});const n=[];for(let t=0;t<e.length;t++){const r=e[t];if(typeof r=="string"){n.push({domainName:r});continue}if(!g(r))return u({kind:"invalid_literal",field:`certificates[${t}]`,reason:"must be a string or object literal"});const i=c(r.domainName);if(i===void 0)return u({kind:"missing_field",field:`certificates[${t}].domainName`});const d=k(r.subjectAlternativeNames),o=y(r.transparencyLogging);n.push({domainName:i,...d!==void 0?{subjectAlternativeNames:d}:{},...o!==void 0?{transparencyLogging:o}:{}})}return a(n)}function S(e){if(e===void 0)return a([]);if(!Array.isArray(e))return u({kind:"invalid_literal",field:"delegations",reason:"must be an array"});const n=[];for(let t=0;t<e.length;t++){const r=e[t];if(!g(r))return u({kind:"invalid_literal",field:`delegations[${t}]`,reason:"must be an object literal"});const i=c(r.subdomain),d=c(r.toAccount);if(i===void 0)return u({kind:"missing_field",field:`delegations[${t}].subdomain`});if(d===void 0)return u({kind:"missing_field",field:`delegations[${t}].toAccount`});const o=y(r.auto);n.push({subdomain:i,toAccount:d,...o!==void 0?{auto:o}:{}})}return a(n)}function M(e){if(e===void 0||!g(e))return;const n={};for(const[t,r]of Object.entries(e)){const i=c(r);i!==void 0&&(n[t]=i)}return Object.keys(n).length===0?void 0:n}function p(e){if(e===void 0)return"undefined";if(e===null)return"null";if(typeof e=="string")return JSON.stringify(e);if(typeof e=="number"||typeof e=="boolean")return String(e);if(Array.isArray(e))return`[${e.map(n=>p(n)).join(", ")}]`;if(typeof e=="object"){if("__call"in e)return String(e.__call);if("__identifier"in e)return String(e.__identifier);if("__expression"in e)return String(e.__expression);if("__unknown"in e)return String(e.__unknown)}return String(e)}export{J as findDomainConstructCall,X as parseDomainErrorMessage,B as parseDomainProps,_ as splitTopLevelArgs};
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Read-only AST parser for DynamoDB tables declared via addDatabase with
3
+ * type: "DynamoDB". Split out of astDatabaseParser.ts to keep both files
4
+ * within the 400-line budget. Write paths live in src/codemod/. Do not add
5
+ * mutation helpers here.
6
+ */
7
+ import * as ts from "typescript";
8
+ import type { ApplicationResourcePlan, ExtraProperty } from "../schemas/resourceSchemas.js";
9
+ import type { ParsedDatabaseResource } from "./astDatabaseParser.js";
10
+ declare const DYNAMODB_KEY_TYPES: readonly ["S", "N", "B"];
11
+ type DynamoDBKeyType = (typeof DYNAMODB_KEY_TYPES)[number];
12
+ interface DynamoDBKey {
13
+ name: string;
14
+ type: DynamoDBKeyType;
15
+ }
16
+ export interface ParsedDynamoDBResource {
17
+ variableName?: string;
18
+ resourceName: string;
19
+ partitionKey: DynamoDBKey;
20
+ sortKey?: DynamoDBKey;
21
+ globalSecondaryIndexes?: Array<{
22
+ indexName: string;
23
+ partitionKey: DynamoDBKey;
24
+ sortKey?: DynamoDBKey;
25
+ }>;
26
+ ttlAttribute?: string;
27
+ stream?: boolean;
28
+ extraProperties?: ExtraProperty[];
29
+ node: ts.Node;
30
+ }
31
+ /** Extract DynamoDB-specific fields from a parsed database resource */
32
+ export declare function extractDynamoDBFields(resource: ParsedDatabaseResource): ParsedDynamoDBResource | null;
33
+ /** Convert parsed DynamoDB resources to plan format */
34
+ export declare function convertDynamoDBResources(dynamodbResources: ParsedDynamoDBResource[]): ApplicationResourcePlan["dynamodb"];
35
+ export {};
@@ -0,0 +1 @@
1
+ import*as s from"typescript";import{asBoolean as A,asString as l,asStringUnion as S,captureExtraProperties as D,isParsedObject as b,omitUndefined as B,parseObjectLiteral as E}from"./astCommonParser.js";const O=["S","N","B"];function a(t){if(!b(t))return;const e=l(t.name),i=S(t.type,O);if(!(!e||!i))return{name:e,type:i}}function P(t){const e=t.node;if(!s.isCallExpression(e))return null;const i=e.arguments[0];if(!s.isCallExpression(i)||i.arguments.length<2)return null;const u=i.arguments[1];if(!s.isObjectLiteralExpression(u))return null;const r=E(u),c=a(r.partitionKey);if(!c)return null;const n={resourceName:t.resourceName,partitionKey:c,node:t.node};t.variableName&&(n.variableName=t.variableName);const m=a(r.sortKey);if(m&&(n.sortKey=m),Array.isArray(r.globalSecondaryIndexes)){const p=r.globalSecondaryIndexes.filter(b).map(o=>{const K=a(o.partitionKey);if(!K)return null;const x=l(o.indexName);if(!x)return null;const N={indexName:x,partitionKey:K},g=a(o.sortKey);return g&&(N.sortKey=g),N}).filter(o=>o!==null);p.length>0&&(n.globalSecondaryIndexes=p)}const f=l(r.ttlAttribute);f&&(n.ttlAttribute=f);const d=A(r.stream);d!==void 0&&(n.stream=d);const y=D(r,new Set(["type","databaseName","partitionKey","sortKey","globalSecondaryIndexes","ttlAttribute","stream"]));return y.length>0&&(n.extraProperties=y),n}function _(t){if(t.length!==0)return t.map(e=>({name:e.resourceName,partitionKey:e.partitionKey,...B({sortKey:e.sortKey,globalSecondaryIndexes:e.globalSecondaryIndexes,ttlAttribute:e.ttlAttribute,stream:e.stream,variableName:e.variableName,extraProperties:e.extraProperties})}))}export{_ as convertDynamoDBResources,P as extractDynamoDBFields};
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Read-only AST expression evaluator. Splits parse/evaluate helpers out of
3
+ * astCommonParser.ts to keep both files within the 400-line budget. Write
4
+ * paths live in src/codemod/. Do not add mutation helpers here.
5
+ */
6
+ import * as ts from "typescript";
7
+ import { type ParsedObject, type ParsedValue } from "./astCommonParser.js";
8
+ /** Parse an object literal expression into a ParsedObject */
9
+ export declare function parseObjectLiteral(node: ts.ObjectLiteralExpression): ParsedObject;
10
+ /** Evaluate a TypeScript AST expression to a ParsedValue */
11
+ export declare function evaluateExpression(node: ts.Expression): ParsedValue;
12
+ /** Find a string variable value by name */
13
+ export declare function findVariableValue(sourceFile: ts.SourceFile, varName: string): string | undefined;
14
+ /** Find an object variable declaration by name */
15
+ export declare function findObjectDeclaration(sourceFile: ts.SourceFile, objName: string): ParsedObject | undefined;
16
+ /** Evaluate a property access expression to a string */
17
+ export declare function evaluatePropertyAccess(sourceFile: ts.SourceFile, node: ts.PropertyAccessExpression): string | undefined;
18
+ /**
19
+ * Resolve a template literal expression to its string value.
20
+ * Walks spans: head.text + resolve each span.expression + span.literal.text.
21
+ * Falls back to stripping backticks from getText() if resolution fails.
22
+ */
23
+ export declare function resolveTemplateLiteral(sourceFile: ts.SourceFile, templateExpr: ts.TemplateExpression): string;
@@ -0,0 +1 @@
1
+ import*as t from"typescript";import{findFirstInAst as l}from"./astCommonParser.js";function f(e){const n={};for(const i of e.properties){if(!t.isPropertyAssignment(i))continue;const r=t.isIdentifier(i.name)||t.isStringLiteral(i.name)?i.name.text:void 0;r!==void 0&&(n[r]=a(i.initializer))}return n}function a(e){if(t.isStringLiteral(e))return e.text;if(t.isNumericLiteral(e))return Number(e.text);if(e.kind===t.SyntaxKind.TrueKeyword)return!0;if(e.kind===t.SyntaxKind.FalseKeyword)return!1;if(t.isArrayLiteralExpression(e))return e.elements.map(n=>a(n));if(t.isObjectLiteralExpression(e))return f(e);if(t.isIdentifier(e))return{__identifier:e.text};if(t.isPropertyAccessExpression(e))return{__expression:e.getText()};if(t.isCallExpression(e))return{__call:e.getText()};if(t.isBinaryExpression(e)&&e.operatorToken.kind===t.SyntaxKind.BarBarToken){const n=a(e.left),i=a(e.right);return typeof i=="string"?i:n}else if(t.isConditionalExpression(e)){const n=a(e.whenTrue),i=a(e.whenFalse);return typeof i=="string"||typeof i=="number"?i:n}else if(t.isTemplateExpression(e)||t.isNoSubstitutionTemplateLiteral(e))return{__expression:e.getText()};return{__unknown:e.getText()}}function u(e,n){return l(e,i=>{if(t.isVariableStatement(i)){for(const r of i.declarationList.declarations)if(t.isIdentifier(r.name)&&r.name.text===n&&r.initializer){if(t.isStringLiteral(r.initializer))return r.initializer.text;if(t.isObjectLiteralExpression(r.initializer)){const s=f(r.initializer);return JSON.stringify(s)}}}})}function o(e,n){return l(e,i=>{if(t.isVariableStatement(i)){for(const r of i.declarationList.declarations)if(t.isIdentifier(r.name)&&r.name.text===n&&r.initializer&&t.isObjectLiteralExpression(r.initializer))return f(r.initializer)}})}function p(e,n){if(!t.isIdentifier(n.expression))return;const i=o(e,n.expression.text),r=n.name.text;if(i&&i[r]!==void 0)return String(i[r])}function c(e,n){let i=n.head.text;for(const r of n.templateSpans){if(t.isIdentifier(r.expression)){const s=u(e,r.expression.text);if(s)i+=s;else return n.getText(e).replace(/^`|`$/g,"")}else if(t.isPropertyAccessExpression(r.expression)){const s=p(e,r.expression);if(s)i+=s;else return n.getText(e).replace(/^`|`$/g,"")}else return n.getText(e).replace(/^`|`$/g,"");i+=r.literal.text}return i}export{a as evaluateExpression,p as evaluatePropertyAccess,o as findObjectDeclaration,u as findVariableValue,f as parseObjectLiteral,c as resolveTemplateLiteral};
@@ -1,5 +1,10 @@
1
+ /**
2
+ * Read-only AST parser for infrastructure.ts. Used by fjall list and by the
3
+ * deploy-worker's convertToResourcePlan. Write paths live in src/codemod/.
4
+ * Do not add mutation helpers here.
5
+ */
1
6
  import * as ts from "typescript";
2
- import { type ApplicationResourcePlan, type StatementType, type CustomCodeBlock } from "../schemas/resourceSchemas.js";
7
+ import type { CustomCodeBlock } from "../schemas/resourceSchemas.js";
3
8
  export { type IdentifierRef, type ExpressionRef, type CallRef, type ParsedValue, type ParsedObject, isPlainObject, isIdentifierRef, isExpressionRef, isCallRef, isParsedObject, asString, asNumber, asBoolean, asStringArray, asStringUnion, captureExtraProperties, } from "./astCommonParser.js";
4
9
  export { type ParsedDatabaseResource } from "./astDatabaseParser.js";
5
10
  export { type ParsedDynamoDBResource } from "./astDatabaseParser.js";
@@ -9,7 +14,13 @@ export { type ParsedSQSResource } from "./astMessagingParser.js";
9
14
  export { type ParsedCDNResource } from "./astCdnParser.js";
10
15
  export { type ParsedNetworkResource } from "./astNetworkParser.js";
11
16
  export { type ParsedLambdaConfig, type ParsedPatternResource, } from "./astPatternParser.js";
17
+ export { type StatementType } from "../schemas/resourceSchemas.js";
18
+ export { type CustomCodeBlock } from "../schemas/resourceSchemas.js";
19
+ export { type ClassifiedStatement, classifyStatements, } from "./astStatementClassifier.js";
20
+ export { extractCustomCodeBlocks, findManagedResourcePosition, getLastManagedStatementOfType, getManagedResourcesByType, } from "./astStatementQueries.js";
21
+ export { convertToResourcePlan } from "./astPlanConverter.js";
12
22
  import { type ParsedNetworkConfig } from "./astNetworkParser.js";
23
+ import { type ClassifiedStatement } from "./astStatementClassifier.js";
13
24
  import type { ParsedDatabaseResource } from "./astDatabaseParser.js";
14
25
  import type { ParsedDynamoDBResource } from "./astDatabaseParser.js";
15
26
  import type { ParsedS3Resource } from "./astStorageParser.js";
@@ -53,51 +64,3 @@ export interface ParsedInfrastructure {
53
64
  export declare function parseInfrastructure(content: string, options?: {
54
65
  extractCustomCode?: boolean;
55
66
  }): ParsedInfrastructure;
56
- export declare function convertToResourcePlan(parsed: ParsedInfrastructure, appName: string, options?: {
57
- skipValidation?: boolean;
58
- }): ApplicationResourcePlan;
59
- /** Re-export for downstream consumers (e.g. astSurgicalModification) */
60
- export type { StatementType } from "../schemas/resourceSchemas.js";
61
- /**
62
- * A classified statement with its type and metadata.
63
- */
64
- export interface ClassifiedStatement {
65
- /** The statement type */
66
- type: StatementType;
67
- /** The AST node */
68
- node: ts.Statement;
69
- /** For managed resources, the resource name (e.g., "MyDatabase") */
70
- resourceName?: string;
71
- /** Start position in source text */
72
- startPos: number;
73
- /** End position in source text */
74
- endPos: number;
75
- /** Whether the statement is classified as managed by Fjall */
76
- isManaged: boolean;
77
- }
78
- /** Re-export for downstream consumers (e.g. astSurgicalModification) */
79
- export type { CustomCodeBlock } from "../schemas/resourceSchemas.js";
80
- /**
81
- * Classify all top-level statements in an infrastructure file.
82
- */
83
- export declare function classifyStatements(sourceFile: ts.SourceFile): ClassifiedStatement[];
84
- /**
85
- * Extract custom code blocks from an infrastructure file.
86
- */
87
- export declare function extractCustomCodeBlocks(sourceFile: ts.SourceFile, precomputedClassifications?: ClassifiedStatement[]): CustomCodeBlock[];
88
- /**
89
- * Find the position information for a specific managed resource.
90
- */
91
- export declare function findManagedResourcePosition(sourceFile: ts.SourceFile, resourceType: StatementType, resourceName: string, precomputedClassifications?: ClassifiedStatement[]): {
92
- startPos: number;
93
- endPos: number;
94
- node: ts.Statement;
95
- } | null;
96
- /**
97
- * Get the last managed statement of a specific type.
98
- */
99
- export declare function getLastManagedStatementOfType(sourceFile: ts.SourceFile, type: StatementType, precomputedClassifications?: ClassifiedStatement[]): ClassifiedStatement | null;
100
- /**
101
- * Get all managed resources grouped by type.
102
- */
103
- export declare function getManagedResourcesByType(sourceFile: ts.SourceFile, precomputedClassifications?: ClassifiedStatement[]): Record<StatementType, ClassifiedStatement[]>;