@fjall/generator 7.0.1 → 7.2.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.
@@ -9,7 +9,7 @@
9
9
  "package.json",
10
10
  "tsconfig.json"
11
11
  ],
12
- "hash": "dc18366d5eed917c10a6c7cfb1e06e959fbbce97bf3f894b34b7d9e86e14ec95",
12
+ "hash": "0baa26e2a704915b32867832ebb1fd741502646d6d1466be1ea84a7a685d901a",
13
13
  "files": {
14
14
  "src/ast/astTestHelpers.ts": "026cac849eb88bdb",
15
15
  "src/ast/domain/astDomainParser.ts": "bac0b16eb2e62552",
@@ -18,7 +18,7 @@
18
18
  "src/ast/mutation/astExpressionEvaluator.ts": "6082789268b91212",
19
19
  "src/ast/mutation/astSurgicalModification.ts": "9c512e11e8239c4d",
20
20
  "src/ast/parsers/common/astCommonParser.ts": "d4c19453e9a75cac",
21
- "src/ast/parsers/common/astStatementClassifier.ts": "b053f2ed51ec76f5",
21
+ "src/ast/parsers/common/astStatementClassifier.ts": "d5cfd1f8d5e35132",
22
22
  "src/ast/parsers/common/astStatementQueries.ts": "e40e31e0fcdc15e3",
23
23
  "src/ast/parsers/orchestrator/astInfrastructureParser.ts": "07fd7a94796ebf5f",
24
24
  "src/ast/parsers/orchestrator/astPlanConverter.ts": "eb9b1f0ab90f6999",
@@ -41,8 +41,8 @@
41
41
  "src/codemod/drift/merge.ts": "29093929befa9abd",
42
42
  "src/codemod/drift/snapshot.ts": "f8ef6b4097aa3d10",
43
43
  "src/codemod/drift/types.ts": "7f1d7899e420e4d7",
44
- "src/codemod/edits/addResource.ts": "002563615dbca570",
45
- "src/codemod/edits/addResource/appBinding.ts": "20fe5dbcfdc378c3",
44
+ "src/codemod/edits/addResource.ts": "bad55550ecff2f72",
45
+ "src/codemod/edits/addResource/appBinding.ts": "3553fdb30fe06335",
46
46
  "src/codemod/edits/addResource/bodyIndex.ts": "3e179eac10d7bcf4",
47
47
  "src/codemod/edits/addResource/propertyBuilder.ts": "18022f8899ba4b38",
48
48
  "src/codemod/edits/appendAccountToStage.ts": "2b92f93734497303",
@@ -52,21 +52,22 @@
52
52
  "src/codemod/edits/ensureImports.ts": "3ca0b6d446c4333c",
53
53
  "src/codemod/edits/findInsertionPosition.ts": "20cd34fdcf781017",
54
54
  "src/codemod/edits/index.ts": "bea5ed7c3983342b",
55
- "src/codemod/edits/modifyResource.ts": "8b91e93dc9a732ec",
56
- "src/codemod/edits/modifyResource/literalConversion.ts": "9a9eefbe72e434bf",
55
+ "src/codemod/edits/modifyResource.ts": "578412079d63ab60",
56
+ "src/codemod/edits/modifyResource/literalConversion.ts": "31295cccd59131b7",
57
57
  "src/codemod/edits/removeResource.ts": "2c7c8fe67bc3a866",
58
58
  "src/codemod/edits/removeResource/commentHeuristic.ts": "90b6ce7ba5aa2a48",
59
59
  "src/codemod/edits/removeResource/importPruning.ts": "f22783108b40f6cb",
60
- "src/codemod/edits/unmanagedShapeErrors.ts": "4ea5a1614f8065f8",
60
+ "src/codemod/edits/unmanagedShapeErrors.ts": "47a2644913c8e619",
61
61
  "src/codemod/edits/vpcPeer.ts": "0bcf90c2e6d16ca4",
62
62
  "src/codemod/edits/vpcPeerAccepter.ts": "c9eace933e9e2345",
63
+ "src/codemod/emitGuard.ts": "cbe270e04e1fea1a",
63
64
  "src/codemod/fileRewriter/builders.ts": "46a0d43240ff0818",
64
65
  "src/codemod/fileRewriter/index.ts": "fd715b41176a7999",
65
66
  "src/codemod/fileRewriter/locateByRange.ts": "889ee6256201c1fe",
66
67
  "src/codemod/fileRewriter/parse.ts": "b12026c31562a13c",
67
68
  "src/codemod/fileRewriter/print.ts": "f5ff7afb5b7786bf",
68
69
  "src/codemod/historyPaths.ts": "ef8084013146db57",
69
- "src/codemod/index.ts": "a555c237989cb6c4",
70
+ "src/codemod/index.ts": "6d786ef76a61fdc6",
70
71
  "src/codemod/listResources.ts": "97f206a50edbea20",
71
72
  "src/codemod/llmFallback/apply.ts": "2e656a6e55b3b4e3",
72
73
  "src/codemod/llmFallback/claudeTier.ts": "0a37fe782c85f75b",
@@ -81,12 +82,12 @@
81
82
  "src/codemod/llmFallback/telemetryEvents.ts": "33a85939739693ab",
82
83
  "src/codemod/llmFallback/tierRunner.ts": "a26094accd78cf15",
83
84
  "src/codemod/llmFallback/types.ts": "14af8d2bd9afae12",
84
- "src/codemod/registry.ts": "14b93cc476fdadd1",
85
+ "src/codemod/registry.ts": "ab1869907bcb957b",
85
86
  "src/codemod/semanticIndex/classifyControlFlow.ts": "ed96215d91a3cae3",
86
87
  "src/codemod/semanticIndex/findReferences.ts": "96aea37418d1e91a",
87
88
  "src/codemod/semanticIndex/index.ts": "cfcd212d34ab20fb",
88
89
  "src/codemod/semanticIndex/listImports.ts": "1e5fba6e34a17dab",
89
- "src/codemod/semanticIndex/locateByShape.ts": "6c2eadd7d1df9464",
90
+ "src/codemod/semanticIndex/locateByShape.ts": "1e00f068d69858ca",
90
91
  "src/codemod/semanticIndex/projectCache.ts": "dfd9b265c9d233c9",
91
92
  "src/codemod/semanticIndex/resolveConstructByLiteralProperty.ts": "2d013a330af15c5c",
92
93
  "src/codemod/telemetry/errorKinds.ts": "66c736abfa8b3a67",
@@ -156,11 +157,11 @@
156
157
  "src/validation/patterns.ts": "f9629eafdad7ac3e",
157
158
  "src/validation/validationMessages.ts": "c727ade4690274f4",
158
159
  "src/validation/validationPatterns.ts": "865f3d688975b7c8",
159
- "src/version.ts": "4ddad92856da915d",
160
+ "src/version.ts": "0e8c8d5ddae4f56f",
160
161
  "../scripts/minify-dist.mjs": "6b2e4b0df8aec601",
161
- "package.json": "e81b68a08f10c396",
162
+ "package.json": "f4b1c9b80d0dbdc7",
162
163
  "tsconfig.json": "1929cf3f99fe9b1e"
163
164
  },
164
- "outputHash": "bde788899e16f96bdef960a9b2ee305202754aa568ccb6e153702114c0142666",
165
- "outputFileCount": 293
165
+ "outputHash": "f4cd7140916d1965092b898aae1c66a849628b3d65177ab511f1207b09329c8f",
166
+ "outputFileCount": 295
166
167
  }
package/dist/.minified CHANGED
@@ -1 +1 @@
1
- 146 files minified at 2026-08-03T05:01:12.517Z
1
+ 147 files minified at 2026-08-06T02:33:58.009Z
@@ -7,7 +7,17 @@
7
7
  */
8
8
  import * as ts from "typescript";
9
9
  import type { AstStatementType } from "../../../schemas/resourceSchemas.js";
10
- /** Imports that the generator always handles -- don't preserve as "additional" */
10
+ /**
11
+ * Imports that the generator always handles -- don't preserve as "additional".
12
+ *
13
+ * Membership is a promise that regeneration will re-emit the import from the
14
+ * plan. `VpcPeerFactory` / `VpcPeerAccepterFactory` are deliberately absent:
15
+ * there is no plan slot and no emitter for either, so listing them dropped the
16
+ * import from every regenerated file that used one, leaving code that no longer
17
+ * compiles. They are preserved as additional managed imports instead, matching
18
+ * the `BuildkiteFactory` / `OrganisationFactory` treatment for the other
19
+ * codemod-only types.
20
+ */
11
21
  declare const KNOWN_FJALL_IMPORTS: Set<string>;
12
22
  export { KNOWN_FJALL_IMPORTS };
13
23
  /** Check if a module specifier belongs to a managed (Fjall/CDK) package */
@@ -1 +1 @@
1
- var d=Object.defineProperty;var o=(e,i)=>d(e,"name",{value:i,configurable:!0});import*as a from"typescript";import{isAppGetAppCall as y}from"./astCommonParser.js";import{S3_BUCKET_CLASSES as l}from"../resources/astStorageParser.js";const g=new Set(["App","Architecture","DatabaseFactory","StorageFactory","ComputeFactory","getConfig","MessagingFactory","CdnFactory","Code","Runtime","FunctionUrlAuthType","NetworkFactory","PatternFactory","VpcPeerFactory","VpcPeerAccepterFactory","CrossPlanConnectionFactory"]);function m(e){return!!(e.startsWith("@fjall/")||e==="aws-cdk-lib"||e.startsWith("aws-cdk-lib/")||e==="constructs")}o(m,"isManagedModuleSpecifier");function E(e){const i=[];for(const t of e.statements){const r=t.getFullStart(),n=t.getEnd();if(a.isImportDeclaration(t)){i.push({type:"import",node:t,startPos:r,endPos:n,isManaged:x(t)});continue}if(a.isVariableStatement(t)){i.push(F(t,r,n));continue}if(a.isExpressionStatement(t)){i.push(S(t,r,n));continue}i.push({type:"custom",node:t,startPos:r,endPos:n,isManaged:!1})}return i}o(E,"classifyStatements");function x(e){return a.isStringLiteral(e.moduleSpecifier)?m(e.moduleSpecifier.text):!1}o(x,"isManagedImport");function F(e,i,t){for(const r of e.declarationList.declarations)if(r.initializer){if(y(r.initializer))return{type:"app-init",node:e,resourceName:a.isIdentifier(r.name)?r.name.text:void 0,startPos:i,endPos:t,isManaged:!0};if(a.isIdentifier(r.name)&&r.name.text==="appName"&&a.isStringLiteral(r.initializer))return{type:"app-init",node:e,startPos:i,endPos:t,isManaged:!0};if(a.isNewExpression(r.initializer)){const n=r.initializer;if(a.isIdentifier(n.expression)){const s=n.expression.text;if(l.has(s)){const p=n.arguments&&n.arguments.length>=2&&a.isStringLiteral(n.arguments[1])?n.arguments[1].text:void 0;return{type:"storage",node:e,resourceName:p,startPos:i,endPos:t,isManaged:!0}}}}if(a.isCallExpression(r.initializer)){const n=u(r.initializer,e,i,t);if(n.type!=="custom")return n}}return{type:"custom",node:e,startPos:i,endPos:t,isManaged:!1}}o(F,"classifyVariableStatement");function S(e,i,t){const r=e.expression;return a.isCallExpression(r)?u(r,e,i,t):{type:"custom",node:e,startPos:i,endPos:t,isManaged:!1}}o(S,"classifyExpressionStatement");function u(e,i,t,r){const n=e.expression;if(a.isPropertyAccessExpression(n)&&a.isIdentifier(n.expression)){const s=n.name.text;if(s==="addTags")return{type:"tags",node:i,startPos:t,endPos:r,isManaged:!0};const c={addDatabase:{type:"database",factory:"DatabaseFactory"},addCompute:{type:"compute",factory:"ComputeFactory"},addNetwork:{type:"network",factory:"NetworkFactory"},addMessaging:{type:"messaging",factory:"MessagingFactory"},addCdn:{type:"cdn",factory:"CdnFactory"},addPattern:{type:"pattern",factory:"PatternFactory"},addStorage:{type:"storage",factory:"StorageFactory"},addVpcPeer:{type:"vpc-peer",factory:"VpcPeerFactory"},addVpcPeerAccepter:{type:"vpc-peer-accepter",factory:"VpcPeerAccepterFactory"}}[s];if(c){const f=M(e,c.factory);return{type:c.type,node:i,resourceName:f,startPos:t,endPos:r,isManaged:!0}}}return{type:"custom",node:i,startPos:t,endPos:r,isManaged:!1}}o(u,"classifyCallExpression");function M(e,i){if(e.arguments.length===0)return;const t=e.arguments[0];if(!a.isCallExpression(t))return;const r=t.expression;if(!a.isPropertyAccessExpression(r)||r.name.text!=="build"||!a.isIdentifier(r.expression)||r.expression.text!==i||t.arguments.length===0)return;const n=t.arguments[0];if(a.isStringLiteral(n))return n.text}o(M,"extractResourceNameFromFactoryCall");export{g as KNOWN_FJALL_IMPORTS,E as classifyStatements,m as isManagedModuleSpecifier};
1
+ var d=Object.defineProperty;var s=(e,i)=>d(e,"name",{value:i,configurable:!0});import*as a from"typescript";import{isAppGetAppCall as y}from"./astCommonParser.js";import{S3_BUCKET_CLASSES as l}from"../resources/astStorageParser.js";const g=new Set(["App","Architecture","DatabaseFactory","StorageFactory","ComputeFactory","getConfig","MessagingFactory","CdnFactory","Code","Runtime","FunctionUrlAuthType","NetworkFactory","PatternFactory","CrossPlanConnectionFactory"]);function m(e){return!!(e.startsWith("@fjall/")||e==="aws-cdk-lib"||e.startsWith("aws-cdk-lib/")||e==="constructs")}s(m,"isManagedModuleSpecifier");function N(e){const i=[];for(const t of e.statements){const r=t.getFullStart(),n=t.getEnd();if(a.isImportDeclaration(t)){i.push({type:"import",node:t,startPos:r,endPos:n,isManaged:x(t)});continue}if(a.isVariableStatement(t)){i.push(S(t,r,n));continue}if(a.isExpressionStatement(t)){i.push(F(t,r,n));continue}i.push({type:"custom",node:t,startPos:r,endPos:n,isManaged:!1})}return i}s(N,"classifyStatements");function x(e){return a.isStringLiteral(e.moduleSpecifier)?m(e.moduleSpecifier.text):!1}s(x,"isManagedImport");function S(e,i,t){for(const r of e.declarationList.declarations)if(r.initializer){if(y(r.initializer))return{type:"app-init",node:e,resourceName:a.isIdentifier(r.name)?r.name.text:void 0,startPos:i,endPos:t,isManaged:!0};if(a.isIdentifier(r.name)&&r.name.text==="appName"&&a.isStringLiteral(r.initializer))return{type:"app-init",node:e,startPos:i,endPos:t,isManaged:!0};if(a.isNewExpression(r.initializer)){const n=r.initializer;if(a.isIdentifier(n.expression)){const o=n.expression.text;if(l.has(o)){const u=n.arguments&&n.arguments.length>=2&&a.isStringLiteral(n.arguments[1])?n.arguments[1].text:void 0;return{type:"storage",node:e,resourceName:u,startPos:i,endPos:t,isManaged:!0}}}}if(a.isCallExpression(r.initializer)){const n=f(r.initializer,e,i,t);if(n.type!=="custom")return n}}return{type:"custom",node:e,startPos:i,endPos:t,isManaged:!1}}s(S,"classifyVariableStatement");function F(e,i,t){const r=e.expression;return a.isCallExpression(r)?f(r,e,i,t):{type:"custom",node:e,startPos:i,endPos:t,isManaged:!1}}s(F,"classifyExpressionStatement");function f(e,i,t,r){const n=e.expression;if(a.isPropertyAccessExpression(n)&&a.isIdentifier(n.expression)){const o=n.name.text;if(o==="addTags")return{type:"tags",node:i,startPos:t,endPos:r,isManaged:!0};const c={addDatabase:{type:"database",factory:"DatabaseFactory"},addCompute:{type:"compute",factory:"ComputeFactory"},addNetwork:{type:"network",factory:"NetworkFactory"},addMessaging:{type:"messaging",factory:"MessagingFactory"},addCdn:{type:"cdn",factory:"CdnFactory"},addPattern:{type:"pattern",factory:"PatternFactory"},addStorage:{type:"storage",factory:"StorageFactory"}}[o];if(c){const p=M(e,c.factory);return{type:c.type,node:i,resourceName:p,startPos:t,endPos:r,isManaged:!0}}}return{type:"custom",node:i,startPos:t,endPos:r,isManaged:!1}}s(f,"classifyCallExpression");function M(e,i){if(e.arguments.length===0)return;const t=e.arguments[0];if(!a.isCallExpression(t))return;const r=t.expression;if(!a.isPropertyAccessExpression(r)||r.name.text!=="build"||!a.isIdentifier(r.expression)||r.expression.text!==i||t.arguments.length===0)return;const n=t.arguments[0];if(a.isStringLiteral(n))return n.text}s(M,"extractResourceNameFromFactoryCall");export{g as KNOWN_FJALL_IMPORTS,N as classifyStatements,m as isManagedModuleSpecifier};
@@ -1,16 +1,20 @@
1
1
  import type { StatementNodeLike } from "./bodyIndex.js";
2
2
  /**
3
- * Match a `const <name> = App.getApp(...)` statement and return the bound
4
- * identifier name. Single matcher shared by `classifyStatement` (which
5
- * classifies the binding as an `app-init` insertion anchor) and
6
- * {@link resolveAppBindingName} the two recognitions must never drift,
7
- * or wrapped emission could insert before the binding it references.
3
+ * Match a `const <name> = App.getApp(...)` / `App.getInstance(...)` statement
4
+ * and return the bound identifier name. Both accessors return the same
5
+ * singleton: the application scaffold emits `App.getApp(appName, { … })` and
6
+ * the organisation scaffolds emit `App.getInstance()`. Single matcher shared
7
+ * by `classifyStatement` (which classifies the binding as an `app-init`
8
+ * insertion anchor) and {@link resolveAppBindingName} — the two recognitions
9
+ * must never drift, or wrapped emission could insert before the binding it
10
+ * references.
8
11
  */
9
12
  export declare function matchAppGetAppBinding(stmt: StatementNodeLike): string | undefined;
10
13
  /**
11
14
  * Resolve the app binding identifier for wrapped emission (registry
12
- * `emitWrapper`): the first `const <name> = App.getApp(...)` in the
13
- * program body. Returns `undefined` when no binding exists — the caller
14
- * surfaces `MissingAppInitError` pre-write.
15
+ * `emitWrapper`): the first `const <name> = App.getApp(...)` (or
16
+ * `App.getInstance(...)`) in the program body. Returns `undefined` when no
17
+ * binding exists — the caller surfaces `MissingAppInitError` pre-write
18
+ * rather than falling back to a bare, synth-inert emission.
15
19
  */
16
20
  export declare function resolveAppBindingName(body: readonly StatementNodeLike[]): string | undefined;
@@ -1 +1 @@
1
- var s=Object.defineProperty;var f=(n,t)=>s(n,"name",{value:t,configurable:!0});import{isRecord as i}from"../../_internal.js";function u(n){if(n.type!=="VariableDeclaration")return;const t=n.declarations;if(Array.isArray(t))for(const e of t){if(!i(e)||e.type!=="VariableDeclarator")continue;const o=e.init;if(!i(o)||o.type!=="CallExpression")continue;const r=o.callee;if(!i(r)||r.type!=="MemberExpression")continue;const c=r.object,p=r.property;if(!i(c)||c.type!=="Identifier"||c.name!=="App"||!i(p)||p.type!=="Identifier"||p.name!=="getApp")continue;const a=e.id;if(!i(a)||a.type!=="Identifier")continue;const d=a.name;if(typeof d=="string")return d}}f(u,"matchAppGetAppBinding");function m(n){for(const t of n){const e=u(t);if(e!==void 0)return e}}f(m,"resolveAppBindingName");export{u as matchAppGetAppBinding,m as resolveAppBindingName};
1
+ var u=Object.defineProperty;var f=(n,t)=>u(n,"name",{value:t,configurable:!0});import{isRecord as i}from"../../_internal.js";const l=new Set(["getApp","getInstance"]);function y(n){if(n.type!=="VariableDeclaration")return;const t=n.declarations;if(Array.isArray(t))for(const e of t){if(!i(e)||e.type!=="VariableDeclarator")continue;const o=e.init;if(!i(o)||o.type!=="CallExpression")continue;const r=o.callee;if(!i(r)||r.type!=="MemberExpression")continue;const c=r.object,a=r.property;if(!i(c)||c.type!=="Identifier"||c.name!=="App"||!i(a)||a.type!=="Identifier")continue;const s=a.name;if(typeof s!="string"||!l.has(s))continue;const p=e.id;if(!i(p)||p.type!=="Identifier")continue;const d=p.name;if(typeof d=="string")return d}}f(y,"matchAppGetAppBinding");function g(n){for(const t of n){const e=y(t);if(e!==void 0)return e}}f(g,"resolveAppBindingName");export{y as matchAppGetAppBinding,g as resolveAppBindingName};
@@ -1 +1 @@
1
- var T=Object.defineProperty;var u=(r,e)=>T(r,"name",{value:e,configurable:!0});import{failure as a,success as S}from"../../types/Result.js";import{DEFAULT_FILE_PATH as A,computeLinesDelta as D,extractProgramBody as F,isRecord as M}from"../_internal.js";import{appendSpecifier as C,buildAppMethodWrappedStatement as x,buildFactoryStatement as v,buildImportDeclaration as w,detectQuoteStyle as N,parse as Q,printFile as B}from"../fileRewriter/index.js";import{STATEMENT_REGISTRY as U}from"../registry.js";import{locateAllShapes as _,locateByShape as G}from"../semanticIndex/index.js";import{checkControlFlowPolicy as O}from"./controlFlowPolicy.js";import{driftGate as W,runPipeline as Y,schemaGate as j}from"../validationGate/index.js";import{resolveAppBindingName as q}from"./addResource/appBinding.js";import{buildUnmanagedDuplicateError as H}from"./unmanagedShapeErrors.js";import{buildResourceLocations as $,indexBody as z,orderByEndPos as J,resolveInsertIndex as K}from"./addResource/bodyIndex.js";import{buildPropertyInputs as V}from"./addResource/propertyBuilder.js";import{findInsertionPosition as X}from"./findInsertionPosition.js";const g="@fjall/components-infrastructure";function fe(r,e,m={}){const i=e.filePath??A,n=Q(r,i);if(!n.success)return a(n.error);const t=G(r,{type:e.type,name:e.name},i);if(!t.success)return t.error.kind==="TemplateLiteralNameError"?a(t.error):a({kind:"SemanticQueryError",reason:t.error.reason,cause:t.error.cause});if(t.data!==void 0){if(t.data.managed===!1)return a(H(e.type,t.data.symbolName));const d=O({ast:n.data,target:t.data,resource:{type:e.type,name:e.name},op:"add"});if(d.refusal!==void 0)return a(d.refusal);const E=Y([j,W],{content:r,plan:{type:e.type,name:e.name,properties:e.properties,op:"add"},baseline:m.baseline,policy:e.driftPolicy});return E.success?E.data.action==="skip"?S({content:r,linesChanged:{added:0,removed:0},skipped:!0}):a({kind:"DuplicateResourceError",type:e.type,name:e.name}):a(Z(E.error))}const l=N(n.data),f=V(e.properties,l);if(!f.success)return a(f.error);const s=F(n.data);if(s===void 0)return a({kind:"SemanticQueryError",reason:"recast File is missing program.body"});const c=U[e.type],h={factory:c.factoryIdentifier,name:e.name,properties:f.data,quoteStyle:l};let y;if(c.emitWrapper!==void 0){const d=q(s);if(d===void 0)return a({kind:"MissingAppInitError",type:e.type,appMethod:c.emitWrapper.appMethod});y=x({...h,appIdentifier:d,appMethod:c.emitWrapper.appMethod})}else y=v(h);const p=z(s,r),o=_(r,i);if(!o.success)return o.error.kind==="TemplateLiteralNameError"?a(o.error):a({kind:"SemanticQueryError",reason:o.error.reason,cause:o.error.cause});const k=$(p.anchors,o.data),P=J([...p.appInitLocations,...k]),L=X(p.importInfos,P,e.type,p.programEnd),R=K(p.anchors,L);s.splice(R,0,y),ee(s,c.factoryIdentifier,l);const I=B(n.data,r),b=D(r,I);return S({content:I,linesChanged:b})}u(fe,"addResource");function Z(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(Z,"narrowGateError");function ee(r,e,m){for(const n of r){if(n.type!=="ImportDeclaration")continue;const t=n.source;if(!(!M(t)||t.type!=="StringLiteral")&&t.value===g){C(n,e);return}}const i=w([e],g,m);r.unshift(i)}u(ee,"ensureFactoryImport");export{fe as addResource};
1
+ var A=Object.defineProperty;var u=(r,e)=>A(r,"name",{value:e,configurable:!0});import{failure as a,success as g}from"../../types/Result.js";import{DEFAULT_FILE_PATH as D,computeLinesDelta as F,extractProgramBody as M,isRecord as C}from"../_internal.js";import{evaluateEmitGuard as v}from"../emitGuard.js";import{appendSpecifier as x,buildAppMethodWrappedStatement as w,buildFactoryStatement as G,buildImportDeclaration as N,detectQuoteStyle as Q,parse as B,printFile as U}from"../fileRewriter/index.js";import{STATEMENT_REGISTRY as _}from"../registry.js";import{locateAllShapes as O,locateByShape as W}from"../semanticIndex/index.js";import{checkControlFlowPolicy as Y}from"./controlFlowPolicy.js";import{driftGate as j,runPipeline as q,schemaGate as H}from"../validationGate/index.js";import{resolveAppBindingName as $}from"./addResource/appBinding.js";import{buildUnmanagedDuplicateError as z}from"./unmanagedShapeErrors.js";import{buildResourceLocations as J,indexBody as K,orderByEndPos as V,resolveInsertIndex as X}from"./addResource/bodyIndex.js";import{buildPropertyInputs as Z}from"./addResource/propertyBuilder.js";import{findInsertionPosition as ee}from"./findInsertionPosition.js";const k="@fjall/components-infrastructure";function he(r,e,m={}){const s=e.filePath??D,n=B(r,s);if(!n.success)return a(n.error);const t=W(r,{type:e.type,name:e.name},s);if(!t.success)return t.error.kind==="TemplateLiteralNameError"?a(t.error):a({kind:"SemanticQueryError",reason:t.error.reason,cause:t.error.cause});if(t.data!==void 0){if(t.data.managed===!1)return a(z(e.type,t.data.symbolName));const d=Y({ast:n.data,target:t.data,resource:{type:e.type,name:e.name},op:"add"});if(d.refusal!==void 0)return a(d.refusal);const E=q([H,j],{content:r,plan:{type:e.type,name:e.name,properties:e.properties,op:"add"},baseline:m.baseline,policy:e.driftPolicy});return E.success?E.data.action==="skip"?g({content:r,linesChanged:{added:0,removed:0},skipped:!0}):a({kind:"DuplicateResourceError",type:e.type,name:e.name}):a(re(E.error))}const l=Q(n.data),f=Z(e.properties,l);if(!f.success)return a(f.error);const c=M(n.data);if(c===void 0)return a({kind:"SemanticQueryError",reason:"recast File is missing program.body"});const o=_[e.type],h=v(o.emitGuard,e.properties);if(h!==void 0)return a(h);const I={factory:o.factoryIdentifier,name:e.name,properties:f.data,quoteStyle:l};let y;if(o.emitWrapper!==void 0){const d=$(c);if(d===void 0)return a({kind:"MissingAppInitError",type:e.type,appMethod:o.emitWrapper.appMethod});y=w({...I,appIdentifier:d,appMethod:o.emitWrapper.appMethod})}else y=G(I);const p=K(c,r),i=O(r,s);if(!i.success)return i.error.kind==="TemplateLiteralNameError"?a(i.error):a({kind:"SemanticQueryError",reason:i.error.reason,cause:i.error.cause});const P=J(p.anchors,i.data),L=V([...p.appInitLocations,...P]),R=ee(p.importInfos,L,e.type,p.programEnd),b=X(p.anchors,R);c.splice(b,0,y),te(c,o.factoryIdentifier,l);const S=U(n.data,r),T=F(r,S);return g({content:S,linesChanged:T})}u(he,"addResource");function re(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(re,"narrowGateError");function te(r,e,m){for(const n of r){if(n.type!=="ImportDeclaration")continue;const t=n.source;if(!(!C(t)||t.type!=="StringLiteral")&&t.value===k){x(n,e);return}}const s=N([e],k,m);r.unshift(s)}u(te,"ensureFactoryImport");export{he as addResource};
@@ -32,6 +32,14 @@ export type LiteralValue = unknown;
32
32
  * (`vpc: app.getVpc()`).
33
33
  */
34
34
  export declare function buildMergedLiteral(configObject: ObjectExpressionNodeLike, requestedProperties: Record<string, unknown>): Record<string, unknown>;
35
+ /**
36
+ * Every key the object declares, whether or not its value reduced to a
37
+ * literal. `buildMergedLiteral` drops non-literal values so `.strict()`
38
+ * fragment validation does not reject real call sites; the emit guard needs
39
+ * the fuller picture — a key holding `Code.fromAsset("./src")` is PRESENT,
40
+ * and proves the statement was authored in construct vocabulary.
41
+ */
42
+ export declare function collectPropertyKeys(configObject: ObjectExpressionNodeLike): string[];
35
43
  export declare function astToLiteral(node: NodeShapeLike): LiteralValue | typeof NON_LITERAL;
36
44
  export declare function readKeyName(key: NodeShapeLike | undefined): string | undefined;
37
45
  export declare function isNodeShape(value: unknown): value is NodeShapeLike;
@@ -1 +1 @@
1
- var l=Object.defineProperty;var u=(e,r)=>l(e,"name",{value:r,configurable:!0});const n=Symbol("non-literal");function L(e,r){const o={};for(const t of e.properties){if(t.type!=="Property"&&t.type!=="ObjectProperty"||t.shorthand===!0||t.computed===!0)continue;const i=c(t.key);if(i===void 0||t.value===void 0)continue;const a=s(t.value);a!==n&&(o[i]=a)}return{...o,...r}}u(L,"buildMergedLiteral");function s(e){const r=e.value;switch(e.type){case"StringLiteral":return typeof r=="string"?r:n;case"NumericLiteral":return typeof r=="number"?r:n;case"BooleanLiteral":return typeof r=="boolean"?r:n;case"NullLiteral":return null;case"ArrayExpression":return y(e);case"ObjectExpression":return d(e);default:return n}}u(s,"astToLiteral");function y(e){const r=e.elements;if(!Array.isArray(r))return n;const o=[];for(const t of r){if(!p(t))return n;const i=s(t);if(i===n)return n;o.push(i)}return o}u(y,"arrayToLiteral");function d(e){const r=e.properties;if(!Array.isArray(r))return n;const o={};for(const t of r){if(!p(t)||t.type!=="Property"&&t.type!=="ObjectProperty")return n;const i=c(t.key),a=t.value;if(i===void 0||a===void 0)return n;const f=s(a);if(f===n)return n;o[i]=f}return o}u(d,"objectToLiteral");function c(e){if(e===void 0)return;const r=e;if(e.type==="Identifier"&&typeof r.name=="string")return r.name;if(e.type==="StringLiteral"&&typeof r.value=="string")return r.value}u(c,"readKeyName");function p(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)&&typeof e.type=="string"}u(p,"isNodeShape");export{n as NON_LITERAL,s as astToLiteral,L as buildMergedLiteral,p as isNodeShape,c as readKeyName};
1
+ var y=Object.defineProperty;var u=(e,r)=>y(e,"name",{value:r,configurable:!0});const o=Symbol("non-literal");function L(e,r){const n={};for(const t of e.properties){if(t.type!=="Property"&&t.type!=="ObjectProperty"||t.shorthand===!0||t.computed===!0)continue;const i=c(t.key);if(i===void 0||t.value===void 0)continue;const s=p(t.value);s!==o&&(n[i]=s)}return{...n,...r}}u(L,"buildMergedLiteral");function b(e){const r=[];for(const n of e.properties){if(n.type!=="Property"&&n.type!=="ObjectProperty"||n.shorthand===!0||n.computed===!0)continue;const t=c(n.key);t!==void 0&&r.push(t)}return r}u(b,"collectPropertyKeys");function p(e){const r=e.value;switch(e.type){case"StringLiteral":return typeof r=="string"?r:o;case"NumericLiteral":return typeof r=="number"?r:o;case"BooleanLiteral":return typeof r=="boolean"?r:o;case"NullLiteral":return null;case"ArrayExpression":return l(e);case"ObjectExpression":return d(e);default:return o}}u(p,"astToLiteral");function l(e){const r=e.elements;if(!Array.isArray(r))return o;const n=[];for(const t of r){if(!a(t))return o;const i=p(t);if(i===o)return o;n.push(i)}return n}u(l,"arrayToLiteral");function d(e){const r=e.properties;if(!Array.isArray(r))return o;const n={};for(const t of r){if(!a(t)||t.type!=="Property"&&t.type!=="ObjectProperty")return o;const i=c(t.key),s=t.value;if(i===void 0||s===void 0)return o;const f=p(s);if(f===o)return o;n[i]=f}return n}u(d,"objectToLiteral");function c(e){if(e===void 0)return;const r=e;if(e.type==="Identifier"&&typeof r.name=="string")return r.name;if(e.type==="StringLiteral"&&typeof r.value=="string")return r.value}u(c,"readKeyName");function a(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)&&typeof e.type=="string"}u(a,"isNodeShape");export{o as NON_LITERAL,p as astToLiteral,L as buildMergedLiteral,b as collectPropertyKeys,a as isNodeShape,c as readKeyName};
@@ -1 +1 @@
1
- var S=Object.defineProperty;var d=(r,e)=>S(r,"name",{value:e,configurable:!0});import{failure as s,success as p}from"../../types/Result.js";import{DEFAULT_FILE_PATH as v,computeLinesDelta as w,extractProgramBody as C,isRecord as m}from"../_internal.js";import{buildObjectProperty as N,detectQuoteStyle as x,parse as R,printFile as T}from"../fileRewriter/index.js";import{STATEMENT_REGISTRY as A}from"../registry.js";import{locateAllShapes as F,locateByShape as L}from"../semanticIndex/index.js";import{buildUnmanagedEditRefusal as j}from"./unmanagedShapeErrors.js";import{checkControlFlowPolicy as O}from"./controlFlowPolicy.js";import{driftGate as Q,runPipeline as I,schemaGate as U}from"../validationGate/index.js";import{toAstValue as G}from"./addResource/propertyBuilder.js";import{buildMergedLiteral as B,isNodeShape as E,readKeyName as D}from"./modifyResource/literalConversion.js";function ie(r,e,a={}){const i=e.filePath??v,t=R(r,i);if(!t.success)return s(t.error);const n=L(r,{type:e.type,name:e.name},i);if(!n.success)return n.error.kind==="TemplateLiteralNameError"?s(n.error):s({kind:"SemanticQueryError",reason:n.error.reason,cause:n.error.cause});if(n.data===void 0)return s({kind:"ResourceNotFoundError",type:e.type,name:e.name,knownNames:H(r,e.type,i)});if(n.data.managed===!1)return s(j(e.type,"modify"));const o=O({ast:t.data,target:n.data,resource:{type:e.type,name:e.name},op:"modify"});if(o.refusal!==void 0)return s(o.refusal);const c=I([U,Q],{content:r,plan:{type:e.type,name:e.name,properties:e.properties,op:"modify"},baseline:a.baseline,policy:e.driftPolicy});if(!c.success)return s(K(c.error));if(c.data.action==="skip")return p({content:r,linesChanged:{added:0,removed:0},skipped:!0});const u=C(t.data);if(u===void 0)return s({kind:"SemanticQueryError",reason:"recast File is missing program.body"});const l=_(u,n.data);if(l===void 0)return s({kind:"SemanticQueryError",reason:"Unable to resolve config ObjectExpression for the located resource."});const k=x(t.data),b=B(l,e.properties),y=A[e.type].schemaFragment.safeParse(b);if(!y.success){const f=y.error.issues[0];return s({kind:"InvalidPropertyError",property:f!==void 0&&f.path.length>0?String(f.path[0]):Object.keys(e.properties)[0]??"<unknown>",reason:f?.message??"Schema validation failed"})}const g=M(l,e.properties,k);if(!g.success)return s(g.error);const h=T(t.data,r),P=o.warning!==void 0?[o.warning.message]:void 0;return p({content:h,linesChanged:w(r,h),warnings:P})}d(ie,"modifyResource");function K(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(K,"narrowGateError");function _(r,e){const a=e.start+e.length;let i;const t=d(n=>{if(i!==void 0||n.type!=="CallExpression")return;const o=n.arguments;if(!Array.isArray(o)||o.length<2)return;const c=o[0];if(!E(c)||c.type!=="StringLiteral"||c.start!==e.start||c.end!==a)return;const u=o[1];E(u)&&u.type==="ObjectExpression"&&(i=u)},"visitor");for(const n of r)if(Y(n,t),i!==void 0)break;return i}d(_,"findConfigObject");function M(r,e,a){const i=$(r);for(const[t,n]of Object.entries(e)){const o=G(n,a);if(o===void 0)return s({kind:"InvalidPropertyError",property:t,reason:`Unsupported property value for "${t}" (accepts string/number/boolean/null/array/object of the same).`});const c=V(r,t);if(c!==void 0){c.value=o;continue}const u=N(t,o,a);i&&(u.extra={...u.extra??{},trailingComma:!0}),r.properties.push(u)}return p(void 0)}d(M,"applyPropertyEdits");function V(r,e){return r.properties.find(a=>(a.type==="Property"||a.type==="ObjectProperty")&&a.shorthand!==!0&&a.computed!==!0&&D(a.key)===e)}d(V,"findPropertyByKey");function $(r){return r.properties[r.properties.length-1]?.extra?.trailingComma===!0}d($,"detectTrailingCommaStyle");function H(r,e,a){const i=F(r,a);return i.success?i.data.filter(t=>t.type===e).map(t=>t.symbolName):[]}d(H,"collectKnownNames");function Y(r,e){const a=[r];for(;a.length>0;){const i=a.pop();if(m(i)){typeof i.type=="string"&&e(i);for(const t of Object.keys(i)){if(t==="loc"||t==="comments"||t==="tokens")continue;const n=i[t];if(Array.isArray(n))for(const o of n)m(o)&&a.push(o);else m(n)&&a.push(n)}}}}d(Y,"visit");export{ie as modifyResource};
1
+ var T=Object.defineProperty;var c=(r,e)=>T(r,"name",{value:e,configurable:!0});import{failure as s,success as m}from"../../types/Result.js";import{DEFAULT_FILE_PATH as A,computeLinesDelta as F,extractProgramBody as L,isRecord as y}from"../_internal.js";import{buildObjectProperty as j,detectQuoteStyle as G,parse as O,printFile as Q}from"../fileRewriter/index.js";import{STATEMENT_REGISTRY as P}from"../registry.js";import{locateAllShapes as U,locateByShape as I}from"../semanticIndex/index.js";import{buildUnmanagedEditRefusal as D}from"./unmanagedShapeErrors.js";import{checkControlFlowPolicy as K}from"./controlFlowPolicy.js";import{driftGate as V,runPipeline as B,schemaGate as _}from"../validationGate/index.js";import{toAstValue as M}from"./addResource/propertyBuilder.js";import{buildMergedLiteral as v,collectPropertyKeys as $,isNodeShape as S,readKeyName as H}from"./modifyResource/literalConversion.js";import{evaluateEmitGuard as w,UNRESOLVED as Y}from"../emitGuard.js";function pe(r,e,t={}){const n=e.filePath??A,a=O(r,n);if(!a.success)return s(a.error);const i=I(r,{type:e.type,name:e.name},n);if(!i.success)return i.error.kind==="TemplateLiteralNameError"?s(i.error):s({kind:"SemanticQueryError",reason:i.error.reason,cause:i.error.cause});if(i.data===void 0)return s({kind:"ResourceNotFoundError",type:e.type,name:e.name,knownNames:Z(r,e.type,n)});if(i.data.managed===!1)return s(D(e.type,"modify"));const o=K({ast:a.data,target:i.data,resource:{type:e.type,name:e.name},op:"modify"});if(o.refusal!==void 0)return s(o.refusal);const u=B([_,V],{content:r,plan:{type:e.type,name:e.name,properties:e.properties,op:"modify"},baseline:t.baseline,policy:e.driftPolicy});if(!u.success)return s(q(u.error));if(u.data.action==="skip")return m({content:r,linesChanged:{added:0,removed:0},skipped:!0});const d=L(a.data);if(d===void 0)return s({kind:"SemanticQueryError",reason:"recast File is missing program.body"});const f=z(d,i.data);if(f===void 0)return s({kind:"SemanticQueryError",reason:"Unable to resolve config ObjectExpression for the located resource."});const N=G(a.data),g=v(f,e.properties),E=P[e.type].emitGuard,R=w(E,C(f,v(f,{}))),p=w(E,C(f,g));if(p!==void 0&&p.property!==R?.property)return s(p);const h=P[e.type].schemaFragment.safeParse(g);if(!h.success){const l=h.error.issues[0];return s({kind:"InvalidPropertyError",property:l!==void 0&&l.path.length>0?String(l.path[0]):Object.keys(e.properties)[0]??"<unknown>",reason:l?.message??"Schema validation failed"})}const k=J(f,e.properties,N);if(!k.success)return s(k.error);const b=Q(a.data,r),x=o.warning!==void 0?[o.warning.message]:void 0;return m({content:b,linesChanged:F(r,b),warnings:x})}c(pe,"modifyResource");function C(r,e){const t={...e};for(const n of $(r))n in t||(t[n]=Y);return t}c(C,"buildGuardView");function q(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}`}}}c(q,"narrowGateError");function z(r,e){const t=e.start+e.length;let n;const a=c(i=>{if(n!==void 0||i.type!=="CallExpression")return;const o=i.arguments;if(!Array.isArray(o)||o.length<2)return;const u=o[0];if(!S(u)||u.type!=="StringLiteral"||u.start!==e.start||u.end!==t)return;const d=o[1];S(d)&&d.type==="ObjectExpression"&&(n=d)},"visitor");for(const i of r)if(ee(i,a),n!==void 0)break;return n}c(z,"findConfigObject");function J(r,e,t){const n=X(r);for(const[a,i]of Object.entries(e)){const o=M(i,t);if(o===void 0)return s({kind:"InvalidPropertyError",property:a,reason:`Unsupported property value for "${a}" (accepts string/number/boolean/null/array/object of the same).`});const u=W(r,a);if(u!==void 0){u.value=o;continue}const d=j(a,o,t);n&&(d.extra={...d.extra??{},trailingComma:!0}),r.properties.push(d)}return m(void 0)}c(J,"applyPropertyEdits");function W(r,e){return r.properties.find(t=>(t.type==="Property"||t.type==="ObjectProperty")&&t.shorthand!==!0&&t.computed!==!0&&H(t.key)===e)}c(W,"findPropertyByKey");function X(r){return r.properties[r.properties.length-1]?.extra?.trailingComma===!0}c(X,"detectTrailingCommaStyle");function Z(r,e,t){const n=U(r,t);return n.success?n.data.filter(a=>a.type===e).map(a=>a.symbolName):[]}c(Z,"collectKnownNames");function ee(r,e){const t=[r];for(;t.length>0;){const n=t.pop();if(y(n)){typeof n.type=="string"&&e(n);for(const a of Object.keys(n)){if(a==="loc"||a==="comments"||a==="tokens")continue;const i=n[a];if(Array.isArray(i))for(const o of i)y(o)&&t.push(o);else y(i)&&t.push(i)}}}}c(ee,"visit");export{pe as modifyResource};
@@ -1 +1 @@
1
- var a=Object.defineProperty;var r=(e,t)=>a(e,"name",{value:t,configurable:!0});import{STATEMENT_REGISTRY as o}from"../registry.js";function i(e){const{emitWrapper:t,factoryIdentifier:n}=o[e];return t===void 0?`${n}.build("<Name>", { \u2026 })`:`app.${t.appMethod}(${n}.build("${t.propsOverloadConstructId}", { \u2026 }))`}r(i,"managedFormExample");function u(e,t){return{kind:"DuplicateResourceError",type:e,name:t,remediation:`The existing statement is the unmanaged method form \u2014 migrate it to ${i(e)} before managing it with fjall.`}}r(u,"buildUnmanagedDuplicateError");function f(e,t){return{kind:"SemanticQueryError",reason:`cannot ${t} "${e}": the statement is not in the managed factory form \u2014 migrate it to ${i(e)} first`}}r(f,"buildUnmanagedEditRefusal");export{u as buildUnmanagedDuplicateError,f as buildUnmanagedEditRefusal};
1
+ var o=Object.defineProperty;var r=(t,e)=>o(t,"name",{value:e,configurable:!0});import{STATEMENT_REGISTRY as m}from"../registry.js";function i(t){const{emitWrapper:e,factoryIdentifier:n}=m[t];if(e===void 0)return`${n}.build("<Name>", { \u2026 })`;const a=e.propsOverloadConstructId??"<Name>";return`app.${e.appMethod}(${n}.build("${a}", { \u2026 }))`}r(i,"managedFormExample");function c(t,e){return{kind:"DuplicateResourceError",type:t,name:e,remediation:`The existing statement is the unmanaged method form \u2014 migrate it to ${i(t)} before managing it with fjall.`}}r(c,"buildUnmanagedDuplicateError");function f(t,e){return{kind:"SemanticQueryError",reason:`cannot ${e} "${t}": the statement is not in the managed factory form \u2014 migrate it to ${i(t)} first`}}r(f,"buildUnmanagedEditRefusal");export{c as buildUnmanagedDuplicateError,f as buildUnmanagedEditRefusal};
@@ -0,0 +1,73 @@
1
+ import type { InvalidPropertyError } from "./types.js";
2
+ /**
3
+ * A value the codemod could not have written: the property is present in
4
+ * the target statement but holds a non-literal expression (`Code.fromAsset(
5
+ * "./src")`, `Runtime.NODEJS_20_X`, `assetsBucket`).
6
+ *
7
+ * Its presence is PROOF the statement was authored by a human or by the
8
+ * generator scaffold, both of which speak construct vocabulary. Rules that
9
+ * refuse a key because the construct needs a live object must therefore
10
+ * treat `UNRESOLVED` as satisfying the construct — otherwise `fjall modify`
11
+ * would refuse to touch perfectly good scaffold output. The ADD path never
12
+ * produces it: every value there comes from a flag.
13
+ */
14
+ export declare const UNRESOLVED: unique symbol;
15
+ /**
16
+ * The property record the emitted statement WOULD carry. `add` passes the
17
+ * requested properties; `modify` passes the merge of the existing statement
18
+ * and the requested edit, with non-literal values as `UNRESOLVED`, because
19
+ * that merge is exactly what lands in the file. Evaluating the post-write
20
+ * shape (rather than the delta) is what lets `fjall modify compute
21
+ * --deployment container` repair a statement the guard would otherwise
22
+ * refuse to touch, and what stops a whole-statement rule such as "messaging
23
+ * has no `type`" from firing on an unrelated one-property edit.
24
+ */
25
+ export type EmitGuardProperties = Readonly<Record<string, unknown>>;
26
+ /**
27
+ * One refusal. `property` names the plan key the operator typed (or the one
28
+ * whose absence is fatal) so the rendered `InvalidPropertyError` points at a
29
+ * real flag; `reason` must say WHY and what to do instead.
30
+ */
31
+ export interface EmitGuardRule {
32
+ readonly property: string;
33
+ readonly refuseWhen: (properties: EmitGuardProperties) => boolean;
34
+ readonly reason: string;
35
+ }
36
+ /**
37
+ * Standard tail for a refusal with no in-vocabulary alternative.
38
+ *
39
+ * It deliberately does NOT name a construct-prop spelling that would work
40
+ * as an unvalidated passthrough (`fjall add` performs no property-key
41
+ * validation today, so `--memorySize` or `--originType` reach the emitted
42
+ * object untouched). Advertising those would document a surface no schema
43
+ * checks and no test pins, and it would go stale the moment the schema gate
44
+ * stops being a no-op. Hand-authoring is always correct.
45
+ */
46
+ export declare const AUTHOR_BY_HAND: string;
47
+ /** True when the key holds a value the codemod itself could have written. */
48
+ export declare function isWrittenValue(value: unknown): boolean;
49
+ /**
50
+ * A rule for a plan key NO construct reads, in any shape — proven by zero
51
+ * `props.<key>` reads across @fjall/components-infrastructure. Presence
52
+ * alone is the refusal; the value cannot rescue it.
53
+ *
54
+ * Phrased as a statement of consequence, because the operator's mental model
55
+ * is "I set it, so it took effect" and the whole point is that it did not.
56
+ */
57
+ export declare function silentlyDropped(property: string, detail: string): EmitGuardRule;
58
+ /**
59
+ * A rule for a key the construct DOES read but only as a live object — a
60
+ * CDK enum member, an asset, another construct. A flag value is a string,
61
+ * so any value the codemod can write is wrong; only `UNRESOLVED` passes.
62
+ */
63
+ export declare function requiresLiveValue(property: string, detail: string): EmitGuardRule;
64
+ /** Refuse whenever the key is missing (the missing-discriminator shape). */
65
+ export declare function whenAbsent(property: string): (properties: EmitGuardProperties) => boolean;
66
+ /**
67
+ * Evaluate a rule table in declaration order and return the first refusal
68
+ * as the codebase's existing actionable error shape. Order is significant:
69
+ * a type lists its most explanatory rule first, so an invocation tripping
70
+ * several (`--deployment code --codePath ./src --runtime nodejs20.x`) is
71
+ * told about the deployment mode rather than about a single dead flag.
72
+ */
73
+ export declare function evaluateEmitGuard(rules: ReadonlyArray<EmitGuardRule> | undefined, properties: EmitGuardProperties): InvalidPropertyError | undefined;
@@ -0,0 +1 @@
1
+ var u=Object.defineProperty;var r=(e,n)=>u(e,"name",{value:n,configurable:!0});const i=Symbol("unresolved-expression"),o="Write this resource in infrastructure.ts by hand \u2014 the construct props it needs cannot be expressed as `fjall add` flags.";function d(e){return e!==void 0&&e!==i}r(d,"isWrittenValue");function f(e,n){return{property:e,refuseWhen:r(t=>t[e]!==void 0,"refuseWhen"),reason:`${n} \`fjall add\` would write it into the factory call and the resource would deploy without it. ${o}`}}r(f,"silentlyDropped");function a(e,n){return{property:e,refuseWhen:r(t=>d(t[e]),"refuseWhen"),reason:`${n} ${o}`}}r(a,"requiresLiveValue");function l(e){return n=>n[e]===void 0}r(l,"whenAbsent");function c(e,n){if(e!==void 0){for(const t of e)if(t.refuseWhen(n))return{kind:"InvalidPropertyError",property:t.property,reason:t.reason}}}r(c,"evaluateEmitGuard");export{o as AUTHOR_BY_HAND,i as UNRESOLVED,c as evaluateEmitGuard,d as isWrittenValue,a as requiresLiveValue,f as silentlyDropped,l as whenAbsent};
@@ -15,6 +15,7 @@ export { detectDrift, mergeProperties, snapshotProperties, type DriftOp, type Dr
15
15
  export { computeLinesDelta } from "./_internal.js";
16
16
  export { ResourceNameSchema, StatementTypeSchema } from "./types.js";
17
17
  export { REGISTERED_STATEMENT_TYPES, STATEMENT_REGISTRY, type StatementTypeEntry, } from "./registry.js";
18
+ export { evaluateEmitGuard, UNRESOLVED, type EmitGuardProperties, type EmitGuardRule, } from "./emitGuard.js";
18
19
  export { CODEMOD_ERROR_KINDS } from "./telemetry/errorKinds.js";
19
20
  export type { CodemodErrorKind } from "./telemetry/errorKinds.js";
20
21
  export type { GateId } from "./validationGate/index.js";
@@ -1 +1 @@
1
- import{addResource as o}from"./edits/addResource.js";import{removeResource as c}from"./edits/removeResource.js";import{modifyResource as m}from"./edits/modifyResource.js";import{appendAccountToStage as a}from"./edits/appendAccountToStage.js";import{addVpcPeer as d,modifyVpcPeer as E,removeVpcPeer as i}from"./edits/vpcPeer.js";import{addVpcPeerAccepter as f,modifyVpcPeerAccepter as u,removeVpcPeerAccepter as P}from"./edits/vpcPeerAccepter.js";import{addCrossPlanConnection as x,modifyCrossPlanConnection as R,removeCrossPlanConnection as S}from"./edits/crossPlanConnection.js";import{resolveDriftPolicy as A}from"./edits/driftPolicy.js";import{listResources as V}from"./listResources.js";import{resolveConstructByLiteralProperty as y}from"./semanticIndex/index.js";import{parse as h}from"./fileRewriter/parse.js";import{CrossPlanConnectionResourcePlanSchema as G,VpcPeerAccepterResourcePlanSchema as N,VpcPeerResourcePlanSchema as F}from"../schemas/index.js";import{detectDrift as L,mergeProperties as M,snapshotProperties as g}from"./drift/index.js";import{computeLinesDelta as B}from"./_internal.js";import{ResourceNameSchema as K,StatementTypeSchema as U}from"./types.js";import{REGISTERED_STATEMENT_TYPES as j,STATEMENT_REGISTRY as q}from"./registry.js";import{CODEMOD_ERROR_KINDS as z}from"./telemetry/errorKinds.js";import{buildEgressBlockedEvent as J,buildFiredEvent as Q,buildGateFailedEvent as W,buildGatePassedEvent as X,buildRejectedEvent as Z,buildSucceededEvent as $,buildTimeoutEvent as ee,estimateCostUsd as re,FALLBACK_EVENTS as oe,GATE_EVENTS as te,PARSE_GATE as ce,RUNTIME_GATE as pe,runFallback as me,shouldTryFallback as se}from"./llmFallback/index.js";export{z as CODEMOD_ERROR_KINDS,G as CrossPlanConnectionResourcePlanSchema,oe as FALLBACK_EVENTS,te as GATE_EVENTS,ce as PARSE_GATE,j as REGISTERED_STATEMENT_TYPES,pe as RUNTIME_GATE,K as ResourceNameSchema,q as STATEMENT_REGISTRY,U as StatementTypeSchema,N as VpcPeerAccepterResourcePlanSchema,F as VpcPeerResourcePlanSchema,x as addCrossPlanConnection,o as addResource,d as addVpcPeer,f as addVpcPeerAccepter,a as appendAccountToStage,J as buildEgressBlockedEvent,Q as buildFiredEvent,W as buildGateFailedEvent,X as buildGatePassedEvent,Z as buildRejectedEvent,$ as buildSucceededEvent,ee as buildTimeoutEvent,B as computeLinesDelta,L as detectDrift,re as estimateCostUsd,V as listResources,M as mergeProperties,R as modifyCrossPlanConnection,m as modifyResource,E as modifyVpcPeer,u as modifyVpcPeerAccepter,h as parse,S as removeCrossPlanConnection,c as removeResource,i as removeVpcPeer,P as removeVpcPeerAccepter,y as resolveConstructByLiteralProperty,A as resolveDriftPolicy,me as runFallback,se as shouldTryFallback,g as snapshotProperties};
1
+ import{addResource as o}from"./edits/addResource.js";import{removeResource as c}from"./edits/removeResource.js";import{modifyResource as m}from"./edits/modifyResource.js";import{appendAccountToStage as s}from"./edits/appendAccountToStage.js";import{addVpcPeer as d,modifyVpcPeer as E,removeVpcPeer as i}from"./edits/vpcPeer.js";import{addVpcPeerAccepter as f,modifyVpcPeerAccepter as u,removeVpcPeerAccepter as P}from"./edits/vpcPeerAccepter.js";import{addCrossPlanConnection as R,modifyCrossPlanConnection as T,removeCrossPlanConnection as S}from"./edits/crossPlanConnection.js";import{resolveDriftPolicy as A}from"./edits/driftPolicy.js";import{listResources as V}from"./listResources.js";import{resolveConstructByLiteralProperty as y}from"./semanticIndex/index.js";import{parse as D}from"./fileRewriter/parse.js";import{CrossPlanConnectionResourcePlanSchema as N,VpcPeerAccepterResourcePlanSchema as h,VpcPeerResourcePlanSchema as F}from"../schemas/index.js";import{detectDrift as I,mergeProperties as M,snapshotProperties as O}from"./drift/index.js";import{computeLinesDelta as k}from"./_internal.js";import{ResourceNameSchema as U,StatementTypeSchema as K}from"./types.js";import{REGISTERED_STATEMENT_TYPES as j,STATEMENT_REGISTRY as q}from"./registry.js";import{evaluateEmitGuard as z,UNRESOLVED as H}from"./emitGuard.js";import{CODEMOD_ERROR_KINDS as Q}from"./telemetry/errorKinds.js";import{buildEgressBlockedEvent as X,buildFiredEvent as Z,buildGateFailedEvent as $,buildGatePassedEvent as ee,buildRejectedEvent as re,buildSucceededEvent as oe,buildTimeoutEvent as te,estimateCostUsd as ce,FALLBACK_EVENTS as pe,GATE_EVENTS as me,PARSE_GATE as ae,RUNTIME_GATE as se,runFallback as ne,shouldTryFallback as de}from"./llmFallback/index.js";export{Q as CODEMOD_ERROR_KINDS,N as CrossPlanConnectionResourcePlanSchema,pe as FALLBACK_EVENTS,me as GATE_EVENTS,ae as PARSE_GATE,j as REGISTERED_STATEMENT_TYPES,se as RUNTIME_GATE,U as ResourceNameSchema,q as STATEMENT_REGISTRY,K as StatementTypeSchema,H as UNRESOLVED,h as VpcPeerAccepterResourcePlanSchema,F as VpcPeerResourcePlanSchema,R as addCrossPlanConnection,o as addResource,d as addVpcPeer,f as addVpcPeerAccepter,s as appendAccountToStage,X as buildEgressBlockedEvent,Z as buildFiredEvent,$ as buildGateFailedEvent,ee as buildGatePassedEvent,re as buildRejectedEvent,oe as buildSucceededEvent,te as buildTimeoutEvent,k as computeLinesDelta,I as detectDrift,ce as estimateCostUsd,z as evaluateEmitGuard,V as listResources,M as mergeProperties,T as modifyCrossPlanConnection,m as modifyResource,E as modifyVpcPeer,u as modifyVpcPeerAccepter,D as parse,S as removeCrossPlanConnection,c as removeResource,i as removeVpcPeer,P as removeVpcPeerAccepter,y as resolveConstructByLiteralProperty,A as resolveDriftPolicy,ne as runFallback,de as shouldTryFallback,O as snapshotProperties};
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { type Result } from "../types/Result.js";
3
+ import { type EmitGuardRule } from "./emitGuard.js";
3
4
  import type { NodeLocation, SemanticQueryError, StatementType, TemplateLiteralNameError } from "./types.js";
4
5
  export type LocatorError = TemplateLiteralNameError | SemanticQueryError;
5
6
  export interface StatementLocator {
@@ -29,12 +30,12 @@ export interface StatementTypeEntry {
29
30
  /**
30
31
  * When present, the ADD path emits `app.<appMethod>(XFactory.build(...))`
31
32
  * instead of the bare factory call. MANDATORY for any type whose factory
32
- * returns a thunk that is only materialised by an App method AND whose
33
- * primary authoring path is `fjall add` (no scaffold emission) a bare
34
- * emission for such a type writes a synth-inert statement. Absent =
35
- * today's bare-emission behaviour. Contract pinned by the registry
36
- * parity test and the components-infrastructure `App.prototype`
37
- * method-existence test.
33
+ * returns a thunk that is only materialised by an App method `cdk.json`
34
+ * executes `infrastructure.ts` directly, so an unmaterialised thunk
35
+ * synthesises nothing at all and a bare emission is silently inert.
36
+ * Absent = bare emission, correct only for a factory that constructs
37
+ * eagerly. Contract pinned by the registry parity test and the
38
+ * components-infrastructure `App.prototype` method-existence test.
38
39
  *
39
40
  * `propsOverloadConstructId` is the construct id the App method pins when
40
41
  * called in the legacy props-direct form (`app.addBuildkite({ … })`) — it
@@ -42,11 +43,56 @@ export interface StatementTypeEntry {
42
43
  * value with no compiler across the seam; proven end-to-end by the
43
44
  * dogfood synth-parity AC). The legacy-shape classifier uses it to name
44
45
  * unmanaged method-form hits (design § D6).
46
+ *
47
+ * It is OPTIONAL because `addBuildkite` is the only App add-method with a
48
+ * props-direct overload; every other one takes a factory thunk and nothing
49
+ * else. Absent means "no props-direct form exists", which withholds the
50
+ * method name from the unmanaged classifier entirely. Inventing a value
51
+ * would make the symmetric idiom (`const b = StorageFactory.build(…);
52
+ * app.addStorage(b);`) and any foreign receiver's `.addStorage(...)`
53
+ * report as phantom unmanaged resources, and would offer migration
54
+ * guidance towards a form the App class does not accept.
45
55
  */
46
56
  emitWrapper?: {
47
57
  readonly appMethod: string;
48
- readonly propsOverloadConstructId: string;
58
+ readonly propsOverloadConstructId?: string;
49
59
  };
60
+ /**
61
+ * Property shapes the ADD and MODIFY paths must REFUSE to write, checked
62
+ * before any file is touched. Declared here, beside `emitWrapper`, because
63
+ * `emitWrapper` is precisely what creates the hazard: wrapping makes the
64
+ * emitted props load-bearing at synth, and the codemod writes resource-PLAN
65
+ * vocabulary verbatim into a file the constructs read as CONSTRUCT
66
+ * vocabulary. The generator scaffold has a translation layer for that seam
67
+ * (`generation/compute/lambda.ts` turns `codePath` into
68
+ * `Code.fromAsset(...)`); the codemod has none, so where the two
69
+ * vocabularies disagree the statement either takes the whole app's synth
70
+ * down or deploys infrastructure that is not what was asked for.
71
+ *
72
+ * Rules cover exactly two classes, and nothing else:
73
+ *
74
+ * · UNTRANSLATABLE — the construct requires a value no CLI flag can
75
+ * carry (a CDK `Code`/`Architecture`, an `IBucket`, a live sibling
76
+ * construct). No invocation can ever synthesise, so writing one is
77
+ * always wrong.
78
+ * · SILENTLY DROPPED — the construct never reads the plan key, so the
79
+ * resource deploys without the behaviour that was requested. Proven
80
+ * per key: zero `props.<key>` reads anywhere in
81
+ * @fjall/components-infrastructure.
82
+ *
83
+ * Deliberately NOT covered: INCOMPLETE input, where the vocabulary can
84
+ * express a working call and the operator has not yet. That fails loudly
85
+ * at synth naming the missing prop and is accepted behaviour — `fjall add
86
+ * buildkite` with no flags has always thrown `Buildkite: invalid props`.
87
+ * Nor is this general schema validation: unknown keys still pass straight
88
+ * through (a separate, recorded gap).
89
+ *
90
+ * Absent = every expressible property shape for this type reaches a
91
+ * synthesising statement. That is a claim, not an oversight: `network`,
92
+ * `vpc-peer` and `buildkite` each have full plan/construct parity, and the
93
+ * components-infrastructure materialisation contract pins it.
94
+ */
95
+ emitGuard?: ReadonlyArray<EmitGuardRule>;
50
96
  }
51
97
  declare const FACTORY_IDENTIFIERS: {
52
98
  readonly database: "DatabaseFactory";
@@ -1 +1 @@
1
- var l=Object.defineProperty;var a=(e,t)=>l(e,"name",{value:t,configurable:!0});import{z as s}from"zod";import{BuildkitePropsObjectSchema as S,CDNResourcePlanSchema as h,ComputeResourcePlanSchema as y,CrossPlanConnectionResourcePlanSchema as F,DatabaseResourcePlanSchema as P,NetworkResourcePlanSchema as b,NextJSPatternConfigSchema as f,OrganisationResourcePlanSchema as C,PayloadPatternConfigSchema as k,S3ResourcePlanSchema as E,SQSResourcePlanSchema as R,StaticSitePatternConfigSchema as _,VpcPeerAccepterResourcePlanSchema as T,VpcPeerResourcePlanSchema as v}from"../schemas/index.js";import{failure as w}from"../types/Result.js";const n={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 o(e){const{name:t,...c}=e.shape;return s.object(c).partial().strict()}a(o,"fragmentOf");const x=o(P),O=o(E),j=(()=>{const{name:e,...t}=y.shape;return s.object(t).partial().strict()})(),B=o(R),N=o(h),A=o(b),D=(()=>{const{name:e,type:t,cdn:c,...m}=k.shape,{name:$,type:z,cdn:J,...u}=f.shape,{name:L,type:q,domain:H,cdn:d,...g}=_.shape;return s.object({...m,...u,...g,cdn:s.union([c,d])}).partial().strict()})(),I=o(v),M=o(T),V=o(F),G=o(C),Y=o(S);function i(e,t){return w({kind:"SemanticQueryError",reason:`StatementTypeEntry.${e} for ${t} is not wired; existing types dispatch through the shared locator/generator.`})}a(i,"notWiredError");function Q(e){return{factoryIdentifier:e,findByShape:a(()=>i("locator.findByShape",e),"findByShape"),validateContext:a(()=>i("locator.validateContext",e),"validateContext")}}a(Q,"createLocator");function W(e){return{build:a(()=>{const t=i("generator.build",e);throw new Error(t.success?"unreachable":t.error.reason)},"build")}}a(W,"createGenerator");function r(e,t,c={}){return{factoryIdentifier:e,locator:Q(e),generator:W(e),schemaFragment:t,...c}}a(r,"createEntry");const p={database:r(n.database,x),storage:r(n.storage,O),compute:r(n.compute,j),messaging:r(n.messaging,B),cdn:r(n.cdn,N),network:r(n.network,A),pattern:r(n.pattern,D),"vpc-peer":r(n["vpc-peer"],I),"vpc-peer-accepter":r(n["vpc-peer-accepter"],M),"cross-plan-connection":r(n["cross-plan-connection"],V),organisation:r(n.organisation,G),buildkite:r(n.buildkite,Y,{emitWrapper:{appMethod:"addBuildkite",propsOverloadConstructId:"Buildkite"}})},ee=Object.keys(p);function te(e){const t=Object.keys(p);for(const c of t)if(p[c].factoryIdentifier===e)return c}a(te,"findTypeByIdentifier");export{ee as REGISTERED_STATEMENT_TYPES,p as STATEMENT_REGISTRY,te as findTypeByIdentifier};
1
+ var v=Object.defineProperty;var a=(e,t)=>v(e,"name",{value:t,configurable:!0});import{z as u}from"zod";import{BuildkitePropsObjectSchema as E,CDNResourcePlanSchema as R,ComputeResourcePlanSchema as k,CrossPlanConnectionResourcePlanSchema as T,DatabaseResourcePlanSchema as w,NetworkResourcePlanSchema as A,NextJSPatternConfigSchema as F,OrganisationResourcePlanSchema as N,PayloadPatternConfigSchema as M,S3ResourcePlanSchema as D,SQSResourcePlanSchema as x,StaticSitePatternConfigSchema as G,VpcPeerAccepterResourcePlanSchema as W,VpcPeerResourcePlanSchema as _}from"../schemas/index.js";import{failure as O}from"../types/Result.js";import{isRecord as I}from"./_internal.js";import{AUTHOR_BY_HAND as c,requiresLiveValue as f,silentlyDropped as n,UNRESOLVED as h,whenAbsent as p}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,...i}=e.shape;return u.object(i).partial().strict()}a(s,"fragmentOf");const B=s(w),j=s(D),q=(()=>{const{name:e,...t}=k.shape;return u.object(t).partial().strict()})(),L=s(x),V=s(R),Y=s(A),K=(()=>{const{name:e,type:t,cdn:i,...b}=M.shape,{name:se,type:ie,cdn:ce,...P}=F.shape,{name:pe,type:de,domain:ue,cdn:S,...C}=G.shape;return u.object({...b,...P,...C,cdn:u.union([i,S])}).partial().strict()})(),U=s(_),z=s(W),H=s(T),Q=s(N),$=s(E);function g(e,t){return O({kind:"SemanticQueryError",reason:`StatementTypeEntry.${e} for ${t} is not wired; existing types dispatch through the shared locator/generator.`})}a(g,"notWiredError");function J(e){return{factoryIdentifier:e,findByShape:a(()=>g("locator.findByShape",e),"findByShape"),validateContext:a(()=>g("locator.validateContext",e),"validateContext")}}a(J,"createLocator");function X(e){return{build:a(()=>{const t=g("generator.build",e);throw new Error(t.success?"unreachable":t.error.reason)},"build")}}a(X,"createGenerator");const m=n("variableName","`variableName` is a plan-only round-trip key naming the `const <var> =` binding the scaffold emits; no construct reads it."),d=n("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."),Z=[n("engineExpression","`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."),m,d],ee=[m,d],l="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.",te=[{property:"deployment",refuseWhen:a(e=>(e.type==="lambda"||e.deployment!==void 0)&&e.deployment!=="container"&&e.code!==h,"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."},n("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."),f("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."),f("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."),n("memory","the Lambda construct reads `memorySize`, so `--memory 1024` deploys a function at the 128 MB default."),n("ssmSecrets","the Lambda construct reads `secrets`, so `--ssmSecrets` deploys a function with no SSM wiring and no secrets environment at all."),n("scheduleExpression","`scheduleExpression` is not a compute prop: the scaffold turns it into a SEPARATE `app.addSchedule(...)` statement, which this command cannot emit."),n("needsConnection",l),n("connectedDatabase",l),n("connectedStorage",l),n("connectedMessaging",l),m,d],ae=[{property:"type",refuseWhen:p("type"),reason:"`MessagingFactory.build` selects queue/topic/eventBus from a `type` discriminator that the messaging vocabulary does not carry, so a queue built from messaging properties throws `Unsupported messaging type: undefined` the moment `app.addMessaging` materialises it. "+c},n("retentionPeriod","the queue construct reads `messageRetentionPeriod`, so `--retentionPeriod` deploys a queue at the 4-day default."),m,d],ne=[{property:"originType",refuseWhen:p("originType"),reason:"`Cdn` selects its origin implementation from an `originType` discriminator that the CDN vocabulary does not carry, so a distribution built from CDN properties throws `Unsupported CDN origin type: undefined` the moment `app.addCdn` materialises it. "+c},{property:"originType",refuseWhen:a(e=>e.originType==="s3"&&e.bucket!==h,"refuseWhen"),reason:"an s3 origin needs `bucket` to be an `IBucket` or a Fjall `Storage` \u2014 a live construct, not a name, and not a string; omitting it throws `Cannot read properties of undefined (reading 'bucketRegionalDomainName')` at synth. "+c},{property:"originType",refuseWhen:a(e=>e.originType==="alb"&&e.loadBalancer!==h,"refuseWhen"),reason:'an alb origin needs `loadBalancer` to be an `IApplicationLoadBalancer` or an ECS compute \u2014 a live construct, not a name, and not a string; a string reaches CloudFormation as `Supplied properties not correct for "OriginProperty"`. '+c},{property:"behaviours",refuseWhen:a(e=>Array.isArray(e.behaviours)&&e.behaviours.some(t=>I(t)&&t.originRef!==void 0),"refuseWhen"),reason:"the plan's `behaviours[].originRef` names another planned resource, while the construct's behaviour takes a live origin object; the plan shape throws `Cannot read properties of undefined (reading 'computeType')` at synth. "+c},n("customDomain","the distribution reads `domainNames`, so `--customDomain` deploys a distribution with no alias."),n("defaultOriginRef","`defaultOriginRef` names another planned resource for the scaffold to resolve into a live origin; no CDN construct reads it."),d],re=[{property:"name",refuseWhen:p("name"),reason:"every pattern construct requires a `name` PROPERTY in addition to its construct id, and `fjall add --name` binds the construct id, so no invocation can deliver it \u2014 `toPascalCase(props.name)` throws at synth and takes the whole app down. "+c},{property:"type",refuseWhen:p("type"),reason:"`PatternFactory.build` reads `PATTERN_REGISTRY[props.type]` before it even returns the thunk, and the pattern vocabulary carries no `type` discriminator. "+c}],oe=[{property:"peerAppName",refuseWhen:p("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:p("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,i={}){return{factoryIdentifier:e,locator:J(e),generator:X(e),schemaFragment:t,...i}}a(o,"createEntry");const y={database:o(r.database,B,{emitWrapper:{appMethod:"addDatabase"},emitGuard:Z}),storage:o(r.storage,j,{emitWrapper:{appMethod:"addStorage"},emitGuard:ee}),compute:o(r.compute,q,{emitWrapper:{appMethod:"addCompute"},emitGuard:te}),messaging:o(r.messaging,L,{emitWrapper:{appMethod:"addMessaging"},emitGuard:ae}),cdn:o(r.cdn,V,{emitWrapper:{appMethod:"addCdn"},emitGuard:ne}),network:o(r.network,Y,{emitWrapper:{appMethod:"addNetwork"}}),pattern:o(r.pattern,K,{emitWrapper:{appMethod:"addPattern"},emitGuard:re}),"vpc-peer":o(r["vpc-peer"],U,{emitWrapper:{appMethod:"addVpcPeer"},emitGuard:oe}),"vpc-peer-accepter":o(r["vpc-peer-accepter"],z,{emitWrapper:{appMethod:"addVpcPeerAccepter"}}),"cross-plan-connection":o(r["cross-plan-connection"],H),organisation:o(r.organisation,Q),buildkite:o(r.buildkite,$,{emitWrapper:{appMethod:"addBuildkite",propsOverloadConstructId:"Buildkite"}})},be=Object.keys(y);function Pe(e){const t=Object.keys(y);for(const i of t)if(y[i].factoryIdentifier===e)return i}a(Pe,"findTypeByIdentifier");export{be as REGISTERED_STATEMENT_TYPES,y as STATEMENT_REGISTRY,Pe as findTypeByIdentifier};
@@ -38,8 +38,9 @@ export type LocatedShape = NodeLocation & {
38
38
  /**
39
39
  * Walks every call expression in the source and returns a
40
40
  * {@link LocatedShape} for each `XFactory.build("Name", ...)` shape,
41
- * plus an unmanaged hit for each legacy method-form call declared via
42
- * the registry's `emitWrapper`. The traversal descends into
41
+ * plus an unmanaged hit for each legacy method-form call the App methods
42
+ * carrying a props-direct overload, per {@link UNMANAGED_METHOD_TYPES}.
43
+ * The traversal descends into
43
44
  * `IfStatement`, `Block`, `ForStatement`, and function bodies via
44
45
  * `forEachDescendant`.
45
46
  *
@@ -49,10 +50,11 @@ export type LocatedShape = NodeLocation & {
49
50
  */
50
51
  export declare function locateAllShapes(content: string, filePath?: string): Result<LocatedShape[], LocateByShapeError>;
51
52
  /**
52
- * A legacy method-form call (`app.addBuildkite({ … })`) recognised via
53
- * the registry's `emitWrapper` declarations. `methodStart`/`methodLength`
54
- * anchor the method-name token — there is no name string literal to
55
- * anchor on, so write paths must never consume this span.
53
+ * A legacy method-form call (`app.addBuildkite({ … })`) recognised via the
54
+ * registry's `emitWrapper.propsOverloadConstructId` declarations.
55
+ * `methodStart`/`methodLength` anchor the method-name token — there is no
56
+ * name string literal to anchor on, so write paths must never consume this
57
+ * span.
56
58
  */
57
59
  export interface UnmanagedMethodMatch {
58
60
  type: StatementType;
@@ -1 +1 @@
1
- var h=Object.defineProperty;var c=(n,e)=>h(n,"name",{value:e,configurable:!0});import{Node as l,SyntaxKind as s}from"ts-morph";import{failure as u,success as d}from"../../types/Result.js";import{DEFAULT_FILE_PATH as f}from"../_internal.js";import{findTypeByIdentifier as E,STATEMENT_REGISTRY as S}from"../registry.js";import{getProject as T}from"./projectCache.js";function w(n,e,t=f){const a=A(n,t);if(!a.success)return a;const r=a.data.find(i=>i.type===e.type&&i.symbolName===e.name);return d(r)}c(w,"locateByShape");function A(n,e=f){const t=[],a=x(n,e,r=>{t.push({filePath:e,start:r.nameStart,length:r.nameLength,symbolName:r.name,type:r.type})},r=>{t.push({filePath:e,start:r.methodStart,length:r.methodLength,symbolName:r.name,type:r.type,managed:!1})});return a.success?d(t):a}c(A,"locateAllShapes");function x(n,e,t,a){let r;try{r=T().createSourceFile(e,n,{overwrite:!0})}catch(i){return u({kind:"SemanticQueryError",reason:"Failed to create source file",cause:i})}try{r.forEachDescendant(i=>{if(!l.isCallExpression(i))return;const o=N(i);if(o==="not-factory-call"){if(a!==void 0){const p=b(i);p!==void 0&&a(p,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 d(void 0)}c(x,"forEachFactoryMatch");function N(n){const e=n.getExpression();if(!l.isPropertyAccessExpression(e))return"not-factory-call";const t=m(e);if(t===void 0||g(n))return"not-factory-call";if(k(n))return{kind:"binding-pattern-declared"};const r=n.getArguments()[0];return r===void 0?"not-factory-call":l.isTemplateExpression(r)||l.isNoSubstitutionTemplateLiteral(r)?{kind:"template-literal-name",type:t}:l.isStringLiteral(r)?{kind:"match",type:t,name:r.getLiteralValue(),nameStart:r.getStart(),nameLength:r.getWidth()}:"not-factory-call"}c(N,"classifyFactoryCall");const L=new Map(Object.entries(S).flatMap(([n,e])=>e.emitWrapper===void 0?[]:[[e.emitWrapper.appMethod,{type:n,name:e.emitWrapper.propsOverloadConstructId}]]));function b(n){const e=n.getExpression();if(!l.isPropertyAccessExpression(e))return;const t=L.get(e.getName());if(t===void 0||g(n))return;const a=n.getArguments()[0];if(a!==void 0&&l.isCallExpression(a)){const i=a.getExpression();if(l.isPropertyAccessExpression(i)&&m(i)!==void 0)return}const r=e.getNameNode();return{type:t.type,name:t.name,methodStart:r.getStart(),methodLength:r.getWidth()}}c(b,"classifyUnmanagedMethodCall");function m(n){const e=n.getExpression();if(l.isIdentifier(e)&&n.getName()==="build")return E(e.getText())}c(m,"factoryTypeFromPropertyAccess");function g(n){let e=n.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 k(n){const e=n.getFirstAncestorByKind(s.VariableDeclaration);if(e===void 0)return!1;const a=e.getNameNode().getKind();return a===s.ObjectBindingPattern||a===s.ArrayBindingPattern}c(k,"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(),r=this.call.getSourceFile(),{line:i,column:o}=r.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{x as forEachFactoryMatch,A as locateAllShapes,w as locateByShape};
1
+ var h=Object.defineProperty;var c=(n,e)=>h(n,"name",{value:e,configurable:!0});import{Node as l,SyntaxKind as s}from"ts-morph";import{failure as u,success as d}from"../../types/Result.js";import{DEFAULT_FILE_PATH as p}from"../_internal.js";import{findTypeByIdentifier as E,STATEMENT_REGISTRY as S}from"../registry.js";import{getProject as T}from"./projectCache.js";function w(n,e,t=p){const a=A(n,t);if(!a.success)return a;const r=a.data.find(i=>i.type===e.type&&i.symbolName===e.name);return d(r)}c(w,"locateByShape");function A(n,e=p){const t=[],a=x(n,e,r=>{t.push({filePath:e,start:r.nameStart,length:r.nameLength,symbolName:r.name,type:r.type})},r=>{t.push({filePath:e,start:r.methodStart,length:r.methodLength,symbolName:r.name,type:r.type,managed:!1})});return a.success?d(t):a}c(A,"locateAllShapes");function x(n,e,t,a){let r;try{r=T().createSourceFile(e,n,{overwrite:!0})}catch(i){return u({kind:"SemanticQueryError",reason:"Failed to create source file",cause:i})}try{r.forEachDescendant(i=>{if(!l.isCallExpression(i))return;const o=N(i);if(o==="not-factory-call"){if(a!==void 0){const f=b(i);f!==void 0&&a(f,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 d(void 0)}c(x,"forEachFactoryMatch");function N(n){const e=n.getExpression();if(!l.isPropertyAccessExpression(e))return"not-factory-call";const t=m(e);if(t===void 0||g(n))return"not-factory-call";if(k(n))return{kind:"binding-pattern-declared"};const r=n.getArguments()[0];return r===void 0?"not-factory-call":l.isTemplateExpression(r)||l.isNoSubstitutionTemplateLiteral(r)?{kind:"template-literal-name",type:t}:l.isStringLiteral(r)?{kind:"match",type:t,name:r.getLiteralValue(),nameStart:r.getStart(),nameLength:r.getWidth()}:"not-factory-call"}c(N,"classifyFactoryCall");const L=new Map(Object.entries(S).flatMap(([n,e])=>{const t=e.emitWrapper?.propsOverloadConstructId;return e.emitWrapper===void 0||t===void 0?[]:[[e.emitWrapper.appMethod,{type:n,name:t}]]}));function b(n){const e=n.getExpression();if(!l.isPropertyAccessExpression(e))return;const t=L.get(e.getName());if(t===void 0||g(n))return;const a=n.getArguments()[0];if(a!==void 0&&l.isCallExpression(a)){const i=a.getExpression();if(l.isPropertyAccessExpression(i)&&m(i)!==void 0)return}const r=e.getNameNode();return{type:t.type,name:t.name,methodStart:r.getStart(),methodLength:r.getWidth()}}c(b,"classifyUnmanagedMethodCall");function m(n){const e=n.getExpression();if(l.isIdentifier(e)&&n.getName()==="build")return E(e.getText())}c(m,"factoryTypeFromPropertyAccess");function g(n){let e=n.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 k(n){const e=n.getFirstAncestorByKind(s.VariableDeclaration);if(e===void 0)return!1;const a=e.getNameNode().getKind();return a===s.ObjectBindingPattern||a===s.ArrayBindingPattern}c(k,"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(),r=this.call.getSourceFile(),{line:i,column:o}=r.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{x as forEachFactoryMatch,A as locateAllShapes,w as locateByShape};
@@ -1 +1 @@
1
- export declare const GENERATOR_VERSION = "7.0.1";
1
+ export declare const GENERATOR_VERSION = "7.2.0";
@@ -1 +1 @@
1
- const E="7.0.1";export{E as GENERATOR_VERSION};
1
+ const E="7.2.0";export{E as GENERATOR_VERSION};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/generator",
3
- "version": "7.0.1",
3
+ "version": "7.2.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/fjall-tech/fjall.git",
@@ -53,7 +53,7 @@
53
53
  },
54
54
  "license": "SEE LICENSE IN LICENSE",
55
55
  "dependencies": {
56
- "@fjall/util": "^7.0.1",
56
+ "@fjall/util": "^7.2.0",
57
57
  "ast-types": "^0.16.1",
58
58
  "recast": "^0.23.12",
59
59
  "ts-morph": "^28.0.0",