@fjall/generator 3.2.1 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/.minified +1 -1
  2. package/dist/src/codemod/drift/types.d.ts +2 -0
  3. package/dist/src/codemod/edits/addResource/appBinding.d.ts +16 -0
  4. package/dist/src/codemod/edits/addResource/appBinding.js +1 -0
  5. package/dist/src/codemod/edits/addResource/bodyIndex.js +1 -1
  6. package/dist/src/codemod/edits/addResource.d.ts +2 -2
  7. package/dist/src/codemod/edits/addResource.js +1 -1
  8. package/dist/src/codemod/edits/findInsertionPosition.d.ts +7 -6
  9. package/dist/src/codemod/edits/findInsertionPosition.js +1 -1
  10. package/dist/src/codemod/edits/modifyResource.js +1 -1
  11. package/dist/src/codemod/edits/removeResource.js +1 -1
  12. package/dist/src/codemod/edits/unmanagedShapeErrors.d.ts +3 -0
  13. package/dist/src/codemod/edits/unmanagedShapeErrors.js +1 -0
  14. package/dist/src/codemod/fileRewriter/builders.d.ts +13 -0
  15. package/dist/src/codemod/fileRewriter/builders.js +1 -1
  16. package/dist/src/codemod/fileRewriter/index.d.ts +1 -1
  17. package/dist/src/codemod/fileRewriter/index.js +1 -1
  18. package/dist/src/codemod/fileRewriter/print.d.ts +4 -1
  19. package/dist/src/codemod/fileRewriter/print.js +2 -2
  20. package/dist/src/codemod/index.d.ts +2 -1
  21. package/dist/src/codemod/index.js +1 -1
  22. package/dist/src/codemod/listResources.js +1 -1
  23. package/dist/src/codemod/registry.d.ts +22 -0
  24. package/dist/src/codemod/registry.js +1 -1
  25. package/dist/src/codemod/semanticIndex/index.d.ts +1 -1
  26. package/dist/src/codemod/semanticIndex/locateByShape.d.ts +34 -7
  27. package/dist/src/codemod/semanticIndex/locateByShape.js +1 -1
  28. package/dist/src/codemod/telemetry/errorKinds.d.ts +3 -1
  29. package/dist/src/codemod/telemetry/errorKinds.js +1 -1
  30. package/dist/src/codemod/types.d.ts +26 -1
  31. package/dist/src/codemod/types.js +1 -1
  32. package/dist/src/schemas/buildkiteSchemas.d.ts +134 -0
  33. package/dist/src/schemas/buildkiteSchemas.js +3 -0
  34. package/dist/src/schemas/index.d.ts +1 -0
  35. package/dist/src/schemas/index.js +1 -1
  36. package/dist/src/version.d.ts +1 -1
  37. package/dist/src/version.js +1 -1
  38. package/package.json +3 -3
package/dist/.minified CHANGED
@@ -1 +1 @@
1
- 143 files minified at 2026-07-18T08:44:00.457Z
1
+ 146 files minified at 2026-07-18T12:19:05.639Z
@@ -15,6 +15,7 @@ export declare const ResourceSnapshotSchema: z.ZodObject<{
15
15
  "vpc-peer-accepter": "vpc-peer-accepter";
16
16
  "cross-plan-connection": "cross-plan-connection";
17
17
  organisation: "organisation";
18
+ buildkite: "buildkite";
18
19
  }>;
19
20
  name: z.ZodString;
20
21
  properties: z.ZodRecord<z.ZodString, z.ZodUnknown>;
@@ -34,6 +35,7 @@ export declare const DriftStateSchema: z.ZodObject<{
34
35
  "vpc-peer-accepter": "vpc-peer-accepter";
35
36
  "cross-plan-connection": "cross-plan-connection";
36
37
  organisation: "organisation";
38
+ buildkite: "buildkite";
37
39
  }>;
38
40
  name: z.ZodString;
39
41
  }, z.core.$strict>;
@@ -0,0 +1,16 @@
1
+ import type { StatementNodeLike } from "./bodyIndex.js";
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.
8
+ */
9
+ export declare function matchAppGetAppBinding(stmt: StatementNodeLike): string | undefined;
10
+ /**
11
+ * 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
+ */
16
+ export declare function resolveAppBindingName(body: readonly StatementNodeLike[]): string | undefined;
@@ -0,0 +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 +1 @@
1
- var l=Object.defineProperty;var p=(e,t)=>l(e,"name",{value:t,configurable:!0});import{isRecord as u}from"../../_internal.js";import{findTypeByIdentifier as y}from"../../registry.js";function g(e,t){const n=[],r=[],i=[];let o=t.length;for(let c=0;c<e.length;c+=1){const s=e[c];if(s===void 0)continue;const a=typeof s.start=="number"?s.start:0,d=typeof s.end=="number"?s.end:a;d>o&&(o=d);const f=m(s);n.push({index:c,start:a,end:d,type:f}),f==="import"?r.push({endPos:d}):(f==="app-init"||f==="tags")&&i.push({endPos:d,type:f})}return{anchors:n,importInfos:r,appInitLocations:i,programEnd:o}}p(g,"indexBody");function m(e){if(e.type==="ImportDeclaration")return"import";if(e.type!=="ExpressionStatement")return;const t=e.expression;if(!u(t)||t.type!=="CallExpression")return;const n=t.callee;if(!u(n)||n.type!=="MemberExpression")return;const r=n.object,i=n.property;if(!u(r)||r.type!=="Identifier"||!u(i)||i.type!=="Identifier"||i.name!=="build")return;const o=r.name;if(typeof o=="string")return o==="AppFactory"?"app-init":y(o)}p(m,"classifyStatement");function b(e,t){const n=[];for(const r of t){const i=e.find(o=>o.start<=r.start&&o.end>=r.start+r.length);i!==void 0&&n.push({endPos:i.end,type:r.type})}return n}p(b,"buildResourceLocations");function P(e){return[...e].sort((t,n)=>t.endPos-n.endPos)}p(P,"orderByEndPos");function E(e,t){const n=e.find(r=>r.end===t);return n!==void 0?n.index+1:e.length}p(E,"resolveInsertIndex");export{b as buildResourceLocations,g as indexBody,P as orderByEndPos,E as resolveInsertIndex};
1
+ var y=Object.defineProperty;var d=(e,t)=>y(e,"name",{value:t,configurable:!0});import{isRecord as c}from"../../_internal.js";import{findTypeByIdentifier as l}from"../../registry.js";import{matchAppGetAppBinding as m}from"./appBinding.js";function P(e,t){const n=[],r=[],o=[];let i=t.length;for(let s=0;s<e.length;s+=1){const p=e[s];if(p===void 0)continue;const a=typeof p.start=="number"?p.start:0,f=typeof p.end=="number"?p.end:a;f>i&&(i=f);const u=x(p);n.push({index:s,start:a,end:f,type:u}),u==="import"?r.push({endPos:f}):(u==="app-init"||u==="tags")&&o.push({endPos:f,type:u})}return{anchors:n,importInfos:r,appInitLocations:o,programEnd:i}}d(P,"indexBody");function x(e){if(e.type==="ImportDeclaration")return"import";if(m(e)!==void 0)return"app-init";if(e.type!=="ExpressionStatement")return;const t=e.expression;if(!c(t)||t.type!=="CallExpression")return;const n=t.callee;if(!c(n)||n.type!=="MemberExpression")return;const r=n.object,o=n.property;if(!c(r)||r.type!=="Identifier"||!c(o)||o.type!=="Identifier")return;const i=r.name,s=o.name;if(!(typeof i!="string"||typeof s!="string")){if(s==="addTags")return"tags";if(s==="build")return i==="AppFactory"?"app-init":l(i)}}d(x,"classifyStatement");function E(e,t){const n=[];for(const r of t){const o=e.find(i=>i.start<=r.start&&i.end>=r.start+r.length);o!==void 0&&n.push({endPos:o.end,type:r.type})}return n}d(E,"buildResourceLocations");function B(e){return[...e].sort((t,n)=>t.endPos-n.endPos)}d(B,"orderByEndPos");function j(e,t){const n=e.find(r=>r.end===t);return n!==void 0?n.index+1:e.length}d(j,"resolveInsertIndex");export{E as buildResourceLocations,P as indexBody,B as orderByEndPos,j as resolveInsertIndex};
@@ -1,8 +1,8 @@
1
1
  import { type Result } from "../../types/Result.js";
2
2
  import { type ResourceSnapshot } from "../drift/index.js";
3
- import type { AddOptions, ControlFlowClassifierError, DriftConflictError, DuplicateResourceError, InvalidPropertyError, LinesChanged, ParseError, SemanticQueryError, TemplateLiteralNameError } from "../types.js";
3
+ import type { AddOptions, ControlFlowClassifierError, DriftConflictError, DuplicateResourceError, InvalidPropertyError, LinesChanged, MissingAppInitError, ParseError, SemanticQueryError, TemplateLiteralNameError } from "../types.js";
4
4
  export type { AddOptions, LinesChanged } from "../types.js";
5
- export type AddResourceError = ParseError | TemplateLiteralNameError | DuplicateResourceError | InvalidPropertyError | SemanticQueryError | DriftConflictError | ControlFlowClassifierError;
5
+ export type AddResourceError = ParseError | TemplateLiteralNameError | DuplicateResourceError | InvalidPropertyError | SemanticQueryError | MissingAppInitError | DriftConflictError | ControlFlowClassifierError;
6
6
  export interface AddResourceSuccess {
7
7
  content: string;
8
8
  linesChanged: LinesChanged;
@@ -1 +1 @@
1
- var T=Object.defineProperty;var u=(e,r)=>T(e,"name",{value:r,configurable:!0});import{failure as o,success as S}from"../../types/Result.js";import{DEFAULT_FILE_PATH as F,computeLinesDelta as C,extractProgramBody as D,isRecord as b}from"../_internal.js";import{appendSpecifier as x,buildFactoryStatement as w,buildImportDeclaration as Q,detectQuoteStyle as v,parse as A,printFile as _}from"../fileRewriter/index.js";import{STATEMENT_REGISTRY as B}from"../registry.js";import{locateAllShapes as G,locateByShape as N}from"../semanticIndex/index.js";import{checkControlFlowPolicy as O}from"./controlFlowPolicy.js";import{driftGate as U,runPipeline as M,schemaGate as Y}from"../validationGate/index.js";import{buildResourceLocations as j,indexBody as q,orderByEndPos as H,resolveInsertIndex as $}from"./addResource/bodyIndex.js";import{buildPropertyInputs as z}from"./addResource/propertyBuilder.js";import{findInsertionPosition as J}from"./findInsertionPosition.js";const I="@fjall/components-infrastructure";function cr(e,r,d={}){const i=r.filePath??F,a=A(e,i);if(!a.success)return o(a.error);const t=N(e,{type:r.type,name:r.name},i);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){const E=O({ast:a.data,target:t.data,resource:{type:r.type,name:r.name},op:"add"});if(E.refusal!==void 0)return o(E.refusal);const m=M([Y,U],{content:e,plan:{type:r.type,name:r.name,properties:r.properties,op:"add"},baseline:d.baseline,policy:r.driftPolicy});return m.success?m.data.action==="skip"?S({content:e,linesChanged:{added:0,removed:0},skipped:!0}):o({kind:"DuplicateResourceError",type:r.type,name:r.name}):o(K(m.error))}const p=v(a.data),l=z(r.properties,p);if(!l.success)return o(l.error);const f=B[r.type].factoryIdentifier,h=w({factory:f,name:r.name,properties:l.data,quoteStyle:p}),c=D(a.data);if(c===void 0)return o({kind:"SemanticQueryError",reason:"recast File is missing program.body"});const s=q(c,e),n=G(e,i);if(!n.success)return n.error.kind==="TemplateLiteralNameError"?o(n.error):o({kind:"SemanticQueryError",reason:n.error.reason,cause:n.error.cause});const k=j(s.anchors,n.data),L=H([...s.appInitLocations,...k]),P=J(s.importInfos,L,r.type,s.programEnd),R=$(s.anchors,P);c.splice(R,0,h),V(c,f,p);const y=_(a.data,e),g=C(e,y);return S({content:y,linesChanged:g})}u(cr,"addResource");function K(e){switch(e.kind){case"ParseError":case"TemplateLiteralNameError":case"DuplicateResourceError":case"InvalidPropertyError":case"SemanticQueryError":case"DriftConflictError":case"ControlFlowClassifierError":return e;default:return{kind:"SemanticQueryError",reason:`Unexpected codemod error in validation-gate pipeline: ${e.kind}`}}}u(K,"narrowGateError");function V(e,r,d){for(const a of e){if(a.type!=="ImportDeclaration")continue;const t=a.source;if(!(!b(t)||t.type!=="StringLiteral")&&t.value===I){x(a,r);return}}const i=Q([r],I,d);e.unshift(i)}u(V,"ensureFactoryImport");export{cr as addResource};
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};
@@ -13,12 +13,13 @@ export interface ImportInfo {
13
13
  }
14
14
  /**
15
15
  * Ordering superset of {@link StatementType}. The codemod engine only
16
- * manipulates the 7 factory-call kinds declared in `StatementType`, but
17
- * the legacy algorithm also recognises `import`, `app-init`, and `tags`
18
- * as positioning anchors. Callers pass `import` entries via the
19
- * dedicated {@link ImportInfo} list; `app-init` and `tags` are currently
20
- * unreachable in Phase 1 (no managed-statement detection for them) and
21
- * retained here purely so the ordering matches the legacy source.
16
+ * manipulates the factory-call kinds declared in `StatementType`, but
17
+ * `import`, `app-init`, and `tags` also serve as positioning anchors.
18
+ * Callers pass `import` entries via the dedicated {@link ImportInfo}
19
+ * list; `app-init` (bare `AppFactory.build` or a `const app =
20
+ * App.getApp(...)` binding) and `tags` (`app.addTags(...)`) are
21
+ * classified by `bodyIndex.ts` so wrapped emission lands after the
22
+ * binding it references.
22
23
  */
23
24
  export type InsertionStatementType = StatementType | "import" | "app-init" | "tags";
24
25
  /**
@@ -1 +1 @@
1
- var d=Object.defineProperty;var i=(n,e)=>d(n,"name",{value:e,configurable:!0});const r={import:0,"app-init":1,tags:2,organisation:3,database:4,storage:5,messaging:6,compute:7,network:8,"vpc-peer":9,"vpc-peer-accepter":10,"cross-plan-connection":11,cdn:12,pattern:13};function g(n,e,a,c){const s=r[a];let o;const p=r.import;for(const t of n)p<=s&&(o=t.endPos);for(const t of e)r[t.type]<=s&&(o=t.endPos);return o??c}i(g,"findInsertionPosition");export{g as findInsertionPosition};
1
+ var d=Object.defineProperty;var s=(n,e)=>d(n,"name",{value:e,configurable:!0});const r={import:0,"app-init":1,tags:2,organisation:3,database:4,storage:5,messaging:6,compute:7,network:8,"vpc-peer":9,"vpc-peer-accepter":10,"cross-plan-connection":11,cdn:12,pattern:13,buildkite:14};function g(n,e,a,c){const i=r[a];let o;const p=r.import;for(const t of n)p<=i&&(o=t.endPos);for(const t of e)r[t.type]<=i&&(o=t.endPos);return o??c}s(g,"findInsertionPosition");export{g as findInsertionPosition};
@@ -1 +1 @@
1
- var S=Object.defineProperty;var d=(r,e)=>S(r,"name",{value:e,configurable:!0});import{failure as c,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 T,printFile as A}from"../fileRewriter/index.js";import{STATEMENT_REGISTRY as F}from"../registry.js";import{locateAllShapes as R,locateByShape as L}from"../semanticIndex/index.js";import{checkControlFlowPolicy as j}from"./controlFlowPolicy.js";import{driftGate as O,runPipeline as Q,schemaGate as I}from"../validationGate/index.js";import{toAstValue as G}from"./addResource/propertyBuilder.js";import{buildMergedLiteral as U,isNodeShape as E,readKeyName as B}from"./modifyResource/literalConversion.js";function ne(r,e,a={}){const i=e.filePath??v,t=T(r,i);if(!t.success)return c(t.error);const n=L(r,{type:e.type,name:e.name},i);if(!n.success)return n.error.kind==="TemplateLiteralNameError"?c(n.error):c({kind:"SemanticQueryError",reason:n.error.reason,cause:n.error.cause});if(n.data===void 0)return c({kind:"ResourceNotFoundError",type:e.type,name:e.name,knownNames:$(r,e.type,i)});const o=j({ast:t.data,target:n.data,resource:{type:e.type,name:e.name},op:"modify"});if(o.refusal!==void 0)return c(o.refusal);const s=Q([I,O],{content:r,plan:{type:e.type,name:e.name,properties:e.properties,op:"modify"},baseline:a.baseline,policy:e.driftPolicy});if(!s.success)return c(D(s.error));if(s.data.action==="skip")return p({content:r,linesChanged:{added:0,removed:0},skipped:!0});const u=C(t.data);if(u===void 0)return c({kind:"SemanticQueryError",reason:"recast File is missing program.body"});const l=K(u,n.data);if(l===void 0)return c({kind:"SemanticQueryError",reason:"Unable to resolve config ObjectExpression for the located resource."});const k=x(t.data),b=U(l,e.properties),y=F[e.type].schemaFragment.safeParse(b);if(!y.success){const f=y.error.issues[0];return c({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=_(l,e.properties,k);if(!g.success)return c(g.error);const h=A(t.data,r),P=o.warning!==void 0?[o.warning.message]:void 0;return p({content:h,linesChanged:w(r,h),warnings:P})}d(ne,"modifyResource");function D(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(D,"narrowGateError");function K(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 s=o[0];if(!E(s)||s.type!=="StringLiteral"||s.start!==e.start||s.end!==a)return;const u=o[1];E(u)&&u.type==="ObjectExpression"&&(i=u)},"visitor");for(const n of r)if(H(n,t),i!==void 0)break;return i}d(K,"findConfigObject");function _(r,e,a){const i=V(r);for(const[t,n]of Object.entries(e)){const o=G(n,a);if(o===void 0)return c({kind:"InvalidPropertyError",property:t,reason:`Unsupported property value for "${t}" (accepts string/number/boolean/null/array/object of the same).`});const s=M(r,t);if(s!==void 0){s.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(_,"applyPropertyEdits");function M(r,e){return r.properties.find(a=>(a.type==="Property"||a.type==="ObjectProperty")&&a.shorthand!==!0&&a.computed!==!0&&B(a.key)===e)}d(M,"findPropertyByKey");function V(r){return r.properties[r.properties.length-1]?.extra?.trailingComma===!0}d(V,"detectTrailingCommaStyle");function $(r,e,a){const i=R(r,a);return i.success?i.data.filter(t=>t.type===e).map(t=>t.symbolName):[]}d($,"collectKnownNames");function H(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(H,"visit");export{ne as modifyResource};
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 +1 @@
1
- var g=Object.defineProperty;var u=(n,r)=>g(n,"name",{value:r,configurable:!0});import{failure as f,success as d}from"../../types/Result.js";import{DEFAULT_FILE_PATH as p,computeLinesDelta as h,extractProgramBody as b,isRecord as l}from"../_internal.js";import{parse as E,printFile as v}from"../fileRewriter/index.js";import{findReferences as k,locateAllShapes as R,locateByShape as S}from"../semanticIndex/index.js";import{checkControlFlowPolicy as N}from"./controlFlowPolicy.js";import{classifyLeadingComments as D}from"./removeResource/commentHeuristic.js";import{pruneUnusedImports as F}from"./removeResource/importPruning.js";function H(n,r){const a=r.filePath??p,t=E(n,a);if(!t.success)return f(t.error);const e=S(n,{type:r.type,name:r.name},a);if(!e.success)return e.error.kind==="TemplateLiteralNameError"?f(e.error):f({kind:"SemanticQueryError",reason:e.error.reason,cause:e.error.cause});if(e.data===void 0)return f({kind:"ResourceNotFoundError",type:r.type,name:r.name,knownNames:Q(n,r.type,a)});const o=N({ast:t.data,target:e.data,resource:{type:r.type,name:r.name},op:"remove"});if(o.refusal!==void 0)return f(o.refusal);const i=b(t.data);if(i===void 0)return f({kind:"SemanticQueryError",reason:"recast File is missing program.body"});const c=P(i,e.data);if(c===void 0)return f({kind:"SemanticQueryError",reason:"Unable to resolve enclosing statement for the located resource."});const s=A(n,c.statement,a);if(!s.success)return f(s.error);if(s.data.locations.length>0&&r.force!==!0)return f({kind:"ReferencesRemainError",variable:s.data.variable??r.name,references:s.data.locations});x(i,c.index,n),F(i);const m=v(t.data,n),y=h(n,m);return d({content:m,linesChanged:y,references:s.data.locations})}u(H,"removeResource");function P(n,r){const a=r.start+r.length;for(let t=0;t<n.length;t+=1){const e=n[t];if(e!==void 0&&!(typeof e.start!="number"||typeof e.end!="number")&&e.start<=r.start&&e.end>=a)return{index:t,statement:e}}}u(P,"findEnclosingStatement");function A(n,r,a){const t=L(r);if(t===void 0)return d({variable:void 0,locations:[]});const e=k(n,t.location,a);return e.success?d({variable:t.name,locations:e.data}):f({kind:"SemanticQueryError",reason:e.error.reason,cause:e.error.cause})}u(A,"resolveReferences");function L(n){let r=n;if(n.type==="ExportNamedDeclaration"){const s=n.declaration;if(!l(s)||s.type!=="VariableDeclaration")return;r=s}if(r.type!=="VariableDeclaration")return;const a=r.declarations;if(!Array.isArray(a)||a.length!==1)return;const t=a[0];if(!l(t))return;const e=t.id;if(!l(e)||e.type!=="Identifier")return;const o=e.name,i=e.start,c=e.end;if(!(typeof o!="string"||typeof i!="number"||typeof c!="number"))return{name:o,location:{filePath:p,start:i,length:c-i,symbolName:o}}}u(L,"extractVariableDeclaration");function x(n,r,a){const t=n[r];if(t===void 0)return;const{preserved:e}=D(t,a);if(e.length>0){const o=n[r+1];if(o!==void 0){const i=e.map(c=>({...c,leading:!0,trailing:!1}));o.comments=[...i,...o.comments??[]]}else{const i=n[r-1];if(i!==void 0){const c=e.map(s=>({...s,leading:!1,trailing:!0}));i.comments=[...i.comments??[],...c]}}}n.splice(r,1)}u(x,"spliceStatement");function Q(n,r,a){const t=R(n,a);if(!t.success)return[];const e=[];for(const o of t.data)o.type===r&&e.push(o.symbolName);return e}u(Q,"collectKnownNames");export{H as removeResource};
1
+ var g=Object.defineProperty;var u=(n,r)=>g(n,"name",{value:r,configurable:!0});import{failure as c,success as d}from"../../types/Result.js";import{DEFAULT_FILE_PATH as p,computeLinesDelta as h,extractProgramBody as b,isRecord as l}from"../_internal.js";import{parse as E,printFile as v}from"../fileRewriter/index.js";import{findReferences as k,locateAllShapes as R,locateByShape as S}from"../semanticIndex/index.js";import{buildUnmanagedEditRefusal as N}from"./unmanagedShapeErrors.js";import{checkControlFlowPolicy as D}from"./controlFlowPolicy.js";import{classifyLeadingComments as F}from"./removeResource/commentHeuristic.js";import{pruneUnusedImports as P}from"./removeResource/importPruning.js";function j(n,r){const a=r.filePath??p,t=E(n,a);if(!t.success)return c(t.error);const e=S(n,{type:r.type,name:r.name},a);if(!e.success)return e.error.kind==="TemplateLiteralNameError"?c(e.error):c({kind:"SemanticQueryError",reason:e.error.reason,cause:e.error.cause});if(e.data===void 0)return c({kind:"ResourceNotFoundError",type:r.type,name:r.name,knownNames:U(n,r.type,a)});if(e.data.managed===!1)return c(N(r.type,"remove"));const o=D({ast:t.data,target:e.data,resource:{type:r.type,name:r.name},op:"remove"});if(o.refusal!==void 0)return c(o.refusal);const i=b(t.data);if(i===void 0)return c({kind:"SemanticQueryError",reason:"recast File is missing program.body"});const f=A(i,e.data);if(f===void 0)return c({kind:"SemanticQueryError",reason:"Unable to resolve enclosing statement for the located resource."});const s=L(n,f.statement,a);if(!s.success)return c(s.error);if(s.data.locations.length>0&&r.force!==!0)return c({kind:"ReferencesRemainError",variable:s.data.variable??r.name,references:s.data.locations});Q(i,f.index,n),P(i);const m=v(t.data,n),y=h(n,m);return d({content:m,linesChanged:y,references:s.data.locations})}u(j,"removeResource");function A(n,r){const a=r.start+r.length;for(let t=0;t<n.length;t+=1){const e=n[t];if(e!==void 0&&!(typeof e.start!="number"||typeof e.end!="number")&&e.start<=r.start&&e.end>=a)return{index:t,statement:e}}}u(A,"findEnclosingStatement");function L(n,r,a){const t=x(r);if(t===void 0)return d({variable:void 0,locations:[]});const e=k(n,t.location,a);return e.success?d({variable:t.name,locations:e.data}):c({kind:"SemanticQueryError",reason:e.error.reason,cause:e.error.cause})}u(L,"resolveReferences");function x(n){let r=n;if(n.type==="ExportNamedDeclaration"){const s=n.declaration;if(!l(s)||s.type!=="VariableDeclaration")return;r=s}if(r.type!=="VariableDeclaration")return;const a=r.declarations;if(!Array.isArray(a)||a.length!==1)return;const t=a[0];if(!l(t))return;const e=t.id;if(!l(e)||e.type!=="Identifier")return;const o=e.name,i=e.start,f=e.end;if(!(typeof o!="string"||typeof i!="number"||typeof f!="number"))return{name:o,location:{filePath:p,start:i,length:f-i,symbolName:o}}}u(x,"extractVariableDeclaration");function Q(n,r,a){const t=n[r];if(t===void 0)return;const{preserved:e}=F(t,a);if(e.length>0){const o=n[r+1];if(o!==void 0){const i=e.map(f=>({...f,leading:!0,trailing:!1}));o.comments=[...i,...o.comments??[]]}else{const i=n[r-1];if(i!==void 0){const f=e.map(s=>({...s,leading:!1,trailing:!0}));i.comments=[...i.comments??[],...f]}}}n.splice(r,1)}u(Q,"spliceStatement");function U(n,r,a){const t=R(n,a);if(!t.success)return[];const e=[];for(const o of t.data)o.type===r&&e.push(o.symbolName);return e}u(U,"collectKnownNames");export{j as removeResource};
@@ -0,0 +1,3 @@
1
+ import type { DuplicateResourceError, SemanticQueryError, StatementType } from "../types.js";
2
+ export declare function buildUnmanagedDuplicateError(type: StatementType, name: string): DuplicateResourceError;
3
+ export declare function buildUnmanagedEditRefusal(type: StatementType, op: "modify" | "remove"): SemanticQueryError;
@@ -0,0 +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};
@@ -19,6 +19,12 @@ export interface BuildFactoryStatementParams {
19
19
  /** Quote style for NEW string literals the builder synthesises. */
20
20
  quoteStyle: QuoteStyle;
21
21
  }
22
+ export interface BuildAppMethodWrappedStatementParams extends BuildFactoryStatementParams {
23
+ /** App binding identifier, e.g. `"app"` — resolved, never assumed. */
24
+ appIdentifier: string;
25
+ /** App method receiving the factory thunk, e.g. `"addBuildkite"`. */
26
+ appMethod: string;
27
+ }
22
28
  /**
23
29
  * Build an `ExpressionStatement` wrapping `XFactory.build("Name", { … })`.
24
30
  *
@@ -28,6 +34,13 @@ export interface BuildFactoryStatementParams {
28
34
  * name literal honours `quoteStyle` via `extra.raw` on the literal.
29
35
  */
30
36
  export declare function buildFactoryStatement(params: BuildFactoryStatementParams): n.ExpressionStatement;
37
+ /**
38
+ * Build an `ExpressionStatement` wrapping
39
+ * `app.<method>(XFactory.build("Name", { … }))` — the two-layer shape for
40
+ * registry types declaring `emitWrapper`, whose factory returns a thunk
41
+ * only materialised by an App method.
42
+ */
43
+ export declare function buildAppMethodWrappedStatement(params: BuildAppMethodWrappedStatementParams): n.ExpressionStatement;
31
44
  /**
32
45
  * Build an object `Property` with a bare-identifier key. If `key` is
33
46
  * not a valid JS identifier (e.g. contains a hyphen), the key is
@@ -1 +1 @@
1
- var p=Object.defineProperty;var n=(e,i)=>p(e,"name",{value:i,configurable:!0});import{builders as t}from"ast-types";function x(e){const i=t.memberExpression(t.identifier(e.factory),t.identifier("build"),!1),r=f(e.name,e.quoteStyle),o=t.objectExpression(e.properties.map(s=>u(s.key,s.value,e.quoteStyle))),c=t.callExpression(i,[r,o]);return t.expressionStatement(c)}n(x,"buildFactoryStatement");function u(e,i,r){const o=l(e)?t.identifier(e):f(e,r);return t.property("init",o,i)}n(u,"buildObjectProperty");function y(e,i,r="double"){const o=e.map(s=>t.importSpecifier(t.identifier(s))),c=f(i,r);return t.importDeclaration(o,c)}n(y,"buildImportDeclaration");function S(e,i){return t.memberExpression(t.identifier(e),t.identifier(i),!1)}n(S,"buildMemberExpression");function g(e,i){Array.isArray(e.specifiers)||(e.specifiers=[]);for(const r of e.specifiers)if(d(r)&&r.imported.name===i)return;e.specifiers.push(t.importSpecifier(t.identifier(i)))}n(g,"appendSpecifier");function f(e,i){const r=i==="single"?"'":'"',o=`${r}${a(e,i)}${r}`;return t.stringLiteral.from({value:e,extra:{rawValue:e,raw:o}})}n(f,"makeStringLiteral");function a(e,i){const r=e.replace(/\\/g,"\\\\");return i==="single"?r.replace(/'/g,"\\'"):r.replace(/"/g,'\\"')}n(a,"escapeForQuote");function l(e){return/^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u.test(e)}n(l,"isValidIdentifier");function d(e){return e!==null&&typeof e=="object"&&"type"in e&&e.type==="ImportSpecifier"}n(d,"isNamedImportSpecifier");export{g as appendSpecifier,x as buildFactoryStatement,y as buildImportDeclaration,S as buildMemberExpression,u as buildObjectProperty};
1
+ var f=Object.defineProperty;var n=(e,t)=>f(e,"name",{value:t,configurable:!0});import{builders as i}from"ast-types";function y(e){return i.expressionStatement(s(e))}n(y,"buildFactoryStatement");function g(e){const t=i.callExpression(l(e.appIdentifier,e.appMethod),[s(e)]);return i.expressionStatement(t)}n(g,"buildAppMethodWrappedStatement");function s(e){const t=i.memberExpression(i.identifier(e.factory),i.identifier("build"),!1),r=p(e.name,e.quoteStyle),o=i.objectExpression(e.properties.map(c=>a(c.key,c.value,e.quoteStyle)));return i.callExpression(t,[r,o])}n(s,"buildFactoryCall");function a(e,t,r){const o=b(e)?i.identifier(e):p(e,r);return i.property("init",o,t)}n(a,"buildObjectProperty");function E(e,t,r="double"){const o=e.map(u=>i.importSpecifier(i.identifier(u))),c=p(t,r);return i.importDeclaration(o,c)}n(E,"buildImportDeclaration");function l(e,t){return i.memberExpression(i.identifier(e),i.identifier(t),!1)}n(l,"buildMemberExpression");function I(e,t){Array.isArray(e.specifiers)||(e.specifiers=[]);for(const r of e.specifiers)if(m(r)&&r.imported.name===t)return;e.specifiers.push(i.importSpecifier(i.identifier(t)))}n(I,"appendSpecifier");function p(e,t){const r=t==="single"?"'":'"',o=`${r}${d(e,t)}${r}`;return i.stringLiteral.from({value:e,extra:{rawValue:e,raw:o}})}n(p,"makeStringLiteral");function d(e,t){const r=e.replace(/\\/g,"\\\\");return t==="single"?r.replace(/'/g,"\\'"):r.replace(/"/g,'\\"')}n(d,"escapeForQuote");function b(e){return/^[$_\p{ID_Start}][$_\u200C\u200D\p{ID_Continue}]*$/u.test(e)}n(b,"isValidIdentifier");function m(e){return e!==null&&typeof e=="object"&&"type"in e&&e.type==="ImportSpecifier"}n(m,"isNamedImportSpecifier");export{I as appendSpecifier,g as buildAppMethodWrappedStatement,y as buildFactoryStatement,E as buildImportDeclaration,l as buildMemberExpression,a as buildObjectProperty};
@@ -1,4 +1,4 @@
1
1
  export { parse, type ParsedFile, type ParseError } from "./parse.js";
2
2
  export { detectLineTerminator, detectQuoteStyle, printFile } from "./print.js";
3
- export { appendSpecifier, buildFactoryStatement, buildImportDeclaration, buildMemberExpression, buildObjectProperty, type BuildFactoryStatementParams, type ObjectPropertyInput, type QuoteStyle, } from "./builders.js";
3
+ export { appendSpecifier, buildAppMethodWrappedStatement, buildFactoryStatement, buildImportDeclaration, buildMemberExpression, buildObjectProperty, type BuildAppMethodWrappedStatementParams, type BuildFactoryStatementParams, type ObjectPropertyInput, type QuoteStyle, } from "./builders.js";
4
4
  export { locateByLineColumn, locateByRange, type LineColumnHint, type NodeLocation, } from "./locateByRange.js";
@@ -1 +1 @@
1
- import{parse as r}from"./parse.js";import{detectLineTerminator as i,detectQuoteStyle as p,printFile as a}from"./print.js";import{appendSpecifier as n,buildFactoryStatement as m,buildImportDeclaration as c,buildMemberExpression as d,buildObjectProperty as b}from"./builders.js";import{locateByLineColumn as f,locateByRange as x}from"./locateByRange.js";export{n as appendSpecifier,m as buildFactoryStatement,c as buildImportDeclaration,d as buildMemberExpression,b as buildObjectProperty,i as detectLineTerminator,p as detectQuoteStyle,f as locateByLineColumn,x as locateByRange,r as parse,a as printFile};
1
+ import{parse as r}from"./parse.js";import{detectLineTerminator as p,detectQuoteStyle as i,printFile as a}from"./print.js";import{appendSpecifier as n,buildAppMethodWrappedStatement as d,buildFactoryStatement as m,buildImportDeclaration as c,buildMemberExpression as b,buildObjectProperty as u}from"./builders.js";import{locateByLineColumn as x,locateByRange as y}from"./locateByRange.js";export{n as appendSpecifier,d as buildAppMethodWrappedStatement,m as buildFactoryStatement,c as buildImportDeclaration,b as buildMemberExpression,u as buildObjectProperty,p as detectLineTerminator,i as detectQuoteStyle,x as locateByLineColumn,y as locateByRange,r as parse,a as printFile};
@@ -3,7 +3,7 @@ import * as recast from "recast";
3
3
  * Print `ast` back to source, preserving the original line terminator
4
4
  * and a leading UTF-8 BOM when the caller passes them via `source`.
5
5
  *
6
- * `source` is the ORIGINAL file text (pre-parse). We inspect it twice:
6
+ * `source` is the ORIGINAL file text (pre-parse). We inspect it thrice:
7
7
  * 1. BOM detection via `charCodeAt(0)`. Recast's reprint normally
8
8
  * carries the BOM through via its reuse-original-whitespace cache,
9
9
  * so we only re-prepend `\uFEFF` when the printed output has lost
@@ -13,6 +13,9 @@ import * as recast from "recast";
13
13
  * the first `\r\n` sighting wins. Passed through to
14
14
  * `recast.print`'s `lineTerminator` option so CRLF fixtures survive
15
15
  * on non-Windows hosts.
16
+ * 3. Shebang separation via `restoreShebangPrefix` — recast's reprint
17
+ * patcher glues the first statement onto a `#!` line when Program
18
+ * body membership changes; see the repair's doc comment.
16
19
  *
17
20
  * The printer consults the AST's dominant quote style via
18
21
  * `detectQuoteStyle` and threads it through `recast.print`'s `quote`
@@ -1,4 +1,4 @@
1
- var p=Object.defineProperty;var s=(t,o)=>p(t,"name",{value:o,configurable:!0});import*as a from"recast";const l="\uFEFF",u=65279;function h(t,o){const i=y(o),e=m(t),r=a.print(t,{quote:e,lineTerminator:i,trailingComma:!0}).code,n=o.charCodeAt(0)===u,c=r.charCodeAt(0)===u;return n&&!c?`${l}${r}`:r}s(h,"printFile");function y(t){return t.includes(`\r
1
+ var g=Object.defineProperty;var c=(t,e)=>g(t,"name",{value:e,configurable:!0});import*as m from"recast";const h="\uFEFF",l=65279;function C(t,e){const i=d(e),n=x(t),o=m.print(t,{quote:n,lineTerminator:i,trailingComma:!0}).code,r=$(o,e),s=e.charCodeAt(0)===l,a=r.charCodeAt(0)===l;return s&&!a?`${h}${r}`:r}c(C,"printFile");const A=/^(#![^\n\r]*)((?:\r?\n)*)/;function $(t,e){const i=e.charCodeAt(0)===l?e.slice(1):e,n=A.exec(i);if(n===null)return t;const o=n[1],r=n[2]??"";if(o===void 0)return t;const s=c(u=>u!==""&&r===""?d(e):r,"separatorOrFloor"),a=t.charCodeAt(0)===l,y=a?h:"",f=a?t.slice(1):t;if(f.startsWith(o)){const u=f.slice(o.length).replace(/^(?:\r?\n)*/,"");return`${y}${o}${s(u)}${u}`}return f.startsWith("#!")?t:`${y}${o}${s(f)}${f}`}c($,"restoreShebangPrefix");function d(t){return t.includes(`\r
2
2
  `)?`\r
3
3
  `:`
4
- `}s(y,"detectLineTerminator");function m(t){let o=0,i=0;return g(t,e=>{if(e.type!=="StringLiteral"&&e.type!=="Literal")return;const r=e.extra;if(!f(r))return;const n=r.raw;if(typeof n!="string"||n.length===0)return;const c=n.charAt(0);c==="'"?o+=1:c==='"'&&(i+=1)}),o>i?"single":"double"}s(m,"detectQuoteStyle");function g(t,o){const i=[t];for(;i.length>0;){const e=i.pop();if(!(!f(e)||typeof e.type!="string")){o(e);for(const r of Object.keys(e)){if(r==="loc"||r==="comments"||r==="tokens")continue;const n=e[r];if(Array.isArray(n))for(const c of n)f(c)&&typeof c.type=="string"&&i.push(c);else f(n)&&typeof n.type=="string"&&i.push(n)}}}}s(g,"visit");function f(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}s(f,"isRecord");export{y as detectLineTerminator,m as detectQuoteStyle,h as printFile};
4
+ `}c(d,"detectLineTerminator");function x(t){let e=0,i=0;return B(t,n=>{if(n.type!=="StringLiteral"&&n.type!=="Literal")return;const o=n.extra;if(!p(o))return;const r=o.raw;if(typeof r!="string"||r.length===0)return;const s=r.charAt(0);s==="'"?e+=1:s==='"'&&(i+=1)}),e>i?"single":"double"}c(x,"detectQuoteStyle");function B(t,e){const i=[t];for(;i.length>0;){const n=i.pop();if(!(!p(n)||typeof n.type!="string")){e(n);for(const o of Object.keys(n)){if(o==="loc"||o==="comments"||o==="tokens")continue;const r=n[o];if(Array.isArray(r))for(const s of r)p(s)&&typeof s.type=="string"&&i.push(s);else p(r)&&typeof r.type=="string"&&i.push(r)}}}}c(B,"visit");function p(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}c(p,"isRecord");export{d as detectLineTerminator,x as detectQuoteStyle,C as printFile};
@@ -14,8 +14,9 @@ export type { CrossPlanConnectionResourcePlan, VpcPeerAccepterResourcePlan, VpcP
14
14
  export { detectDrift, mergeProperties, snapshotProperties, type DriftOp, type DriftPlan, type DriftPolicy, type DriftState, type MergeResult, type PropertyDelta, type ResourceSnapshot, } from "./drift/index.js";
15
15
  export { computeLinesDelta } from "./_internal.js";
16
16
  export { ResourceNameSchema, StatementTypeSchema } from "./types.js";
17
+ export { REGISTERED_STATEMENT_TYPES, STATEMENT_REGISTRY, type StatementTypeEntry, } from "./registry.js";
17
18
  export { CODEMOD_ERROR_KINDS } from "./telemetry/errorKinds.js";
18
19
  export type { CodemodErrorKind } from "./telemetry/errorKinds.js";
19
20
  export type { GateId } from "./validationGate/index.js";
20
21
  export { buildEgressBlockedEvent, buildFiredEvent, buildGateFailedEvent, buildGatePassedEvent, buildRejectedEvent, buildSucceededEvent, buildTimeoutEvent, estimateCostUsd, FALLBACK_EVENTS, GATE_EVENTS, PARSE_GATE, RUNTIME_GATE, runFallback, shouldTryFallback, type AnthropicClientProvider, type FallbackClients, type FallbackDecision, type FallbackEgressBlockedEvent, type FallbackGuardConfig, type FallbackInput, type FallbackIntent, type FallbackOp, type FallbackOutput, type FallbackTelemetry, type FallbackTelemetryEvent, type MorphClientProvider, type RunFallbackInput, type TelemetrySource, type TriggerReason, } from "./llmFallback/index.js";
21
- export type { AddOptions, CodemodError, CodemodSuccess, ControlFlowClassifierError, DriftConflictError, DriftUnmergeableError, DuplicateResourceError, EditOrchestratorSuccess, InvalidPropertyError, LinesChanged, LlmFallbackRejectedError, LlmFallbackTimeoutError, LlmFallbackTier, LlmFallbackUnsafeInputError, ModifyOptions, NodeLocation, ParseError, PermissionError, ReferenceLocation, ReferencesRemainError, RemoveOptions, ResourceListing, ResourceListingEntry, ResourceName, ResourceNotFoundError, SemanticQueryError, StatementType, TemplateLiteralNameError, } from "./types.js";
22
+ export type { AddOptions, CodemodError, CodemodSuccess, ControlFlowClassifierError, DriftConflictError, DriftUnmergeableError, DuplicateResourceError, EditOrchestratorSuccess, InvalidPropertyError, LinesChanged, LlmFallbackRejectedError, LlmFallbackTimeoutError, LlmFallbackTier, LlmFallbackUnsafeInputError, MissingAppInitError, ModifyOptions, NodeLocation, ParseError, PermissionError, ReferenceLocation, ReferencesRemainError, RemoveOptions, ResourceListing, ResourceListingEntry, ResourceName, ResourceNotFoundError, SemanticQueryError, StatementType, TemplateLiteralNameError, } from "./types.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 i,removeVpcPeer as l}from"./edits/vpcPeer.js";import{addVpcPeerAccepter as u,modifyVpcPeerAccepter as P,removeVpcPeerAccepter as E}from"./edits/vpcPeerAccepter.js";import{addCrossPlanConnection as R,modifyCrossPlanConnection as v,removeCrossPlanConnection as C}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 F,VpcPeerAccepterResourcePlanSchema as G,VpcPeerResourcePlanSchema as N}from"../schemas/index.js";import{detectDrift as g,mergeProperties as k,snapshotProperties as B}from"./drift/index.js";import{computeLinesDelta as I}from"./_internal.js";import{ResourceNameSchema as M,StatementTypeSchema as U}from"./types.js";import{CODEMOD_ERROR_KINDS as q}from"./telemetry/errorKinds.js";import{buildEgressBlockedEvent as z,buildFiredEvent as H,buildGateFailedEvent as J,buildGatePassedEvent as Q,buildRejectedEvent as W,buildSucceededEvent as X,buildTimeoutEvent as Y,estimateCostUsd as Z,FALLBACK_EVENTS as $,GATE_EVENTS as ee,PARSE_GATE as re,RUNTIME_GATE as oe,runFallback as te,shouldTryFallback as ce}from"./llmFallback/index.js";export{q as CODEMOD_ERROR_KINDS,F as CrossPlanConnectionResourcePlanSchema,$ as FALLBACK_EVENTS,ee as GATE_EVENTS,re as PARSE_GATE,oe as RUNTIME_GATE,M as ResourceNameSchema,U as StatementTypeSchema,G as VpcPeerAccepterResourcePlanSchema,N as VpcPeerResourcePlanSchema,R as addCrossPlanConnection,o as addResource,d as addVpcPeer,u as addVpcPeerAccepter,a as appendAccountToStage,z as buildEgressBlockedEvent,H as buildFiredEvent,J as buildGateFailedEvent,Q as buildGatePassedEvent,W as buildRejectedEvent,X as buildSucceededEvent,Y as buildTimeoutEvent,I as computeLinesDelta,g as detectDrift,Z as estimateCostUsd,V as listResources,k as mergeProperties,v as modifyCrossPlanConnection,m as modifyResource,i as modifyVpcPeer,P as modifyVpcPeerAccepter,D as parse,C as removeCrossPlanConnection,c as removeResource,l as removeVpcPeer,E as removeVpcPeerAccepter,y as resolveConstructByLiteralProperty,A as resolveDriftPolicy,te as runFallback,ce as shouldTryFallback,B 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 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 +1 @@
1
- var c=Object.defineProperty;var o=(s,r)=>c(s,"name",{value:r,configurable:!0});import{failure as m,success as l}from"../types/Result.js";import{DEFAULT_FILE_PATH as n}from"./_internal.js";import{locateAllShapes as p}from"./semanticIndex/index.js";function A(s,r=n){const t=p(s,r);if(!t.success)return m(t.error);const a=t.data.map(e=>({type:e.type,name:e.symbolName,filePath:e.filePath,start:e.start,length:e.length}));return l({filePath:r,resources:a})}o(A,"listResources");export{A as listResources};
1
+ var m=Object.defineProperty;var t=(r,s)=>m(r,"name",{value:s,configurable:!0});import{failure as l,success as n}from"../types/Result.js";import{DEFAULT_FILE_PATH as c}from"./_internal.js";import{locateAllShapes as f}from"./semanticIndex/index.js";function i(r,s=c){const a=f(r,s);if(!a.success)return l(a.error);const o=a.data.map(e=>({type:e.type,name:e.symbolName,filePath:e.filePath,start:e.start,length:e.length,...e.managed===!1&&{managed:!1}}));return n({filePath:s,resources:o})}t(i,"listResources");export{i as listResources};
@@ -26,6 +26,27 @@ export interface StatementTypeEntry {
26
26
  locator: StatementLocator;
27
27
  generator: StatementGenerator;
28
28
  schemaFragment: z.ZodObject<z.ZodRawShape>;
29
+ /**
30
+ * When present, the ADD path emits `app.<appMethod>(XFactory.build(...))`
31
+ * 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.
38
+ *
39
+ * `propsOverloadConstructId` is the construct id the App method pins when
40
+ * called in the legacy props-direct form (`app.addBuildkite({ … })`) — it
41
+ * MUST equal the literal in the App dispatcher (cross-package coupled
42
+ * value with no compiler across the seam; proven end-to-end by the
43
+ * dogfood synth-parity AC). The legacy-shape classifier uses it to name
44
+ * unmanaged method-form hits (design § D6).
45
+ */
46
+ emitWrapper?: {
47
+ readonly appMethod: string;
48
+ readonly propsOverloadConstructId: string;
49
+ };
29
50
  }
30
51
  declare const FACTORY_IDENTIFIERS: {
31
52
  readonly database: "DatabaseFactory";
@@ -39,6 +60,7 @@ declare const FACTORY_IDENTIFIERS: {
39
60
  readonly "vpc-peer-accepter": "VpcPeerAccepterFactory";
40
61
  readonly "cross-plan-connection": "CrossPlanConnectionFactory";
41
62
  readonly organisation: "OrganisationFactory";
63
+ readonly buildkite: "BuildkiteFactory";
42
64
  };
43
65
  export type FactoryIdentifier = (typeof FACTORY_IDENTIFIERS)[StatementType];
44
66
  export declare const STATEMENT_REGISTRY: Record<StatementType, StatementTypeEntry>;
@@ -1 +1 @@
1
- var d=Object.defineProperty;var r=(e,t)=>d(e,"name",{value:t,configurable:!0});import{z as s}from"zod";import{CDNResourcePlanSchema as S,ComputeResourcePlanSchema as h,CrossPlanConnectionResourcePlanSchema as y,DatabaseResourcePlanSchema as P,NetworkResourcePlanSchema as F,NextJSPatternConfigSchema as f,OrganisationResourcePlanSchema as C,PayloadPatternConfigSchema as E,S3ResourcePlanSchema as R,SQSResourcePlanSchema as b,StaticSitePatternConfigSchema as _,VpcPeerAccepterResourcePlanSchema as T,VpcPeerResourcePlanSchema as v}from"../schemas/index.js";import{failure as k}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"};function o(e){const{name:t,...c}=e.shape;return s.object(c).partial().strict()}r(o,"fragmentOf");const w=o(P),x=o(R),N=(()=>{const{name:e,...t}=h.shape;return s.object(t).partial().strict()})(),j=o(b),A=o(S),O=o(F),D=(()=>{const{name:e,type:t,cdn:c,...m}=E.shape,{name:Q,type:$,cdn:z,...g}=f.shape,{name:J,type:L,domain:W,cdn:u,...l}=_.shape;return s.object({...m,...g,...l,cdn:s.union([c,u])}).partial().strict()})(),V=o(v),B=o(T),G=o(y),I=o(C);function p(e,t){return k({kind:"SemanticQueryError",reason:`StatementTypeEntry.${e} for ${t} is not wired; existing types dispatch through the shared locator/generator.`})}r(p,"notWiredError");function M(e){return{factoryIdentifier:e,findByShape:r(()=>p("locator.findByShape",e),"findByShape"),validateContext:r(()=>p("locator.validateContext",e),"validateContext")}}r(M,"createLocator");function Y(e){return{build:r(()=>{const t=p("generator.build",e);throw new Error(t.success?"unreachable":t.error.reason)},"build")}}r(Y,"createGenerator");function a(e,t){return{factoryIdentifier:e,locator:M(e),generator:Y(e),schemaFragment:t}}r(a,"createEntry");const i={database:a(n.database,w),storage:a(n.storage,x),compute:a(n.compute,N),messaging:a(n.messaging,j),cdn:a(n.cdn,A),network:a(n.network,O),pattern:a(n.pattern,D),"vpc-peer":a(n["vpc-peer"],V),"vpc-peer-accepter":a(n["vpc-peer-accepter"],B),"cross-plan-connection":a(n["cross-plan-connection"],G),organisation:a(n.organisation,I)},X=Object.keys(i);function Z(e){const t=Object.keys(i);for(const c of t)if(i[c].factoryIdentifier===e)return c}r(Z,"findTypeByIdentifier");export{X as REGISTERED_STATEMENT_TYPES,i as STATEMENT_REGISTRY,Z as findTypeByIdentifier};
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,4 +1,4 @@
1
- export { locateByShape, locateAllShapes, forEachFactoryMatch, type FactoryCallMatch, type NodeLocation, type StatementType, type LocateByShapeError, } from "./locateByShape.js";
1
+ export { locateByShape, locateAllShapes, forEachFactoryMatch, type FactoryCallMatch, type LocatedShape, type NodeLocation, type StatementType, type LocateByShapeError, type UnmanagedMethodMatch, } from "./locateByShape.js";
2
2
  export { resolveConstructByLiteralProperty, type ConstructResolution, type ConstructResolutionFailureReason, type ResolveConstructQuery, type ResolvedConstruct, } from "./resolveConstructByLiteralProperty.js";
3
3
  export { findReferences, type ReferenceLocation, type FindReferencesError, } from "./findReferences.js";
4
4
  export { getProject, resetProjectForTest } from "./projectCache.js";
@@ -13,7 +13,7 @@ export type LocateByShapeError = TemplateLiteralNameError | SemanticQueryError;
13
13
  export declare function locateByShape(content: string, query: {
14
14
  type: StatementType;
15
15
  name: string;
16
- }, filePath?: string): Result<NodeLocation | undefined, LocateByShapeError>;
16
+ }, filePath?: string): Result<LocatedShape | undefined, LocateByShapeError>;
17
17
  /**
18
18
  * A `XFactory.build("Name", ...)` call whose name is a plain string
19
19
  * literal. `nameStart`/`nameLength` anchor the name token (ADR §4(a)).
@@ -24,19 +24,42 @@ export interface FactoryCallMatch {
24
24
  nameStart: number;
25
25
  nameLength: number;
26
26
  }
27
+ /**
28
+ * A located statement: managed hits anchor `start`/`length` on the name
29
+ * token of `XFactory.build("Name", ...)`; unmanaged hits (`managed:
30
+ * false`) anchor on the method-name token of a legacy method-form call
31
+ * (`app.addBuildkite({ … })`, design § D6) and are visible to list and
32
+ * duplicate detection but refused by the write paths.
33
+ */
34
+ export type LocatedShape = NodeLocation & {
35
+ type: StatementType;
36
+ managed?: false;
37
+ };
27
38
  /**
28
39
  * Walks every call expression in the source and returns a
29
- * `NodeLocation & { type }` for each `XFactory.build("Name", ...)`
30
- * shape. The traversal descends into `IfStatement`, `Block`,
31
- * `ForStatement`, and function bodies via `forEachDescendant`.
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
43
+ * `IfStatement`, `Block`, `ForStatement`, and function bodies via
44
+ * `forEachDescendant`.
32
45
  *
33
46
  * Emits `TemplateLiteralNameError` for the first non-plain-string
34
47
  * factory name encountered — the engine cannot safely locate a
35
48
  * template-literal name by shape.
36
49
  */
37
- export declare function locateAllShapes(content: string, filePath?: string): Result<Array<NodeLocation & {
50
+ export declare function locateAllShapes(content: string, filePath?: string): Result<LocatedShape[], LocateByShapeError>;
51
+ /**
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.
56
+ */
57
+ export interface UnmanagedMethodMatch {
38
58
  type: StatementType;
39
- }>, LocateByShapeError>;
59
+ name: string;
60
+ methodStart: number;
61
+ methodLength: number;
62
+ }
40
63
  /**
41
64
  * Shared walk over every `XFactory.build("Name", ...)` call with a
42
65
  * plain string-literal name. Invokes `onMatch(match, call)` for each —
@@ -44,8 +67,12 @@ export declare function locateAllShapes(content: string, filePath?: string): Res
44
67
  * live ts-morph node so callers can read further arguments (e.g. the
45
68
  * second-argument config object literal).
46
69
  *
70
+ * When `onUnmanagedMatch` is supplied, the same walk also reports legacy
71
+ * method-form calls (design § D6) — consumers that omit it (validation
72
+ * gates, construct resolution) see factory matches only, unchanged.
73
+ *
47
74
  * Binding-pattern and type-space calls are skipped (parity with the
48
75
  * `locateByShape` contract); the first template-literal name aborts the
49
76
  * walk as a `TemplateLiteralNameError` failure.
50
77
  */
51
- export declare function forEachFactoryMatch(content: string, filePath: string, onMatch: (match: FactoryCallMatch, call: CallExpression) => void): Result<void, LocateByShapeError>;
78
+ export declare function forEachFactoryMatch(content: string, filePath: string, onMatch: (match: FactoryCallMatch, call: CallExpression) => void, onUnmanagedMatch?: (match: UnmanagedMethodMatch, call: CallExpression) => void): Result<void, LocateByShapeError>;
@@ -1 +1 @@
1
- var m=Object.defineProperty;var s=(n,e)=>m(n,"name",{value:e,configurable:!0});import{Node as c,SyntaxKind as i}from"ts-morph";import{failure as l,success as u}from"../../types/Result.js";import{DEFAULT_FILE_PATH as f}from"../_internal.js";import{findTypeByIdentifier as g}from"../registry.js";import{getProject as y}from"./projectCache.js";function w(n,e,r=f){const a=h(n,r);if(!a.success)return a;const t=a.data.find(o=>o.type===e.type&&o.symbolName===e.name);return u(t)}s(w,"locateByShape");function h(n,e=f){const r=[],a=S(n,e,t=>{r.push({filePath:e,start:t.nameStart,length:t.nameLength,symbolName:t.name,type:t.type})});return a.success?u(r):a}s(h,"locateAllShapes");function S(n,e,r){let a;try{a=y().createSourceFile(e,n,{overwrite:!0})}catch(t){return l({kind:"SemanticQueryError",reason:"Failed to create source file",cause:t})}try{a.forEachDescendant(t=>{if(!c.isCallExpression(t))return;const o=E(t);if(o!=="not-factory-call"&&o.kind!=="binding-pattern-declared"){if(o.kind==="template-literal-name")throw new p(t,o.type);r({type:o.type,name:o.name,nameStart:o.nameStart,nameLength:o.nameLength},t)}})}catch(t){return t instanceof p?l(t.toError(e)):l({kind:"SemanticQueryError",reason:"forEachDescendant traversal failed",cause:t})}return u(void 0)}s(S,"forEachFactoryMatch");function E(n){const e=n.getExpression();if(!c.isPropertyAccessExpression(e))return"not-factory-call";const r=T(e);if(r===void 0||x(n))return"not-factory-call";if(A(n))return{kind:"binding-pattern-declared"};const t=n.getArguments()[0];return t===void 0?"not-factory-call":c.isTemplateExpression(t)||c.isNoSubstitutionTemplateLiteral(t)?{kind:"template-literal-name",type:r}:c.isStringLiteral(t)?{kind:"match",type:r,name:t.getLiteralValue(),nameStart:t.getStart(),nameLength:t.getWidth()}:"not-factory-call"}s(E,"classifyFactoryCall");function T(n){const e=n.getExpression();if(c.isIdentifier(e)&&n.getName()==="build")return g(e.getText())}s(T,"factoryTypeFromPropertyAccess");function x(n){let e=n.getParent();for(;e!==void 0;){const r=e.getKind();if(r===i.TypeReference||r===i.TypeQuery||r===i.TypeLiteral||r===i.TypeAliasDeclaration||r===i.InterfaceDeclaration||r===i.TypeParameter||r===i.PropertySignature||r===i.MethodSignature||r===i.JsxOpeningElement||r===i.JsxClosingElement||r===i.JsxSelfClosingElement||r===i.JsxAttribute)return!0;e=e.getParent()}return!1}s(x,"isInsideTypeSpace");function A(n){const e=n.getFirstAncestorByKind(i.VariableDeclaration);if(e===void 0)return!1;const a=e.getNameNode().getKind();return a===i.ObjectBindingPattern||a===i.ArrayBindingPattern}s(A,"isInsideBindingPattern");class p extends Error{static{s(this,"TemplateLiteralMarker")}call;type;constructor(e,r){super("Template-literal factory name detected"),this.call=e,this.type=r,this.name="TemplateLiteralMarker"}toError(e){const a=this.call.getArguments()[0]?.getStart()??this.call.getStart(),t=this.call.getSourceFile(),{line:o,column:d}=t.getLineAndColumnAtPos(a);return{kind:"TemplateLiteralNameError",file:e,line:o,column:d,suggestion:"Replace the template literal with a plain string literal so the resource name can be resolved statically."}}}export{S as forEachFactoryMatch,h 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 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,2 +1,4 @@
1
- export declare const CODEMOD_ERROR_KINDS: readonly ["ParseError", "ResourceNotFoundError", "DuplicateResourceError", "ReferencesRemainError", "InvalidPropertyError", "TemplateLiteralNameError", "SemanticQueryError", "ValidationError", "IoError", "DriftConflictError", "DriftUnmergeableError", "PermissionError", "ControlFlowClassifierError", "LlmFallbackRejectedError", "LlmFallbackTimeoutError", "LlmFallbackUnsafeInputError"];
1
+ import type { CodemodError } from "../types.js";
2
+ export declare const CODEMOD_ERROR_KINDS: readonly ["ParseError", "ResourceNotFoundError", "DuplicateResourceError", "ReferencesRemainError", "InvalidPropertyError", "TemplateLiteralNameError", "SemanticQueryError", "MissingAppInitError", "ValidationError", "IoError", "DriftConflictError", "DriftUnmergeableError", "PermissionError", "ControlFlowClassifierError", "LlmFallbackRejectedError", "LlmFallbackTimeoutError", "LlmFallbackUnsafeInputError"];
2
3
  export type CodemodErrorKind = (typeof CODEMOD_ERROR_KINDS)[number];
4
+ export declare const CODEMOD_ENGINE_ERROR_KINDS: ReadonlyArray<CodemodError["kind"]>;
@@ -1 +1 @@
1
- const r=["ParseError","ResourceNotFoundError","DuplicateResourceError","ReferencesRemainError","InvalidPropertyError","TemplateLiteralNameError","SemanticQueryError","ValidationError","IoError","DriftConflictError","DriftUnmergeableError","PermissionError","ControlFlowClassifierError","LlmFallbackRejectedError","LlmFallbackTimeoutError","LlmFallbackUnsafeInputError"],e=!0;export{r as CODEMOD_ERROR_KINDS};
1
+ const e=["ParseError","ResourceNotFoundError","DuplicateResourceError","ReferencesRemainError","InvalidPropertyError","TemplateLiteralNameError","SemanticQueryError","MissingAppInitError","ValidationError","IoError","DriftConflictError","DriftUnmergeableError","PermissionError","ControlFlowClassifierError","LlmFallbackRejectedError","LlmFallbackTimeoutError","LlmFallbackUnsafeInputError"],o=!0,r={ParseError:!0,TemplateLiteralNameError:!0,DuplicateResourceError:!0,ResourceNotFoundError:!0,ReferencesRemainError:!0,InvalidPropertyError:!0,SemanticQueryError:!0,MissingAppInitError:!0,DriftConflictError:!0,DriftUnmergeableError:!0,PermissionError:!0,ControlFlowClassifierError:!0,LlmFallbackRejectedError:!0,LlmFallbackTimeoutError:!0,LlmFallbackUnsafeInputError:!0},t=Object.keys(r);export{t as CODEMOD_ENGINE_ERROR_KINDS,e as CODEMOD_ERROR_KINDS};
@@ -23,6 +23,7 @@ export declare const StatementTypeSchema: z.ZodEnum<{
23
23
  "vpc-peer-accepter": "vpc-peer-accepter";
24
24
  "cross-plan-connection": "cross-plan-connection";
25
25
  organisation: "organisation";
26
+ buildkite: "buildkite";
26
27
  }>;
27
28
  export type StatementType = z.infer<typeof StatementTypeSchema>;
28
29
  export declare const ResourceNameSchema: z.ZodString;
@@ -40,6 +41,7 @@ export declare const AddOptionsSchema: z.ZodObject<{
40
41
  "vpc-peer-accepter": "vpc-peer-accepter";
41
42
  "cross-plan-connection": "cross-plan-connection";
42
43
  organisation: "organisation";
44
+ buildkite: "buildkite";
43
45
  }>;
44
46
  name: z.ZodString;
45
47
  properties: z.ZodRecord<z.ZodString, z.ZodUnknown>;
@@ -64,6 +66,7 @@ export declare const RemoveOptionsSchema: z.ZodObject<{
64
66
  "vpc-peer-accepter": "vpc-peer-accepter";
65
67
  "cross-plan-connection": "cross-plan-connection";
66
68
  organisation: "organisation";
69
+ buildkite: "buildkite";
67
70
  }>;
68
71
  name: z.ZodString;
69
72
  filePath: z.ZodOptional<z.ZodString>;
@@ -84,6 +87,7 @@ export declare const ModifyOptionsSchema: z.ZodObject<{
84
87
  "vpc-peer-accepter": "vpc-peer-accepter";
85
88
  "cross-plan-connection": "cross-plan-connection";
86
89
  organisation: "organisation";
90
+ buildkite: "buildkite";
87
91
  }>;
88
92
  name: z.ZodString;
89
93
  properties: z.ZodRecord<z.ZodString, z.ZodUnknown>;
@@ -119,11 +123,13 @@ export declare const ResourceListingEntrySchema: z.ZodObject<{
119
123
  "vpc-peer-accepter": "vpc-peer-accepter";
120
124
  "cross-plan-connection": "cross-plan-connection";
121
125
  organisation: "organisation";
126
+ buildkite: "buildkite";
122
127
  }>;
123
128
  name: z.ZodString;
124
129
  filePath: z.ZodString;
125
130
  start: z.ZodNumber;
126
131
  length: z.ZodNumber;
132
+ managed: z.ZodOptional<z.ZodLiteral<false>>;
127
133
  }, z.core.$strict>;
128
134
  export type ResourceListingEntry = z.infer<typeof ResourceListingEntrySchema>;
129
135
  export declare const ResourceListingSchema: z.ZodObject<{
@@ -141,11 +147,13 @@ export declare const ResourceListingSchema: z.ZodObject<{
141
147
  "vpc-peer-accepter": "vpc-peer-accepter";
142
148
  "cross-plan-connection": "cross-plan-connection";
143
149
  organisation: "organisation";
150
+ buildkite: "buildkite";
144
151
  }>;
145
152
  name: z.ZodString;
146
153
  filePath: z.ZodString;
147
154
  start: z.ZodNumber;
148
155
  length: z.ZodNumber;
156
+ managed: z.ZodOptional<z.ZodLiteral<false>>;
149
157
  }, z.core.$strict>>;
150
158
  }, z.core.$strict>;
151
159
  export type ResourceListing = z.infer<typeof ResourceListingSchema>;
@@ -194,6 +202,12 @@ export interface DuplicateResourceError {
194
202
  kind: "DuplicateResourceError";
195
203
  type: StatementType;
196
204
  name: string;
205
+ /**
206
+ * Operator guidance appended by renderers when present — set when the
207
+ * duplicate is a legacy method-form statement that must be migrated to
208
+ * the managed factory form before the engine can manage it (design § D6).
209
+ */
210
+ remediation?: string;
197
211
  }
198
212
  export interface ResourceNotFoundError {
199
213
  kind: "ResourceNotFoundError";
@@ -216,6 +230,17 @@ export interface SemanticQueryError {
216
230
  reason: string;
217
231
  cause?: unknown;
218
232
  }
233
+ /**
234
+ * The add path was asked to emit a wrapped `app.<appMethod>(...)`
235
+ * statement (registry `emitWrapper`), but the target file has no
236
+ * `const <name> = App.getApp(...)` binding to receive it. Surfaced
237
+ * pre-write — the file is never modified.
238
+ */
239
+ export interface MissingAppInitError {
240
+ kind: "MissingAppInitError";
241
+ type: StatementType;
242
+ appMethod: string;
243
+ }
219
244
  export declare const PropertyDeltaSchema: z.ZodObject<{
220
245
  property: z.ZodString;
221
246
  base: z.ZodOptional<z.ZodUnknown>;
@@ -284,4 +309,4 @@ export interface LlmFallbackUnsafeInputError {
284
309
  reason: EgressRiskReason;
285
310
  count: number;
286
311
  }
287
- export type CodemodError = ParseError | TemplateLiteralNameError | DuplicateResourceError | ResourceNotFoundError | ReferencesRemainError | InvalidPropertyError | SemanticQueryError | DriftConflictError | DriftUnmergeableError | PermissionError | ControlFlowClassifierError | LlmFallbackRejectedError | LlmFallbackTimeoutError | LlmFallbackUnsafeInputError;
312
+ export type CodemodError = ParseError | TemplateLiteralNameError | DuplicateResourceError | ResourceNotFoundError | ReferencesRemainError | InvalidPropertyError | SemanticQueryError | MissingAppInitError | DriftConflictError | DriftUnmergeableError | PermissionError | ControlFlowClassifierError | LlmFallbackRejectedError | LlmFallbackTimeoutError | LlmFallbackUnsafeInputError;
@@ -1 +1 @@
1
- import{z as t}from"zod";import{VALIDATION_MESSAGES as i,VALIDATION_PATTERNS as c}from"../validation/patterns.js";const o=t.object({force:t.boolean().optional(),resolutionMap:t.record(t.string(),t.unknown()).optional()}).strict(),e=t.enum(["database","storage","compute","messaging","cdn","network","pattern","vpc-peer","vpc-peer-accepter","cross-plan-connection","organisation"]),n=t.string().regex(c.PASCAL_CASE,i.PASCAL_CASE),r=t.record(t.string(),t.unknown()),g=t.object({type:e,name:n,properties:r,filePath:t.string().optional(),driftPolicy:o.optional(),branch:t.string().optional()}).strict(),h=t.object({type:e,name:n,filePath:t.string().optional(),force:t.boolean().optional(),branch:t.string().optional()}).strict(),b=t.object({type:e,name:n,properties:r,filePath:t.string().optional(),driftPolicy:o.optional(),branch:t.string().optional()}).strict(),a=t.object({line:t.number().int().positive(),column:t.number().int().positive(),context:t.string()}).strict(),s=t.object({added:t.number().int().nonnegative(),removed:t.number().int().nonnegative()}).strict(),p=t.object({type:e,name:t.string(),filePath:t.string(),start:t.number().int().nonnegative(),length:t.number().int().nonnegative()}).strict(),S=t.object({filePath:t.string(),resources:t.array(p)}).strict(),u=t.object({content:t.string(),linesChanged:s,references:t.array(a).optional(),warnings:t.array(t.string()).optional()}).strict(),d=t.object({property:t.string(),base:t.unknown().optional(),theirs:t.unknown(),ours:t.unknown(),verdict:t.enum(["clean","no-op","compatible","conflict"])}).strict();export{g as AddOptionsSchema,u as CodemodSuccessSchema,o as DriftPolicySchema,s as LinesChangedSchema,b as ModifyOptionsSchema,d as PropertyDeltaSchema,a as ReferenceLocationSchema,h as RemoveOptionsSchema,p as ResourceListingEntrySchema,S as ResourceListingSchema,n as ResourceNameSchema,e as StatementTypeSchema};
1
+ import{z as t}from"zod";import{VALIDATION_MESSAGES as i,VALIDATION_PATTERNS as c}from"../validation/patterns.js";const o=t.object({force:t.boolean().optional(),resolutionMap:t.record(t.string(),t.unknown()).optional()}).strict(),e=t.enum(["database","storage","compute","messaging","cdn","network","pattern","vpc-peer","vpc-peer-accepter","cross-plan-connection","organisation","buildkite"]),n=t.string().regex(c.PASCAL_CASE,i.PASCAL_CASE),r=t.record(t.string(),t.unknown()),g=t.object({type:e,name:n,properties:r,filePath:t.string().optional(),driftPolicy:o.optional(),branch:t.string().optional()}).strict(),b=t.object({type:e,name:n,filePath:t.string().optional(),force:t.boolean().optional(),branch:t.string().optional()}).strict(),h=t.object({type:e,name:n,properties:r,filePath:t.string().optional(),driftPolicy:o.optional(),branch:t.string().optional()}).strict(),a=t.object({line:t.number().int().positive(),column:t.number().int().positive(),context:t.string()}).strict(),s=t.object({added:t.number().int().nonnegative(),removed:t.number().int().nonnegative()}).strict(),p=t.object({type:e,name:t.string(),filePath:t.string(),start:t.number().int().nonnegative(),length:t.number().int().nonnegative(),managed:t.literal(!1).optional()}).strict(),u=t.object({filePath:t.string(),resources:t.array(p)}).strict(),S=t.object({content:t.string(),linesChanged:s,references:t.array(a).optional(),warnings:t.array(t.string()).optional()}).strict(),d=t.object({property:t.string(),base:t.unknown().optional(),theirs:t.unknown(),ours:t.unknown(),verdict:t.enum(["clean","no-op","compatible","conflict"])}).strict();export{g as AddOptionsSchema,S as CodemodSuccessSchema,o as DriftPolicySchema,s as LinesChangedSchema,h as ModifyOptionsSchema,d as PropertyDeltaSchema,a as ReferenceLocationSchema,b as RemoveOptionsSchema,p as ResourceListingEntrySchema,u as ResourceListingSchema,n as ResourceNameSchema,e as StatementTypeSchema};
@@ -0,0 +1,134 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Unrefined object shape — EXISTS ONLY for codemod fragment derivation
4
+ * (`fragmentOf` requires a plain ZodObject; `.refine` blocks `.partial()`).
5
+ * ALL validation MUST use `BuildkitePropsSchema` — this export drops the
6
+ * `agentMinInstances <= agentMaxInstances` cross-field check.
7
+ */
8
+ export declare const BuildkitePropsObjectSchema: z.ZodObject<{
9
+ buildkiteQueue: z.ZodString;
10
+ buildkiteOrgSlug: z.ZodString;
11
+ agentTokenSsmParameterName: z.ZodString;
12
+ agentTokenKmsKeyArn: z.ZodOptional<z.ZodString>;
13
+ fjallApiKeySsmParameterName: z.ZodOptional<z.ZodString>;
14
+ instanceType: z.ZodDefault<z.ZodString>;
15
+ agentVolumeSizeGib: z.ZodDefault<z.ZodNumber>;
16
+ agentMinInstances: z.ZodDefault<z.ZodNumber>;
17
+ agentMaxInstances: z.ZodDefault<z.ZodNumber>;
18
+ agentsPerInstance: z.ZodDefault<z.ZodNumber>;
19
+ spotCapacityPercentage: z.ZodDefault<z.ZodNumber>;
20
+ scaleInIdlePeriodSeconds: z.ZodDefault<z.ZodNumber>;
21
+ disconnectAfterUptimeSeconds: z.ZodDefault<z.ZodNumber>;
22
+ maxInstanceLifetimeDays: z.ZodDefault<z.ZodNumber>;
23
+ terminateInstanceAfterJob: z.ZodDefault<z.ZodBoolean>;
24
+ purgeBuildsOnDiskFull: z.ZodDefault<z.ZodBoolean>;
25
+ terminateInstanceOnDiskFull: z.ZodDefault<z.ZodBoolean>;
26
+ logRetentionDays: z.ZodDefault<z.ZodNumber>;
27
+ agentLogRetentionDays: z.ZodDefault<z.ZodLiteral<1 | 60 | 5 | 3 | 30 | 7 | 14 | 365 | 90 | 120 | 150 | 180 | 400 | 545 | 731 | 1827 | 3653>>;
28
+ buildkiteAgentRelease: z.ZodDefault<z.ZodEnum<{
29
+ stable: "stable";
30
+ beta: "beta";
31
+ edge: "edge";
32
+ }>>;
33
+ buildkiteAgentTags: z.ZodDefault<z.ZodString>;
34
+ buildkiteAgentTimestampLines: z.ZodDefault<z.ZodBoolean>;
35
+ buildkiteAgentExperiments: z.ZodDefault<z.ZodString>;
36
+ buildkiteAgentTracingBackend: z.ZodDefault<z.ZodEnum<{
37
+ "": "";
38
+ datadog: "datadog";
39
+ opentelemetry: "opentelemetry";
40
+ }>>;
41
+ buildkiteAgentCancelGracePeriodSeconds: z.ZodDefault<z.ZodNumber>;
42
+ enableSecretsPlugin: z.ZodDefault<z.ZodBoolean>;
43
+ enableEcrPlugin: z.ZodDefault<z.ZodBoolean>;
44
+ enableDockerLoginPlugin: z.ZodDefault<z.ZodBoolean>;
45
+ enableDockerUserNamespaceRemap: z.ZodDefault<z.ZodBoolean>;
46
+ enableDockerExperimental: z.ZodDefault<z.ZodBoolean>;
47
+ dockerNetworkingProtocol: z.ZodDefault<z.ZodEnum<{
48
+ ipv4: "ipv4";
49
+ dualstack: "dualstack";
50
+ }>>;
51
+ enableInstanceStorage: z.ZodDefault<z.ZodBoolean>;
52
+ mountTmpfsAtTmp: z.ZodDefault<z.ZodBoolean>;
53
+ buildkiteAgentEnableGitMirrors: z.ZodDefault<z.ZodBoolean>;
54
+ bootstrapScriptUrl: z.ZodDefault<z.ZodString>;
55
+ agentEnvFileUrl: z.ZodDefault<z.ZodString>;
56
+ scalerEventSchedulePeriod: z.ZodDefault<z.ZodString>;
57
+ scalerMinPollInterval: z.ZodDefault<z.ZodString>;
58
+ scaleOutFactor: z.ZodDefault<z.ZodString>;
59
+ scaleOutWaitingForJobs: z.ZodDefault<z.ZodBoolean>;
60
+ rolePermissionsBoundaryArn: z.ZodOptional<z.ZodString>;
61
+ alarmSnsTopicArn: z.ZodOptional<z.ZodString>;
62
+ applicationId: z.ZodOptional<z.ZodString>;
63
+ costAllocationEnvironment: z.ZodOptional<z.ZodString>;
64
+ costAllocationOwner: z.ZodOptional<z.ZodString>;
65
+ }, z.core.$strict>;
66
+ /** Structurally identical to `BuildkiteProps`; companion of the unrefined split. */
67
+ export type BuildkitePropsObject = z.infer<typeof BuildkitePropsObjectSchema>;
68
+ export declare const BuildkitePropsSchema: z.ZodObject<{
69
+ buildkiteQueue: z.ZodString;
70
+ buildkiteOrgSlug: z.ZodString;
71
+ agentTokenSsmParameterName: z.ZodString;
72
+ agentTokenKmsKeyArn: z.ZodOptional<z.ZodString>;
73
+ fjallApiKeySsmParameterName: z.ZodOptional<z.ZodString>;
74
+ instanceType: z.ZodDefault<z.ZodString>;
75
+ agentVolumeSizeGib: z.ZodDefault<z.ZodNumber>;
76
+ agentMinInstances: z.ZodDefault<z.ZodNumber>;
77
+ agentMaxInstances: z.ZodDefault<z.ZodNumber>;
78
+ agentsPerInstance: z.ZodDefault<z.ZodNumber>;
79
+ spotCapacityPercentage: z.ZodDefault<z.ZodNumber>;
80
+ scaleInIdlePeriodSeconds: z.ZodDefault<z.ZodNumber>;
81
+ disconnectAfterUptimeSeconds: z.ZodDefault<z.ZodNumber>;
82
+ maxInstanceLifetimeDays: z.ZodDefault<z.ZodNumber>;
83
+ terminateInstanceAfterJob: z.ZodDefault<z.ZodBoolean>;
84
+ purgeBuildsOnDiskFull: z.ZodDefault<z.ZodBoolean>;
85
+ terminateInstanceOnDiskFull: z.ZodDefault<z.ZodBoolean>;
86
+ logRetentionDays: z.ZodDefault<z.ZodNumber>;
87
+ agentLogRetentionDays: z.ZodDefault<z.ZodLiteral<1 | 60 | 5 | 3 | 30 | 7 | 14 | 365 | 90 | 120 | 150 | 180 | 400 | 545 | 731 | 1827 | 3653>>;
88
+ buildkiteAgentRelease: z.ZodDefault<z.ZodEnum<{
89
+ stable: "stable";
90
+ beta: "beta";
91
+ edge: "edge";
92
+ }>>;
93
+ buildkiteAgentTags: z.ZodDefault<z.ZodString>;
94
+ buildkiteAgentTimestampLines: z.ZodDefault<z.ZodBoolean>;
95
+ buildkiteAgentExperiments: z.ZodDefault<z.ZodString>;
96
+ buildkiteAgentTracingBackend: z.ZodDefault<z.ZodEnum<{
97
+ "": "";
98
+ datadog: "datadog";
99
+ opentelemetry: "opentelemetry";
100
+ }>>;
101
+ buildkiteAgentCancelGracePeriodSeconds: z.ZodDefault<z.ZodNumber>;
102
+ enableSecretsPlugin: z.ZodDefault<z.ZodBoolean>;
103
+ enableEcrPlugin: z.ZodDefault<z.ZodBoolean>;
104
+ enableDockerLoginPlugin: z.ZodDefault<z.ZodBoolean>;
105
+ enableDockerUserNamespaceRemap: z.ZodDefault<z.ZodBoolean>;
106
+ enableDockerExperimental: z.ZodDefault<z.ZodBoolean>;
107
+ dockerNetworkingProtocol: z.ZodDefault<z.ZodEnum<{
108
+ ipv4: "ipv4";
109
+ dualstack: "dualstack";
110
+ }>>;
111
+ enableInstanceStorage: z.ZodDefault<z.ZodBoolean>;
112
+ mountTmpfsAtTmp: z.ZodDefault<z.ZodBoolean>;
113
+ buildkiteAgentEnableGitMirrors: z.ZodDefault<z.ZodBoolean>;
114
+ bootstrapScriptUrl: z.ZodDefault<z.ZodString>;
115
+ agentEnvFileUrl: z.ZodDefault<z.ZodString>;
116
+ scalerEventSchedulePeriod: z.ZodDefault<z.ZodString>;
117
+ scalerMinPollInterval: z.ZodDefault<z.ZodString>;
118
+ scaleOutFactor: z.ZodDefault<z.ZodString>;
119
+ scaleOutWaitingForJobs: z.ZodDefault<z.ZodBoolean>;
120
+ rolePermissionsBoundaryArn: z.ZodOptional<z.ZodString>;
121
+ alarmSnsTopicArn: z.ZodOptional<z.ZodString>;
122
+ applicationId: z.ZodOptional<z.ZodString>;
123
+ costAllocationEnvironment: z.ZodOptional<z.ZodString>;
124
+ costAllocationOwner: z.ZodOptional<z.ZodString>;
125
+ }, z.core.$strict>;
126
+ export type BuildkiteProps = z.infer<typeof BuildkitePropsSchema>;
127
+ /** Caller-facing shape: fields with defaults are optional at the call site. */
128
+ export type BuildkitePropsInput = z.input<typeof BuildkitePropsSchema>;
129
+ /**
130
+ * Validate + default the plain-data props at construct time. Throws a
131
+ * synth-time error listing every violation — the pattern's constructor is the
132
+ * validation boundary, mirroring `ClickHouseDatabase`'s Stage-1 shape.
133
+ */
134
+ export declare function validateBuildkiteProps(props: BuildkitePropsInput): BuildkiteProps;
@@ -0,0 +1,3 @@
1
+ var r=Object.defineProperty;var i=(n,t)=>r(n,"name",{value:t,configurable:!0});import{z as e}from"zod";const s=[1,3,5,7,14,30,60,90,120,150,180,365,400,545,731,1827,3653],o=e.object({buildkiteQueue:e.string().min(1,"buildkiteQueue cannot be empty").max(100).regex(/^[a-zA-Z0-9-_]+$/,"buildkiteQueue must be alphanumeric with hyphens/underscores"),buildkiteOrgSlug:e.string().min(1,"buildkiteOrgSlug cannot be empty").max(100).regex(/^[a-z0-9-]+$/,"buildkiteOrgSlug must be a lowercase Buildkite organisation slug"),agentTokenSsmParameterName:e.string().min(2).regex(/^\//,"agentTokenSsmParameterName must be a full path (leading /)"),agentTokenKmsKeyArn:e.string().min(1).optional(),fjallApiKeySsmParameterName:e.string().min(2).regex(/^\//,"fjallApiKeySsmParameterName must be a full path (leading /)").optional(),instanceType:e.string().min(1).default("c8g.xlarge"),agentVolumeSizeGib:e.number().int().min(20).max(1e3).default(250),agentMinInstances:e.number().int().min(0).default(0),agentMaxInstances:e.number().int().min(1).default(2),agentsPerInstance:e.number().int().min(1).default(1),spotCapacityPercentage:e.number().int().min(0).max(100).default(0),scaleInIdlePeriodSeconds:e.number().int().min(60).default(600),disconnectAfterUptimeSeconds:e.number().int().min(3600).default(86400),maxInstanceLifetimeDays:e.number().int().min(1).max(365).default(7),terminateInstanceAfterJob:e.boolean().default(!1),purgeBuildsOnDiskFull:e.boolean().default(!0),terminateInstanceOnDiskFull:e.boolean().default(!1),logRetentionDays:e.number().int().min(1).default(30),agentLogRetentionDays:e.literal(s).default(7),buildkiteAgentRelease:e.enum(["stable","beta","edge"]).default("stable"),buildkiteAgentTags:e.string().default(""),buildkiteAgentTimestampLines:e.boolean().default(!1),buildkiteAgentExperiments:e.string().default(""),buildkiteAgentTracingBackend:e.enum(["","datadog","opentelemetry"]).default(""),buildkiteAgentCancelGracePeriodSeconds:e.number().int().min(10).default(60),enableSecretsPlugin:e.boolean().default(!0),enableEcrPlugin:e.boolean().default(!1),enableDockerLoginPlugin:e.boolean().default(!1),enableDockerUserNamespaceRemap:e.boolean().default(!0),enableDockerExperimental:e.boolean().default(!1),dockerNetworkingProtocol:e.enum(["ipv4","dualstack"]).default("ipv4"),enableInstanceStorage:e.boolean().default(!1),mountTmpfsAtTmp:e.boolean().default(!0),buildkiteAgentEnableGitMirrors:e.boolean().default(!1),bootstrapScriptUrl:e.string().default(""),agentEnvFileUrl:e.string().default(""),scalerEventSchedulePeriod:e.string().min(1).default("1 minute"),scalerMinPollInterval:e.string().min(1).default("10s"),scaleOutFactor:e.string().min(1).default("1.0"),scaleOutWaitingForJobs:e.boolean().default(!1),rolePermissionsBoundaryArn:e.string().min(1).optional(),alarmSnsTopicArn:e.string().min(1).optional(),applicationId:e.string().min(1).optional(),costAllocationEnvironment:e.string().min(1).optional(),costAllocationOwner:e.string().min(1).optional()}).strict(),u=o.refine(n=>n.agentMinInstances<=n.agentMaxInstances,{message:"agentMinInstances must be <= agentMaxInstances"});function g(n){const t=u.safeParse(n);if(!t.success){const l=t.error.issues.map(a=>` - ${a.path.join(".")||"(root)"}: ${a.message}`).join(`
2
+ `);throw new Error(`Buildkite: invalid props:
3
+ ${l}`)}return t.data}i(g,"validateBuildkiteProps");export{o as BuildkitePropsObjectSchema,u as BuildkitePropsSchema,g as validateBuildkiteProps};
@@ -1,4 +1,5 @@
1
1
  export * from "./resourceSchemas.js";
2
+ export * from "./buildkiteSchemas.js";
2
3
  export * from "./constants.js";
3
4
  export * from "./securityBoundary.js";
4
5
  export * from "./devRolePolicies.js";
@@ -1 +1 @@
1
- export*from"./resourceSchemas.js";export*from"./constants.js";export*from"./securityBoundary.js";export*from"./devRolePolicies.js";import{getArchitectureForInstanceType as i,validateArchitectureMatch as m,isArchitectureCompatible as a}from"./instanceTypeArchitecture.js";export{i as getArchitectureForInstanceType,a as isArchitectureCompatible,m as validateArchitectureMatch};
1
+ export*from"./resourceSchemas.js";export*from"./buildkiteSchemas.js";export*from"./constants.js";export*from"./securityBoundary.js";export*from"./devRolePolicies.js";import{getArchitectureForInstanceType as f,validateArchitectureMatch as i,isArchitectureCompatible as x}from"./instanceTypeArchitecture.js";export{f as getArchitectureForInstanceType,x as isArchitectureCompatible,i as validateArchitectureMatch};
@@ -1 +1 @@
1
- export declare const GENERATOR_VERSION = "3.2.1";
1
+ export declare const GENERATOR_VERSION = "3.3.0";
@@ -1 +1 @@
1
- const E="3.2.1";export{E as GENERATOR_VERSION};
1
+ const E="3.3.0";export{E as GENERATOR_VERSION};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/generator",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "description": "Pure infrastructure generation logic for Fjall",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "license": "SEE LICENSE IN LICENSE",
50
50
  "dependencies": {
51
- "@fjall/util": "^3.2.1",
51
+ "@fjall/util": "^3.3.0",
52
52
  "ast-types": "^0.16.1",
53
53
  "recast": "^0.23.11",
54
54
  "ts-morph": "^28.0.0",
@@ -64,5 +64,5 @@
64
64
  "typescript-eslint": "^8.59.1",
65
65
  "vitest": "^4.1.5"
66
66
  },
67
- "gitHead": "1a249298df7bf3104d9d49b47700234db815ebb1"
67
+ "gitHead": "cc1e0f520f4b6b5312e16df3751d60ea746dfb7d"
68
68
  }