@fjall/generator 0.89.5 → 0.94.0

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 +5 -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/fileRewriter/builders.d.ts +57 -0
  69. package/dist/src/codemod/fileRewriter/builders.js +1 -0
  70. package/dist/src/codemod/fileRewriter/index.d.ts +4 -0
  71. package/dist/src/codemod/fileRewriter/index.js +1 -0
  72. package/dist/src/codemod/fileRewriter/locateByRange.d.ts +65 -0
  73. package/dist/src/codemod/fileRewriter/locateByRange.js +1 -0
  74. package/dist/src/codemod/fileRewriter/parse.d.ts +18 -0
  75. package/dist/src/codemod/fileRewriter/parse.js +2 -0
  76. package/dist/src/codemod/fileRewriter/print.d.ts +46 -0
  77. package/dist/src/codemod/fileRewriter/print.js +4 -0
  78. package/dist/src/codemod/historyPaths.d.ts +2 -0
  79. package/dist/src/codemod/historyPaths.js +1 -0
  80. package/dist/src/codemod/index.d.ts +7 -0
  81. package/dist/src/codemod/index.js +1 -0
  82. package/dist/src/codemod/listResources.d.ts +4 -0
  83. package/dist/src/codemod/listResources.js +1 -0
  84. package/dist/src/codemod/registry.d.ts +42 -0
  85. package/dist/src/codemod/registry.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
package/LICENSE CHANGED
@@ -1,21 +1,50 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Fjall
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ Fjall Proprietary Software Licence
2
+
3
+ Copyright (c) 2026 Fjall. All rights reserved.
4
+
5
+ This software, including all source, object, bundled, and minified forms
6
+ ("the Software"), is the proprietary and confidential property of Fjall.
7
+
8
+ 1. Permitted Use. Subject to the terms of this Licence, Fjall grants you
9
+ a non-exclusive, non-transferable, revocable licence to install the
10
+ Software via the npm registry and to execute it solely for the purpose
11
+ of deploying, operating, and managing your own applications and
12
+ infrastructure on cloud providers.
13
+
14
+ 2. Restrictions. You may NOT, and may not permit any third party to:
15
+ (a) copy, redistribute, sublicense, sell, rent, lease, or otherwise
16
+ transfer the Software;
17
+ (b) modify, adapt, translate, or create derivative works of the Software;
18
+ (c) reverse engineer, decompile, disassemble, deminify, or otherwise
19
+ attempt to derive the source code, structure, or organisation of
20
+ the Software, except to the minimum extent expressly permitted by
21
+ applicable mandatory law;
22
+ (d) use the Software, or any portion of it, to develop, train, or
23
+ improve any product or service that competes with Fjall;
24
+ (e) remove, alter, or obscure any proprietary notices contained in
25
+ the Software;
26
+ (f) publish, share, or otherwise disclose the Software or its contents
27
+ to any third party.
28
+
29
+ 3. Ownership. All right, title, and interest in and to the Software,
30
+ including all intellectual property rights, remain with Fjall. No
31
+ rights are granted except as expressly set out in this Licence.
32
+
33
+ 4. Termination. This Licence terminates automatically if you breach any
34
+ of its terms. Upon termination you must cease all use of the Software
35
+ and destroy all copies in your possession.
36
+
37
+ 5. Disclaimer of Warranty. THE SOFTWARE IS PROVIDED "AS IS" WITHOUT
38
+ WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
39
+ THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
40
+ AND NON-INFRINGEMENT.
41
+
42
+ 6. Limitation of Liability. IN NO EVENT SHALL FJALL BE LIABLE FOR ANY
43
+ INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES
44
+ ARISING OUT OF OR RELATED TO THE SOFTWARE, EVEN IF ADVISED OF THE
45
+ POSSIBILITY OF SUCH DAMAGES.
46
+
47
+ 7. Governing Law. This Licence is governed by the laws of England and
48
+ Wales, without regard to conflict of laws principles.
49
+
50
+ For commercial licensing enquiries, contact: contact@fjall.io
package/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # @fjall/generator
2
+
3
+ Pure infrastructure generation logic for Fjall. Detects application patterns (Next.js, Payload CMS, Remix, etc.) and generates the AWS CDK resources, IAM policies, and config required to deploy them.
4
+
5
+ This package contains no AWS SDK calls — it is a deterministic transformer from application source + config to a resource plan. Consumed by `@fjall/cli` and the Fjall webapp deployment worker.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @fjall/generator
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```typescript
16
+ import { generateResourcePlan } from "@fjall/generator";
17
+
18
+ const plan = generateResourcePlan({
19
+ appPath: "./my-app",
20
+ config: fjallConfig,
21
+ });
22
+ ```
23
+
24
+ See [docs.fjall.io](https://docs.fjall.io) for full usage.
25
+
26
+ ## Licence
27
+
28
+ Proprietary — see [LICENSE](./LICENSE).
package/dist/.minified ADDED
@@ -0,0 +1 @@
1
+ 93 files minified at 2026-04-21T02:11:58.926Z
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Read-only AST parser for the CDN section of infrastructure.ts. Used by
3
+ * fjall list and by the deploy-worker's convertToResourcePlan. Write paths
4
+ * live in src/codemod/. Do not add mutation helpers here.
5
+ */
1
6
  import * as ts from "typescript";
2
7
  import type { ApplicationResourcePlan } from "../schemas/resourceSchemas.js";
3
8
  import { type ParsedObject } from "./astCommonParser.js";
@@ -1,114 +1 @@
1
- import * as ts from "typescript";
2
- import { asString, asStringArray, asStringUnion, captureExtraProperties, findFirstInAst, isFactoryBuildCall, isFactoryMethodCall, isIdentifierRef, isParsedObject, parseObjectLiteral, } from "./astCommonParser.js";
3
- // ---- Extraction helpers ----
4
- function extractCDNResource(buildCall) {
5
- if (buildCall.arguments.length < 2)
6
- return null;
7
- const nameArg = buildCall.arguments[0];
8
- const configArg = buildCall.arguments[1];
9
- if (!ts.isStringLiteral(nameArg) ||
10
- !ts.isObjectLiteralExpression(configArg)) {
11
- return null;
12
- }
13
- return {
14
- resourceName: nameArg.text,
15
- config: parseObjectLiteral(configArg),
16
- node: buildCall,
17
- };
18
- }
19
- /** Resolve a CDN origin identifier back to its resource name */
20
- function resolveOriginIdentifier(identifier, s3Resources, computeResources) {
21
- const s3Match = s3Resources.find((s3) => s3.variableName === identifier);
22
- if (s3Match)
23
- return s3Match.resourceName;
24
- const computeMatch = computeResources.find((c) => c.variableName === identifier ||
25
- c.resourceName.charAt(0).toLowerCase() + c.resourceName.slice(1) ===
26
- identifier);
27
- if (computeMatch)
28
- return computeMatch.resourceName;
29
- return identifier;
30
- }
31
- const CDN_CACHE_POLICIES = ["CACHING_OPTIMIZED", "CACHING_DISABLED"];
32
- // ---- Public API ----
33
- /** Find CDN resource from addCdn call */
34
- export function findCDNResource(sourceFile) {
35
- return findFirstInAst(sourceFile, (node) => {
36
- if (!ts.isCallExpression(node) || !isFactoryMethodCall(node, "addCdn"))
37
- return undefined;
38
- const cdnArg = node.arguments[0];
39
- if (!isFactoryBuildCall(cdnArg, "CdnFactory"))
40
- return undefined;
41
- return extractCDNResource(cdnArg) ?? undefined;
42
- });
43
- }
44
- /** Convert parsed CDN resource to plan format */
45
- export function convertCDNResource(cdnResource, s3Resources, computeResources) {
46
- if (!cdnResource)
47
- return undefined;
48
- const cdn = cdnResource;
49
- const config = cdn.config;
50
- const resolveOrigin = (val) => {
51
- if (isIdentifierRef(val)) {
52
- return resolveOriginIdentifier(val.__identifier, s3Resources, computeResources);
53
- }
54
- return asString(val) ?? "";
55
- };
56
- const defaultOriginRef = resolveOrigin(config.origin);
57
- const result = {
58
- name: cdn.resourceName,
59
- defaultOriginRef,
60
- };
61
- if (Array.isArray(config.behaviours)) {
62
- const behaviours = config.behaviours.filter(isParsedObject).map((b) => ({
63
- pathPattern: asString(b.pathPattern) ?? "",
64
- originRef: resolveOrigin(b.origin),
65
- ...{
66
- ...(asStringUnion(b.cachePolicy, CDN_CACHE_POLICIES) !== undefined && {
67
- cachePolicy: asStringUnion(b.cachePolicy, CDN_CACHE_POLICIES),
68
- }),
69
- },
70
- }));
71
- if (behaviours.length > 0)
72
- result.behaviours = behaviours;
73
- }
74
- const customDomain = asString(config.customDomain);
75
- if (customDomain) {
76
- result.customDomain = customDomain;
77
- }
78
- else {
79
- const domainNames = asStringArray(config.domainNames);
80
- if (domainNames && domainNames.length > 0) {
81
- result.customDomain = domainNames[0];
82
- }
83
- }
84
- const certificateArn = asString(config.certificateArn);
85
- if (certificateArn)
86
- result.certificateArn = certificateArn;
87
- if (config.accessGate !== undefined) {
88
- if (config.accessGate === false) {
89
- result.accessGate = false;
90
- }
91
- else if (isParsedObject(config.accessGate)) {
92
- const gate = config.accessGate;
93
- const gateType = asString(gate.type);
94
- const username = asString(gate.username);
95
- const password = asString(gate.password);
96
- if (gateType === "basic-auth" && username && password) {
97
- result.accessGate = { type: "basic-auth", username, password };
98
- }
99
- }
100
- }
101
- const CDN_KNOWN_KEYS = new Set([
102
- "originType",
103
- "origin",
104
- "behaviours",
105
- "customDomain",
106
- "domainNames",
107
- "certificateArn",
108
- "accessGate",
109
- ]);
110
- const extras = captureExtraProperties(config, CDN_KNOWN_KEYS);
111
- if (extras.length > 0)
112
- result.extraProperties = extras;
113
- return result;
114
- }
1
+ import*as f from"typescript";import{asString as c,asStringArray as D,asStringUnion as h,captureExtraProperties as y,findFirstInAst as I,isFactoryBuildCall as O,isFactoryMethodCall as P,isIdentifierRef as _,isParsedObject as p,parseObjectLiteral as x}from"./astCommonParser.js";function E(e){if(e.arguments.length<2)return null;const n=e.arguments[0],s=e.arguments[1];return!f.isStringLiteral(n)||!f.isObjectLiteralExpression(s)?null:{resourceName:n.text,config:x(s),node:e}}function G(e,n,s){const u=n.find(i=>i.variableName===e);if(u)return u.resourceName;const r=s.find(i=>i.variableName===e||i.resourceName.charAt(0).toLowerCase()+i.resourceName.slice(1)===e);return r?r.resourceName:e}const A=["CACHING_OPTIMIZED","CACHING_DISABLED"];function b(e){return I(e,n=>{if(!f.isCallExpression(n)||!P(n,"addCdn"))return;const s=n.arguments[0];if(O(s,"CdnFactory"))return E(s)??void 0})}function L(e,n,s){if(!e)return;const u=e,r=u.config,i=t=>_(t)?G(t.__identifier,n,s):c(t)??"",C=i(r.origin),a={name:u.resourceName,defaultOriginRef:C};if(Array.isArray(r.behaviours)){const t=r.behaviours.filter(p).map(o=>({pathPattern:c(o.pathPattern)??"",originRef:i(o.origin),...h(o.cachePolicy,A)!==void 0&&{cachePolicy:h(o.cachePolicy,A)}}));t.length>0&&(a.behaviours=t)}const m=c(r.customDomain);if(m)a.customDomain=m;else{const t=D(r.domainNames);t&&t.length>0&&(a.customDomain=t[0])}const g=c(r.certificateArn);if(g&&(a.certificateArn=g),r.accessGate!==void 0){if(r.accessGate===!1)a.accessGate=!1;else if(p(r.accessGate)){const t=r.accessGate,o=c(t.type),N=c(t.username),l=c(t.password);o==="basic-auth"&&N&&l&&(a.accessGate={type:"basic-auth",username:N,password:l})}}const d=y(r,new Set(["originType","origin","behaviours","customDomain","domainNames","certificateArn","accessGate"]));return d.length>0&&(a.extraProperties=d),a}export{L as convertCDNResource,b as findCDNResource};
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Read-only AST parser utilities shared across the other ast*Parser.ts files.
3
+ * Used by fjall list and by the deploy-worker's convertToResourcePlan. Write
4
+ * paths live in src/codemod/. Do not add mutation helpers here.
5
+ */
1
6
  import * as ts from "typescript";
2
7
  import type { ExtraProperty } from "../schemas/resourceSchemas.js";
3
8
  /** Special marker for identifier references in parsed AST */
@@ -71,20 +76,4 @@ export declare function parseBooleanOrConfig<T>(value: ParsedValue | undefined,
71
76
  export declare function parseOptionalConfig<T>(value: ParsedValue | undefined, parser: (obj: ParsedObject) => T): T | undefined;
72
77
  /** Extract a named sub-object from a config, returning undefined if not a plain object */
73
78
  export declare function extractSubConfig<T>(rawConfig: ParsedObject, field: string, transform: (obj: ParsedObject) => T): T | undefined;
74
- /** Parse an object literal expression into a ParsedObject */
75
- export declare function parseObjectLiteral(node: ts.ObjectLiteralExpression): ParsedObject;
76
- /** Evaluate a TypeScript AST expression to a ParsedValue */
77
- export declare function evaluateExpression(node: ts.Expression): ParsedValue;
78
- /** Find a string variable value by name */
79
- export declare function findVariableValue(sourceFile: ts.SourceFile, varName: string): string | undefined;
80
- /** Find an object variable declaration by name */
81
- export declare function findObjectDeclaration(sourceFile: ts.SourceFile, objName: string): ParsedObject | undefined;
82
- /** Evaluate a property access expression to a string */
83
- export declare function evaluatePropertyAccess(sourceFile: ts.SourceFile, node: ts.PropertyAccessExpression): string | undefined;
84
- /**
85
- * Resolve a template literal expression to its string value.
86
- * Walks spans: head.text + resolve each span.expression + span.literal.text.
87
- * Falls back to stripping backticks from getText() if resolution fails.
88
- */
89
- export declare function resolveTemplateLiteral(sourceFile: ts.SourceFile, templateExpr: ts.TemplateExpression): string;
90
- export {};
79
+ export { parseObjectLiteral, evaluateExpression, findVariableValue, findObjectDeclaration, evaluatePropertyAccess, resolveTemplateLiteral, } from "./astExpressionEvaluator.js";
@@ -1,351 +1 @@
1
- import * as ts from "typescript";
2
- import { constIncludes } from "../schemas/constants.js";
3
- /** Base check for non-null, non-array objects */
4
- export function isPlainObject(value) {
5
- return typeof value === "object" && value !== null && !Array.isArray(value);
6
- }
7
- /** Type guard for identifier references */
8
- export function isIdentifierRef(value) {
9
- return isPlainObject(value) && "__identifier" in value;
10
- }
11
- /** Type guard for expression references */
12
- export function isExpressionRef(value) {
13
- return isPlainObject(value) && "__expression" in value;
14
- }
15
- /** Type guard for call references */
16
- export function isCallRef(value) {
17
- return isPlainObject(value) && "__call" in value;
18
- }
19
- /** Type guard for parsed objects */
20
- export function isParsedObject(value) {
21
- return (isPlainObject(value) &&
22
- !("__identifier" in value) &&
23
- !("__expression" in value) &&
24
- !("__call" in value) &&
25
- !("__unknown" in value));
26
- }
27
- /** Safely extract a string from ParsedValue */
28
- export function asString(value) {
29
- return typeof value === "string" ? value : undefined;
30
- }
31
- /** Safely extract a number from ParsedValue */
32
- export function asNumber(value) {
33
- return typeof value === "number" ? value : undefined;
34
- }
35
- /** Safely extract a boolean from ParsedValue */
36
- export function asBoolean(value) {
37
- return typeof value === "boolean" ? value : undefined;
38
- }
39
- /** Safely extract a string array from ParsedValue */
40
- export function asStringArray(value) {
41
- if (!Array.isArray(value))
42
- return undefined;
43
- const result = [];
44
- for (const item of value) {
45
- if (typeof item === "string")
46
- result.push(item);
47
- }
48
- return result.length > 0 ? result : undefined;
49
- }
50
- /** Narrow a string to a union member, returning undefined if not a valid member */
51
- export function asStringUnion(value, validValues) {
52
- const str = asString(value);
53
- if (str === undefined)
54
- return undefined;
55
- return constIncludes(validValues, str) ? str : undefined;
56
- }
57
- /** Returns a shallow copy with all undefined-valued properties removed */
58
- export function omitUndefined(obj) {
59
- const result = {};
60
- for (const [key, value] of Object.entries(obj)) {
61
- if (value !== undefined) {
62
- result[key] = value;
63
- }
64
- }
65
- return result;
66
- }
67
- /** Reconstruct source text from a parsed AST value for round-trip preservation */
68
- export function parsedValueToSourceText(value) {
69
- if (value === null)
70
- return "null";
71
- if (value === undefined)
72
- return "undefined";
73
- if (typeof value === "string")
74
- return JSON.stringify(value);
75
- if (typeof value === "number" || typeof value === "boolean")
76
- return String(value);
77
- if (Array.isArray(value)) {
78
- return `[${value.map(parsedValueToSourceText).join(", ")}]`;
79
- }
80
- if (!isPlainObject(value))
81
- return String(value);
82
- if (isIdentifierRef(value))
83
- return value.__identifier;
84
- if (isExpressionRef(value))
85
- return value.__expression;
86
- if (isCallRef(value))
87
- return value.__call;
88
- if ("__unknown" in value && typeof value.__unknown === "string")
89
- return value.__unknown;
90
- const entries = Object.entries(value);
91
- if (entries.length === 0)
92
- return "{}";
93
- const inner = entries
94
- .map(([k, v]) => `${k}: ${parsedValueToSourceText(v)}`)
95
- .join(", ");
96
- return `{ ${inner} }`;
97
- }
98
- /** Capture properties from a parsed config that are NOT in the known keys set */
99
- export function captureExtraProperties(config, knownKeys) {
100
- const extras = [];
101
- for (const [key, value] of Object.entries(config)) {
102
- if (knownKeys.has(key) || value === undefined)
103
- continue;
104
- extras.push({ key, sourceText: parsedValueToSourceText(value) });
105
- }
106
- return extras;
107
- }
108
- /** Check if an object literal property is a named property assignment */
109
- export function isNamedProperty(prop, name) {
110
- return (ts.isPropertyAssignment(prop) &&
111
- ts.isIdentifier(prop.name) &&
112
- prop.name.text === name);
113
- }
114
- /** Check if a node is an App.getApp() call expression */
115
- export function isAppGetAppCall(node) {
116
- return (ts.isCallExpression(node) &&
117
- ts.isPropertyAccessExpression(node.expression) &&
118
- node.expression.name.text === "getApp" &&
119
- ts.isIdentifier(node.expression.expression) &&
120
- node.expression.expression.text === "App");
121
- }
122
- /** Check if a node is a chained factory method call (e.g., app.addDatabase(...)) */
123
- export function isFactoryMethodCall(node, methodName) {
124
- const { expression } = node;
125
- return (ts.isPropertyAccessExpression(expression) &&
126
- expression.name.text === methodName &&
127
- node.arguments.length > 0);
128
- }
129
- /** Traverse AST and return the first non-undefined result from the finder. */
130
- export function findFirstInAst(sourceFile, finder) {
131
- let result;
132
- const visit = (node) => {
133
- if (result !== undefined)
134
- return;
135
- result = finder(node);
136
- if (result === undefined)
137
- ts.forEachChild(node, visit);
138
- };
139
- visit(sourceFile);
140
- return result;
141
- }
142
- /** Traverse AST and collect all non-null results from the collector. */
143
- export function collectFromAst(sourceFile, collector) {
144
- const results = [];
145
- const visit = (node) => {
146
- const item = collector(node);
147
- if (item !== null)
148
- results.push(item);
149
- ts.forEachChild(node, visit);
150
- };
151
- visit(sourceFile);
152
- return results;
153
- }
154
- /** Type guard for Factory.build() call expressions */
155
- export function isFactoryBuildCall(node, factoryName) {
156
- return (ts.isCallExpression(node) &&
157
- ts.isPropertyAccessExpression(node.expression) &&
158
- node.expression.name.text === "build" &&
159
- ts.isIdentifier(node.expression.expression) &&
160
- node.expression.expression.text === factoryName);
161
- }
162
- /** Extract variable name from the parent declaration of a node */
163
- export function extractVariableName(node) {
164
- const parent = node.parent;
165
- if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) {
166
- return parent.name.text;
167
- }
168
- return undefined;
169
- }
170
- /** Identity cast - trusts that parsed CDK output matches the expected shape.
171
- * Safe because input is always generated CDK code that was originally validated by Zod schemas. */
172
- export const typed = () => (v) => v;
173
- /** Safely extract an object or false from ParsedValue */
174
- export function asObjectOrFalse(value) {
175
- if (value === undefined || value === null)
176
- return undefined;
177
- if (value === false)
178
- return false;
179
- if (typeof value === "object" && !Array.isArray(value))
180
- return value;
181
- return undefined;
182
- }
183
- export function parseBooleanOrConfig(value, cast) {
184
- if (value === false)
185
- return false;
186
- return isParsedObject(value) ? cast(value) : undefined;
187
- }
188
- export function parseOptionalConfig(value, parser) {
189
- return isParsedObject(value) ? parser(value) : undefined;
190
- }
191
- /** Extract a named sub-object from a config, returning undefined if not a plain object */
192
- export function extractSubConfig(rawConfig, field, transform) {
193
- const value = rawConfig[field];
194
- return isParsedObject(value) ? transform(value) : undefined;
195
- }
196
- /** Parse an object literal expression into a ParsedObject */
197
- export function parseObjectLiteral(node) {
198
- const result = {};
199
- for (const prop of node.properties) {
200
- if (!ts.isPropertyAssignment(prop))
201
- continue;
202
- const key = ts.isIdentifier(prop.name)
203
- ? prop.name.text
204
- : ts.isStringLiteral(prop.name)
205
- ? prop.name.text
206
- : undefined;
207
- if (key === undefined)
208
- continue;
209
- result[key] = evaluateExpression(prop.initializer);
210
- }
211
- return result;
212
- }
213
- /** Evaluate a TypeScript AST expression to a ParsedValue */
214
- export function evaluateExpression(node) {
215
- if (ts.isStringLiteral(node)) {
216
- return node.text;
217
- }
218
- else if (ts.isNumericLiteral(node)) {
219
- return Number(node.text);
220
- }
221
- else if (node.kind === ts.SyntaxKind.TrueKeyword) {
222
- return true;
223
- }
224
- else if (node.kind === ts.SyntaxKind.FalseKeyword) {
225
- return false;
226
- }
227
- else if (ts.isArrayLiteralExpression(node)) {
228
- return node.elements.map((element) => evaluateExpression(element));
229
- }
230
- else if (ts.isObjectLiteralExpression(node)) {
231
- return parseObjectLiteral(node);
232
- }
233
- else if (ts.isIdentifier(node)) {
234
- return { __identifier: node.text };
235
- }
236
- else if (ts.isPropertyAccessExpression(node)) {
237
- return { __expression: node.getText() };
238
- }
239
- else if (ts.isCallExpression(node)) {
240
- return { __call: node.getText() };
241
- }
242
- else if (ts.isBinaryExpression(node) &&
243
- node.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
244
- // Handle || operator - return the left side if it's a literal
245
- const left = evaluateExpression(node.left);
246
- const right = evaluateExpression(node.right);
247
- // For simplicity, prefer string literals from the right side for defaults
248
- if (typeof right === "string") {
249
- return right;
250
- }
251
- return left;
252
- }
253
- else if (ts.isConditionalExpression(node)) {
254
- // Handle ternary operator - for simplicity, try to evaluate the branches
255
- const whenTrue = evaluateExpression(node.whenTrue);
256
- const whenFalse = evaluateExpression(node.whenFalse);
257
- // Default to the false branch for simplicity
258
- if (typeof whenFalse === "string" || typeof whenFalse === "number") {
259
- return whenFalse;
260
- }
261
- return whenTrue;
262
- }
263
- else if (ts.isTemplateExpression(node) ||
264
- ts.isNoSubstitutionTemplateLiteral(node)) {
265
- // Handle template literals to preserve them as expressions during round-trip parsing
266
- return { __expression: node.getText() };
267
- }
268
- return { __unknown: node.getText() };
269
- }
270
- /** Find a string variable value by name */
271
- export function findVariableValue(sourceFile, varName) {
272
- return findFirstInAst(sourceFile, (node) => {
273
- if (!ts.isVariableStatement(node))
274
- return undefined;
275
- for (const declaration of node.declarationList.declarations) {
276
- if (ts.isIdentifier(declaration.name) &&
277
- declaration.name.text === varName &&
278
- declaration.initializer) {
279
- if (ts.isStringLiteral(declaration.initializer)) {
280
- return declaration.initializer.text;
281
- }
282
- if (ts.isObjectLiteralExpression(declaration.initializer)) {
283
- const obj = parseObjectLiteral(declaration.initializer);
284
- return JSON.stringify(obj);
285
- }
286
- }
287
- }
288
- return undefined;
289
- });
290
- }
291
- /** Find an object variable declaration by name */
292
- export function findObjectDeclaration(sourceFile, objName) {
293
- return findFirstInAst(sourceFile, (node) => {
294
- if (!ts.isVariableStatement(node))
295
- return undefined;
296
- for (const declaration of node.declarationList.declarations) {
297
- if (ts.isIdentifier(declaration.name) &&
298
- declaration.name.text === objName &&
299
- declaration.initializer &&
300
- ts.isObjectLiteralExpression(declaration.initializer)) {
301
- return parseObjectLiteral(declaration.initializer);
302
- }
303
- }
304
- return undefined;
305
- });
306
- }
307
- /** Evaluate a property access expression to a string */
308
- export function evaluatePropertyAccess(sourceFile, node) {
309
- if (!ts.isIdentifier(node.expression))
310
- return undefined;
311
- const objValue = findObjectDeclaration(sourceFile, node.expression.text);
312
- const propName = node.name.text;
313
- if (objValue && objValue[propName] !== undefined) {
314
- return String(objValue[propName]);
315
- }
316
- return undefined;
317
- }
318
- /**
319
- * Resolve a template literal expression to its string value.
320
- * Walks spans: head.text + resolve each span.expression + span.literal.text.
321
- * Falls back to stripping backticks from getText() if resolution fails.
322
- */
323
- export function resolveTemplateLiteral(sourceFile, templateExpr) {
324
- let result = templateExpr.head.text;
325
- for (const span of templateExpr.templateSpans) {
326
- if (ts.isIdentifier(span.expression)) {
327
- const resolved = findVariableValue(sourceFile, span.expression.text);
328
- if (resolved) {
329
- result += resolved;
330
- }
331
- else {
332
- // Can't resolve -- fall back to raw getText()
333
- return templateExpr.getText(sourceFile).replace(/^`|`$/g, "");
334
- }
335
- }
336
- else if (ts.isPropertyAccessExpression(span.expression)) {
337
- const resolved = evaluatePropertyAccess(sourceFile, span.expression);
338
- if (resolved) {
339
- result += resolved;
340
- }
341
- else {
342
- return templateExpr.getText(sourceFile).replace(/^`|`$/g, "");
343
- }
344
- }
345
- else {
346
- return templateExpr.getText(sourceFile).replace(/^`|`$/g, "");
347
- }
348
- result += span.literal.text;
349
- }
350
- return result;
351
- }
1
+ import*as i from"typescript";import{constIncludes as c}from"../schemas/constants.js";function o(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function x(n){return o(n)&&"__identifier"in n}function d(n){return o(n)&&"__expression"in n}function a(n){return o(n)&&"__call"in n}function f(n){return o(n)&&!("__identifier"in n)&&!("__expression"in n)&&!("__call"in n)&&!("__unknown"in n)}function y(n){return typeof n=="string"?n:void 0}function m(n){return typeof n=="number"?n:void 0}function _(n){return typeof n=="boolean"?n:void 0}function b(n){if(!Array.isArray(n))return;const e=[];for(const r of n)typeof r=="string"&&e.push(r);return e.length>0?e:void 0}function A(n,e){const r=y(n);if(r!==void 0)return c(e,r)?r:void 0}function g(n){const e={};for(const[r,t]of Object.entries(n))t!==void 0&&(e[r]=t);return e}function p(n){if(n===null)return"null";if(n===void 0)return"undefined";if(typeof n=="string")return JSON.stringify(n);if(typeof n=="number"||typeof n=="boolean")return String(n);if(Array.isArray(n))return`[${n.map(p).join(", ")}]`;if(!o(n))return String(n);if(x(n))return n.__identifier;if(d(n))return n.__expression;if(a(n))return n.__call;if("__unknown"in n&&typeof n.__unknown=="string")return n.__unknown;const e=Object.entries(n);return e.length===0?"{}":`{ ${e.map(([t,s])=>`${t}: ${p(s)}`).join(", ")} }`}function h(n,e){const r=[];for(const[t,s]of Object.entries(n))e.has(t)||s===void 0||r.push({key:t,sourceText:p(s)});return r}function j(n,e){return i.isPropertyAssignment(n)&&i.isIdentifier(n.name)&&n.name.text===e}function O(n){return i.isCallExpression(n)&&i.isPropertyAccessExpression(n.expression)&&n.expression.name.text==="getApp"&&i.isIdentifier(n.expression.expression)&&n.expression.expression.text==="App"}function C(n,e){const{expression:r}=n;return i.isPropertyAccessExpression(r)&&r.name.text===e&&n.arguments.length>0}function E(n,e){let r;const t=s=>{r===void 0&&(r=e(s),r===void 0&&i.forEachChild(s,t))};return t(n),r}function P(n,e){const r=[],t=s=>{const u=e(s);u!==null&&r.push(u),i.forEachChild(s,t)};return t(n),r}function S(n,e){return i.isCallExpression(n)&&i.isPropertyAccessExpression(n.expression)&&n.expression.name.text==="build"&&i.isIdentifier(n.expression.expression)&&n.expression.expression.text===e}function I(n){const e=n.parent;if(i.isVariableDeclaration(e)&&i.isIdentifier(e.name))return e.name.text}const k=()=>n=>n;function F(n){if(n!=null){if(n===!1)return!1;if(typeof n=="object"&&!Array.isArray(n))return n}}function V(n,e){return n===!1?!1:f(n)?e(n):void 0}function w(n,e){return f(n)?e(n):void 0}function N(n,e,r){const t=n[e];return f(t)?r(t):void 0}import{parseObjectLiteral as B,evaluateExpression as R,findVariableValue as D,findObjectDeclaration as L,evaluatePropertyAccess as U,resolveTemplateLiteral as G}from"./astExpressionEvaluator.js";export{_ as asBoolean,m as asNumber,F as asObjectOrFalse,y as asString,b as asStringArray,A as asStringUnion,h as captureExtraProperties,P as collectFromAst,R as evaluateExpression,U as evaluatePropertyAccess,N as extractSubConfig,I as extractVariableName,E as findFirstInAst,L as findObjectDeclaration,D as findVariableValue,O as isAppGetAppCall,a as isCallRef,d as isExpressionRef,S as isFactoryBuildCall,C as isFactoryMethodCall,x as isIdentifierRef,j as isNamedProperty,f as isParsedObject,o as isPlainObject,g as omitUndefined,V as parseBooleanOrConfig,B as parseObjectLiteral,w as parseOptionalConfig,p as parsedValueToSourceText,G as resolveTemplateLiteral,k as typed};
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Read-only AST helpers that resolve compute→database/storage connections
3
+ * and infer them from environment variables. Split out of
4
+ * astComputeParserHelpers.ts to keep both files within the 400-line budget.
5
+ * Write paths live in src/codemod/. Do not add mutation helpers here.
6
+ */
7
+ import { type ParsedValue } from "./astCommonParser.js";
8
+ import type { ComputeResourcePlan, ApplicationResourcePlan } from "../schemas/resourceSchemas.js";
9
+ import type { ParsedDatabaseResource } from "./astDatabaseParser.js";
10
+ import type { ParsedS3Resource } from "./astStorageParser.js";
11
+ /** Resolve connected database names from AST connection references */
12
+ export declare function resolveConnectedDatabaseNames(connections: ParsedValue, databaseResources: ParsedDatabaseResource[]): string[];
13
+ /** Resolve connected storage names from AST connection references */
14
+ export declare function resolveConnectedStorageNames(connections: ParsedValue, s3Resources: ParsedS3Resource[]): string[];
15
+ /** Infer database connections from environment variables in ECS containers */
16
+ export declare function inferDatabaseConnectionsFromEnv(computePlan: ComputeResourcePlan, servicesVal: ParsedValue, databasePlans: ApplicationResourcePlan["database"]): void;
17
+ /** Infer storage connections from environment variables in ECS containers */
18
+ export declare function inferStorageConnectionsFromEnv(computePlan: ComputeResourcePlan, servicesVal: ParsedValue, s3Plans: ApplicationResourcePlan["s3"]): void;
@@ -0,0 +1 @@
1
+ import{isIdentifierRef as s,isParsedObject as f}from"./astCommonParser.js";const c=10;function d(n,r){return Array.isArray(n)?n.filter(s).map(e=>r.find(t=>t.variableName===e.__identifier)).filter(e=>e!==void 0).map(e=>e.resourceName):[]}function _(n,r){return Array.isArray(n)?n.filter(s).map(e=>r.find(t=>t.variableName===e.__identifier)).filter(e=>e!==void 0).map(e=>e.resourceName):[]}function m(n,r,e){if(!Array.isArray(r)||r.length===0)return;const t=r[0];if(!f(t))return;const i=t.containers;if(!Array.isArray(i)||i.length===0)return;const o=i[0];if(!f(o)||!f(o.environment))return;const a=o.environment;(a.DATABASE_HOST||a.DATABASE_PORT||a.DATABASE_NAME)&&(n.needsConnection=!0,e.length>0&&(n.connectedDatabase??[]).length===0&&(n.connectedDatabase=[e[0].name]));for(let A=1;A<=c;A++)(a[`DATABASE_HOST_${A}`]||a[`DATABASE_PORT_${A}`]||a[`DATABASE_NAME_${A}`])&&(n.needsConnection=!0)}function S(n,r,e){if(!Array.isArray(r)||r.length===0)return;const t=r[0];if(!f(t))return;const i=t.containers;if(!Array.isArray(i)||i.length===0)return;const o=i[0];if(!f(o)||!f(o.environment))return;o.environment.BUCKET_NAME&&e.length>0&&(n.connectedStorage??[]).length===0&&(n.connectedStorage=[e[0].name])}export{m as inferDatabaseConnectionsFromEnv,S as inferStorageConnectionsFromEnv,d as resolveConnectedDatabaseNames,_ as resolveConnectedStorageNames};
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Read-only AST parser for the compute section of infrastructure.ts (ECS,
3
+ * Lambda, EC2). Used by fjall list and by the deploy-worker's
4
+ * convertToResourcePlan. Write paths live in src/codemod/. Do not add
5
+ * mutation helpers here.
6
+ */
1
7
  import * as ts from "typescript";
2
8
  import { type ParsedObject } from "./astCommonParser.js";
3
9
  import { type ApplicationResourcePlan } from "../schemas/resourceSchemas.js";