@fjall/generator 13.1.0 → 14.0.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.
- package/dist/.build-source-hash +26 -23
- package/dist/.minified +1 -1
- package/dist/src/codemod/drift/detect.js +1 -1
- package/dist/src/codemod/drift/snapshot.d.ts +12 -0
- package/dist/src/codemod/drift/snapshot.js +1 -1
- package/dist/src/codemod/edits/addResource/propertyBuilder.d.ts +32 -2
- package/dist/src/codemod/edits/addResource/propertyBuilder.js +1 -1
- package/dist/src/codemod/edits/addResource.js +1 -1
- package/dist/src/codemod/edits/connectResourceToCompute.js +1 -1
- package/dist/src/codemod/edits/modifyResource.js +1 -1
- package/dist/src/codemod/edits/resourceStatementLocator.d.ts +82 -0
- package/dist/src/codemod/edits/resourceStatementLocator.js +1 -0
- package/dist/src/codemod/edits/siblingBindingResolution.d.ts +22 -0
- package/dist/src/codemod/edits/siblingBindingResolution.js +1 -0
- package/dist/src/codemod/emitProjection.d.ts +28 -7
- package/dist/src/codemod/emitProjection.js +1 -1
- package/dist/src/codemod/llmFallback/gateFallbackOutput.js +1 -1
- package/dist/src/codemod/registry.d.ts +57 -9
- package/dist/src/codemod/registry.js +1 -1
- package/dist/src/codemod/semanticIndex/locateByShape.d.ts +11 -4
- package/dist/src/codemod/semanticIndex/locateByShape.js +1 -1
- package/dist/src/codemod/validationGate/gates/projection.d.ts +2 -0
- package/dist/src/codemod/validationGate/gates/projection.js +1 -0
- package/dist/src/codemod/validationGate/index.d.ts +1 -0
- package/dist/src/codemod/validationGate/index.js +1 -1
- package/dist/src/codemod/validationGate/types.d.ts +1 -1
- package/dist/src/generation/generatePatternCode.js +15 -15
- package/dist/src/projection/index.d.ts +1 -1
- package/dist/src/projection/project.js +1 -1
- package/dist/src/projection/tables.d.ts +9 -8
- package/dist/src/projection/tables.js +1 -1
- package/dist/src/projection/types.d.ts +41 -2
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/package.json +2 -2
package/dist/.build-source-hash
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"package.json",
|
|
10
10
|
"tsconfig.json"
|
|
11
11
|
],
|
|
12
|
-
"hash": "
|
|
12
|
+
"hash": "fe228542c5effce565f86ec415ca4d58d80acec5ad591fe00d8609a9680acb88",
|
|
13
13
|
"files": {
|
|
14
14
|
"src/ast/astTestHelpers.ts": "026cac849eb88bdb",
|
|
15
15
|
"src/ast/domain/astDomainParser.ts": "940ce5742507477d",
|
|
@@ -36,38 +36,40 @@
|
|
|
36
36
|
"src/ast/parsers/resources/astStorageParser.ts": "309bc3257f46cfdf",
|
|
37
37
|
"src/aws/regions.ts": "a028bcb92b0e41d9",
|
|
38
38
|
"src/codemod/_internal.ts": "e865b7172fcc457b",
|
|
39
|
-
"src/codemod/drift/detect.ts": "
|
|
39
|
+
"src/codemod/drift/detect.ts": "05f17c36c25a76ad",
|
|
40
40
|
"src/codemod/drift/index.ts": "e87e1ced35eefa44",
|
|
41
41
|
"src/codemod/drift/merge.ts": "29093929befa9abd",
|
|
42
|
-
"src/codemod/drift/snapshot.ts": "
|
|
42
|
+
"src/codemod/drift/snapshot.ts": "e389b8dbc41f6dc3",
|
|
43
43
|
"src/codemod/drift/types.ts": "7f1d7899e420e4d7",
|
|
44
|
-
"src/codemod/edits/addResource.ts": "
|
|
44
|
+
"src/codemod/edits/addResource.ts": "7d0fb772913f64c7",
|
|
45
45
|
"src/codemod/edits/addResource/appBinding.ts": "3553fdb30fe06335",
|
|
46
46
|
"src/codemod/edits/addResource/bodyIndex.ts": "3e179eac10d7bcf4",
|
|
47
|
-
"src/codemod/edits/addResource/propertyBuilder.ts": "
|
|
47
|
+
"src/codemod/edits/addResource/propertyBuilder.ts": "3152f13c4a0f600d",
|
|
48
48
|
"src/codemod/edits/appendAccountToStage.ts": "1796d909fa3ef79d",
|
|
49
49
|
"src/codemod/edits/computeServiceLocator.ts": "7f86483d9a35e053",
|
|
50
|
-
"src/codemod/edits/connectResourceToCompute.ts": "
|
|
50
|
+
"src/codemod/edits/connectResourceToCompute.ts": "ab704b6e75a7f173",
|
|
51
51
|
"src/codemod/edits/controlFlowPolicy.ts": "e32bbe2894f76c65",
|
|
52
52
|
"src/codemod/edits/crossPlanConnection.ts": "54a4ecb7b3368160",
|
|
53
53
|
"src/codemod/edits/driftPolicy.ts": "5d9b7bb3505f987d",
|
|
54
54
|
"src/codemod/edits/ensureImports.ts": "3ca0b6d446c4333c",
|
|
55
55
|
"src/codemod/edits/findInsertionPosition.ts": "20cd34fdcf781017",
|
|
56
56
|
"src/codemod/edits/index.ts": "bea5ed7c3983342b",
|
|
57
|
-
"src/codemod/edits/modifyResource.ts": "
|
|
57
|
+
"src/codemod/edits/modifyResource.ts": "a9882dc62dacb11e",
|
|
58
58
|
"src/codemod/edits/modifyResource/literalConversion.ts": "31295cccd59131b7",
|
|
59
59
|
"src/codemod/edits/moduleConstResolver.ts": "85a8597427849a80",
|
|
60
60
|
"src/codemod/edits/objectGraph.ts": "5efc4181547237f8",
|
|
61
61
|
"src/codemod/edits/removeResource.ts": "6af70ee482fabc06",
|
|
62
62
|
"src/codemod/edits/removeResource/commentHeuristic.ts": "90b6ce7ba5aa2a48",
|
|
63
63
|
"src/codemod/edits/removeResource/importPruning.ts": "f22783108b40f6cb",
|
|
64
|
+
"src/codemod/edits/resourceStatementLocator.ts": "e3094282860c764f",
|
|
64
65
|
"src/codemod/edits/secretsProvability.ts": "d723283918e31efd",
|
|
65
66
|
"src/codemod/edits/setContainerSecrets.ts": "24478c4205e79cbd",
|
|
67
|
+
"src/codemod/edits/siblingBindingResolution.ts": "7ed8938cfff4b38d",
|
|
66
68
|
"src/codemod/edits/unmanagedShapeErrors.ts": "47a2644913c8e619",
|
|
67
69
|
"src/codemod/edits/vpcPeer.ts": "0bcf90c2e6d16ca4",
|
|
68
70
|
"src/codemod/edits/vpcPeerAccepter.ts": "c9eace933e9e2345",
|
|
69
|
-
"src/codemod/emitGuard.ts": "
|
|
70
|
-
"src/codemod/emitProjection.ts": "
|
|
71
|
+
"src/codemod/emitGuard.ts": "c04655a3cbfea38b",
|
|
72
|
+
"src/codemod/emitProjection.ts": "26909ef16e498ac2",
|
|
71
73
|
"src/codemod/fileRewriter/builders.ts": "46a0d43240ff0818",
|
|
72
74
|
"src/codemod/fileRewriter/index.ts": "fd715b41176a7999",
|
|
73
75
|
"src/codemod/fileRewriter/locateByRange.ts": "889ee6256201c1fe",
|
|
@@ -80,7 +82,7 @@
|
|
|
80
82
|
"src/codemod/llmFallback/claudeTier.ts": "ace3e3baa51383c9",
|
|
81
83
|
"src/codemod/llmFallback/egressGate.ts": "1b9076a5c51508fc",
|
|
82
84
|
"src/codemod/llmFallback/egressGate.types.ts": "e30947f12ee546ff",
|
|
83
|
-
"src/codemod/llmFallback/gateFallbackOutput.ts": "
|
|
85
|
+
"src/codemod/llmFallback/gateFallbackOutput.ts": "c630f3f0215ef077",
|
|
84
86
|
"src/codemod/llmFallback/index.ts": "d32779fa95df6b94",
|
|
85
87
|
"src/codemod/llmFallback/morphTier.ts": "adcc1cf280f9a65d",
|
|
86
88
|
"src/codemod/llmFallback/prompt.ts": "60e8f4ab434bf9ec",
|
|
@@ -90,12 +92,12 @@
|
|
|
90
92
|
"src/codemod/llmFallback/telemetryEvents.ts": "827282cb185eea6c",
|
|
91
93
|
"src/codemod/llmFallback/tierRunner.ts": "a26094accd78cf15",
|
|
92
94
|
"src/codemod/llmFallback/types.ts": "0b528ccbab7d48b8",
|
|
93
|
-
"src/codemod/registry.ts": "
|
|
95
|
+
"src/codemod/registry.ts": "4b55358c3db17cea",
|
|
94
96
|
"src/codemod/semanticIndex/classifyControlFlow.ts": "ed96215d91a3cae3",
|
|
95
97
|
"src/codemod/semanticIndex/findReferences.ts": "96aea37418d1e91a",
|
|
96
98
|
"src/codemod/semanticIndex/index.ts": "cfcd212d34ab20fb",
|
|
97
99
|
"src/codemod/semanticIndex/listImports.ts": "1e5fba6e34a17dab",
|
|
98
|
-
"src/codemod/semanticIndex/locateByShape.ts": "
|
|
100
|
+
"src/codemod/semanticIndex/locateByShape.ts": "017f2b271862e894",
|
|
99
101
|
"src/codemod/semanticIndex/projectCache.ts": "dfd9b265c9d233c9",
|
|
100
102
|
"src/codemod/semanticIndex/resolveConstructByLiteralProperty.ts": "2d013a330af15c5c",
|
|
101
103
|
"src/codemod/telemetry/errorKinds.ts": "66c736abfa8b3a67",
|
|
@@ -104,9 +106,10 @@
|
|
|
104
106
|
"src/codemod/validationGate/gates/drift.ts": "bd603a216fbb91a9",
|
|
105
107
|
"src/codemod/validationGate/gates/locate.ts": "2c186c32edbb97ce",
|
|
106
108
|
"src/codemod/validationGate/gates/parse.ts": "5433c5c8ffa35324",
|
|
109
|
+
"src/codemod/validationGate/gates/projection.ts": "a29d627ce75bc6c0",
|
|
107
110
|
"src/codemod/validationGate/gates/schema.ts": "7ed5acaec0620a46",
|
|
108
|
-
"src/codemod/validationGate/index.ts": "
|
|
109
|
-
"src/codemod/validationGate/types.ts": "
|
|
111
|
+
"src/codemod/validationGate/index.ts": "bbe1f460330a11cf",
|
|
112
|
+
"src/codemod/validationGate/types.ts": "4a1cfa054e3383d5",
|
|
110
113
|
"src/detection/index.ts": "b4ad9a935564cb3e",
|
|
111
114
|
"src/dns/bindParser.ts": "376d274bf9e4bf9f",
|
|
112
115
|
"src/dns/bindWriter.ts": "c296911ce5aef77c",
|
|
@@ -122,7 +125,7 @@
|
|
|
122
125
|
"src/generation/compute/lambda.ts": "4f5e31080941b83a",
|
|
123
126
|
"src/generation/compute/shared.ts": "3724d4bfe92cfcb7",
|
|
124
127
|
"src/generation/database.ts": "dd4a1540986ad350",
|
|
125
|
-
"src/generation/generatePatternCode.ts": "
|
|
128
|
+
"src/generation/generatePatternCode.ts": "ab752292dd72b676",
|
|
126
129
|
"src/generation/index.ts": "fd58a833e13bcf07",
|
|
127
130
|
"src/generation/infrastructure.ts": "6381d502f4733926",
|
|
128
131
|
"src/generation/messagingConnections.ts": "fef976a8261c6751",
|
|
@@ -143,10 +146,10 @@
|
|
|
143
146
|
"src/presets/storagePresets.ts": "5df2d4d7d21a66d8",
|
|
144
147
|
"src/presets/tierPresets.ts": "c0148771bffbef9b",
|
|
145
148
|
"src/presets/tierTypes.ts": "6526373876daacf0",
|
|
146
|
-
"src/projection/index.ts": "
|
|
147
|
-
"src/projection/project.ts": "
|
|
148
|
-
"src/projection/tables.ts": "
|
|
149
|
-
"src/projection/types.ts": "
|
|
149
|
+
"src/projection/index.ts": "85d17974561fb3d9",
|
|
150
|
+
"src/projection/project.ts": "5613c875194dede9",
|
|
151
|
+
"src/projection/tables.ts": "21786d551ca8cfd0",
|
|
152
|
+
"src/projection/types.ts": "588ef43b70ab3127",
|
|
150
153
|
"src/schemas/alarmSchemas.ts": "a6f6ac07b2a102de",
|
|
151
154
|
"src/schemas/applicationSchemas.ts": "d85771a4607cf2da",
|
|
152
155
|
"src/schemas/baseSchemas.ts": "93d9bd1c0adfcaa0",
|
|
@@ -171,11 +174,11 @@
|
|
|
171
174
|
"src/validation/patterns.ts": "f9629eafdad7ac3e",
|
|
172
175
|
"src/validation/validationMessages.ts": "c727ade4690274f4",
|
|
173
176
|
"src/validation/validationPatterns.ts": "865f3d688975b7c8",
|
|
174
|
-
"src/version.ts": "
|
|
177
|
+
"src/version.ts": "518440098d418cfe",
|
|
175
178
|
"../scripts/minify-dist.mjs": "6b2e4b0df8aec601",
|
|
176
|
-
"package.json": "
|
|
179
|
+
"package.json": "da98ce052c859b1e",
|
|
177
180
|
"tsconfig.json": "1929cf3f99fe9b1e"
|
|
178
181
|
},
|
|
179
|
-
"outputHash": "
|
|
180
|
-
"outputFileCount":
|
|
182
|
+
"outputHash": "6dfec0cd60c145edc1aa2657cabb603af9cd222546e37f6e82091457d0d3dc42",
|
|
183
|
+
"outputFileCount": 329
|
|
181
184
|
}
|
package/dist/.minified
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
164 files minified at 2026-08-17T02:04:02.655Z
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var h=Object.defineProperty;var c=(t,e)=>h(t,"name",{value:e,configurable:!0});import{failure as u,success as d}from"../../types/Result.js";import{listResources as b}from"../listResources.js";import{locateNamesFor as k}from"../registry.js";import{mergeProperties as N}from"./merge.js";import{snapshotProperties as g}from"./snapshot.js";function x(t,e,o){const r=b(t);if(!r.success)return u(r.error);const a=k(e.type,e.name);if(r.data.resources.find(s=>s.type===e.type&&a.includes(s.name))===void 0)return e.op==="add"?d({resource:{type:e.type,name:e.name},deltas:[],summary:"clean"}):u({kind:"ResourceNotFoundError",type:e.type,name:e.name,knownNames:r.data.resources.filter(s=>s.type===e.type).map(s=>s.name)});const n=g(t,e.type,e.name);if(!n.success)return u(n.error);const p={...n.data.properties},l={...e.properties},f=o===void 0?void 0:{...o.properties},m=N(f,p,l),y=C(m.deltas,f!==void 0);return d({resource:{type:e.type,name:e.name},deltas:m.deltas,summary:y})}c(x,"detectDrift");function C(t,e){if(t.length===0)return"clean";let o=!1,r=!1,a=!1,i=!1;for(const n of t)switch(n.verdict){case"conflict":o=!0;break;case"compatible":r=!0;break;case"clean":a=!0;break;case"no-op":i=!0;break}return o?"drifted-conflict":r?"drifted-compatible":i&&!a?"no-op":"clean"}c(C,"summariseDeltas");export{x as detectDrift};
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import { type Result } from "../../types/Result.js";
|
|
2
|
+
import { type NodeShapeLike, type ObjectExpressionNodeLike } from "../edits/modifyResource/literalConversion.js";
|
|
2
3
|
import type { CodemodError, ResourceName, StatementType } from "../types.js";
|
|
3
4
|
import type { ResourceSnapshot } from "./types.js";
|
|
4
5
|
export declare function snapshotProperties(content: string, type: StatementType, name: ResourceName): Result<ResourceSnapshot, CodemodError>;
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the config `ObjectExpression` for a located statement by matching
|
|
8
|
+
* the recast/babel span of the factory call's name `StringLiteral` against
|
|
9
|
+
* the semantic-index anchor (`start`/`length` on the name token — ts-morph
|
|
10
|
+
* and babel offsets agree, the same contract `gates/classify.ts` relies on).
|
|
11
|
+
* Shared with the projection gate, which inspects the same object.
|
|
12
|
+
*/
|
|
13
|
+
export declare function findConfigObject(body: NodeShapeLike[], target: {
|
|
14
|
+
start: number;
|
|
15
|
+
length: number;
|
|
16
|
+
}): ObjectExpressionNodeLike | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var h=Object.defineProperty;var u=(r,e)=>h(r,"name",{value:e,configurable:!0});import{failure as f,success as b}from"../../types/Result.js";import{extractProgramBody as g}from"../_internal.js";import{astToLiteral as E,isNodeShape as l,NON_LITERAL as x,readKeyName as k}from"../edits/modifyResource/literalConversion.js";import{visit as N}from"../edits/objectGraph.js";import{parse as O}from"../fileRewriter/index.js";import{listResources as S}from"../listResources.js";import{locateNamesFor as j,STATEMENT_REGISTRY as P}from"../registry.js";function Q(r,e,o){const n=S(r);if(!n.success)return f(n.error);const d=j(e,o),s=n.data.resources.find(t=>t.type===e&&d.includes(t.name));if(s===void 0)return f({kind:"ResourceNotFoundError",type:e,name:o,knownNames:n.data.resources.filter(t=>t.type===e).map(t=>t.name)});const i=O(r,s.filePath);if(!i.success)return f(i.error);const a=g(i.data);if(a===void 0)return f({kind:"SemanticQueryError",reason:"recast File is missing program.body"});const c=T(a,s);if(c===void 0)return f({kind:"SemanticQueryError",reason:"Unable to resolve config ObjectExpression for the located resource."});const y=new Set(Object.keys(P[e].schemaFragment.shape)),m={};for(const t of c.properties){if(t.type!=="Property"&&t.type!=="ObjectProperty"||t.shorthand===!0||t.computed===!0)continue;const p=k(t.key);p===void 0||!y.has(p)||t.value!==void 0&&(m[p]=v(t.value,r))}return b({type:e,name:o,properties:m,schemaVersion:1})}u(Q,"snapshotProperties");function T(r,e){const o=e.start+e.length;let n;const d=u(s=>{if(n!==void 0||s.type!=="CallExpression")return;const i=s.arguments;if(!Array.isArray(i)||i.length<2)return;const a=i[0];if(!l(a)||a.type!=="StringLiteral"||a.start!==e.start||a.end!==o)return;const c=i[1];l(c)&&c.type==="ObjectExpression"&&(n=c)},"visitor");for(const s of r)if(N(s,d),n!==void 0)break;return n}u(T,"findConfigObject");function v(r,e){const o=E(r);return o!==x?o:R(r,e)}u(v,"extractPropertyValue");function R(r,e){const o=typeof r.start=="number"?r.start:void 0,n=typeof r.end=="number"?r.end:void 0;return{kind:"expression",text:o!==void 0&&n!==void 0&&o<n?e.slice(o,n):""}}u(R,"toExpressionValue");export{T as findConfigObject,Q as snapshotProperties};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type namedTypes as n } from "ast-types";
|
|
2
2
|
import { type Result } from "../../../types/Result.js";
|
|
3
3
|
import { type ObjectPropertyInput, type QuoteStyle } from "../../fileRewriter/index.js";
|
|
4
|
-
import type {
|
|
4
|
+
import type { EmittedProp } from "../../emitProjection.js";
|
|
5
5
|
import type { InvalidPropertyError } from "../../types.js";
|
|
6
6
|
/**
|
|
7
7
|
* Build the emitted object literal from CONSTRUCT-vocabulary props.
|
|
@@ -9,6 +9,36 @@ import type { InvalidPropertyError } from "../../types.js";
|
|
|
9
9
|
* The caller has already run the plan fragment through the projection, so
|
|
10
10
|
* every key here is one a construct reads, in emission order.
|
|
11
11
|
*/
|
|
12
|
-
export declare function buildPropertyInputs(properties: ReadonlyArray<
|
|
12
|
+
export declare function buildPropertyInputs(properties: ReadonlyArray<EmittedProp>, quoteStyle: QuoteStyle): Result<ObjectPropertyInput[], InvalidPropertyError>;
|
|
13
|
+
/**
|
|
14
|
+
* Names that match {@link IDENTIFIER_SOURCE_PATTERN} lexically but can never
|
|
15
|
+
* be an identifier in the emitted file: ES reserved words, the strict-mode
|
|
16
|
+
* future-reserved words, the contextual keywords (`await`/`yield`/`let`/
|
|
17
|
+
* `static` — reserved only in some contexts, so failing closed is the only
|
|
18
|
+
* safe reading), and the strict-mode restricted binding names
|
|
19
|
+
* (`eval`/`arguments` — modules are always strict). This is reachable from a
|
|
20
|
+
* plain resource name: `ResourceNameSchema` accepts `"Import"`, and
|
|
21
|
+
* `toVariableName("Import")` derives `import` — splicing or `const`-declaring
|
|
22
|
+
* it writes a file that does not parse, with a green exit code.
|
|
23
|
+
*
|
|
24
|
+
* Shared with the locator's wrap-path derivation
|
|
25
|
+
* (`resourceStatementLocator.ts § planBinding`) — the two sites judge the
|
|
26
|
+
* same physical name and must refuse the same set.
|
|
27
|
+
*/
|
|
28
|
+
export declare const RESERVED_IDENTIFIER_NAMES: ReadonlySet<string>;
|
|
29
|
+
/**
|
|
30
|
+
* Resolve one emitted construct prop to its AST value node.
|
|
31
|
+
*
|
|
32
|
+
* An `expression` prop carries the NAME of a live binding the projection
|
|
33
|
+
* resolved, so it is spliced as a bare identifier. General expression source
|
|
34
|
+
* (`app.getVpc()`, a member read) is a deliberate limitation, not an
|
|
35
|
+
* oversight: no rule produces one yet, and splicing source text this module
|
|
36
|
+
* cannot parse is how a mangled file gets written with a green exit code.
|
|
37
|
+
* Refused by name so a future rule that returns one surfaces as a property
|
|
38
|
+
* complaint here rather than a corrupt infrastructure.ts. Reserved words are
|
|
39
|
+
* refused for the same reason: they pass the lexical pattern but the file
|
|
40
|
+
* they land in does not parse.
|
|
41
|
+
*/
|
|
42
|
+
export declare function buildEmittedValue(prop: EmittedProp, quoteStyle: QuoteStyle): Result<n.Property["value"], InvalidPropertyError>;
|
|
13
43
|
export declare function toAstValue(value: unknown, quoteStyle: QuoteStyle): n.Property["value"] | undefined;
|
|
14
44
|
export declare function makeStringLiteral(value: string, quote: QuoteStyle): n.StringLiteral;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var d=Object.defineProperty;var s=(e,t)=>d(e,"name",{value:t,configurable:!0});import{builders as o}from"ast-types";import{failure as a,success as c}from"../../../types/Result.js";import{buildObjectProperty as l}from"../../fileRewriter/index.js";function w(e,t){const r=[];for(const i of e){const n=m(i,t);if(!n.success)return a(n.error);r.push({key:i.key,value:n.data})}return c(r)}s(w,"buildPropertyInputs");const p=/^[A-Za-z_$][A-Za-z0-9_$]*$/,y=new Set(["await","break","case","catch","class","const","continue","debugger","default","delete","do","else","enum","export","extends","false","finally","for","function","if","import","in","instanceof","new","null","return","super","switch","this","throw","true","try","typeof","var","void","while","with","yield","implements","interface","package","private","protected","public","let","static","eval","arguments"]);function m(e,t){if(e.kind==="expression")return p.test(e.source)?y.has(e.source)?a({kind:"InvalidPropertyError",property:e.key,reason:`\`${e.key}\` resolved to \`${e.source}\`, which is a JavaScript reserved word \u2014 no binding can carry that name, so splicing it would write a file that does not parse.`}):c(o.identifier(e.source)):a({kind:"InvalidPropertyError",property:e.key,reason:`\`${e.key}\` resolved to the expression \`${e.source}\`, which is not a bare identifier; this emitter only splices the name of a live binding.`});const r=u(e.value,t);return r===void 0?a({kind:"InvalidPropertyError",property:e.key,reason:`Unsupported property value for "${e.key}" (accepts string/number/boolean/null/array/object of the same).`}):c(r)}s(m,"buildEmittedValue");function u(e,t){if(typeof e=="string")return b(e,t);if(typeof e=="number"&&Number.isFinite(e))return o.numericLiteral(e);if(typeof e=="boolean")return o.booleanLiteral(e);if(e===null)return o.nullLiteral();if(Array.isArray(e)){const r=[];for(const i of e){const n=u(i,t);if(n===void 0)return;r.push(n)}return o.arrayExpression(r)}if(typeof e=="object"&&e!==null){const r=[];for(const[i,n]of Object.entries(e)){const f=u(n,t);if(f===void 0)return;r.push(l(i,f,t))}return o.objectExpression(r)}}s(u,"toAstValue");function b(e,t){const r=t==="single"?"'":'"',i=t==="single"?e.replace(/\\/g,"\\\\").replace(/'/g,"\\'"):e.replace(/\\/g,"\\\\").replace(/"/g,'\\"'),n=`${r}${i}${r}`;return o.stringLiteral.from({value:e,extra:{rawValue:e,raw:n}})}s(b,"makeStringLiteral");export{y as RESERVED_IDENTIFIER_NAMES,m as buildEmittedValue,w as buildPropertyInputs,b as makeStringLiteral,u as toAstValue};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var M=Object.defineProperty;var u=(r,e)=>M(r,"name",{value:e,configurable:!0});import{failure as t,success as
|
|
1
|
+
var M=Object.defineProperty;var u=(r,e)=>M(r,"name",{value:e,configurable:!0});import{failure as t,success as R}from"../../types/Result.js";import{DEFAULT_FILE_PATH as C,computeLinesDelta as w,extractProgramBody as b,isRecord as x}from"../_internal.js";import{evaluateEmitGuard as N}from"../emitGuard.js";import{projectEmittedProperties as G}from"../emitProjection.js";import{appendSpecifier as Q,buildAppMethodWrappedStatement as O,buildFactoryStatement as U,buildImportDeclaration as W,detectQuoteStyle as _,parse as j,printFile as Y}from"../fileRewriter/index.js";import{STATEMENT_REGISTRY as q,constructIdFor as H}from"../registry.js";import{locateAllShapes as $,locateByShape as z}from"../semanticIndex/index.js";import{checkControlFlowPolicy as J}from"./controlFlowPolicy.js";import{driftGate as K,runPipeline as V,schemaGate as X}from"../validationGate/index.js";import{resolveAppBindingName as Z}from"./addResource/appBinding.js";import{buildUnmanagedDuplicateError as ee}from"./unmanagedShapeErrors.js";import{buildResourceLocations as re,indexBody as te,orderByEndPos as ae,resolveInsertIndex as ne}from"./addResource/bodyIndex.js";import{buildPropertyInputs as ie}from"./addResource/propertyBuilder.js";import{findInsertionPosition as oe}from"./findInsertionPosition.js";import{applyBinding as se}from"./resourceStatementLocator.js";import{createSiblingBindingResolution as ce}from"./siblingBindingResolution.js";const L="@fjall/components-infrastructure";function Fe(r,e,m={}){const p=e.filePath??C,n=j(r,p);if(!n.success)return t(n.error);const a=z(r,{type:e.type,name:e.name},p);if(!a.success)return a.error.kind==="TemplateLiteralNameError"?t(a.error):t({kind:"SemanticQueryError",reason:a.error.reason,cause:a.error.cause});if(a.data!==void 0){if(a.data.managed===!1)return t(ee(e.type,a.data.symbolName));const i=J({ast:n.data,target:a.data,resource:{type:e.type,name:e.name},op:"add"});if(i.refusal!==void 0)return t(i.refusal);const g=V([K],{content:r,plan:{type:e.type,name:e.name,properties:e.properties,op:"add"},baseline:m.baseline,policy:e.driftPolicy});return g.success?g.data.action==="skip"?R({content:r,linesChanged:{added:0,removed:0},skipped:!0}):t({kind:"DuplicateResourceError",type:e.type,name:e.name}):t(B(g.error))}const l=_(n.data),h=ce(e.type,()=>b(n.data)),f=G(e.type,e.properties,{resourceName:e.name,resolveBinding:h.resolveBinding});if("refusal"in f)return t(f.refusal);const y=ie(f.props,l);if(!y.success)return t(y.error);const o=b(n.data);if(o===void 0)return t({kind:"SemanticQueryError",reason:"recast File is missing program.body"});const s=q[e.type],I=N(s.emitGuard,e.properties);if(I!==void 0)return t(I);const S=X.run({content:r,plan:{type:e.type,name:e.name,properties:e.properties,op:"add"}});if(!S.success)return t(B(S.error));const P={factory:s.factoryIdentifier,name:H(e.type,e.name,e.properties),properties:y.data,quoteStyle:l};let E;if(s.emitWrapper!==void 0){const i=Z(o);if(i===void 0)return t({kind:"MissingAppInitError",type:e.type,appMethod:s.emitWrapper.appMethod});E=O({...P,appIdentifier:i,appMethod:s.emitWrapper.appMethod})}else E=U(P);const d=te(o,r),c=$(r,p);if(!c.success)return c.error.kind==="TemplateLiteralNameError"?t(c.error):t({kind:"SemanticQueryError",reason:c.error.reason,cause:c.error.cause});const F=re(d.anchors,c.data),T=ae([...d.appInitLocations,...F]),v=oe(d.importInfos,T,e.type,d.programEnd),A=ne(d.anchors,v);for(const i of h.takePendingWraps())se(o,i);o.splice(A,0,E),pe(o,s.factoryIdentifier,l);const k=Y(n.data,r),D=w(r,k);return R({content:k,linesChanged:D})}u(Fe,"addResource");function B(r){switch(r.kind){case"ParseError":case"TemplateLiteralNameError":case"DuplicateResourceError":case"InvalidPropertyError":case"SemanticQueryError":case"MissingAppInitError":case"DriftConflictError":case"ControlFlowClassifierError":return r;default:return{kind:"SemanticQueryError",reason:`Unexpected codemod error in validation-gate pipeline: ${r.kind}`}}}u(B,"narrowGateError");function pe(r,e,m){for(const n of r){if(n.type!=="ImportDeclaration")continue;const a=n.source;if(!(!x(a)||a.type!=="StringLiteral")&&a.value===L){Q(n,e);return}}const p=W([e],L,m);r.unshift(p)}u(pe,"ensureFactoryImport");export{Fe as addResource};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var H=Object.defineProperty;var u=(t,e)=>H(t,"name",{value:e,configurable:!0});import{builders as E}from"ast-types";import{CREDENTIAL_KEYS as U,DATABASE_ACCESSORS as C,DATABASE_ENV_VARS as b,DATABASE_SSL_VALUE as z}from"../../generation/database.js";import{MESSAGING_ENV_VARS as Y}from"../../generation/messagingConnections.js";import{STORAGE_ACCESSORS as Q,STORAGE_ENV_VARS as O}from"../../generation/storageConnections.js";import{connectionEnvSuffix as J,connectionKeyOrdinal as T,toVariableName as X}from"../../generation/common.js";import{failure as c,success as S}from"../../types/Result.js";import{DEFAULT_FILE_PATH as Z,computeLinesDelta as q,extractProgramBody as ee}from"../_internal.js";import{buildObjectProperty as D,detectQuoteStyle as ne,parse as te,printFile as re}from"../fileRewriter/index.js";import{FACTORY_IDENTIFIERS as P,STATEMENT_REGISTRY as oe}from"../registry.js";import{makeStringLiteral as _}from"./addResource/propertyBuilder.js";import{findLastPlainPropertyIndex as j,isArrayExpression as ie,locateContainer as ae,locateServiceByName as se}from"./computeServiceLocator.js";import{isNodeShape as f,readKeyName as M}from"./modifyResource/literalConversion.js";import{unwrapTsWrappers as I}from"./moduleConstResolver.js";import{objectAbsenceIsProvable as $,pushPropertyPreservingComma as ce,visit as L}from"./objectGraph.js";const v=Object.freeze({database:P.database,storage:P.storage});function x(t){const e=oe[t].emitWrapper?.appMethod;if(e===void 0)throw new Error(`No app method registered for statement type "${t}"`);return e}u(x,"requireAppMethod");const A=Object.freeze({database:x("database"),storage:x("storage")}),F=new Map([[A.database,0],[A.storage,1],[x("messaging"),2]]);function Me(t,e){const n=e.filePath??Z,{resourceType:o,resourceName:r}=e,i=[...new Set(e.serviceNames)];if(i.length===0)return c({kind:"UnsupportedConnectionShapeError",reason:"No target services were supplied."});const a=te(t,n);if(!a.success)return c(a.error);const s=ee(a.data);if(s===void 0)return c({kind:"UnsupportedConnectionShapeError",reason:"recast File is missing program.body"});const d=de(s,o,r);if(!d.success)return c(d.error);const{variableName:p}=d.data,l=[],y=[];for(const h of i){const k=fe(s,h,p,o);if(!k.success)return c(k.error);if(k.data==="already-connected"){l.push(h);continue}y.push(k.data)}const m=l.map(h=>`Service "${h}" already lists "${p}" in its \`connections\` array \u2014 left untouched.`);for(const h of y)h.container===void 0&&m.push(`Service "${h.serviceName}" has no \`containers\` array \u2014 wired \`connections\` only, without env/secret entries (the generator lane emits the same shape for container-less services).`);if(y.length===0)return S({content:t,linesChanged:{added:0,removed:0},variableName:p,wiredServices:[],skipped:!0,warnings:m});const g=ne(a.data),G=Se(s);pe(s,d.data);for(const h of y)he(h,p,o,g,G);const w=re(a.data,t);return S({content:w,linesChanged:q(t,w),variableName:p,wiredServices:y.map(h=>h.serviceName),skipped:!1,warnings:m})}u(Me,"connectResourceToCompute");function de(t,e,n){const o=v[e],r=[];for(let p=0;p<t.length;p++){const l=t[p];if(l===void 0)continue;let y=!1;L(l,m=>{m.type==="CallExpression"&&R(m,o,n)&&(y=!0)}),y&&r.push({statementIndex:p})}if(r.length===0)return c({kind:"ResourceStatementNotFoundError",resourceType:e,resourceName:n});if(r.length>1)return c({kind:"AmbiguousResourceStatementError",resourceType:e,resourceName:n,count:r.length});const i=r[0];if(i===void 0)return c({kind:"ResourceStatementNotFoundError",resourceType:e,resourceName:n});const a=t[i.statementIndex];if(a===void 0)return c({kind:"ResourceStatementNotFoundError",resourceType:e,resourceName:n});if(a.type==="VariableDeclaration"){const p=a.declarations;if(!Array.isArray(p)||p.length!==1)return c({kind:"UnsupportedConnectionShapeError",reason:`The statement declaring "${n}" carries multiple declarators \u2014 the binding cannot be identified.`});const l=p[0].id;if(!f(l)||l.type!=="Identifier")return c({kind:"UnsupportedConnectionShapeError",reason:`The statement declaring "${n}" binds a pattern, not an identifier.`});const y=l.name;if(typeof y!="string")return c({kind:"UnsupportedConnectionShapeError",reason:`The binding for "${n}" has no readable name.`});const m=p[0].init;return!f(m)||!B(m,e,n)?c({kind:"UnsupportedConnectionShapeError",reason:`The binding for "${n}" is not a direct \`app.${A[e]}(${v[e]}.build(...))\` call \u2014 the bound value is not the construct \`connections\` needs.`}):S({variableName:y})}if(a.type!=="ExpressionStatement")return c({kind:"UnsupportedConnectionShapeError",reason:`The statement containing "${n}" is a ${a.type}, which cannot be bound to a const.`});const s=a.expression;if(!f(s)||s.type!=="CallExpression")return c({kind:"UnsupportedConnectionShapeError",reason:`The statement containing "${n}" is not an app-method call \u2014 there is no construct value to bind.`});if(R(s,v[e],n))return c({kind:"UnsupportedConnectionShapeError",reason:`"${n}" is a bare factory call not wrapped in an app method \u2014 there is no construct value to bind.`});if(!B(s,e,n))return c({kind:"UnsupportedConnectionShapeError",reason:`The statement containing "${n}" is not a direct \`app.${A[e]}(...)\` call \u2014 binding it would wire a value \`connections\` cannot use.`});const d=X(n);return ue(t,d)?c({kind:"VariableNameConflictError",variableName:d}):S({variableName:d,wrap:{statementIndex:i.statementIndex,expression:s}})}u(de,"planBinding");function pe(t,e){if(e.wrap===void 0)return;const{statementIndex:n,expression:o}=e.wrap,r=t[n],i=E.variableDeclaration("const",[E.variableDeclarator(E.identifier(e.variableName),o)]),a=r?.comments;a!==void 0&&(i.comments=a),t[n]=i}u(pe,"applyBinding");function R(t,e,n){const o=t.callee;if(!f(o)||o.type!=="MemberExpression"||o.computed===!0)return!1;const r=o.object,i=o.property;if(!f(r)||r.type!=="Identifier"||r.name!==e||!f(i)||i.type!=="Identifier"||i.name!=="build")return!1;const a=t.arguments;if(!Array.isArray(a))return!1;const s=a[0];return!f(s)||s.type!=="StringLiteral"&&s.type!=="Literal"?!1:s.value===n}u(R,"isFactoryBuildOf");function N(t){if(t.type!=="ExportNamedDeclaration"&&t.type!=="ExportDefaultDeclaration")return t;const e=t.declaration;return f(e)?e:void 0}u(N,"unwrapExportDeclaration");function V(t){const e=I(t);if(e.type!=="CallExpression")return;const n=e.callee;if(!f(n)||n.type!=="MemberExpression"||n.computed===!0)return;const o=n.property;if(!f(o)||o.type!=="Identifier")return;const r=o.name;return typeof r=="string"?r:void 0}u(V,"appMethodNameOf");function B(t,e,n){const o=I(t);if(V(o)!==A[e])return!1;const r=o.arguments;if(!Array.isArray(r))return!1;const i=r[0];return f(i)?R(I(i),v[e],n):!1}u(B,"isAppMethodWrap");function ue(t,e){for(const n of t){const o=N(n);if(o!==void 0){if(o.type==="ImportDeclaration"){const r=o.specifiers;if(!Array.isArray(r))continue;for(const i of r){const a=i.local;if(f(a)&&a.name===e)return!0}continue}if(o.type==="VariableDeclaration"){const r=o.declarations;if(!Array.isArray(r))continue;for(const i of r){if(!f(i))continue;const a=i.id;if(!f(a))continue;let s=!1;if(L(a,d=>{d.type==="Identifier"&&d.name===e&&(s=!0)}),s)return!0}continue}if(o.type==="FunctionDeclaration"||o.type==="ClassDeclaration"){const r=o.id;if(f(r)&&r.name===e)return!0}}}return!1}u(ue,"moduleScopeDeclares");function fe(t,e,n,o){const r=se(t,e);if(!r.success){const m=r.error;return m.kind==="AmbiguousService"?c({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:`${String(m.count)} services share the name "${e}" across ComputeFactory.build calls \u2014 the edit cannot be proven to target the right one.`}):c({kind:"ConnectServiceNotFoundError",serviceName:e,knownServices:m.knownServices})}const i=r.data,a=ae(i,0);let s;if(a.success)s=a.data;else switch(a.error.kind){case"ContainerNotObjectLiteral":return c({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:"The first container is not an object literal."});case"ContainersNotStaticArray":return c({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:"`containers` is not a static array literal, so the container to wire cannot be located."});case"NoContainersArray":if(!$(i,"containers"))return c({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:"Service carries a spread, shorthand or computed key that could supply `containers` invisibly, so an absent property cannot be proven."});break;case"ContainerIndexOutOfRange":break}const d=le(i,e,n);if(!d.success)return c(d.error);if(d.data.alreadyConnected)return S("already-connected");let p,l,y="";if(s!==void 0){const m=W(s,"environment",e);if(!m.success)return c(m.error);const g=W(s,"secretsImport",e);if(!g.success)return c(g.error);p=m.data,l=g.data,y=me(o,[...m.data.keys,...g.data.keys])}return S({serviceName:e,service:i,container:s,environment:p,secretsImport:l,suffix:y,connectionsArray:d.data.array})}u(fe,"planService");function le(t,e,n){const o=j(t,"connections");if(o===-1)return $(t,"connections")?S({array:void 0,alreadyConnected:!1}):c({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:"Service carries a spread, shorthand or computed key that could supply `connections` invisibly, so an absent property cannot be proven."});const r=t.properties[o]?.value;if(!ie(r))return c({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:"`connections` is not an array literal."});for(const i of r.elements)if(f(i)){if(i.type==="Identifier"){if(i.name===n)return S({array:r,alreadyConnected:!0});continue}return c({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:`\`connections\` contains a ${i.type}, so "${n}" cannot be proven absent from it.`})}return S({array:r,alreadyConnected:!1})}u(le,"inspectConnections");function W(t,e,n){const o=j(t,e);if(o===-1)return $(t,e)?S({obj:void 0,keys:[]}):c({kind:"UnsupportedConnectionShapeError",serviceName:n,reason:`The first container carries a spread, shorthand or computed key that could supply \`${e}\` invisibly, so an absent property cannot be proven.`});const r=t.properties[o]?.value;if(!f(r)||r.type!=="ObjectExpression")return c({kind:"UnsupportedConnectionShapeError",serviceName:n,reason:`\`${e}\` is not an object literal.`});const i=r,a=[];for(const s of i.properties){if(s.type==="SpreadElement"||s.type==="SpreadProperty")return c({kind:"UnsupportedConnectionShapeError",serviceName:n,reason:`\`${e}\` contains a spread, so existing connection keys cannot be enumerated to derive the next suffix.`});if(s.type!=="Property"&&s.type!=="ObjectProperty")continue;if(s.computed===!0)return c({kind:"UnsupportedConnectionShapeError",serviceName:n,reason:`\`${e}\` contains a computed key.`});const d=M(s.key);d!==void 0&&a.push(d)}return S({obj:i,keys:a})}u(W,"collectWiringTarget");function me(t,e){const n=Object.values(t==="database"?b:O),o=new Set;for(const r of e)for(const i of n){const a=T(r,i);a!==void 0&&o.add(a)}return J(o.size===0?0:Math.max(...o))}u(me,"nextConnectionSuffix");function ye(t,e,n,o){const r=u((s,d,p=[])=>E.callExpression(E.memberExpression(s,E.identifier(d),!1),p),"call"),i=u(()=>E.identifier(e),"variable");if(t==="storage")return[{key:`${O.NAME}${n}`,value:r(i(),Q.BUCKET_NAME),target:"environment"}];const a=u(s=>r(r(i(),C.CREDENTIALS),C.IMPORT,[_(s,o)]),"credential");return[{key:`${b.HOST}${n}`,value:r(i(),C.HOST),target:"environment"},{key:`${b.PORT}${n}`,value:r(i(),C.PORT),target:"environment"},{key:`${b.NAME}${n}`,value:r(i(),C.NAME),target:"environment"},{key:`${b.SSL}${n}`,value:_(z,o),target:"environment"},{key:`${b.USERNAME}${n}`,value:a(U.USERNAME),target:"secretsImport"},{key:`${b.PASSWORD}${n}`,value:a(U.PASSWORD),target:"secretsImport"}]}u(ye,"buildWiringEntries");function he(t,e,n,o,r){if(t.connectionsArray!==void 0){const d=Ee(t.connectionsArray,n,r);t.connectionsArray.elements.splice(d,0,E.identifier(e))}else K(t.service,"connections",E.arrayExpression([E.identifier(e)]),o);const i=t.container;if(i===void 0)return;const a=ye(n,e,t.suffix,o),s=[{key:"environment",state:t.environment},{key:"secretsImport",state:t.secretsImport}];for(const{key:d,state:p}of s){const l=a.filter(y=>y.target===d);l.length!==0&&Ae(i,d,p,l,o)}}u(he,"applyServiceWiring");function Ee(t,e,n){const o=F.get(A[e])??0;for(let r=0;r<t.elements.length;r++){const i=t.elements[r];if(!f(i)||i.type!=="Identifier")continue;const a=i.name;if(typeof a!="string")continue;const s=n.get(a);if(s!==void 0&&s>o)return r}return t.elements.length}u(Ee,"connectionInsertIndex");function Se(t){const e=new Map;for(const n of t){const o=N(n);if(o===void 0||o.type!=="VariableDeclaration")continue;const r=o.declarations;if(Array.isArray(r))for(const i of r){if(!f(i))continue;const a=i.id,s=i.init;if(!f(a)||a.type!=="Identifier"||!f(s))continue;const d=a.name;if(typeof d!="string")continue;const p=V(s);if(p===void 0)continue;const l=F.get(p);l!==void 0&&e.set(d,l)}}return e}u(Se,"collectConnectionRanks");const be=Object.freeze([...Object.values(b),...Object.values(O),...Object.values(Y)]);function ge(t){let e=-1;for(let n=0;n<t.properties.length;n++){const o=t.properties[n];if(o===void 0||o.type!=="Property"&&o.type!=="ObjectProperty"||o.computed===!0)continue;const r=M(o.key);if(r===void 0)continue;be.some(a=>T(r,a)!==void 0)&&(e=n)}return e===-1?t.properties.length:e+1}u(ge,"connectionEntryInsertIndex");function Ae(t,e,n,o,r){const i=o.map(d=>D(d.key,d.value,r)),a=n?.obj;if(a===void 0){K(t,e,E.objectExpression(i),r);return}const s=ge(a);a.properties.splice(s,0,...i)}u(Ae,"insertObjectEntries");function K(t,e,n,o){const r=D(e,n,o);ce(t,r)}u(K,"appendProperty");export{Me as connectResourceToCompute};
|
|
1
|
+
var B=Object.defineProperty;var p=(n,e)=>B(n,"name",{value:e,configurable:!0});import{builders as y}from"ast-types";import{CREDENTIAL_KEYS as T,DATABASE_ACCESSORS as v,DATABASE_ENV_VARS as E,DATABASE_SSL_VALUE as V}from"../../generation/database.js";import{MESSAGING_ENV_VARS as F}from"../../generation/messagingConnections.js";import{STORAGE_ACCESSORS as K,STORAGE_ENV_VARS as A}from"../../generation/storageConnections.js";import{connectionEnvSuffix as W,connectionKeyOrdinal as w}from"../../generation/common.js";import{failure as d,success as S}from"../../types/Result.js";import{DEFAULT_FILE_PATH as G,computeLinesDelta as H,extractProgramBody as z}from"../_internal.js";import{buildObjectProperty as U,detectQuoteStyle as Y,parse as J,printFile as Q}from"../fileRewriter/index.js";import{FACTORY_IDENTIFIERS as I,STATEMENT_REGISTRY as X}from"../registry.js";import{makeStringLiteral as P}from"./addResource/propertyBuilder.js";import{findLastPlainPropertyIndex as _,isArrayExpression as Z,locateContainer as q,locateServiceByName as ee}from"./computeServiceLocator.js";import{isNodeShape as g,readKeyName as x}from"./modifyResource/literalConversion.js";import{objectAbsenceIsProvable as $,pushPropertyPreservingComma as ne}from"./objectGraph.js";import{applyBinding as te,appMethodNameOf as re,planBinding as oe,unwrapExportDeclaration as ie}from"./resourceStatementLocator.js";const j=Object.freeze({database:I.database,storage:I.storage});function O(n){const e=X[n].emitWrapper?.appMethod;if(e===void 0)throw new Error(`No app method registered for statement type "${n}"`);return e}p(O,"requireAppMethod");const k=Object.freeze({database:O("database"),storage:O("storage")}),M=new Map([[k.database,0],[k.storage,1],[O("messaging"),2]]);function Pe(n,e){const t=e.filePath??G,{resourceType:o,resourceName:r}=e,i=[...new Set(e.serviceNames)];if(i.length===0)return d({kind:"UnsupportedConnectionShapeError",reason:"No target services were supplied."});const a=J(n,t);if(!a.success)return d(a.error);const s=z(a.data);if(s===void 0)return d({kind:"UnsupportedConnectionShapeError",reason:"recast File is missing program.body"});const c=oe(s,{factory:j[o],appMethod:k[o]},r);if(!c.success)return d(ae(c.error,o,r));const{variableName:u}=c.data,l=[],h=[];for(const m of i){const C=se(s,m,u,o);if(!C.success)return d(C.error);if(C.data==="already-connected"){l.push(m);continue}h.push(C.data)}const f=l.map(m=>`Service "${m}" already lists "${u}" in its \`connections\` array \u2014 left untouched.`);for(const m of h)m.container===void 0&&f.push(`Service "${m.serviceName}" has no \`containers\` array \u2014 wired \`connections\` only, without env/secret entries (the generator lane emits the same shape for container-less services).`);if(h.length===0)return S({content:n,linesChanged:{added:0,removed:0},variableName:u,wiredServices:[],skipped:!0,warnings:f});const b=Y(a.data),L=le(s);te(s,c.data);for(const m of h)ue(m,u,o,b,L);const R=Q(a.data,n);return S({content:R,linesChanged:H(n,R),variableName:u,wiredServices:h.map(m=>m.serviceName),skipped:!1,warnings:f})}p(Pe,"connectResourceToCompute");function ae(n,e,t){switch(n.kind){case"statement-not-found":return{kind:"ResourceStatementNotFoundError",resourceType:e,resourceName:t};case"ambiguous":return{kind:"AmbiguousResourceStatementError",resourceType:e,resourceName:t,count:n.count};case"multiple-declarators":return{kind:"UnsupportedConnectionShapeError",reason:`The statement declaring "${t}" carries multiple declarators \u2014 the binding cannot be identified.`};case"pattern-binding":return{kind:"UnsupportedConnectionShapeError",reason:`The statement declaring "${t}" binds a pattern, not an identifier.`};case"unreadable-name":return{kind:"UnsupportedConnectionShapeError",reason:`The binding for "${t}" has no readable name.`};case"init-not-app-method-wrap":return{kind:"UnsupportedConnectionShapeError",reason:`The binding for "${t}" is not a direct \`app.${k[e]}(${j[e]}.build(...))\` call \u2014 the bound value is not the construct \`connections\` needs.`};case"unbindable-statement":return{kind:"UnsupportedConnectionShapeError",reason:`The statement containing "${t}" is a ${n.statementType}, which cannot be bound to a const.`};case"not-app-method-call":return{kind:"UnsupportedConnectionShapeError",reason:`The statement containing "${t}" is not an app-method call \u2014 there is no construct value to bind.`};case"bare-factory-call":return{kind:"UnsupportedConnectionShapeError",reason:`"${t}" is a bare factory call not wrapped in an app method \u2014 there is no construct value to bind.`};case"foreign-wrapper":return{kind:"UnsupportedConnectionShapeError",reason:`The statement containing "${t}" is not a direct \`app.${k[e]}(...)\` call \u2014 binding it would wire a value \`connections\` cannot use.`};case"name-conflict":return{kind:"VariableNameConflictError",variableName:n.variableName};case"reserved-word":return{kind:"UnsupportedConnectionShapeError",reason:`Binding "${t}" would derive the variable name "${n.variableName}", a JavaScript reserved word no \`const\` can carry \u2014 bind the statement to a const of your own naming, or rename the resource.`}}}p(ae,"mapLocatorFailure");function se(n,e,t,o){const r=ee(n,e);if(!r.success){const f=r.error;return f.kind==="AmbiguousService"?d({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:`${String(f.count)} services share the name "${e}" across ComputeFactory.build calls \u2014 the edit cannot be proven to target the right one.`}):d({kind:"ConnectServiceNotFoundError",serviceName:e,knownServices:f.knownServices})}const i=r.data,a=q(i,0);let s;if(a.success)s=a.data;else switch(a.error.kind){case"ContainerNotObjectLiteral":return d({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:"The first container is not an object literal."});case"ContainersNotStaticArray":return d({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:"`containers` is not a static array literal, so the container to wire cannot be located."});case"NoContainersArray":if(!$(i,"containers"))return d({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:"Service carries a spread, shorthand or computed key that could supply `containers` invisibly, so an absent property cannot be proven."});break;case"ContainerIndexOutOfRange":break}const c=ce(i,e,t);if(!c.success)return d(c.error);if(c.data.alreadyConnected)return S("already-connected");let u,l,h="";if(s!==void 0){const f=N(s,"environment",e);if(!f.success)return d(f.error);const b=N(s,"secretsImport",e);if(!b.success)return d(b.error);u=f.data,l=b.data,h=de(o,[...f.data.keys,...b.data.keys])}return S({serviceName:e,service:i,container:s,environment:u,secretsImport:l,suffix:h,connectionsArray:c.data.array})}p(se,"planService");function ce(n,e,t){const o=_(n,"connections");if(o===-1)return $(n,"connections")?S({array:void 0,alreadyConnected:!1}):d({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:"Service carries a spread, shorthand or computed key that could supply `connections` invisibly, so an absent property cannot be proven."});const r=n.properties[o]?.value;if(!Z(r))return d({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:"`connections` is not an array literal."});for(const i of r.elements)if(g(i)){if(i.type==="Identifier"){if(i.name===t)return S({array:r,alreadyConnected:!0});continue}return d({kind:"UnsupportedConnectionShapeError",serviceName:e,reason:`\`connections\` contains a ${i.type}, so "${t}" cannot be proven absent from it.`})}return S({array:r,alreadyConnected:!1})}p(ce,"inspectConnections");function N(n,e,t){const o=_(n,e);if(o===-1)return $(n,e)?S({obj:void 0,keys:[]}):d({kind:"UnsupportedConnectionShapeError",serviceName:t,reason:`The first container carries a spread, shorthand or computed key that could supply \`${e}\` invisibly, so an absent property cannot be proven.`});const r=n.properties[o]?.value;if(!g(r)||r.type!=="ObjectExpression")return d({kind:"UnsupportedConnectionShapeError",serviceName:t,reason:`\`${e}\` is not an object literal.`});const i=r,a=[];for(const s of i.properties){if(s.type==="SpreadElement"||s.type==="SpreadProperty")return d({kind:"UnsupportedConnectionShapeError",serviceName:t,reason:`\`${e}\` contains a spread, so existing connection keys cannot be enumerated to derive the next suffix.`});if(s.type!=="Property"&&s.type!=="ObjectProperty")continue;if(s.computed===!0)return d({kind:"UnsupportedConnectionShapeError",serviceName:t,reason:`\`${e}\` contains a computed key.`});const c=x(s.key);c!==void 0&&a.push(c)}return S({obj:i,keys:a})}p(N,"collectWiringTarget");function de(n,e){const t=Object.values(n==="database"?E:A),o=new Set;for(const r of e)for(const i of t){const a=w(r,i);a!==void 0&&o.add(a)}return W(o.size===0?0:Math.max(...o))}p(de,"nextConnectionSuffix");function pe(n,e,t,o){const r=p((s,c,u=[])=>y.callExpression(y.memberExpression(s,y.identifier(c),!1),u),"call"),i=p(()=>y.identifier(e),"variable");if(n==="storage")return[{key:`${A.NAME}${t}`,value:r(i(),K.BUCKET_NAME),target:"environment"}];const a=p(s=>r(r(i(),v.CREDENTIALS),v.IMPORT,[P(s,o)]),"credential");return[{key:`${E.HOST}${t}`,value:r(i(),v.HOST),target:"environment"},{key:`${E.PORT}${t}`,value:r(i(),v.PORT),target:"environment"},{key:`${E.NAME}${t}`,value:r(i(),v.NAME),target:"environment"},{key:`${E.SSL}${t}`,value:P(V,o),target:"environment"},{key:`${E.USERNAME}${t}`,value:a(T.USERNAME),target:"secretsImport"},{key:`${E.PASSWORD}${t}`,value:a(T.PASSWORD),target:"secretsImport"}]}p(pe,"buildWiringEntries");function ue(n,e,t,o,r){if(n.connectionsArray!==void 0){const c=fe(n.connectionsArray,t,r);n.connectionsArray.elements.splice(c,0,y.identifier(e))}else D(n.service,"connections",y.arrayExpression([y.identifier(e)]),o);const i=n.container;if(i===void 0)return;const a=pe(t,e,n.suffix,o),s=[{key:"environment",state:n.environment},{key:"secretsImport",state:n.secretsImport}];for(const{key:c,state:u}of s){const l=a.filter(h=>h.target===c);l.length!==0&&Se(i,c,u,l,o)}}p(ue,"applyServiceWiring");function fe(n,e,t){const o=M.get(k[e])??0;for(let r=0;r<n.elements.length;r++){const i=n.elements[r];if(!g(i)||i.type!=="Identifier")continue;const a=i.name;if(typeof a!="string")continue;const s=t.get(a);if(s!==void 0&&s>o)return r}return n.elements.length}p(fe,"connectionInsertIndex");function le(n){const e=new Map;for(const t of n){const o=ie(t);if(o===void 0||o.type!=="VariableDeclaration")continue;const r=o.declarations;if(Array.isArray(r))for(const i of r){if(!g(i))continue;const a=i.id,s=i.init;if(!g(a)||a.type!=="Identifier"||!g(s))continue;const c=a.name;if(typeof c!="string")continue;const u=re(s);if(u===void 0)continue;const l=M.get(u);l!==void 0&&e.set(c,l)}}return e}p(le,"collectConnectionRanks");const me=Object.freeze([...Object.values(E),...Object.values(A),...Object.values(F)]);function he(n){let e=-1;for(let t=0;t<n.properties.length;t++){const o=n.properties[t];if(o===void 0||o.type!=="Property"&&o.type!=="ObjectProperty"||o.computed===!0)continue;const r=x(o.key);if(r===void 0)continue;me.some(a=>w(r,a)!==void 0)&&(e=t)}return e===-1?n.properties.length:e+1}p(he,"connectionEntryInsertIndex");function Se(n,e,t,o,r){const i=o.map(c=>U(c.key,c.value,r)),a=t?.obj;if(a===void 0){D(n,e,y.objectExpression(i),r);return}const s=he(a);a.properties.splice(s,0,...i)}p(Se,"insertObjectEntries");function D(n,e,t,o){const r=U(e,t,o);ne(n,r)}p(D,"appendProperty");export{Pe as connectResourceToCompute};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var Q=Object.defineProperty;var d=(r,e)=>Q(r,"name",{value:e,configurable:!0});import{failure as o,success as E}from"../../types/Result.js";import{DEFAULT_FILE_PATH as U,computeLinesDelta as I,extractProgramBody as V}from"../_internal.js";import{buildObjectProperty as D,detectQuoteStyle as O,parse as K,printFile as _}from"../fileRewriter/index.js";import{STATEMENT_REGISTRY as M}from"../registry.js";import{locateAllShapes as W,locateByShape as H}from"../semanticIndex/index.js";import{buildUnmanagedEditRefusal as Y}from"./unmanagedShapeErrors.js";import{checkControlFlowPolicy as $}from"./controlFlowPolicy.js";import{driftGate as q,runPipeline as z,schemaGate as J}from"../validationGate/index.js";import{buildEmittedValue as X}from"./addResource/propertyBuilder.js";import{buildMergedLiteral as C,collectPropertyKeys as Z,isNodeShape as v}from"./modifyResource/literalConversion.js";import{findPropertyByKey as ee,visit as re}from"./objectGraph.js";import{evaluateEmitGuard as N,UNRESOLVED as te}from"../emitGuard.js";import{projectEmittedProperties as ne,projectionRefusals as R}from"../emitProjection.js";import{applyBinding as ie}from"./resourceStatementLocator.js";import{createSiblingBindingResolution as ae}from"./siblingBindingResolution.js";function Ne(r,e,s={}){const n=e.filePath??U,i=K(r,n);if(!i.success)return o(i.error);const t=H(r,{type:e.type,name:e.name},n);if(!t.success)return t.error.kind==="TemplateLiteralNameError"?o(t.error):o({kind:"SemanticQueryError",reason:t.error.reason,cause:t.error.cause});if(t.data===void 0)return o({kind:"ResourceNotFoundError",type:e.type,name:e.name,knownNames:ce(r,e.type,n)});if(t.data.managed===!1)return o(Y(e.type,"modify"));const a=$({ast:i.data,target:t.data,resource:{type:e.type,name:e.name},op:"modify"});if(a.refusal!==void 0)return o(a.refusal);const u=z([q],{content:r,plan:{type:e.type,name:e.name,properties:e.properties,op:"modify"},baseline:s.baseline,policy:e.driftPolicy});if(!u.success)return o(G(u.error));if(u.data.action==="skip")return E({content:r,linesChanged:{added:0,removed:0},skipped:!0});const c=V(i.data);if(c===void 0)return o({kind:"SemanticQueryError",reason:"recast File is missing program.body"});const f=se(c,t.data);if(f===void 0)return o({kind:"SemanticQueryError",reason:"Unable to resolve config ObjectExpression for the located resource."});const L=O(i.data),B=C(f,e.properties),h=M[e.type].emitGuard,l=ae(e.type,()=>c,{mustPrecedeStatementIndex:oe(c,t.data)??0}),m={editingExisting:!0,resourceName:e.name,resolveBinding:l.resolveBinding},P=T(f,C(f,{})),b=T(f,B),F=N(h,P),y=N(h,b);if(y!==void 0&&y.property!==F?.property)return o(y);const j=new Set(R(e.type,P,m).map(p=>p.property)),k=R(e.type,b,m).find(p=>!j.has(p.property));if(k!==void 0)return o(k);const S=J.run({content:r,plan:{type:e.type,name:e.name,properties:e.properties,op:"modify"}});if(!S.success)return o(G(S.error));l.takePendingWraps();const g=ne(e.type,e.properties,m);if("refusal"in g)return o(g.refusal);const w=ue(f,g.props,L);if(!w.success)return o(w.error);for(const p of l.takePendingWraps())ie(c,p);const x=_(i.data,r),A=a.warning!==void 0?[a.warning.message]:void 0;return E({content:x,linesChanged:I(r,x),warnings:A})}d(Ne,"modifyResource");function oe(r,e){const s=e.start+e.length;for(let n=0;n<r.length;n++){const i=r[n];if(i===void 0)continue;const{start:t,end:a}=i;if(!(typeof t!="number"||typeof a!="number")&&t<=e.start&&s<=a)return n}}d(oe,"findStatementIndexContaining");function T(r,e){const s={...e};for(const n of Z(r))n in s||(s[n]=te);return s}d(T,"buildGuardView");function G(r){switch(r.kind){case"ParseError":case"ResourceNotFoundError":case"InvalidPropertyError":case"TemplateLiteralNameError":case"SemanticQueryError":case"DriftConflictError":case"ControlFlowClassifierError":return r;default:return{kind:"SemanticQueryError",reason:`Unexpected codemod error in validation-gate pipeline: ${r.kind}`}}}d(G,"narrowGateError");function se(r,e){const s=e.start+e.length;let n;const i=d(t=>{if(n!==void 0||t.type!=="CallExpression")return;const a=t.arguments;if(!Array.isArray(a)||a.length<2)return;const u=a[0];if(!v(u)||u.type!=="StringLiteral"||u.start!==e.start||u.end!==s)return;const c=a[1];v(c)&&c.type==="ObjectExpression"&&(n=c)},"visitor");for(const t of r)if(re(t,i),n!==void 0)break;return n}d(se,"findConfigObject");function ue(r,e,s){const n=de(r);for(const i of e){const t=X(i,s);if(!t.success)return o(t.error);const a=ee(r,i.key);if(a!==void 0){a.value=t.data;continue}const u=D(i.key,t.data,s);n&&(u.extra={...u.extra??{},trailingComma:!0}),r.properties.push(u)}return E(void 0)}d(ue,"applyPropertyEdits");function de(r){return r.properties[r.properties.length-1]?.extra?.trailingComma===!0}d(de,"detectTrailingCommaStyle");function ce(r,e,s){const n=W(r,s);return n.success?n.data.filter(i=>i.type===e).map(i=>i.symbolName):[]}d(ce,"collectKnownNames");export{Ne as modifyResource};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { type Result } from "../../types/Result.js";
|
|
2
|
+
import { type NodeShapeLike } from "./modifyResource/literalConversion.js";
|
|
3
|
+
/** The construct-producing statement shape an edit binds against. */
|
|
4
|
+
export interface LocatorTarget {
|
|
5
|
+
/** Factory identifier — the `<factory>` of `<factory>.build("<name>", …)`. */
|
|
6
|
+
factory: string;
|
|
7
|
+
/** Method that materialises the thunk — the `<m>` of `app.<m>(…)`. */
|
|
8
|
+
appMethod: string;
|
|
9
|
+
}
|
|
10
|
+
export interface BindingPlan {
|
|
11
|
+
variableName: string;
|
|
12
|
+
/** Index of the matched statement in the module body — callers that emit a
|
|
13
|
+
* reference to the binding need it to judge declaration order. */
|
|
14
|
+
statementIndex: number;
|
|
15
|
+
/** Set when the statement must be wrapped in a `const` declaration. */
|
|
16
|
+
wrap?: {
|
|
17
|
+
statementIndex: number;
|
|
18
|
+
expression: NodeShapeLike;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export type LocatorFailure = {
|
|
22
|
+
kind: "statement-not-found";
|
|
23
|
+
} | {
|
|
24
|
+
kind: "ambiguous";
|
|
25
|
+
count: number;
|
|
26
|
+
} | {
|
|
27
|
+
kind: "multiple-declarators";
|
|
28
|
+
} | {
|
|
29
|
+
kind: "pattern-binding";
|
|
30
|
+
} | {
|
|
31
|
+
kind: "unreadable-name";
|
|
32
|
+
}
|
|
33
|
+
/** A `const` already binds the statement, but its initialiser is not the
|
|
34
|
+
* app-method wrap — the bound value is not the construct. */
|
|
35
|
+
| {
|
|
36
|
+
kind: "init-not-app-method-wrap";
|
|
37
|
+
}
|
|
38
|
+
/** The matched statement can never carry a `const` binding: an `if` body, a
|
|
39
|
+
* declaration-less export, or an export wrapper around anything that is not
|
|
40
|
+
* already a `const` declaration (`export default app.addStorage(...)` —
|
|
41
|
+
* wrapping inside the export would change the module's exported surface).
|
|
42
|
+
* An `export const x = app.addX(...)` is NOT this: its declaration already
|
|
43
|
+
* binds, and `planBinding` unwraps the export to reuse it. */
|
|
44
|
+
| {
|
|
45
|
+
kind: "unbindable-statement";
|
|
46
|
+
statementType: string;
|
|
47
|
+
} | {
|
|
48
|
+
kind: "not-app-method-call";
|
|
49
|
+
} | {
|
|
50
|
+
kind: "bare-factory-call";
|
|
51
|
+
} | {
|
|
52
|
+
kind: "foreign-wrapper";
|
|
53
|
+
} | {
|
|
54
|
+
kind: "name-conflict";
|
|
55
|
+
variableName: string;
|
|
56
|
+
}
|
|
57
|
+
/** Same family as `name-conflict` — the statement shape is bindable, but
|
|
58
|
+
* the derived variable name is unusable: `toVariableName("Import")` yields
|
|
59
|
+
* `import`, and `const import = …` does not parse. */
|
|
60
|
+
| {
|
|
61
|
+
kind: "reserved-word";
|
|
62
|
+
variableName: string;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Pure analysis: find the one top-level statement containing
|
|
66
|
+
* `<factory>.build("<resourceName>", …)` and decide how the construct value
|
|
67
|
+
* is (or would be) bound. Reuses an existing `const` binding; otherwise
|
|
68
|
+
* plans a wrap under `toVariableName(resourceName)`, refusing on a
|
|
69
|
+
* module-scope name conflict rather than renaming.
|
|
70
|
+
*/
|
|
71
|
+
export declare function planBinding(body: NodeShapeLike[], target: LocatorTarget, resourceName: string): Result<BindingPlan, LocatorFailure>;
|
|
72
|
+
export declare function applyBinding(body: NodeShapeLike[], plan: BindingPlan): void;
|
|
73
|
+
export declare function isFactoryBuildOf(node: NodeShapeLike, factory: string, resourceName: string): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* The inner declaration of an export statement, the statement itself
|
|
76
|
+
* otherwise; `undefined` for declaration-less exports (`export default expr`,
|
|
77
|
+
* `export { x }`).
|
|
78
|
+
*/
|
|
79
|
+
export declare function unwrapExportDeclaration(statement: NodeShapeLike): NodeShapeLike | undefined;
|
|
80
|
+
/** Method name of a non-computed `<recv>.method(...)` call, else undefined. */
|
|
81
|
+
export declare function appMethodNameOf(node: NodeShapeLike): string | undefined;
|
|
82
|
+
export declare function moduleScopeDeclares(body: NodeShapeLike[], name: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var w=Object.defineProperty;var d=(r,n)=>w(r,"name",{value:n,configurable:!0});import{builders as b}from"ast-types";import{toVariableName as A}from"../../generation/common.js";import{failure as o,success as E}from"../../types/Result.js";import{RESERVED_IDENTIFIER_NAMES as v}from"./addResource/propertyBuilder.js";import{isNodeShape as s}from"./modifyResource/literalConversion.js";import{unwrapTsWrappers as I}from"./moduleConstResolver.js";import{visit as k}from"./objectGraph.js";function j(r,n,a){const e=[];for(let p=0;p<r.length;p++){const l=r[p];if(l===void 0)continue;let y=!1;k(l,x=>{x.type==="CallExpression"&&D(x,n.factory,a)&&(y=!0)}),y&&e.push({statementIndex:p})}if(e.length===0)return o({kind:"statement-not-found"});if(e.length>1)return o({kind:"ambiguous",count:e.length});const t=e[0];if(t===void 0)return o({kind:"statement-not-found"});const i=r[t.statementIndex];if(i===void 0)return o({kind:"statement-not-found"});const c=i.type==="ExportNamedDeclaration"||i.type==="ExportDefaultDeclaration",f=h(i);if(f===void 0)return o({kind:"unbindable-statement",statementType:i.type});if(f.type==="VariableDeclaration"){const p=f.declarations;if(!Array.isArray(p)||p.length!==1)return o({kind:"multiple-declarators"});const l=p[0].id;if(!s(l)||l.type!=="Identifier")return o({kind:"pattern-binding"});const y=l.name;if(typeof y!="string")return o({kind:"unreadable-name"});const x=p[0].init;return!s(x)||!g(x,n,a)?o({kind:"init-not-app-method-wrap"}):E({variableName:y,statementIndex:t.statementIndex})}if(c)return o({kind:"unbindable-statement",statementType:i.type});if(f.type!=="ExpressionStatement")return o({kind:"unbindable-statement",statementType:f.type});const u=f.expression;if(!s(u)||u.type!=="CallExpression")return o({kind:"not-app-method-call"});if(D(u,n.factory,a))return o({kind:"bare-factory-call"});if(!g(u,n,a))return o({kind:"foreign-wrapper"});const m=A(a);return v.has(m)?o({kind:"reserved-word",variableName:m}):N(r,m)?o({kind:"name-conflict",variableName:m}):E({variableName:m,statementIndex:t.statementIndex,wrap:{statementIndex:t.statementIndex,expression:u}})}d(j,"planBinding");function L(r,n){if(n.wrap===void 0)return;const{statementIndex:a,expression:e}=n.wrap,t=r[a],i=b.variableDeclaration("const",[b.variableDeclarator(b.identifier(n.variableName),e)]),c=t?.comments;c!==void 0&&(i.comments=c),r[a]=i}d(L,"applyBinding");function D(r,n,a){const e=r.callee;if(!s(e)||e.type!=="MemberExpression"||e.computed===!0)return!1;const t=e.object,i=e.property;if(!s(t)||t.type!=="Identifier"||t.name!==n||!s(i)||i.type!=="Identifier"||i.name!=="build")return!1;const c=r.arguments;if(!Array.isArray(c))return!1;const f=c[0];return!s(f)||f.type!=="StringLiteral"&&f.type!=="Literal"?!1:f.value===a}d(D,"isFactoryBuildOf");function h(r){if(r.type!=="ExportNamedDeclaration"&&r.type!=="ExportDefaultDeclaration")return r;const n=r.declaration;return s(n)?n:void 0}d(h,"unwrapExportDeclaration");function M(r){const n=I(r);if(n.type!=="CallExpression")return;const a=n.callee;if(!s(a)||a.type!=="MemberExpression"||a.computed===!0)return;const e=a.property;if(!s(e)||e.type!=="Identifier")return;const t=e.name;return typeof t=="string"?t:void 0}d(M,"appMethodNameOf");function g(r,n,a){const e=I(r);if(M(e)!==n.appMethod)return!1;const t=e.arguments;if(!Array.isArray(t))return!1;const i=t[0];return s(i)?D(I(i),n.factory,a):!1}d(g,"isAppMethodWrap");function N(r,n){for(const a of r){const e=h(a);if(e!==void 0){if(e.type==="ImportDeclaration"){const t=e.specifiers;if(!Array.isArray(t))continue;for(const i of t){const c=i.local;if(s(c)&&c.name===n)return!0}continue}if(e.type==="VariableDeclaration"){const t=e.declarations;if(!Array.isArray(t))continue;for(const i of t){if(!s(i))continue;const c=i.id;if(!s(c))continue;let f=!1;if(k(c,u=>{u.type==="Identifier"&&u.name===n&&(f=!0)}),f)return!0}continue}if(e.type==="FunctionDeclaration"||e.type==="ClassDeclaration"){const t=e.id;if(s(t)&&t.name===n)return!0}}}return!1}d(N,"moduleScopeDeclares");export{M as appMethodNameOf,L as applyBinding,D as isFactoryBuildOf,N as moduleScopeDeclares,j as planBinding,h as unwrapExportDeclaration};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { StatementType } from "../types.js";
|
|
2
|
+
import type { NodeShapeLike } from "./modifyResource/literalConversion.js";
|
|
3
|
+
import { type BindingPlan } from "./resourceStatementLocator.js";
|
|
4
|
+
export interface SiblingBindingResolution {
|
|
5
|
+
resolveBinding: (planResourceName: string) => string | undefined;
|
|
6
|
+
/** Wrap plans recorded by successful resolutions since the last drain. */
|
|
7
|
+
takePendingWraps: () => BindingPlan[];
|
|
8
|
+
}
|
|
9
|
+
export interface SiblingBindingConstraints {
|
|
10
|
+
/**
|
|
11
|
+
* Body index the resolved binding must sit strictly BEFORE. The modify
|
|
12
|
+
* path supplies its own statement's index: it emits a reference into an
|
|
13
|
+
* EXISTING statement, so a binding declared after it — existing `const` or
|
|
14
|
+
* freshly planned wrap alike — would be read before its declaration (TDZ
|
|
15
|
+
* at runtime, TS2448 at typecheck). A violating candidate refuses to
|
|
16
|
+
* `undefined` rather than emit the broken reference. The add path needs no
|
|
17
|
+
* constraint: its insertion-order table lands the new statement after
|
|
18
|
+
* every bindable sibling type.
|
|
19
|
+
*/
|
|
20
|
+
mustPrecedeStatementIndex?: number;
|
|
21
|
+
}
|
|
22
|
+
export declare function createSiblingBindingResolution(type: StatementType, getBody: () => NodeShapeLike[] | undefined, constraints?: SiblingBindingConstraints): SiblingBindingResolution;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var l=Object.defineProperty;var e=(t,i)=>l(t,"name",{value:i,configurable:!0});import{FACTORY_IDENTIFIERS as g,STATEMENT_REGISTRY as I}from"../registry.js";import{planBinding as T}from"./resourceStatementLocator.js";const E={cdn:["storage","compute"]};function A(t,i,p={}){const m=E[t]??[];let d=[];return{resolveBinding:e(r=>{const u=i();if(u===void 0)return;const o=[];for(const c of m){const f=I[c].emitWrapper?.appMethod;if(f===void 0)continue;const s=T(u,{factory:g[c],appMethod:f},r);if(s.success){o.push(s.data);continue}if(s.error.kind!=="statement-not-found")return}if(o.length!==1)return;const n=o[0];if(n===void 0)return;const a=p.mustPrecedeStatementIndex;if(!(a!==void 0&&n.statementIndex>=a))return n.wrap!==void 0&&d.push(n),n.variableName},"resolveBinding"),takePendingWraps:e(()=>{const r=d;return d=[],r},"takePendingWraps")}}e(A,"createSiblingBindingResolution");export{A as createSiblingBindingResolution};
|
|
@@ -1,29 +1,50 @@
|
|
|
1
1
|
import { type ProjectionContext } from "../projection/index.js";
|
|
2
2
|
import { type EmitGuardProperties } from "./emitGuard.js";
|
|
3
3
|
import type { InvalidPropertyError, StatementType } from "./types.js";
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* One emitted construct prop. `literal` is a serialisable value; `expression`
|
|
6
|
+
* carries the source text of a live binding a projection rule resolved — the
|
|
7
|
+
* emitters splice it as an identifier rather than serialising it.
|
|
8
|
+
*/
|
|
9
|
+
export type EmittedProp = {
|
|
6
10
|
key: string;
|
|
11
|
+
kind: "literal";
|
|
7
12
|
value: unknown;
|
|
8
|
-
}
|
|
13
|
+
} | {
|
|
14
|
+
key: string;
|
|
15
|
+
kind: "expression";
|
|
16
|
+
source: string;
|
|
17
|
+
};
|
|
9
18
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
19
|
+
* EVERY plan key in `properties` this type cannot turn into a construct
|
|
20
|
+
* prop, one refusal per key, as the codebase's actionable error shape.
|
|
21
|
+
*
|
|
22
|
+
* The modify judge is why this is a set and not a first-refusal probe: it
|
|
23
|
+
* compares a pre-edit view against a post-merge view and refuses only what
|
|
24
|
+
* the edit introduced. A statement can carry several pre-existing
|
|
25
|
+
* unprojectable keys, and holding only the first per view blamed the repair
|
|
26
|
+
* of one on an untouched other (fixing a dead `defaultOriginRef` was refused
|
|
27
|
+
* for the `behaviours` array the edit never named).
|
|
12
28
|
*
|
|
13
29
|
* Values are passed through verbatim, `UNRESOLVED` included: a plan-only key
|
|
14
30
|
* is inert whatever it holds, which is exactly the presence test the
|
|
15
31
|
* `silentlyDropped` rules applied.
|
|
16
32
|
*/
|
|
17
|
-
export declare function
|
|
33
|
+
export declare function projectionRefusals(type: StatementType, properties: EmitGuardProperties, context?: ProjectionContext): InvalidPropertyError[];
|
|
18
34
|
/**
|
|
19
35
|
* The construct props to write for `properties`, or the refusal that stops
|
|
20
36
|
* the write.
|
|
21
37
|
*
|
|
22
38
|
* A non-projectable type is emitted as it always was — its plan keys go into
|
|
23
39
|
* the file verbatim and its `emitGuard` is what decides whether that is safe.
|
|
40
|
+
*
|
|
41
|
+
* An `expression` prop reaches the emitters only when a live rule's `bind`
|
|
42
|
+
* resolved a binding for it: an unresolvable bind lands in `unprojectable`
|
|
43
|
+
* and refuses the whole statement above, so there is no fall-through path
|
|
44
|
+
* that writes a plan value where a live construct belongs.
|
|
24
45
|
*/
|
|
25
46
|
export declare function projectEmittedProperties(type: StatementType, properties: Readonly<Record<string, unknown>>, context?: ProjectionContext): {
|
|
26
|
-
props:
|
|
47
|
+
props: EmittedProp[];
|
|
27
48
|
} | {
|
|
28
49
|
refusal: InvalidPropertyError;
|
|
29
50
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var p=Object.defineProperty;var a=(e,n)=>p(e,"name",{value:n,configurable:!0});import{isProjectableType as s,projectPlanToConstructProps as u}from"../projection/index.js";import{AUTHOR_BY_HAND as f}from"./emitGuard.js";const m={"plan-only":`\`fjall add\` would write it into the factory call and the resource would deploy without it. ${f}`,"unresolved-binding":"Nothing has been written: the engine refuses rather than guessing a construct. Add or bind a sibling resource with that name (or fix the name) and run the same command again \u2014 it succeeds once a unique binding exists.","missing-context":"Nothing has been written: the command context supplied no resource name to derive it from."};function l(e,n,r="plan-only"){return{kind:"InvalidPropertyError",property:e,reason:`${n} ${m[r]}`}}a(l,"unprojectableRefusal");function g(e,n,r={}){return s(e)?u(e,n,r).unprojectable.map(o=>l(o.key,o.reason,o.kind)):[]}a(g,"projectionRefusals");function j(e,n,r={}){if(!s(e))return{props:Object.entries(n).map(([t,d])=>({key:t,kind:"literal",value:d}))};const{props:o,unprojectable:c}=u(e,n,r),[i]=c;return i!==void 0?{refusal:l(i.key,i.reason,i.kind)}:{props:o.map(t=>t.value.kind==="expression"?{key:t.key,kind:"expression",source:t.value.source}:{key:t.key,kind:"literal",value:t.value.value})}}a(j,"projectEmittedProperties");export{j as projectEmittedProperties,g as projectionRefusals};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var m=Object.defineProperty;var c=(e,t)=>m(e,"name",{value:t,configurable:!0});import{isDeepStrictEqual as $}from"node:util";import{maskSensitiveOutput as d}from"@fjall/util";import{STATEMENT_REGISTRY as h}from"../registry.js";import{classifyGate as l,createLocateGate as p,driftGate as G,parseGate as f,schemaGate as
|
|
1
|
+
var m=Object.defineProperty;var c=(e,t)=>m(e,"name",{value:t,configurable:!0});import{isDeepStrictEqual as $}from"node:util";import{maskSensitiveOutput as d}from"@fjall/util";import{STATEMENT_REGISTRY as h}from"../registry.js";import{classifyGate as l,createLocateGate as p,driftGate as G,parseGate as f,projectionGate as b,schemaGate as E}from"../validationGate/index.js";function k(e){const{intent:t,tier:i}=e;if(t.op==="add"&&h[t.type].addContract===void 0)return{state:"rejected",tier:i,failedGate:"schema",diagnostics:`LLM fallback cannot add a ${t.type}: its complete add contract is not yet declared. Nothing has been written.`};const g={type:t.type,name:t.name,properties:t.properties,op:t.op==="add"?"add":"modify"},y={content:e.outputContent,plan:g,inputContent:e.inputContent,...e.baseline!==void 0&&{baseline:e.baseline},...e.abortSignal!==void 0&&{signal:e.abortSignal}};for(const n of S(t.op)){if(e.abortSignal?.aborted===!0)return{state:"cancelled"};const u=Date.now();let a;try{a=n.run(y)}catch(o){return e.onGateResult?.(n.id,"fail",Date.now()-u),{state:"rejected",tier:i,failedGate:n.id,diagnostics:d(o instanceof Error?o.message:String(o))}}const s=Date.now()-u;if(!a.success)return e.onGateResult?.(n.id,"fail",s),{state:"rejected",tier:i,failedGate:n.id,diagnostics:d(j(a.error))};if(a.data.action==="reject")return e.onGateResult?.(n.id,"fail",s),{state:"rejected",tier:i,failedGate:a.data.failedGate??n.id,diagnostics:d(a.data.diagnostics??"gate rejected the output")};if(a.data.driftState!==void 0){const o=a.data.driftState.deltas.filter(r=>r.verdict==="clean"&&Object.hasOwn(t.properties,r.property)&&!$(r.theirs,r.ours)).map(r=>`\`${r.property}\``);if(o.length>0)return e.onGateResult?.(n.id,"fail",s),{state:"rejected",tier:i,failedGate:n.id,diagnostics:d(`output left requested ${o.length===1?"property":"properties"} at the baseline value: ${o.join(", ")}`)}}e.onGateResult?.(n.id,"pass",s)}}c(k,"gateFallbackOutput");function S(e){return e==="remove"?[f,l,p({mode:"absent"})]:[f,l,p({mode:"present"}),b,E,G]}c(S,"gatesForOp");function j(e){switch(e.kind){case"ParseError":return`output does not parse: ${e.message}`;case"ControlFlowClassifierError":return`output moved ${e.resource.type} "${e.resource.name}" out of top-level scope (${e.reason})`;case"ResourceNotFoundError":return`${e.type} "${e.name}" is missing from the output`;case"DuplicateResourceError":return`${e.type} "${e.name}" is still present in the output`;case"TemplateLiteralNameError":return`output names the resource with a template literal (line ${String(e.line)})`;case"InvalidPropertyError":return`property \`${e.property}\`: ${e.reason}`;case"DriftConflictError":{const t=e.deltas.filter(i=>i.verdict==="conflict").map(i=>`\`${i.property}\``).join(", ");return`output conflicts with the requested properties on ${e.resource.type} "${e.resource.name}"`+(t.length>0?` (${t})`:"")}case"SemanticQueryError":return`output could not be analysed: ${e.reason}`;default:return e.kind}}c(j,"describeGateError");export{k as gateFallbackOutput};
|
|
@@ -38,11 +38,10 @@ export interface StatementTypeEntry {
|
|
|
38
38
|
* convenience: a guarded type's required plan keys are exactly the
|
|
39
39
|
* scaffold-consumed keys its own guard REFUSES to write
|
|
40
40
|
* (`compute.needsConnection` is required by the plan schema and
|
|
41
|
-
* `silentlyDropped` by the guard
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* XOR test pins the pairing.
|
|
41
|
+
* `silentlyDropped` by the guard), so demanding them at the gate would be
|
|
42
|
+
* a catch-22 no invocation could satisfy. When an increment lands a
|
|
43
|
+
* type's projection and deletes its guard table, declare `addContract` in
|
|
44
|
+
* the same edit — the schema-gate XOR test pins the pairing.
|
|
46
45
|
*
|
|
47
46
|
* Absent = the schema gate applies `schemaFragment` to adds too
|
|
48
47
|
* (unknown-key and per-key-shape checks only, no required demand).
|
|
@@ -88,10 +87,10 @@ export interface StatementTypeEntry {
|
|
|
88
87
|
* ONLY for types the plan→construct projection cannot describe. Where it
|
|
89
88
|
* can (`src/projection/tables.ts`), the disagreement is TRANSLATED at
|
|
90
89
|
* emission and no rule belongs here — `emitProjection.ts` reports what is
|
|
91
|
-
* left from the projection's own `unprojectable` list
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* state.
|
|
90
|
+
* left from the projection's own `unprojectable` list, and a single live
|
|
91
|
+
* sibling binding is now expressible through a `live` rule (`cdn`'s
|
|
92
|
+
* origin). What survives is `compute`'s connection expansion (more than
|
|
93
|
+
* one statement) and cross-key conditions no per-key table can state.
|
|
95
94
|
*
|
|
96
95
|
* Rules cover exactly two classes, and nothing else:
|
|
97
96
|
*
|
|
@@ -120,6 +119,42 @@ export interface StatementTypeEntry {
|
|
|
120
119
|
* both.
|
|
121
120
|
*/
|
|
122
121
|
emitGuard?: ReadonlyArray<EmitGuardRule>;
|
|
122
|
+
/**
|
|
123
|
+
* Per-type derivation of the factory call's FIRST ARGUMENT — the construct
|
|
124
|
+
* id — where it must not be the resource name verbatim.
|
|
125
|
+
*
|
|
126
|
+
* Declared only for `pattern`, and it exists because the verbatim identity
|
|
127
|
+
* was synth-fatal there: a pattern construct hands `props.name` on to its
|
|
128
|
+
* children as construct ids — `StaticSite` materialises its internal Cdn
|
|
129
|
+
* via `this.app.addCdn(CdnFactory.build(this.props.name, cdnProps))`
|
|
130
|
+
* (components/infrastructure `staticSite.ts:274`, `createCdn`) — and a
|
|
131
|
+
* staticsite's placement is the SAME cdn stack the pattern construct
|
|
132
|
+
* occupies, so `build("Site", { name: "Site", … })` registered the id
|
|
133
|
+
* "Site" twice in one scope and died at synth with `There is already a
|
|
134
|
+
* Construct with name 'Site'`. The scaffold never had the problem because
|
|
135
|
+
* it splits the two identities: construct id `patternConstructId(name,
|
|
136
|
+
* type)` (`@fjall/util`, the ONE shared derivation — the scaffold's
|
|
137
|
+
* `generatePatternCodeWithComments` and both halves below consume it, so
|
|
138
|
+
* the emit/locate contract cannot drift site-by-site), `name` prop the
|
|
139
|
+
* kebab workload name. `emitConstructId` adopts that convention for the
|
|
140
|
+
* codemod's emission.
|
|
141
|
+
*
|
|
142
|
+
* `locateCandidates` is the read half of the same contract: `--name Site`
|
|
143
|
+
* must keep addressing a hand-written `build("Site", …)` (raw name FIRST —
|
|
144
|
+
* the legacy bare shape is pinned) and gain the scaffold-idiom
|
|
145
|
+
* `build("SiteStaticSite", …)` forms. Candidates derive from the FULL
|
|
146
|
+
* pattern registry, not the deployable subset, so a scaffold-emitted
|
|
147
|
+
* nextjs statement stays addressable for modify/remove. A lookup whose
|
|
148
|
+
* candidates match statements under more than one id is ambiguous and
|
|
149
|
+
* refuses — never silently picks one.
|
|
150
|
+
*
|
|
151
|
+
* Absent = both identities are the resource name, which is every other
|
|
152
|
+
* type's contract.
|
|
153
|
+
*/
|
|
154
|
+
statementIdentity?: {
|
|
155
|
+
emitConstructId: (name: string, properties: Readonly<Record<string, unknown>>) => string;
|
|
156
|
+
locateCandidates: (name: string) => string[];
|
|
157
|
+
};
|
|
123
158
|
}
|
|
124
159
|
export declare const FACTORY_IDENTIFIERS: {
|
|
125
160
|
readonly database: "DatabaseFactory";
|
|
@@ -146,4 +181,17 @@ export declare const STATEMENT_REGISTRY: Record<StatementType, StatementTypeEntr
|
|
|
146
181
|
* the key set derive it from here rather than re-listing the literals.
|
|
147
182
|
*/
|
|
148
183
|
export declare const REGISTERED_STATEMENT_TYPES: ReadonlyArray<StatementType>;
|
|
184
|
+
/**
|
|
185
|
+
* The construct id the ADD path writes as the factory's first argument:
|
|
186
|
+
* the type's `statementIdentity` derivation where one is declared, the
|
|
187
|
+
* resource name verbatim everywhere else.
|
|
188
|
+
*/
|
|
189
|
+
export declare function constructIdFor(type: StatementType, name: string, properties: Readonly<Record<string, unknown>>): string;
|
|
190
|
+
/**
|
|
191
|
+
* Every factory first argument a `--name` lookup for `name` may address,
|
|
192
|
+
* raw name first. The single source every locate site matches against —
|
|
193
|
+
* a site comparing `=== name` instead silently loses the scaffold-idiom
|
|
194
|
+
* statements `statementIdentity` types emit.
|
|
195
|
+
*/
|
|
196
|
+
export declare function locateNamesFor(type: StatementType, name: string): string[];
|
|
149
197
|
export declare function findTypeByIdentifier(identifier: string): StatementType | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var _=Object.defineProperty;var a=(e,t)=>_(e,"name",{value:t,configurable:!0});import{DEPLOYABLE_PATTERN_TYPES as w,PATTERN_TYPE_VALUES as x,isPatternType as M,patternConstructId as l}from"@fjall/util";import{z as d}from"zod";import{BuildkitePropsObjectSchema as h,CDNResourcePlanSchema as y,ComputeResourcePlanSchema as I,CrossPlanConnectionResourcePlanSchema as g,DatabaseResourcePlanSchema as f,NetworkResourcePlanSchema as S,NextJSPatternConfigSchema as O,OrganisationResourcePlanSchema as C,PayloadPatternConfigSchema as D,S3ResourcePlanSchema as P,SQSResourcePlanSchema as b,StaticSitePatternConfigSchema as W,VpcPeerAccepterResourcePlanSchema as E,VpcPeerResourcePlanSchema as L}from"../schemas/index.js";import{failure as j}from"../types/Result.js";import{requiresLiveValue as A,silentlyDropped as c,UNRESOLVED as G,whenAbsent as F}from"./emitGuard.js";const r={database:"DatabaseFactory",storage:"StorageFactory",compute:"ComputeFactory",messaging:"MessagingFactory",cdn:"CdnFactory",network:"NetworkFactory",pattern:"PatternFactory","vpc-peer":"VpcPeerFactory","vpc-peer-accepter":"VpcPeerAccepterFactory","cross-plan-connection":"CrossPlanConnectionFactory",organisation:"OrganisationFactory",buildkite:"BuildkiteFactory"};function s(e){const{name:t,...n}=e.shape;return d.object(n).partial().strict()}a(s,"fragmentOf");function i(e){const{name:t,...n}=e.shape;return d.object(n).strict()}a(i,"completeFragmentOf");const V=s(f),B=s(P),Y=(()=>{const{name:e,...t}=I.shape;return d.object(t).partial().strict()})(),q=s(b),K=s(y),U=s(S),T=(()=>{const{name:e,type:t,cdn:n,...k}=D.shape,{name:se,type:ie,cdn:de,...v}=O.shape,{name:pe,type:me,domain:ue,cdn:N,...R}=W.shape;return{...k,...v,...R,cdn:d.union([n,N]),type:d.enum(w)}})(),z=d.object(T).partial().strict(),Q=d.object(T).partial().required({type:!0}).strict(),$={emitConstructId:a((e,t)=>M(t.type)?l(e,t.type):e,"emitConstructId"),locateCandidates:a(e=>[e,...x.map(t=>l(e,t))],"locateCandidates")},J=s(L),H=s(E),X=s(g),Z=s(C),ee=s(h);function u(e,t){return j({kind:"SemanticQueryError",reason:`StatementTypeEntry.${e} for ${t} is not wired; existing types dispatch through the shared locator/generator.`})}a(u,"notWiredError");function te(e){return{factoryIdentifier:e,findByShape:a(()=>u("locator.findByShape",e),"findByShape"),validateContext:a(()=>u("locator.validateContext",e),"validateContext")}}a(te,"createLocator");function ae(e){return{build:a(()=>{const t=u("generator.build",e);throw new Error(t.success?"unreachable":t.error.reason)},"build")}}a(ae,"createGenerator");const ne=c("variableName","`variableName` is a plan-only round-trip key naming the `const <var> =` binding the scaffold emits; no construct reads it."),re=c("extraProperties","`extraProperties` is a plan-only round-trip key: the scaffold flattens each `{ key, sourceText }` entry into a sibling property, and no construct reads the array."),m="the connection keys are scaffold inputs, not construct props: the scaffold expands them into environment variables and a `connections: [...]` array, and the compute constructs read none of them.",oe=[{property:"deployment",refuseWhen:a(e=>(e.type==="lambda"||e.deployment!==void 0)&&e.deployment!=="container"&&e.code!==G,"refuseWhen"),reason:"a code-deployed Lambda requires `code: Code`, a CDK object built by `Code.fromAsset(...)` that no flag value can carry, so the statement takes the whole app's synth down with `Cannot read properties of undefined (reading 'bind')` \u2014 naming no resource. Use `--deployment container`, which is fully expressible, or write this compute in infrastructure.ts by hand."},c("codePath","`codePath` is the scaffold's input to `Code.fromAsset(...)`; no compute construct reads it, and a container Lambda takes its code from the image."),A("runtime","the construct expects a CDK `Runtime`, not a version string, and a container Lambda takes its runtime from the image (`Runtime.FROM_IMAGE`) regardless."),A("architecture","the construct expects a CDK `Architecture`, not a string: `--architecture ARM_64` emits an EMPTY `Architectures` list, whereas omitting the flag emits the correct default."),c("memory","the Lambda construct reads `memorySize`, so `--memory 1024` deploys a function at the 128 MB default."),c("ssmSecrets","the Lambda construct reads `secrets`, so `--ssmSecrets` deploys a function with no SSM wiring and no secrets environment at all."),c("scheduleExpression","`scheduleExpression` is not a compute prop: the scaffold turns it into a SEPARATE `app.addSchedule(...)` statement, which this command cannot emit."),c("needsConnection",m),c("connectedDatabase",m),c("connectedStorage",m),c("connectedMessaging",m),ne,re],ce=[{property:"peerAppName",refuseWhen:F("peerAppName"),reason:"`peerAppName` is required: it is the SSM prefix every remote lookup is built from, and omitting it does NOT fail \u2014 synth succeeds and the app deploys a peering connection pointed at `/fjall/default/undefined/vpc-id`. Pass `--peerAppName <remote app>`."},{property:"peerAccountId",refuseWhen:F("peerAccountId"),reason:"`peerAccountId` is required: omitting it does NOT fail, it deploys a VPC peering connection with no `PeerOwnerId`. Pass `--peerAccountId <12-digit account>`."}];function o(e,t,n={}){return{factoryIdentifier:e,locator:te(e),generator:ae(e),schemaFragment:t,...n}}a(o,"createEntry");const p={database:o(r.database,V,{emitWrapper:{appMethod:"addDatabase"},addContract:i(f)}),storage:o(r.storage,B,{emitWrapper:{appMethod:"addStorage"},addContract:i(P)}),compute:o(r.compute,Y,{emitWrapper:{appMethod:"addCompute"},emitGuard:oe}),messaging:o(r.messaging,q,{emitWrapper:{appMethod:"addMessaging"},addContract:i(b)}),cdn:o(r.cdn,K,{emitWrapper:{appMethod:"addCdn"},addContract:i(y)}),network:o(r.network,U,{emitWrapper:{appMethod:"addNetwork"},addContract:i(S)}),pattern:o(r.pattern,z,{emitWrapper:{appMethod:"addPattern"},addContract:Q,statementIdentity:$}),"vpc-peer":o(r["vpc-peer"],J,{emitWrapper:{appMethod:"addVpcPeer"},emitGuard:ce}),"vpc-peer-accepter":o(r["vpc-peer-accepter"],H,{emitWrapper:{appMethod:"addVpcPeerAccepter"},addContract:i(E)}),"cross-plan-connection":o(r["cross-plan-connection"],X,{addContract:i(g)}),organisation:o(r.organisation,Z,{addContract:i(C)}),buildkite:o(r.buildkite,ee,{emitWrapper:{appMethod:"addBuildkite",propsOverloadConstructId:"Buildkite"},addContract:i(h)})},Ce=Object.keys(p);function Pe(e,t,n){return p[e].statementIdentity?.emitConstructId(t,n)??t}a(Pe,"constructIdFor");function be(e,t){return p[e].statementIdentity?.locateCandidates(t)??[t]}a(be,"locateNamesFor");function Ee(e){const t=Object.keys(p);for(const n of t)if(p[n].factoryIdentifier===e)return n}a(Ee,"findTypeByIdentifier");export{r as FACTORY_IDENTIFIERS,Ce as REGISTERED_STATEMENT_TYPES,p as STATEMENT_REGISTRY,Pe as constructIdFor,Ee as findTypeByIdentifier,be as locateNamesFor};
|
|
@@ -5,10 +5,17 @@ export type { NodeLocation, StatementType } from "../types.js";
|
|
|
5
5
|
export type LocateByShapeError = TemplateLiteralNameError | SemanticQueryError;
|
|
6
6
|
/**
|
|
7
7
|
* Locates a single `XFactory.build("Name", ...)` call matching the
|
|
8
|
-
* supplied `{ type, name }` query.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* supplied `{ type, name }` query. The name is matched against the
|
|
9
|
+
* registry's identity candidates (`locateNamesFor`) — the raw name plus,
|
|
10
|
+
* for `statementIdentity` types, every scaffold-idiom suffixed form — so
|
|
11
|
+
* `--name Site` addresses a hand-written `build("Site", …)` AND a
|
|
12
|
+
* scaffold-shaped `build("SiteStaticSite", …)`. Returns
|
|
13
|
+
* `success(undefined)` when the file contains no matching call; returns
|
|
14
|
+
* `failure(...)` for template-literal factory names (Joint 1 rejection),
|
|
15
|
+
* a genuine semantic-query error from ts-morph, or an AMBIGUOUS lookup —
|
|
16
|
+
* candidates matching statements under more than one construct id refuse
|
|
17
|
+
* rather than silently picking one. Repeated statements under ONE id keep
|
|
18
|
+
* the long-standing first-match resolution.
|
|
12
19
|
*/
|
|
13
20
|
export declare function locateByShape(content: string, query: {
|
|
14
21
|
type: StatementType;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var S=Object.defineProperty;var c=(r,e)=>S(r,"name",{value:e,configurable:!0});import{Node as d,SyntaxKind as s}from"ts-morph";import{failure as u,success as f}from"../../types/Result.js";import{DEFAULT_FILE_PATH as m}from"../_internal.js";import{findTypeByIdentifier as T,locateNamesFor as x,STATEMENT_REGISTRY as A}from"../registry.js";import{getProject as N}from"./projectCache.js";function $(r,e,t=m){const a=w(r,t);if(!a.success)return a;const n=x(e.type,e.name),i=a.data.filter(l=>l.type===e.type&&n.includes(l.symbolName)),o=[...new Set(i.map(l=>l.symbolName))];if(o.length>1){const h=o.includes(e.name)?`The raw id "${e.name}" is shadowed by its own suffixed twin, so no \`--name\` query can single it out \u2014 rename one of the two statements by hand in infrastructure.ts to disambiguate.`:"Rename or remove one of them, or target the exact construct id.";return u({kind:"SemanticQueryError",reason:`"${e.name}" matches more than one ${e.type} statement in this file (${o.map(E=>`"${E}"`).join(", ")}); the engine will not pick one. ${h}`})}return f(i[0])}c($,"locateByShape");function w(r,e=m){const t=[],a=b(r,e,n=>{t.push({filePath:e,start:n.nameStart,length:n.nameLength,symbolName:n.name,type:n.type})},n=>{t.push({filePath:e,start:n.methodStart,length:n.methodLength,symbolName:n.name,type:n.type,managed:!1})});return a.success?f(t):a}c(w,"locateAllShapes");function b(r,e,t,a){let n;try{n=N().createSourceFile(e,r,{overwrite:!0})}catch(i){return u({kind:"SemanticQueryError",reason:"Failed to create source file",cause:i})}try{n.forEachDescendant(i=>{if(!d.isCallExpression(i))return;const o=L(i);if(o==="not-factory-call"){if(a!==void 0){const l=F(i);l!==void 0&&a(l,i)}return}if(o.kind!=="binding-pattern-declared"){if(o.kind==="template-literal-name")throw new y(i,o.type);t({type:o.type,name:o.name,nameStart:o.nameStart,nameLength:o.nameLength},i)}})}catch(i){return i instanceof y?u(i.toError(e)):u({kind:"SemanticQueryError",reason:"forEachDescendant traversal failed",cause:i})}return f(void 0)}c(b,"forEachFactoryMatch");function L(r){const e=r.getExpression();if(!d.isPropertyAccessExpression(e))return"not-factory-call";const t=p(e);if(t===void 0||g(r))return"not-factory-call";if(I(r))return{kind:"binding-pattern-declared"};const n=r.getArguments()[0];return n===void 0?"not-factory-call":d.isTemplateExpression(n)||d.isNoSubstitutionTemplateLiteral(n)?{kind:"template-literal-name",type:t}:d.isStringLiteral(n)?{kind:"match",type:t,name:n.getLiteralValue(),nameStart:n.getStart(),nameLength:n.getWidth()}:"not-factory-call"}c(L,"classifyFactoryCall");const k=new Map(Object.entries(A).flatMap(([r,e])=>{const t=e.emitWrapper?.propsOverloadConstructId;return e.emitWrapper===void 0||t===void 0?[]:[[e.emitWrapper.appMethod,{type:r,name:t}]]}));function F(r){const e=r.getExpression();if(!d.isPropertyAccessExpression(e))return;const t=k.get(e.getName());if(t===void 0||g(r))return;const a=r.getArguments()[0];if(a!==void 0&&d.isCallExpression(a)){const i=a.getExpression();if(d.isPropertyAccessExpression(i)&&p(i)!==void 0)return}const n=e.getNameNode();return{type:t.type,name:t.name,methodStart:n.getStart(),methodLength:n.getWidth()}}c(F,"classifyUnmanagedMethodCall");function p(r){const e=r.getExpression();if(d.isIdentifier(e)&&r.getName()==="build")return T(e.getText())}c(p,"factoryTypeFromPropertyAccess");function g(r){let e=r.getParent();for(;e!==void 0;){const t=e.getKind();if(t===s.TypeReference||t===s.TypeQuery||t===s.TypeLiteral||t===s.TypeAliasDeclaration||t===s.InterfaceDeclaration||t===s.TypeParameter||t===s.PropertySignature||t===s.MethodSignature||t===s.JsxOpeningElement||t===s.JsxClosingElement||t===s.JsxSelfClosingElement||t===s.JsxAttribute)return!0;e=e.getParent()}return!1}c(g,"isInsideTypeSpace");function I(r){const e=r.getFirstAncestorByKind(s.VariableDeclaration);if(e===void 0)return!1;const a=e.getNameNode().getKind();return a===s.ObjectBindingPattern||a===s.ArrayBindingPattern}c(I,"isInsideBindingPattern");class y extends Error{static{c(this,"TemplateLiteralMarker")}call;type;constructor(e,t){super("Template-literal factory name detected"),this.call=e,this.type=t,this.name="TemplateLiteralMarker"}toError(e){const a=this.call.getArguments()[0]?.getStart()??this.call.getStart(),n=this.call.getSourceFile(),{line:i,column:o}=n.getLineAndColumnAtPos(a);return{kind:"TemplateLiteralNameError",file:e,line:i,column:o,suggestion:"Replace the template literal with a plain string literal so the resource name can be resolved statically."}}}export{b as forEachFactoryMatch,w as locateAllShapes,$ as locateByShape};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var h=Object.defineProperty;var c=(n,t)=>h(n,"name",{value:t,configurable:!0});import{failure as u,success as a}from"../../../types/Result.js";import{isProjectableType as v,TYPE_PROJECTIONS as b}from"../../../projection/index.js";import{extractProgramBody as g}from"../../_internal.js";import{findConfigObject as j}from"../../drift/snapshot.js";import{astToLiteral as N,isNodeShape as P,NON_LITERAL as O,readKeyName as y}from"../../edits/modifyResource/literalConversion.js";import{parse as T}from"../../fileRewriter/parse.js";import{constructIdFor as $,STATEMENT_REGISTRY as k}from"../../registry.js";import{locateByShape as E}from"../../semanticIndex/locateByShape.js";function S(n){if(!v(n))return[];const t=b[n].keys??{};return Object.entries(t).flatMap(([e,r])=>r.kind==="live"?[{planKey:e,constructKey:r.as??e,reason:r.reason}]:[])}c(S,"liveConstructKeys");function m(n){return a({action:"reject",diagnostics:n})}c(m,"rejectOutcome");const q={id:"projection",run(n){const{type:t,name:e,op:r}=n.plan,o=S(t),f=r==="add"&&k[t].statementIdentity!==void 0;if(o.length===0&&!f)return a({action:"proceed"});const s=I(n);if(!s.success)return s;if(s.data===void 0)return m(`could not resolve the emitted config object for ${t} "${e}"; the output cannot be verified against the projection contract`);const{symbolName:p,configObject:l}=s.data;for(const d of o){const i=K(l,d.constructKey);if(i!==void 0&&(i.type==="StringLiteral"||i.type==="TemplateLiteral"))return u({kind:"InvalidPropertyError",property:d.constructKey,reason:`the ${t} construct reads a live binding here and the output wrote a ${i.type==="StringLiteral"?"string":"template"} literal; ${d.reason}`})}if(f){const d=L(l),i=$(t,e,d);if(p!==i)return m(`output writes construct id "${p}" where the ${t} identity derivation for "${e}" requires "${i}" \u2014 an id the deterministic lane never emits (the type declares an identity precisely because non-derived ids collide or go unaddressable at synth)`)}return a({action:"proceed"})}};function I(n){const t=E(n.content,{type:n.plan.type,name:n.plan.name});if(!t.success)return u(t.error);if(t.data===void 0)return a(void 0);const e=T(n.content,t.data.filePath);if(!e.success)return u(e.error);const r=g(e.data);if(r===void 0)return a(void 0);const o=j(r,{start:t.data.start,length:t.data.length});return o===void 0?a(void 0):a({symbolName:t.data.symbolName,configObject:o})}c(I,"locateEmittedStatement");function K(n,t){for(const e of n.properties)if(!(e.type!=="Property"&&e.type!=="ObjectProperty")&&!(e.shorthand===!0||e.computed===!0)&&y(e.key)===t&&e.value!==void 0&&P(e.value))return e.value}c(K,"readPropertyValueNode");function L(n){const t={};for(const e of n.properties){if(e.type!=="Property"&&e.type!=="ObjectProperty"||e.shorthand===!0||e.computed===!0)continue;const r=y(e.key);if(r===void 0||e.value===void 0)continue;const o=N(e.value);o!==O&&(t[r]=o)}return t}c(L,"literalPropertiesOf");export{q as projectionGate};
|
|
@@ -4,3 +4,4 @@ export { schemaGate } from "./gates/schema.js";
|
|
|
4
4
|
export { parseGate } from "./gates/parse.js";
|
|
5
5
|
export { createLocateGate, locateGate, type LocateGateOptions, type LocateMode, } from "./gates/locate.js";
|
|
6
6
|
export { classifyGate } from "./gates/classify.js";
|
|
7
|
+
export { projectionGate } from "./gates/projection.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{runPipeline as t,runPipelineAsync as o}from"./types.js";import{driftGate as p}from"./gates/drift.js";import{schemaGate as m}from"./gates/schema.js";import{parseGate as i}from"./gates/parse.js";import{createLocateGate as G,locateGate as n}from"./gates/locate.js";import{classifyGate as l}from"./gates/classify.js";export{l as classifyGate,G as createLocateGate,p as driftGate,n as locateGate,i as parseGate,t as runPipeline,o as runPipelineAsync,m as schemaGate};
|
|
1
|
+
import{runPipeline as t,runPipelineAsync as o}from"./types.js";import{driftGate as p}from"./gates/drift.js";import{schemaGate as m}from"./gates/schema.js";import{parseGate as i}from"./gates/parse.js";import{createLocateGate as G,locateGate as n}from"./gates/locate.js";import{classifyGate as l}from"./gates/classify.js";import{projectionGate as y}from"./gates/projection.js";export{l as classifyGate,G as createLocateGate,p as driftGate,n as locateGate,i as parseGate,y as projectionGate,t as runPipeline,o as runPipelineAsync,m as schemaGate};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Result } from "../../types/Result.js";
|
|
2
2
|
import type { DriftOp, DriftPolicy, DriftState, ResourceSnapshot } from "../drift/index.js";
|
|
3
3
|
import type { CodemodError, ResourceName, StatementType } from "../types.js";
|
|
4
|
-
export type GateId = "parse" | "tsc" | "classify" | "locate" | "schema" | "drift" | "runtime";
|
|
4
|
+
export type GateId = "parse" | "tsc" | "classify" | "locate" | "projection" | "schema" | "drift" | "runtime";
|
|
5
5
|
export type GateAction = "proceed" | "skip" | "reject";
|
|
6
6
|
export interface GateContext {
|
|
7
7
|
content: string;
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
var f=Object.defineProperty;var r=(n,e)=>f(n,"name",{value:e,configurable:!0});import{
|
|
1
|
+
var f=Object.defineProperty;var r=(n,e)=>f(n,"name",{value:e,configurable:!0});import{formatValue as l}from"./common.js";import{patternConstructId as $}from"@fjall/util";const m=Object.freeze({database:{type:"Instance",backupRetention:7,deletionProtection:!0},compute:{server:{memorySize:1536,timeout:30},imageOptimisation:{memorySize:1536,timeout:30},revalidation:{memorySize:768,timeout:300}}});function c(n,e,t){return e===void 0?"":`
|
|
2
2
|
${t}${n}: ${e},`}r(c,"emitScalar");function s(n,e,t){return e===void 0?"":`
|
|
3
|
-
${t}${n}: ${JSON.stringify(e)},`}r(s,"emitStringField");function
|
|
3
|
+
${t}${n}: ${JSON.stringify(e)},`}r(s,"emitStringField");function d(n,e,t){return e===void 0?"":e===!1?`
|
|
4
4
|
${t}${n}: false,`:`
|
|
5
|
-
${t}${n}: ${l(e,t)},`}r(
|
|
6
|
-
${t}${n}: ${l(e,t)},`}r(a,"emitObject");function
|
|
7
|
-
${t}type: "${
|
|
8
|
-
${t}backupRetention: ${
|
|
9
|
-
${t}deletionProtection: ${p},`,i+=c("publiclyAccessible",e.publiclyAccessible,t),i+=s("allowedIpCidr",e.allowedIpCidr,t),i+=c("multiAz",e.multiAz,t),i+=c("allowVpcAccess",e.allowVpcAccess,t),i+=c("monitoringInterval",e.monitoringInterval,t),i+=s("preferredMaintenanceWindow",e.preferredMaintenanceWindow,t),i+=s("snapshotIdentifier",e.snapshotIdentifier,t),i+=s("snapshotUsername",e.snapshotUsername,t),i+=
|
|
5
|
+
${t}${n}: ${l(e,t)},`}r(d,"emitObjectOrFalse");function a(n,e,t){return e===void 0||Object.keys(e).length===0?"":`
|
|
6
|
+
${t}${n}: ${l(e,t)},`}r(a,"emitObject");function b(n){const e=n??{},t=" ",o=e.type??m.database.type,u=e.backupRetention??m.database.backupRetention,p=e.deletionProtection??m.database.deletionProtection;let i=`
|
|
7
|
+
${t}type: "${o}",`;return i+=s("databaseName",e.databaseName,t),i+=s("databaseEngine",e.databaseEngine,t),o==="Instance"&&e.instanceType!==void 0&&(i+=s("instanceType",e.instanceType,t)),i+=c("allocatedStorage",e.allocatedStorage,t),i+=c("port",e.port,t),i+=`
|
|
8
|
+
${t}backupRetention: ${u},`,i+=`
|
|
9
|
+
${t}deletionProtection: ${p},`,i+=c("publiclyAccessible",e.publiclyAccessible,t),i+=s("allowedIpCidr",e.allowedIpCidr,t),i+=c("multiAz",e.multiAz,t),i+=c("allowVpcAccess",e.allowVpcAccess,t),i+=c("monitoringInterval",e.monitoringInterval,t),i+=s("preferredMaintenanceWindow",e.preferredMaintenanceWindow,t),i+=s("snapshotIdentifier",e.snapshotIdentifier,t),i+=s("snapshotUsername",e.snapshotUsername,t),i+=d("readReplica",e.readReplica,t),i+=a("writer",e.writer,t),i+=d("readers",e.readers,t),i+=d("databaseInsights",e.databaseInsights,t),i+=d("proxy",e.proxy,t),i+=a("credentials",e.credentials,t),i+=a("encryption",e.encryption,t),`
|
|
10
10
|
database: {${i}
|
|
11
|
-
},`}r(
|
|
11
|
+
},`}r(b,"emitDatabaseBlock");function g(n){const e=n??{},t=e.server?.memorySize??m.compute.server.memorySize,o=e.server?.timeout??m.compute.server.timeout,u=e.imageOptimisation?.memorySize??m.compute.imageOptimisation.memorySize,p=e.imageOptimisation?.timeout??m.compute.imageOptimisation.timeout,i=e.revalidation?.memorySize??m.compute.revalidation.memorySize,y=e.revalidation?.timeout??m.compute.revalidation.timeout;return`
|
|
12
12
|
compute: {
|
|
13
13
|
server: {
|
|
14
14
|
memorySize: ${t},
|
|
15
|
-
timeout: ${
|
|
15
|
+
timeout: ${o},
|
|
16
16
|
},
|
|
17
17
|
imageOptimisation: {
|
|
18
|
-
memorySize: ${
|
|
18
|
+
memorySize: ${u},
|
|
19
19
|
timeout: ${p},
|
|
20
20
|
},
|
|
21
21
|
revalidation: {
|
|
22
22
|
memorySize: ${i},
|
|
23
23
|
timeout: ${y},
|
|
24
24
|
},
|
|
25
|
-
},`}r(
|
|
26
|
-
${e}domain: ${JSON.stringify(n.domain)},`),t+=a("forms",n.forms,e),t+=a("cdn",n.cdn,e),t}r(
|
|
27
|
-
PatternFactory.build("${
|
|
25
|
+
},`}r(g,"emitComputeBlock");function S(n){return a("storage",n," ")}r(S,"emitStorageBlock");function v(n){return a("messaging",n," ")}r(v,"emitMessagingBlock");function z(n){return a("cdn",n," ")}r(z,"emitCdnBlock");function O(n){return a("environment",n," ")}r(O,"emitEnvironmentBlock");function I(n){const e=" ";let t="";return t+=s("source",n.source,e),t+=a("build",n.build,e),t+=s("routing",n.routing,e),t+=a("security",n.security,e),n.domain!==void 0&&n.domain!==""&&(t+=`
|
|
26
|
+
${e}domain: ${JSON.stringify(n.domain)},`),t+=a("forms",n.forms,e),t+=a("cdn",n.cdn,e),t}r(I,"emitStaticSiteFields");function T(n){if(!n.patternConfig)return"";const e=n.patternConfig;let o=`app.addPattern(
|
|
27
|
+
PatternFactory.build("${$(e.name,e.type)}", {
|
|
28
28
|
type: "${e.type}",
|
|
29
29
|
name: "${e.name}",`;return e.type==="payload"||e.type==="nextjs"?(e.domain!==void 0&&e.domain!==""&&(o+=`
|
|
30
|
-
domain: "${e.domain}",`),o+=
|
|
30
|
+
domain: "${e.domain}",`),o+=b(e.database),o+=g(e.compute),o+=S(e.storage),o+=v(e.messaging),o+=z(e.cdn),o+=O(e.environment)):o+=I(e),o+=`
|
|
31
31
|
})
|
|
32
32
|
);
|
|
33
33
|
|
|
34
|
-
`,o}r(
|
|
34
|
+
`,o}r(T,"generatePatternCodeWithComments");export{m as OPENNEXT_DEFAULTS,T as generatePatternCodeWithComments};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { projectPlanToConstructProps } from "./project.js";
|
|
2
2
|
export { isProjectableType, TYPE_PROJECTIONS, type ProjectableType, } from "./tables.js";
|
|
3
|
-
export type { PlanKeyRule, Projection, ProjectionContext, ProjectedProp, ProjectedValue, TypeProjection, UnprojectableProp, } from "./types.js";
|
|
3
|
+
export type { PlanKeyRule, Projection, ProjectionContext, ProjectedProp, ProjectedValue, TypeProjection, UnprojectableKind, UnprojectableProp, } from "./types.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var k=Object.defineProperty;var f=(
|
|
1
|
+
var k=Object.defineProperty;var f=(r,u)=>k(r,"name",{value:u,configurable:!0});import{TYPE_PROJECTIONS as y}from"./tables.js";function b(r,u,a={}){const o=y[r],i=[];let p=[];if(a.editingExisting!==!0)if(typeof o.constants=="function"){const n=o.constants(a);p=n.props,i.push(...n.unprojectable.map(s=>({...s,kind:s.kind??"missing-context"})))}else p=o.constants??[];const c=new Map(p.map(n=>[n.key,n]));for(const[n,s]of Object.entries(u)){if(s===void 0)continue;const e=o.keys?.[n];if(e===void 0||e.kind==="prop"){const t=e?.as??n;c.set(t,{key:t,value:{kind:"literal",value:s}});continue}if(e.kind==="transform"){const t=e.as??n;c.set(t,{key:t,value:{kind:"literal",value:e.apply(s)}});continue}if(e.kind==="planOnly"){i.push({key:n,reason:e.reason,kind:"plan-only"});continue}const d=e.bind(s,a);if(d===void 0){i.push({key:n,reason:e.reason,kind:"unresolved-binding"});continue}const l=e.as??n;c.set(l,{key:l,value:{kind:"expression",source:d}})}return{props:[...c.values()],unprojectable:i}}f(b,"projectPlanToConstructProps");export{b as projectPlanToConstructProps};
|
|
@@ -12,14 +12,13 @@
|
|
|
12
12
|
* `extraProperties` (round-trip preservation the scaffold flattens into
|
|
13
13
|
* sibling properties). Neither is a construct prop anywhere.
|
|
14
14
|
*
|
|
15
|
-
* `compute
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* never both.
|
|
15
|
+
* `compute` and `vpc-peer` are deliberately ABSENT. A compute's four
|
|
16
|
+
* connection keys expand into environment variables plus a whole second
|
|
17
|
+
* statement (`app.addSchedule(...)`) — more than one statement is beyond
|
|
18
|
+
* what a projection can emit, so it keeps its `emitGuard` table and a type
|
|
19
|
+
* is projected or guarded, never both. `vpc-peer`'s rules are required-key
|
|
20
|
+
* conditions whose absence deploys silently wrong infrastructure — guard
|
|
21
|
+
* territory, not vocabulary.
|
|
23
22
|
*/
|
|
24
23
|
import type { TypeProjection } from "./types.js";
|
|
25
24
|
export declare const TYPE_PROJECTIONS: {
|
|
@@ -27,6 +26,8 @@ export declare const TYPE_PROJECTIONS: {
|
|
|
27
26
|
readonly storage: TypeProjection;
|
|
28
27
|
readonly database: TypeProjection;
|
|
29
28
|
readonly network: TypeProjection;
|
|
29
|
+
readonly pattern: TypeProjection;
|
|
30
|
+
readonly cdn: TypeProjection;
|
|
30
31
|
};
|
|
31
32
|
export type ProjectableType = keyof typeof TYPE_PROJECTIONS;
|
|
32
33
|
export declare function isProjectableType(value: string): value is ProjectableType;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var s=Object.defineProperty;var
|
|
1
|
+
var s=Object.defineProperty;var n=(e,r)=>s(e,"name",{value:r,configurable:!0});import{toKebab as i}from"@fjall/util";const o={kind:"planOnly",reason:"`variableName` is a plan-only round-trip key naming the `const <var> =` binding the scaffold emits; no construct reads it."},t={kind:"planOnly",reason:"`extraProperties` is a plan-only round-trip key: the scaffold flattens each `{ key, sourceText }` entry into a sibling property, and no construct reads the array."},a={variableName:o,extraProperties:t},l={constants:[{key:"type",value:{kind:"literal",value:"queue"}}],keys:{retentionPeriod:{kind:"prop",as:"messageRetentionPeriod"},...a}},d={keys:{...a}},p={keys:{engineExpression:{kind:"planOnly",reason:"`engineExpression` carries a raw CDK engine expression for the scaffold to inline; the construct reads `databaseEngine` instead, so a cluster pinned to `DatabaseClusterEngine.auroraMysql(...)` still deploys as aurora-postgresql."},...a}},c={keys:{...a}},u={constants:n(e=>e.resourceName!==void 0?{props:[{key:"name",value:{kind:"literal",value:i(e.resourceName)}}],unprojectable:[]}:{props:[],unprojectable:[{key:"name",reason:"every pattern construct reads a `name` prop (`toPascalCase(props.name)` names its child constructs), and this caller supplied no resource name to derive it from."}]},"constants")},y={constants:[{key:"originType",value:{kind:"literal",value:"auto"}}],keys:{defaultOriginRef:{kind:"live",as:"origin",reason:"`defaultOriginRef` names a planned sibling resource and the construct reads a live `origin` binding in its place; no unique storage or compute binding for that name could be resolved in this file, and writing the name as a string would deploy a distribution treating it as an HTTP origin domain.",bind:n((e,r)=>typeof e=="string"?r.resolveBinding?.(e):void 0,"bind")},customDomain:{kind:"transform",as:"domainNames",apply:n(e=>[e],"apply")},behaviours:{kind:"planOnly",reason:"each `behaviours[].originRef` names a live origin PER ELEMENT, and a single-value binding cannot reach inside an array literal; the plan shape throws `Cannot read properties of undefined (reading 'computeType')` at synth."},extraProperties:t}},g={messaging:l,storage:d,database:p,network:c,pattern:u,cdn:y};function b(e){return Object.prototype.hasOwnProperty.call(g,e)}n(b,"isProjectableType");export{g as TYPE_PROJECTIONS,b as isProjectableType};
|
|
@@ -35,15 +35,34 @@ export interface ProjectedProp {
|
|
|
35
35
|
key: string;
|
|
36
36
|
value: ProjectedValue;
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Why a plan key failed to project — three distinct classes with three
|
|
40
|
+
* distinct consequences, which is why the refusal composer needs to know:
|
|
41
|
+
*
|
|
42
|
+
* - `plan-only` — the key is NEVER a construct prop; writing it would put an
|
|
43
|
+
* inert key in the file and the resource would deploy without the asked-for
|
|
44
|
+
* behaviour.
|
|
45
|
+
* - `unresolved-binding` — the key IS projectable in principle (a live rule
|
|
46
|
+
* exists) but no unique live binding resolved in this file, so the
|
|
47
|
+
* statement is refused and nothing is written at all.
|
|
48
|
+
* - `missing-context` — a constants factory needed something the command
|
|
49
|
+
* context did not carry (the resource name); again nothing is written.
|
|
50
|
+
*/
|
|
51
|
+
export type UnprojectableKind = "plan-only" | "unresolved-binding" | "missing-context";
|
|
38
52
|
/**
|
|
39
53
|
* A plan key this context cannot turn into a construct prop, and why. The
|
|
40
54
|
* scaffold ignores these — it consumes such keys through its own paths. The
|
|
41
55
|
* codemod refuses the whole statement, because writing the key would either
|
|
42
56
|
* take synth down or deploy something other than what was asked for.
|
|
57
|
+
*
|
|
58
|
+
* `kind` is stamped at each construction site in `project.ts`; absent means
|
|
59
|
+
* `plan-only` (the original class, kept as the default so table-authored
|
|
60
|
+
* entries need not restate it).
|
|
43
61
|
*/
|
|
44
62
|
export interface UnprojectableProp {
|
|
45
63
|
key: string;
|
|
46
64
|
reason: string;
|
|
65
|
+
kind?: UnprojectableKind;
|
|
47
66
|
}
|
|
48
67
|
export interface Projection {
|
|
49
68
|
props: ProjectedProp[];
|
|
@@ -59,6 +78,14 @@ export interface Projection {
|
|
|
59
78
|
*/
|
|
60
79
|
export interface ProjectionContext {
|
|
61
80
|
resolveBinding?: (planResourceName: string) => string | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* The name of the resource the statement is for, when the caller has one
|
|
83
|
+
* (`fjall add` always does — it is the factory's first argument). A
|
|
84
|
+
* constants factory may derive a prop from it; a factory that needs it and
|
|
85
|
+
* finds it absent must report the prop unprojectable rather than emit a
|
|
86
|
+
* statement without it.
|
|
87
|
+
*/
|
|
88
|
+
resourceName?: string;
|
|
62
89
|
/**
|
|
63
90
|
* The fragment is an EDIT to an existing statement rather than a whole
|
|
64
91
|
* resource. Constants describe the statement, so an edit must not carry
|
|
@@ -72,6 +99,10 @@ export interface ProjectionContext {
|
|
|
72
99
|
*
|
|
73
100
|
* - `prop` — carried through as a literal, under `as` when the two
|
|
74
101
|
* vocabularies name it differently.
|
|
102
|
+
* - `transform` — carried through as a literal, but reshaped by `apply` on
|
|
103
|
+
* the way: the vocabularies disagree about the value's shape, not just the
|
|
104
|
+
* key's name (a plan `customDomain: string` is the construct's
|
|
105
|
+
* `domainNames: string[]`).
|
|
75
106
|
* - `planOnly` — never a construct prop. The scaffold consumes it (a
|
|
76
107
|
* `const <var> =` binding, flattened extra properties); anywhere else it is
|
|
77
108
|
* inert, so it is reported rather than silently dropped.
|
|
@@ -82,6 +113,10 @@ export interface ProjectionContext {
|
|
|
82
113
|
export type PlanKeyRule = {
|
|
83
114
|
kind: "prop";
|
|
84
115
|
as?: string;
|
|
116
|
+
} | {
|
|
117
|
+
kind: "transform";
|
|
118
|
+
as?: string;
|
|
119
|
+
apply: (value: unknown) => unknown;
|
|
85
120
|
} | {
|
|
86
121
|
kind: "planOnly";
|
|
87
122
|
reason: string;
|
|
@@ -96,13 +131,17 @@ export type PlanKeyRule = {
|
|
|
96
131
|
*
|
|
97
132
|
* `constants` are props every statement of the type carries no matter what
|
|
98
133
|
* the plan says — the discriminators the constructs switch on and the plan
|
|
99
|
-
* vocabulary never carried.
|
|
134
|
+
* vocabulary never carried. The static form is a fixed list; the factory
|
|
135
|
+
* form derives them from the context (a pattern's `name` prop is the
|
|
136
|
+
* resource name). A factory that cannot derive a constant from the context
|
|
137
|
+
* it was given reports it in `unprojectable` — refusing the statement is the
|
|
138
|
+
* fail-closed alternative to emitting one that throws at synth.
|
|
100
139
|
*
|
|
101
140
|
* `keys` is consulted per plan key; a key with no entry passes through under
|
|
102
141
|
* its own name, which is the common case and is why the tables stay short
|
|
103
142
|
* enough to read as the specification they are.
|
|
104
143
|
*/
|
|
105
144
|
export interface TypeProjection {
|
|
106
|
-
constants?: ProjectedProp[];
|
|
145
|
+
constants?: ProjectedProp[] | ((context: ProjectionContext) => Projection);
|
|
107
146
|
keys?: Record<string, PlanKeyRule>;
|
|
108
147
|
}
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const GENERATOR_VERSION = "
|
|
1
|
+
export declare const GENERATOR_VERSION = "14.0.0";
|
package/dist/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const E="
|
|
1
|
+
const E="14.0.0";export{E as GENERATOR_VERSION};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/generator",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "14.0.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/fjall-tech/fjall.git",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
},
|
|
58
58
|
"license": "SEE LICENSE IN LICENSE",
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@fjall/util": "^
|
|
60
|
+
"@fjall/util": "^14.0.0",
|
|
61
61
|
"ast-types": "^0.16.1",
|
|
62
62
|
"recast": "^0.23.12",
|
|
63
63
|
"ts-morph": "^28.0.0",
|