@fjall/generator 14.0.0 → 14.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-source-hash +42 -37
- package/dist/.minified +1 -1
- package/dist/src/ast/astTestHelpers.d.ts +2 -0
- package/dist/src/ast/domain/astDomainParser.d.ts +12 -0
- package/dist/src/ast/domain/astDomainParser.js +1 -1
- package/dist/src/ast/index.d.ts +1 -1
- package/dist/src/ast/index.js +1 -1
- package/dist/src/ast/parsers/resources/astCdnParser.js +1 -1
- package/dist/src/ast/parsers/resources/astComputeParser.js +1 -1
- package/dist/src/codemod/edits/addResource/propertyBuilder.d.ts +8 -0
- package/dist/src/codemod/edits/addResource/propertyBuilder.js +1 -1
- package/dist/src/codemod/edits/addResource/siblingEmission.d.ts +61 -0
- package/dist/src/codemod/edits/addResource/siblingEmission.js +1 -0
- package/dist/src/codemod/edits/addResource.js +1 -1
- package/dist/src/codemod/edits/connectResourceToCompute.js +1 -1
- package/dist/src/codemod/edits/ensureImports.d.ts +18 -0
- package/dist/src/codemod/edits/ensureImports.js +1 -1
- package/dist/src/codemod/edits/modifyResource.js +1 -1
- package/dist/src/codemod/edits/resourceStatementLocator.d.ts +3 -0
- package/dist/src/codemod/edits/resourceStatementLocator.js +1 -1
- package/dist/src/codemod/edits/siblingBindingResolution.d.ts +54 -1
- package/dist/src/codemod/edits/siblingBindingResolution.js +1 -1
- package/dist/src/codemod/emitGuard.d.ts +2 -30
- package/dist/src/codemod/emitGuard.js +1 -1
- package/dist/src/codemod/emitProjection.d.ts +31 -2
- package/dist/src/codemod/emitProjection.js +1 -1
- package/dist/src/codemod/fileRewriter/builders.d.ts +18 -0
- package/dist/src/codemod/fileRewriter/builders.js +1 -1
- package/dist/src/codemod/fileRewriter/index.d.ts +1 -1
- package/dist/src/codemod/fileRewriter/index.js +1 -1
- package/dist/src/codemod/index.d.ts +1 -0
- package/dist/src/codemod/index.js +1 -1
- package/dist/src/codemod/registry.d.ts +26 -27
- package/dist/src/codemod/registry.js +1 -1
- package/dist/src/codemod/validationGate/gates/projection.js +1 -1
- package/dist/src/generation/common.js +8 -8
- package/dist/src/generation/connectionWiring.d.ts +83 -0
- package/dist/src/generation/connectionWiring.js +1 -0
- package/dist/src/generation/database.d.ts +3 -34
- package/dist/src/generation/database.js +20 -20
- package/dist/src/generation/index.d.ts +1 -0
- package/dist/src/generation/index.js +1 -1
- package/dist/src/generation/infrastructure.d.ts +11 -0
- package/dist/src/generation/infrastructure.js +38 -28
- package/dist/src/generation/messagingConnections.d.ts +1 -4
- package/dist/src/generation/messagingConnections.js +1 -1
- package/dist/src/generation/storageConnections.d.ts +1 -12
- package/dist/src/generation/storageConnections.js +1 -1
- package/dist/src/planning/resourceAddition.d.ts +3 -0
- package/dist/src/planning/resourceAddition.js +1 -1
- package/dist/src/projection/compute.d.ts +31 -0
- package/dist/src/projection/compute.js +1 -0
- package/dist/src/projection/index.d.ts +3 -2
- package/dist/src/projection/index.js +1 -1
- package/dist/src/projection/project.d.ts +16 -1
- package/dist/src/projection/project.js +1 -1
- package/dist/src/projection/roundTripKeys.d.ts +12 -0
- package/dist/src/projection/roundTripKeys.js +1 -0
- package/dist/src/projection/tables.d.ts +13 -9
- package/dist/src/projection/tables.js +1 -1
- package/dist/src/projection/types.d.ts +204 -4
- package/dist/src/projection/unresolved.d.ts +17 -0
- package/dist/src/projection/unresolved.js +1 -0
- package/dist/src/schemas/applicationSchemas.d.ts +2 -0
- package/dist/src/schemas/cdnSchemas.d.ts +4 -0
- package/dist/src/schemas/cdnSchemas.js +1 -1
- package/dist/src/schemas/computeSchemas.js +1 -1
- package/dist/src/validation/validationMessages.d.ts +1 -0
- package/dist/src/validation/validationMessages.js +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/package.json +2 -2
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import type * as recast from "recast";
|
|
2
2
|
import { type Result } from "../../types/Result.js";
|
|
3
|
+
import { type QuoteStyle } from "../fileRewriter/index.js";
|
|
3
4
|
import type { SemanticQueryError } from "../types.js";
|
|
4
5
|
type ParsedFile = ReturnType<typeof recast.parse>;
|
|
6
|
+
/** The components barrel every emitted factory/value import comes from. */
|
|
7
|
+
export declare const FACTORY_MODULE_SOURCE = "@fjall/components-infrastructure";
|
|
8
|
+
/**
|
|
9
|
+
* Ensure `specifiers` are named imports from the components barrel
|
|
10
|
+
* (`FACTORY_MODULE_SOURCE`) in a program body. Appends to the existing
|
|
11
|
+
* barrel import line when one exists (deduped by imported name via
|
|
12
|
+
* `appendSpecifier`); otherwise unshifts a new declaration at body[0] — the
|
|
13
|
+
* add path's historical placement, preserved byte-for-byte from its private
|
|
14
|
+
* `ensureFactoryImport`. This is the ONLY import-management path the emitted
|
|
15
|
+
* statements use; structured-expression `imports` are barrel specifiers by
|
|
16
|
+
* contract, never other modules.
|
|
17
|
+
*/
|
|
18
|
+
export declare function ensureBarrelSpecifiers(body: StatementNode[], specifiers: readonly string[], quoteStyle: QuoteStyle): void;
|
|
5
19
|
export interface EnsureImportsAddition {
|
|
6
20
|
module: string;
|
|
7
21
|
specifiers: string[];
|
|
@@ -23,4 +37,8 @@ export type EnsureImportsError = SemanticQueryError;
|
|
|
23
37
|
* Never throws — every failure path returns `failure(EnsureImportsError)`.
|
|
24
38
|
*/
|
|
25
39
|
export declare function ensureImports(file: ParsedFile, additions: EnsureImportsAddition[]): Result<EnsureImportsSuccess, EnsureImportsError>;
|
|
40
|
+
interface StatementNode {
|
|
41
|
+
type: string;
|
|
42
|
+
[key: string]: unknown;
|
|
43
|
+
}
|
|
26
44
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var g=Object.defineProperty;var f=(e,r)=>g(e,"name",{value:r,configurable:!0});import{failure as S,success as c}from"../../types/Result.js";import{extractProgramBody as x,isRecord as h}from"../_internal.js";import{appendSpecifier as u,buildImportDeclaration as p,detectQuoteStyle as A}from"../fileRewriter/index.js";const a="@fjall/components-infrastructure";function j(e,r,t){if(r.length===0)return;const n=m(e,a);if(n!==void 0){for(const i of r)u(n,i);return}const o=p([...r],a,t);e.unshift(o)}f(j,"ensureBarrelSpecifiers");function w(e,r){const t=x(e);if(t===void 0)return S({kind:"SemanticQueryError",reason:"recast File is missing program.body"});if(r.length===0)return c({mutated:!1});const n=A(e);let o=!1;for(const i of r){const s=m(t,i.module);if(s!==void 0){for(const y of i.specifiers){const I=l(s);u(s,y),l(s)>I&&(o=!0)}continue}if(i.specifiers.length===0)continue;const d=p(i.specifiers,i.module,n);D(t,d),o=!0}return c({mutated:o})}f(w,"ensureImports");function m(e,r){for(const t of e){if(t.type!=="ImportDeclaration")continue;const n=t.source;if(h(n)&&!(n.type!=="StringLiteral"&&n.type!=="Literal")&&n.value===r)return t}}f(m,"findImportDeclaration");function D(e,r){let t=-1;for(let o=0;o<e.length;o+=1){const i=e[o];i!==void 0&&i.type==="ImportDeclaration"&&(t=o)}const n=t===-1?0:t+1;e.splice(n,0,r)}f(D,"insertAfterLastImport");function l(e){if(!Array.isArray(e.specifiers))return 0;let r=0;for(const t of e.specifiers)t!==null&&typeof t=="object"&&"type"in t&&t.type==="ImportSpecifier"&&(r+=1);return r}f(l,"countImportedNames");export{a as FACTORY_MODULE_SOURCE,j as ensureBarrelSpecifiers,w as ensureImports};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var U=Object.defineProperty;var p=(r,e)=>U(r,"name",{value:e,configurable:!0});import{failure as s,success as x}from"../../types/Result.js";import{DEFAULT_FILE_PATH as V,computeLinesDelta as j,extractProgramBody as D}from"../_internal.js";import{buildObjectProperty as B,detectQuoteStyle as M,parse as _,printFile as W}from"../fileRewriter/index.js";import{STATEMENT_REGISTRY as H}from"../registry.js";import{locateAllShapes as Y,locateByShape as z}from"../semanticIndex/index.js";import{buildUnmanagedEditRefusal as J}from"./unmanagedShapeErrors.js";import{checkControlFlowPolicy as O}from"./controlFlowPolicy.js";import{driftGate as X,runPipeline as Z,schemaGate as q}from"../validationGate/index.js";import{buildEmittedValue as ee}from"./addResource/propertyBuilder.js";import{buildMergedLiteral as R,collectPropertyKeys as re,isNodeShape as I,readKeyName as te}from"./modifyResource/literalConversion.js";import{findPropertyByKey as T,visit as ne}from"./objectGraph.js";import{evaluateEmitGuard as F,UNRESOLVED as ie}from"../emitGuard.js";import{collectImportSpecifiers as ae,projectEmittedProperties as oe,projectionRefusals as G}from"../emitProjection.js";import{constructKeyAliasesFor as se}from"../../projection/index.js";import{ensureBarrelSpecifiers as de}from"./ensureImports.js";import{applyBinding as ue}from"./resourceStatementLocator.js";import{createSiblingBindingResolution as pe}from"./siblingBindingResolution.js";function $e(r,e,i={}){const t=e.filePath??V,a=_(r,t);if(!a.success)return s(a.error);const n=z(r,{type:e.type,name:e.name},t);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:Ee(r,e.type,t)});if(n.data.managed===!1)return s(J(e.type,"modify"));const o=O({ast:a.data,target:n.data,resource:{type:e.type,name:e.name},op:"modify"});if(o.refusal!==void 0)return s(o.refusal);const d=Z([X],{content:r,plan:{type:e.type,name:e.name,properties:e.properties,op:"modify"},baseline:i.baseline,policy:e.driftPolicy});if(!d.success)return s(L(d.error));if(d.data.action==="skip")return x({content:r,linesChanged:{added:0,removed:0},skipped:!0});const u=D(a.data);if(u===void 0)return s({kind:"SemanticQueryError",reason:"recast File is missing program.body"});const c=fe(u,n.data);if(c===void 0)return s({kind:"SemanticQueryError",reason:"Unable to resolve config ObjectExpression for the located resource."});const l=M(a.data),m=R(c,e.properties),k=H[e.type].emitGuard,h=pe(e.type,()=>u,{mustPrecedeStatementIndex:ce(u,n.data)??0}),E={editingExisting:!0,resourceName:e.name,resolveBinding:h.resolveBinding,resolveBindings:h.resolveBindings},w=K(c,R(c,{})),S=K(c,m),A=F(k,w),P=F(k,S);if(P!==void 0&&P.property!==A?.property)return s(P);const $=new Set(G(e.type,w,E).map(g=>g.property)),b=G(e.type,S,E).find(g=>!$.has(g.property));if(b!==void 0)return s(b);const v=q.run({content:r,plan:{type:e.type,name:e.name,properties:e.properties,op:"modify"}});if(!v.success)return s(L(v.error));h.takePendingWraps();const y=oe(e.type,e.properties,E);if("refusal"in y)return s(y.refusal);const f=y.siblings?.[0];if(f!==void 0)return s({kind:"InvalidPropertyError",property:f.planKey,reason:`\`${f.planKey}\` expands into its own \`app.${f.appMethod}("${f.constructId}", \u2026)\` statement, and \`fjall modify\` edits exactly one statement. Nothing has been written \u2014 this resource already exists, so \`fjall add\` would refuse it as a duplicate: author the \`app.${f.appMethod}("${f.constructId}", \u2026)\` statement in infrastructure.ts by hand, or remove the resource and re-add it with \`${f.planKey}\`.`});const C=le(c,e.type,y.props,l);if(!C.success)return s(C.error);for(const g of h.takePendingWraps())ue(u,g);de(u,ae(y.props),l);const N=W(a.data,r),Q=o.warning!==void 0?[o.warning.message]:void 0;return x({content:N,linesChanged:j(r,N),warnings:Q})}p($e,"modifyResource");function ce(r,e){const i=e.start+e.length;for(let t=0;t<r.length;t++){const a=r[t];if(a===void 0)continue;const{start:n,end:o}=a;if(!(typeof n!="number"||typeof o!="number")&&n<=e.start&&i<=o)return t}}p(ce,"findStatementIndexContaining");function K(r,e){const i={...e};for(const t of re(r))t in i||(i[t]=ie);return i}p(K,"buildGuardView");function L(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}`}}}p(L,"narrowGateError");function fe(r,e){const i=e.start+e.length;let t;const a=p(n=>{if(t!==void 0||n.type!=="CallExpression")return;const o=n.arguments;if(!Array.isArray(o)||o.length<2)return;const d=o[0];if(!I(d)||d.type!=="StringLiteral"||d.start!==e.start||d.end!==i)return;const u=o[1];I(u)&&u.type==="ObjectExpression"&&(t=u)},"visitor");for(const n of r)if(ne(n,a),t!==void 0)break;return t}p(fe,"findConfigObject");function le(r,e,i,t){const a=he(r),n=se(e);for(const o of i){const d=ee(o,t);if(!d.success)return s(d.error);const u=n[o.key]??[],c=T(r,o.key);if(c!==void 0){c.value=d.data,ye(r,u);continue}const l=me(r,u);if(l!==void 0){ge(r,l,o.key,d.data,t);continue}const m=B(o.key,d.data,t);a&&(m.extra={...m.extra??{},trailingComma:!0}),r.properties.push(m)}return x(void 0)}p(le,"applyPropertyEdits");function me(r,e){for(const i of e){const t=T(r,i);if(t!==void 0)return t}}p(me,"findAliasProperty");function ye(r,e){if(e.length!==0)for(let i=r.properties.length-1;i>=0;i--){const t=r.properties[i];if(t===void 0||t.type!=="Property"&&t.type!=="ObjectProperty"||t.shorthand===!0||t.computed===!0)continue;const a=te(t.key);a!==void 0&&e.includes(a)&&r.properties.splice(i,1)}}p(ye,"removePropertiesByKey");function ge(r,e,i,t,a){const n=r.properties.indexOf(e);if(n<0)return;const o=B(i,t,a);e.extra?.trailingComma===!0&&(o.extra={...o.extra??{},trailingComma:!0}),r.properties.splice(n,1,o)}p(ge,"replacePropertyInPlace");function he(r){return r.properties[r.properties.length-1]?.extra?.trailingComma===!0}p(he,"detectTrailingCommaStyle");function Ee(r,e,i){const t=Y(r,i);return t.success?t.data.filter(a=>a.type===e).map(a=>a.symbolName):[]}p(Ee,"collectKnownNames");export{$e as modifyResource};
|
|
@@ -9,6 +9,9 @@ export interface LocatorTarget {
|
|
|
9
9
|
}
|
|
10
10
|
export interface BindingPlan {
|
|
11
11
|
variableName: string;
|
|
12
|
+
/** The resource name the plan binds — collision refusals name it so the
|
|
13
|
+
* operator sees which two resources derive the same variable. */
|
|
14
|
+
resourceName: string;
|
|
12
15
|
/** Index of the matched statement in the module body — callers that emit a
|
|
13
16
|
* reference to the binding need it to judge declaration order. */
|
|
14
17
|
statementIndex: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var w=Object.defineProperty;var d=(r,n)=>w(r,"name",{value:n,configurable:!0});import{builders as b}from"ast-types";import{toVariableName as A}from"../../generation/common.js";import{failure as o,success as E}from"../../types/Result.js";import{RESERVED_IDENTIFIER_NAMES as v}from"./addResource/propertyBuilder.js";import{isNodeShape as s}from"./modifyResource/literalConversion.js";import{unwrapTsWrappers as I}from"./moduleConstResolver.js";import{visit as k}from"./objectGraph.js";function j(r,n,
|
|
1
|
+
var w=Object.defineProperty;var d=(r,n)=>w(r,"name",{value:n,configurable:!0});import{builders as b}from"ast-types";import{toVariableName as A}from"../../generation/common.js";import{failure as o,success as E}from"../../types/Result.js";import{RESERVED_IDENTIFIER_NAMES as v}from"./addResource/propertyBuilder.js";import{isNodeShape as s}from"./modifyResource/literalConversion.js";import{unwrapTsWrappers as I}from"./moduleConstResolver.js";import{visit as k}from"./objectGraph.js";function j(r,n,i){const e=[];for(let c=0;c<r.length;c++){const l=r[c];if(l===void 0)continue;let y=!1;k(l,x=>{x.type==="CallExpression"&&D(x,n.factory,i)&&(y=!0)}),y&&e.push({statementIndex:c})}if(e.length===0)return o({kind:"statement-not-found"});if(e.length>1)return o({kind:"ambiguous",count:e.length});const t=e[0];if(t===void 0)return o({kind:"statement-not-found"});const a=r[t.statementIndex];if(a===void 0)return o({kind:"statement-not-found"});const p=a.type==="ExportNamedDeclaration"||a.type==="ExportDefaultDeclaration",f=h(a);if(f===void 0)return o({kind:"unbindable-statement",statementType:a.type});if(f.type==="VariableDeclaration"){const c=f.declarations;if(!Array.isArray(c)||c.length!==1)return o({kind:"multiple-declarators"});const l=c[0].id;if(!s(l)||l.type!=="Identifier")return o({kind:"pattern-binding"});const y=l.name;if(typeof y!="string")return o({kind:"unreadable-name"});const x=c[0].init;return!s(x)||!g(x,n,i)?o({kind:"init-not-app-method-wrap"}):E({variableName:y,resourceName:i,statementIndex:t.statementIndex})}if(p)return o({kind:"unbindable-statement",statementType:a.type});if(f.type!=="ExpressionStatement")return o({kind:"unbindable-statement",statementType:f.type});const u=f.expression;if(!s(u)||u.type!=="CallExpression")return o({kind:"not-app-method-call"});if(D(u,n.factory,i))return o({kind:"bare-factory-call"});if(!g(u,n,i))return o({kind:"foreign-wrapper"});const m=A(i);return v.has(m)?o({kind:"reserved-word",variableName:m}):S(r,m)?o({kind:"name-conflict",variableName:m}):E({variableName:m,resourceName:i,statementIndex:t.statementIndex,wrap:{statementIndex:t.statementIndex,expression:u}})}d(j,"planBinding");function L(r,n){if(n.wrap===void 0)return;const{statementIndex:i,expression:e}=n.wrap,t=r[i],a=b.variableDeclaration("const",[b.variableDeclarator(b.identifier(n.variableName),e)]),p=t?.comments;p!==void 0&&(a.comments=p),r[i]=a}d(L,"applyBinding");function D(r,n,i){const e=r.callee;if(!s(e)||e.type!=="MemberExpression"||e.computed===!0)return!1;const t=e.object,a=e.property;if(!s(t)||t.type!=="Identifier"||t.name!==n||!s(a)||a.type!=="Identifier"||a.name!=="build")return!1;const p=r.arguments;if(!Array.isArray(p))return!1;const f=p[0];return!s(f)||f.type!=="StringLiteral"&&f.type!=="Literal"?!1:f.value===i}d(D,"isFactoryBuildOf");function h(r){if(r.type!=="ExportNamedDeclaration"&&r.type!=="ExportDefaultDeclaration")return r;const n=r.declaration;return s(n)?n:void 0}d(h,"unwrapExportDeclaration");function M(r){const n=I(r);if(n.type!=="CallExpression")return;const i=n.callee;if(!s(i)||i.type!=="MemberExpression"||i.computed===!0)return;const e=i.property;if(!s(e)||e.type!=="Identifier")return;const t=e.name;return typeof t=="string"?t:void 0}d(M,"appMethodNameOf");function g(r,n,i){const e=I(r);if(M(e)!==n.appMethod)return!1;const t=e.arguments;if(!Array.isArray(t))return!1;const a=t[0];return s(a)?D(I(a),n.factory,i):!1}d(g,"isAppMethodWrap");function S(r,n){for(const i of r){const e=h(i);if(e!==void 0){if(e.type==="ImportDeclaration"){const t=e.specifiers;if(!Array.isArray(t))continue;for(const a of t){const p=a.local;if(s(p)&&p.name===n)return!0}continue}if(e.type==="VariableDeclaration"){const t=e.declarations;if(!Array.isArray(t))continue;for(const a of t){if(!s(a))continue;const p=a.id;if(!s(p))continue;let f=!1;if(k(p,u=>{u.type==="Identifier"&&u.name===n&&(f=!0)}),f)return!0}continue}if(e.type==="FunctionDeclaration"||e.type==="ClassDeclaration"){const t=e.id;if(s(t)&&t.name===n)return!0}}}return!1}d(S,"moduleScopeDeclares");export{M as appMethodNameOf,L as applyBinding,D as isFactoryBuildOf,S as moduleScopeDeclares,j as planBinding,h as unwrapExportDeclaration};
|
|
@@ -1,10 +1,48 @@
|
|
|
1
1
|
import type { StatementType } from "../types.js";
|
|
2
2
|
import type { NodeShapeLike } from "./modifyResource/literalConversion.js";
|
|
3
3
|
import { type BindingPlan } from "./resourceStatementLocator.js";
|
|
4
|
+
/**
|
|
5
|
+
* Which sibling types may satisfy a live binding for one edited type.
|
|
6
|
+
* `default` applies to every plan key without its own entry; `perKey` narrows
|
|
7
|
+
* a specific plan key to the types it may bind — compute's connection keys
|
|
8
|
+
* each name exactly one resource type, so `connectedDatabase: "Uploads"`
|
|
9
|
+
* must never resolve against a storage statement even though a same-named
|
|
10
|
+
* one exists.
|
|
11
|
+
*/
|
|
12
|
+
export interface BindingCandidates {
|
|
13
|
+
default?: ReadonlyArray<StatementType>;
|
|
14
|
+
perKey?: Readonly<Partial<Record<string, ReadonlyArray<StatementType>>>>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* One module-scope `const` a pending wrap plan will declare when applied.
|
|
18
|
+
* `planBinding` checks each wrap name against the PRE-mutation body only, so
|
|
19
|
+
* the caller must judge the pending declarations against EACH OTHER and
|
|
20
|
+
* against any primary binding it derives later — two resources whose names
|
|
21
|
+
* collapse to the same variable (`"Uploads"` and `"uploads"` both derive
|
|
22
|
+
* `uploads`) would otherwise emit two `const` declarations and write a file
|
|
23
|
+
* that does not parse.
|
|
24
|
+
*/
|
|
25
|
+
export interface PendingDeclaration {
|
|
26
|
+
variableName: string;
|
|
27
|
+
resourceName: string;
|
|
28
|
+
statementIndex: number;
|
|
29
|
+
/** The plan key whose resolution recorded the wrap, when the caller
|
|
30
|
+
* supplied one — collision refusals attribute themselves to it. */
|
|
31
|
+
planKey?: string;
|
|
32
|
+
}
|
|
4
33
|
export interface SiblingBindingResolution {
|
|
5
|
-
resolveBinding: (planResourceName: string) => string | undefined;
|
|
34
|
+
resolveBinding: (planResourceName: string, planKey?: string) => string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* All-or-nothing array form: every name resolves or the whole call answers
|
|
37
|
+
* `undefined` — and any wrap plans recorded by the partial resolution are
|
|
38
|
+
* rolled back, so a refused array never leaves a half-bound file.
|
|
39
|
+
*/
|
|
40
|
+
resolveBindings: (planResourceNames: ReadonlyArray<string>, planKey?: string) => ReadonlyArray<string> | undefined;
|
|
6
41
|
/** Wrap plans recorded by successful resolutions since the last drain. */
|
|
7
42
|
takePendingWraps: () => BindingPlan[];
|
|
43
|
+
/** The `const` names those pending wraps will declare — consulted before
|
|
44
|
+
* any mutation so no two planned declarations share a name. */
|
|
45
|
+
pendingDeclarations: () => ReadonlyArray<PendingDeclaration>;
|
|
8
46
|
}
|
|
9
47
|
export interface SiblingBindingConstraints {
|
|
10
48
|
/**
|
|
@@ -20,3 +58,18 @@ export interface SiblingBindingConstraints {
|
|
|
20
58
|
mustPrecedeStatementIndex?: number;
|
|
21
59
|
}
|
|
22
60
|
export declare function createSiblingBindingResolution(type: StatementType, getBody: () => NodeShapeLike[] | undefined, constraints?: SiblingBindingConstraints): SiblingBindingResolution;
|
|
61
|
+
/**
|
|
62
|
+
* The first pair of pending declarations that would declare the same
|
|
63
|
+
* module-scope `const` for two DIFFERENT statements. Each wrap passed
|
|
64
|
+
* `planBinding`'s body-conflict check individually, but none of the planned
|
|
65
|
+
* names is in the body yet, so two resources collapsing to one variable
|
|
66
|
+
* (`"Uploads"` and `"uploads"`) sail through separately and collide only in
|
|
67
|
+
* the written file — `Identifier 'uploads' has already been declared`, from
|
|
68
|
+
* an edit that reported success. The caller refuses pre-mutation instead.
|
|
69
|
+
* Same-statement duplicates are NOT a collision: re-resolving one resource
|
|
70
|
+
* plans the identical wrap twice, and applying it twice is idempotent.
|
|
71
|
+
*/
|
|
72
|
+
export declare function findPendingWrapCollision(declarations: ReadonlyArray<PendingDeclaration>): {
|
|
73
|
+
first: PendingDeclaration;
|
|
74
|
+
second: PendingDeclaration;
|
|
75
|
+
} | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var I=Object.defineProperty;var d=(a,o)=>I(a,"name",{value:o,configurable:!0});import{FACTORY_IDENTIFIERS as b,STATEMENT_REGISTRY as h}from"../registry.js";import{planBinding as v}from"./resourceStatementLocator.js";const x={cdn:{default:["storage","compute"]},compute:{perKey:{connectedDatabase:["database"],connectedStorage:["storage"],connectedMessaging:["messaging"]}}};function M(a,o,i={}){const r=x[a];let s=[];const p=d((n,e)=>{const u=o();if(u===void 0)return;const f=(e!==void 0?r?.perKey?.[e]:void 0)??r?.default??[],c=[];for(const l of f){const N=h[l].emitWrapper?.appMethod;if(N===void 0)continue;const m=v(u,{factory:b[l],appMethod:N},n);if(m.success){c.push(m.data);continue}if(m.error.kind!=="statement-not-found")return}if(c.length!==1)return;const t=c[0];if(t===void 0)return;const g=i.mustPrecedeStatementIndex;if(!(g!==void 0&&t.statementIndex>=g))return t.wrap!==void 0&&s.push({plan:t,...e!==void 0&&{planKey:e}}),t.variableName},"resolveBinding");return{resolveBinding:p,resolveBindings:d((n,e)=>{const u=s.length,f=[];for(const c of n){const t=p(c,e);if(t===void 0){s.length=u;return}f.push(t)}return f},"resolveBindings"),takePendingWraps:d(()=>{const n=s;return s=[],n.map(e=>e.plan)},"takePendingWraps"),pendingDeclarations:d(()=>s.map(({plan:n,planKey:e})=>({variableName:n.variableName,resourceName:n.resourceName,statementIndex:n.statementIndex,...e!==void 0&&{planKey:e}})),"pendingDeclarations")}}d(M,"createSiblingBindingResolution");function P(a){const o=new Map;for(const i of a){const r=o.get(i.variableName);if(r===void 0){o.set(i.variableName,i);continue}if(r.statementIndex!==i.statementIndex)return{first:r,second:i}}}d(P,"findPendingWrapCollision");export{M as createSiblingBindingResolution,P as findPendingWrapCollision};
|
|
@@ -1,17 +1,6 @@
|
|
|
1
|
+
import { UNRESOLVED } from "../projection/unresolved.js";
|
|
1
2
|
import type { InvalidPropertyError } from "./types.js";
|
|
2
|
-
|
|
3
|
-
* A value the codemod could not have written: the property is present in
|
|
4
|
-
* the target statement but holds a non-literal expression (`Code.fromAsset(
|
|
5
|
-
* "./src")`, `Runtime.NODEJS_20_X`, `assetsBucket`).
|
|
6
|
-
*
|
|
7
|
-
* Its presence is PROOF the statement was authored by a human or by the
|
|
8
|
-
* generator scaffold, both of which speak construct vocabulary. Rules that
|
|
9
|
-
* refuse a key because the construct needs a live object must therefore
|
|
10
|
-
* treat `UNRESOLVED` as satisfying the construct — otherwise `fjall modify`
|
|
11
|
-
* would refuse to touch perfectly good scaffold output. The ADD path never
|
|
12
|
-
* produces it: every value there comes from a flag.
|
|
13
|
-
*/
|
|
14
|
-
export declare const UNRESOLVED: unique symbol;
|
|
3
|
+
export { UNRESOLVED };
|
|
15
4
|
/**
|
|
16
5
|
* The property record the emitted statement WOULD carry. `add` passes the
|
|
17
6
|
* requested properties; `modify` passes the merge of the existing statement
|
|
@@ -43,23 +32,6 @@ export interface EmitGuardRule {
|
|
|
43
32
|
* always correct.
|
|
44
33
|
*/
|
|
45
34
|
export declare const AUTHOR_BY_HAND: string;
|
|
46
|
-
/** True when the key holds a value the codemod itself could have written. */
|
|
47
|
-
export declare function isWrittenValue(value: unknown): boolean;
|
|
48
|
-
/**
|
|
49
|
-
* A rule for a plan key NO construct reads, in any shape — proven by zero
|
|
50
|
-
* `props.<key>` reads across @fjall/components-infrastructure. Presence
|
|
51
|
-
* alone is the refusal; the value cannot rescue it.
|
|
52
|
-
*
|
|
53
|
-
* Phrased as a statement of consequence, because the operator's mental model
|
|
54
|
-
* is "I set it, so it took effect" and the whole point is that it did not.
|
|
55
|
-
*/
|
|
56
|
-
export declare function silentlyDropped(property: string, detail: string): EmitGuardRule;
|
|
57
|
-
/**
|
|
58
|
-
* A rule for a key the construct DOES read but only as a live object — a
|
|
59
|
-
* CDK enum member, an asset, another construct. A flag value is a string,
|
|
60
|
-
* so any value the codemod can write is wrong; only `UNRESOLVED` passes.
|
|
61
|
-
*/
|
|
62
|
-
export declare function requiresLiveValue(property: string, detail: string): EmitGuardRule;
|
|
63
35
|
/** Refuse whenever the key is missing (the missing-discriminator shape). */
|
|
64
36
|
export declare function whenAbsent(property: string): (properties: EmitGuardProperties) => boolean;
|
|
65
37
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var o=Object.defineProperty;var t=(e,r)=>o(e,"name",{value:r,configurable:!0});import{UNRESOLVED as i}from"../projection/unresolved.js";const s="Write this resource in infrastructure.ts by hand \u2014 the construct props it needs cannot be expressed as `fjall add` flags.";function f(e){return r=>r[e]===void 0}t(f,"whenAbsent");function a(e,r){if(e!==void 0){for(const n of e)if(n.refuseWhen(r))return{kind:"InvalidPropertyError",property:n.property,reason:n.reason}}}t(a,"evaluateEmitGuard");export{s as AUTHOR_BY_HAND,i as UNRESOLVED,a as evaluateEmitGuard,f as whenAbsent};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { type ProjectionContext } from "../projection/index.js";
|
|
1
|
+
import { type ProjectionContext, type StructuredValue } from "../projection/index.js";
|
|
2
2
|
import { type EmitGuardProperties } from "./emitGuard.js";
|
|
3
3
|
import type { InvalidPropertyError, StatementType } from "./types.js";
|
|
4
4
|
/**
|
|
5
5
|
* One emitted construct prop. `literal` is a serialisable value; `expression`
|
|
6
6
|
* carries the source text of a live binding a projection rule resolved — the
|
|
7
|
-
* emitters splice it as an identifier rather than serialising it
|
|
7
|
+
* emitters splice it as an identifier rather than serialising it;
|
|
8
|
+
* `structured` carries a validated expression tree plus the components-barrel
|
|
9
|
+
* specifiers it needs (`collectImportSpecifiers` gathers those for the
|
|
10
|
+
* emitters to apply once).
|
|
8
11
|
*/
|
|
9
12
|
export type EmittedProp = {
|
|
10
13
|
key: string;
|
|
@@ -14,7 +17,32 @@ export type EmittedProp = {
|
|
|
14
17
|
key: string;
|
|
15
18
|
kind: "expression";
|
|
16
19
|
source: string;
|
|
20
|
+
} | {
|
|
21
|
+
key: string;
|
|
22
|
+
kind: "structured";
|
|
23
|
+
expression: StructuredValue;
|
|
24
|
+
imports?: readonly string[];
|
|
17
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* One sibling statement in emission vocabulary — the projection's
|
|
28
|
+
* {@link SiblingStatement} with its props mapped to {@link EmittedProp}s. The
|
|
29
|
+
* add path emits each as `app.<appMethod>("<constructId>", { …props })`
|
|
30
|
+
* directly after the primary statement; modify refuses the whole edit when
|
|
31
|
+
* any arrive, because it edits exactly one statement.
|
|
32
|
+
*/
|
|
33
|
+
export interface EmittedSibling {
|
|
34
|
+
planKey: string;
|
|
35
|
+
constructId: string;
|
|
36
|
+
appMethod: string;
|
|
37
|
+
props: EmittedProp[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Every components-barrel specifier the emitted props need, deduplicated in
|
|
41
|
+
* first-appearance order. The emitters apply these once per write — a
|
|
42
|
+
* specifier requested by several props (or by a prop and a sibling) lands as
|
|
43
|
+
* one named import.
|
|
44
|
+
*/
|
|
45
|
+
export declare function collectImportSpecifiers(props: ReadonlyArray<EmittedProp>): string[];
|
|
18
46
|
/**
|
|
19
47
|
* EVERY plan key in `properties` this type cannot turn into a construct
|
|
20
48
|
* prop, one refusal per key, as the codebase's actionable error shape.
|
|
@@ -45,6 +73,7 @@ export declare function projectionRefusals(type: StatementType, properties: Emit
|
|
|
45
73
|
*/
|
|
46
74
|
export declare function projectEmittedProperties(type: StatementType, properties: Readonly<Record<string, unknown>>, context?: ProjectionContext): {
|
|
47
75
|
props: EmittedProp[];
|
|
76
|
+
siblings?: EmittedSibling[];
|
|
48
77
|
} | {
|
|
49
78
|
refusal: InvalidPropertyError;
|
|
50
79
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var m=Object.defineProperty;var r=(e,t)=>m(e,"name",{value:t,configurable:!0});import{crossKeyUnprojectables as h,isProjectableType as u,projectPlanToConstructProps as c}from"../projection/index.js";import{AUTHOR_BY_HAND as k}from"./emitGuard.js";function x(e){const t=new Set;for(const n of e)if(!(n.kind!=="structured"||n.imports===void 0))for(const i of n.imports)t.add(i);return[...t]}r(x,"collectImportSpecifiers");const y={"plan-only":`\`fjall add\` would write it into the factory call and the resource would deploy without it. ${k}`,"unresolved-binding":"Nothing has been written: the engine refuses rather than guessing a construct. Add or bind a sibling resource with that name (or fix the name) and run the same command again \u2014 it succeeds once a unique binding exists.","missing-context":"Nothing has been written: the command context supplied no resource name to derive it from.","cross-key":"Nothing has been written: the refusal follows from the statement's properties taken together, not from this key alone. Change the named property (or the counterpart it conflicts with) and run the same command again."};function d(e,t,n="plan-only"){return{kind:"InvalidPropertyError",property:e,reason:`${t} ${y[n]}`}}r(d,"unprojectableRefusal");function j(e,t,n={}){return u(e)?[...n.editingExisting===!0?h(e,t):[],...c(e,t,n).unprojectable].map(o=>d(o.key,o.reason,o.kind)):[]}r(j,"projectionRefusals");function E(e,t,n={}){if(!u(e))return{props:Object.entries(t).map(([p,f])=>({key:p,kind:"literal",value:f}))};const{props:i,unprojectable:o,siblings:a}=c(e,t,n),[s]=o;return s!==void 0?{refusal:d(s.key,s.reason,s.kind)}:{props:i.map(l),...a!==void 0&&{siblings:a.map(g)}}}r(E,"projectEmittedProperties");function g(e){return{planKey:e.planKey,constructId:e.constructId,appMethod:e.appMethod,props:e.props.map(l)}}r(g,"toEmittedSibling");function l(e){switch(e.value.kind){case"expression":return{key:e.key,kind:"expression",source:e.value.source};case"structured":return{key:e.key,kind:"structured",expression:e.value.expression,...e.value.imports!==void 0&&{imports:e.value.imports}};case"literal":return{key:e.key,kind:"literal",value:e.value.value}}}r(l,"toEmittedProp");export{x as collectImportSpecifiers,E as projectEmittedProperties,j as projectionRefusals};
|
|
@@ -41,6 +41,24 @@ export declare function buildFactoryStatement(params: BuildFactoryStatementParam
|
|
|
41
41
|
* only materialised by an App method.
|
|
42
42
|
*/
|
|
43
43
|
export declare function buildAppMethodWrappedStatement(params: BuildAppMethodWrappedStatementParams): n.ExpressionStatement;
|
|
44
|
+
export interface BuildAppMethodStatementParams {
|
|
45
|
+
/** App binding identifier, e.g. `"app"` — resolved, never assumed. */
|
|
46
|
+
appIdentifier: string;
|
|
47
|
+
/** App method called directly, e.g. `"addConnection"`. */
|
|
48
|
+
appMethod: string;
|
|
49
|
+
/** Construct id, used as the first argument literal. */
|
|
50
|
+
name: string;
|
|
51
|
+
/** Configuration object properties. */
|
|
52
|
+
properties: ObjectPropertyInput[];
|
|
53
|
+
/** Quote style for NEW string literals the builder synthesises. */
|
|
54
|
+
quoteStyle: QuoteStyle;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build an `ExpressionStatement` wrapping `app.<method>("Name", { … })` — a
|
|
58
|
+
* direct app-method call with NO factory layer, the shape sibling statements
|
|
59
|
+
* take (a connection is materialised by the App method itself).
|
|
60
|
+
*/
|
|
61
|
+
export declare function buildAppMethodStatement(params: BuildAppMethodStatementParams): n.ExpressionStatement;
|
|
44
62
|
/**
|
|
45
63
|
* Build an object `Property` with a bare-identifier key. If `key` is
|
|
46
64
|
* not a valid JS identifier (e.g. contains a hyphen), the key is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var a=Object.defineProperty;var n=(e,i)=>a(e,"name",{value:i,configurable:!0});import{builders as t}from"ast-types";function y(e){return t.expressionStatement(s(e))}n(y,"buildFactoryStatement");function E(e){const i=t.callExpression(f(e.appIdentifier,e.appMethod),[s(e)]);return t.expressionStatement(i)}n(E,"buildAppMethodWrappedStatement");function g(e){const i=t.callExpression(f(e.appIdentifier,e.appMethod),[p(e.name,e.quoteStyle),t.objectExpression(e.properties.map(r=>u(r.key,r.value,e.quoteStyle)))]);return t.expressionStatement(i)}n(g,"buildAppMethodStatement");function s(e){const i=t.memberExpression(t.identifier(e.factory),t.identifier("build"),!1),r=p(e.name,e.quoteStyle),o=t.objectExpression(e.properties.map(c=>u(c.key,c.value,e.quoteStyle)));return t.callExpression(i,[r,o])}n(s,"buildFactoryCall");function u(e,i,r){const o=b(e)?t.identifier(e):p(e,r);return t.property("init",o,i)}n(u,"buildObjectProperty");function I(e,i,r="double"){const o=e.map(l=>t.importSpecifier(t.identifier(l))),c=p(i,r);return t.importDeclaration(o,c)}n(I,"buildImportDeclaration");function f(e,i){return t.memberExpression(t.identifier(e),t.identifier(i),!1)}n(f,"buildMemberExpression");function h(e,i){Array.isArray(e.specifiers)||(e.specifiers=[]);for(const r of e.specifiers)if(x(r)&&r.imported.name===i)return;e.specifiers.push(t.importSpecifier(t.identifier(i)))}n(h,"appendSpecifier");function p(e,i){const r=i==="single"?"'":'"',o=`${r}${d(e,i)}${r}`;return t.stringLiteral.from({value:e,extra:{rawValue:e,raw:o}})}n(p,"makeStringLiteral");function d(e,i){const r=e.replace(/\\/g,"\\\\");return i==="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 x(e){return e!==null&&typeof e=="object"&&"type"in e&&e.type==="ImportSpecifier"}n(x,"isNamedImportSpecifier");export{h as appendSpecifier,g as buildAppMethodStatement,E as buildAppMethodWrappedStatement,y as buildFactoryStatement,I as buildImportDeclaration,f as buildMemberExpression,u 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, buildAppMethodWrappedStatement, buildFactoryStatement, buildImportDeclaration, buildMemberExpression, buildObjectProperty, type BuildAppMethodWrappedStatementParams, type BuildFactoryStatementParams, type ObjectPropertyInput, type QuoteStyle, } from "./builders.js";
|
|
3
|
+
export { appendSpecifier, buildAppMethodStatement, buildAppMethodWrappedStatement, buildFactoryStatement, buildImportDeclaration, buildMemberExpression, buildObjectProperty, type BuildAppMethodStatementParams, 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 p,detectQuoteStyle as i,printFile as a}from"./print.js";import{appendSpecifier as n,buildAppMethodWrappedStatement as
|
|
1
|
+
import{parse as r}from"./parse.js";import{detectLineTerminator as p,detectQuoteStyle as i,printFile as a}from"./print.js";import{appendSpecifier as l,buildAppMethodStatement as n,buildAppMethodWrappedStatement as m,buildFactoryStatement as b,buildImportDeclaration as c,buildMemberExpression as u,buildObjectProperty as f}from"./builders.js";import{locateByLineColumn as y,locateByRange as S}from"./locateByRange.js";export{l as appendSpecifier,n as buildAppMethodStatement,m as buildAppMethodWrappedStatement,b as buildFactoryStatement,c as buildImportDeclaration,u as buildMemberExpression,f as buildObjectProperty,p as detectLineTerminator,i as detectQuoteStyle,y as locateByLineColumn,S as locateByRange,r as parse,a as printFile};
|
|
@@ -18,6 +18,7 @@ export { computeLinesDelta } from "./_internal.js";
|
|
|
18
18
|
export { ResourceNameSchema, StatementTypeSchema } from "./types.js";
|
|
19
19
|
export { REGISTERED_STATEMENT_TYPES, STATEMENT_REGISTRY, type StatementTypeEntry, } from "./registry.js";
|
|
20
20
|
export { evaluateEmitGuard, UNRESOLVED, type EmitGuardProperties, type EmitGuardRule, } from "./emitGuard.js";
|
|
21
|
+
export { projectionRefusals } from "./emitProjection.js";
|
|
21
22
|
export { CODEMOD_ERROR_KINDS } from "./telemetry/errorKinds.js";
|
|
22
23
|
export type { CodemodErrorKind } from "./telemetry/errorKinds.js";
|
|
23
24
|
export type { GateId } from "./validationGate/index.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{addResource as o}from"./edits/addResource.js";import{removeResource as c}from"./edits/removeResource.js";import{modifyResource as m}from"./edits/modifyResource.js";import{appendAccountToStage as s}from"./edits/appendAccountToStage.js";import{setContainerSecrets as E}from"./edits/setContainerSecrets.js";import{connectResourceToCompute as l}from"./edits/connectResourceToCompute.js";import{addVpcPeer as
|
|
1
|
+
import{addResource as o}from"./edits/addResource.js";import{removeResource as c}from"./edits/removeResource.js";import{modifyResource as m}from"./edits/modifyResource.js";import{appendAccountToStage as s}from"./edits/appendAccountToStage.js";import{setContainerSecrets as E}from"./edits/setContainerSecrets.js";import{connectResourceToCompute as l}from"./edits/connectResourceToCompute.js";import{addVpcPeer as f,modifyVpcPeer as u,removeVpcPeer as T}from"./edits/vpcPeer.js";import{addVpcPeerAccepter as x,modifyVpcPeerAccepter as P,removeVpcPeerAccepter as S}from"./edits/vpcPeerAccepter.js";import{addCrossPlanConnection as v,modifyCrossPlanConnection as C,removeCrossPlanConnection as N}from"./edits/crossPlanConnection.js";import{resolveDriftPolicy as b}from"./edits/driftPolicy.js";import{listResources as y}from"./listResources.js";import{resolveConstructByLiteralProperty as G}from"./semanticIndex/index.js";import{parse as I}from"./fileRewriter/parse.js";import{CrossPlanConnectionResourcePlanSchema as F,VpcPeerAccepterResourcePlanSchema as L,VpcPeerResourcePlanSchema as U}from"../schemas/index.js";import{detectDrift as k,mergeProperties as B,snapshotProperties as M}from"./drift/index.js";import{computeLinesDelta as K}from"./_internal.js";import{ResourceNameSchema as q,StatementTypeSchema as w}from"./types.js";import{REGISTERED_STATEMENT_TYPES as H,STATEMENT_REGISTRY as J}from"./registry.js";import{evaluateEmitGuard as W,UNRESOLVED as X}from"./emitGuard.js";import{projectionRefusals as $}from"./emitProjection.js";import{CODEMOD_ERROR_KINDS as re}from"./telemetry/errorKinds.js";import{buildEgressBlockedEvent as te,buildFiredEvent as ce,buildGateFailedEvent as pe,buildGatePassedEvent as me,buildRejectedEvent as ae,buildSucceededEvent as se,buildTimeoutEvent as ne,estimateCostUsd as Ee,FALLBACK_EVENTS as de,GATE_EVENTS as le,gateFallbackOutput as ie,PARSE_GATE as fe,RUNTIME_GATE as ue,runFallback as Te,shouldTryFallback as Re,UNATTRIBUTED_ORGANISATION as xe}from"./llmFallback/index.js";export{re as CODEMOD_ERROR_KINDS,F as CrossPlanConnectionResourcePlanSchema,de as FALLBACK_EVENTS,le as GATE_EVENTS,fe as PARSE_GATE,H as REGISTERED_STATEMENT_TYPES,ue as RUNTIME_GATE,q as ResourceNameSchema,J as STATEMENT_REGISTRY,w as StatementTypeSchema,xe as UNATTRIBUTED_ORGANISATION,X as UNRESOLVED,L as VpcPeerAccepterResourcePlanSchema,U as VpcPeerResourcePlanSchema,v as addCrossPlanConnection,o as addResource,f as addVpcPeer,x as addVpcPeerAccepter,s as appendAccountToStage,te as buildEgressBlockedEvent,ce as buildFiredEvent,pe as buildGateFailedEvent,me as buildGatePassedEvent,ae as buildRejectedEvent,se as buildSucceededEvent,ne as buildTimeoutEvent,K as computeLinesDelta,l as connectResourceToCompute,k as detectDrift,Ee as estimateCostUsd,W as evaluateEmitGuard,ie as gateFallbackOutput,y as listResources,B as mergeProperties,C as modifyCrossPlanConnection,m as modifyResource,u as modifyVpcPeer,P as modifyVpcPeerAccepter,I as parse,$ as projectionRefusals,N as removeCrossPlanConnection,c as removeResource,T as removeVpcPeer,S as removeVpcPeerAccepter,G as resolveConstructByLiteralProperty,b as resolveDriftPolicy,Te as runFallback,E as setContainerSecrets,Re as shouldTryFallback,M as snapshotProperties};
|
|
@@ -30,18 +30,19 @@ export interface StatementTypeEntry {
|
|
|
30
30
|
/**
|
|
31
31
|
* The ADD path's required-aware input contract: the plan schema minus
|
|
32
32
|
* `name`, WITHOUT `.partial()`, so a first-time add must carry every
|
|
33
|
-
* required plan key (`database` demands `type` + `databaseName`
|
|
34
|
-
* as satisfying the per-key
|
|
35
|
-
* delta contract for MODIFY.
|
|
33
|
+
* required plan key (`database` demands `type` + `databaseName`; `compute`
|
|
34
|
+
* demands `type` + `needsConnection`) as well as satisfying the per-key
|
|
35
|
+
* shapes. `schemaFragment` stays the partial delta contract for MODIFY.
|
|
36
36
|
*
|
|
37
37
|
* Declared ONLY for guard-free types, and that is a rule, not a
|
|
38
|
-
* convenience: a guarded type's required plan keys
|
|
39
|
-
* scaffold-consumed keys its own guard
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* type's projection and deletes its guard table, declare
|
|
44
|
-
* the same edit — the schema-gate XOR test pins the
|
|
38
|
+
* convenience: a guarded type's required plan keys would be exactly the
|
|
39
|
+
* scaffold-consumed keys its own guard refuses to write — the catch-22
|
|
40
|
+
* `compute` sat in until its projection landed (its guard `silentlyDropped`
|
|
41
|
+
* the required `needsConnection`, so demanding it at the gate was
|
|
42
|
+
* unsatisfiable; the projection's expansion now CONSUMES it). When an
|
|
43
|
+
* increment lands a type's projection and deletes its guard table, declare
|
|
44
|
+
* `addContract` in the same edit — the schema-gate XOR test pins the
|
|
45
|
+
* pairing. `vpc-peer`, the one guarded type left, correctly declares none.
|
|
45
46
|
*
|
|
46
47
|
* Absent = the schema gate applies `schemaFragment` to adds too
|
|
47
48
|
* (unknown-key and per-key-shape checks only, no required demand).
|
|
@@ -87,21 +88,19 @@ export interface StatementTypeEntry {
|
|
|
87
88
|
* ONLY for types the plan→construct projection cannot describe. Where it
|
|
88
89
|
* can (`src/projection/tables.ts`), the disagreement is TRANSLATED at
|
|
89
90
|
* emission and no rule belongs here — `emitProjection.ts` reports what is
|
|
90
|
-
* left from the projection's own `unprojectable` list
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
91
|
+
* left from the projection's own `unprojectable` list; a live sibling
|
|
92
|
+
* binding is expressible through a `live` rule (`cdn`'s origin), a second
|
|
93
|
+
* statement through a sibling projection (`compute`'s schedule), a merged
|
|
94
|
+
* prop through a fragment expansion (`compute`'s connection keys), and a
|
|
95
|
+
* key combination through a `crossKey` rule. What survives is `vpc-peer`
|
|
96
|
+
* alone: required-key conditions whose absence deploys silently wrong
|
|
97
|
+
* infrastructure.
|
|
94
98
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* always wrong.
|
|
101
|
-
* · SILENTLY DROPPED — the construct never reads the plan key, so the
|
|
102
|
-
* resource deploys without the behaviour that was requested. Proven
|
|
103
|
-
* per key: zero `props.<key>` reads anywhere in
|
|
104
|
-
* @fjall/components-infrastructure.
|
|
99
|
+
* The one class rules still cover: a required key whose ABSENCE deploys
|
|
100
|
+
* silently wrong infrastructure — synth succeeds, the deploy is green, and
|
|
101
|
+
* the emitted resource points at garbage (`vpc-peer`'s two required
|
|
102
|
+
* members). Refusing at write time is the only net, because `cdk.json`
|
|
103
|
+
* runs `infrastructure.ts` through tsx, which does not typecheck.
|
|
105
104
|
*
|
|
106
105
|
* Deliberately NOT covered: INCOMPLETE input, where the vocabulary can
|
|
107
106
|
* express a working call and the operator has not yet — that is
|
|
@@ -114,9 +113,9 @@ export interface StatementTypeEntry {
|
|
|
114
113
|
* Absent = every expressible property shape for this type reaches a
|
|
115
114
|
* synthesising statement. That is a claim, not an oversight, and it is now
|
|
116
115
|
* true two ways: `network` and `buildkite` have outright plan/construct
|
|
117
|
-
* parity, while `database`, `storage` and `
|
|
118
|
-
* projection. The components-infrastructure materialisation
|
|
119
|
-
* both.
|
|
116
|
+
* parity, while `database`, `storage`, `messaging` and `compute` reach it
|
|
117
|
+
* through the projection. The components-infrastructure materialisation
|
|
118
|
+
* contract pins both.
|
|
120
119
|
*/
|
|
121
120
|
emitGuard?: ReadonlyArray<EmitGuardRule>;
|
|
122
121
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var R=Object.defineProperty;var r=(e,t)=>R(e,"name",{value:t,configurable:!0});import{DEPLOYABLE_PATTERN_TYPES as I,PATTERN_TYPE_VALUES as N,isPatternType as M,patternConstructId as m}from"@fjall/util";import{z as s}from"zod";import{BuildkitePropsObjectSchema as u,CDNResourcePlanSchema as l,ComputeResourcePlanSchema as g,CrossPlanConnectionResourcePlanSchema as h,DatabaseResourcePlanSchema as y,NetworkResourcePlanSchema as P,NextJSPatternConfigSchema as v,OrganisationResourcePlanSchema as S,PayloadPatternConfigSchema as w,S3ResourcePlanSchema as C,SQSResourcePlanSchema as f,StaticSitePatternConfigSchema as O,VpcPeerAccepterResourcePlanSchema as F,VpcPeerResourcePlanSchema as W}from"../schemas/index.js";import{failure as x}from"../types/Result.js";import{whenAbsent as b}from"./emitGuard.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 c(e){const{name:t,...a}=e.shape;return s.object(a).partial().strict()}r(c,"fragmentOf");function p(e){const{name:t,...a}=e.shape;return s.object(a).strict()}r(p,"completeFragmentOf");const j=c(y),B=c(C),V=(()=>{const{name:e,...t}=g.shape;return s.object(t).partial().strict()})(),D=(()=>{const{name:e,...t}=g.shape;return s.object(t).strict()})(),Y=c(f),G=c(l),L=c(P),E=(()=>{const{name:e,type:t,cdn:a,...A}=w.shape,{name:te,type:re,cdn:ae,...T}=v.shape,{name:ne,type:oe,domain:ce,cdn:_,...k}=O.shape;return{...A,...T,...k,cdn:s.union([a,_]),type:s.enum(I)}})(),q=s.object(E).partial().strict(),Q=s.object(E).partial().required({type:!0}).strict(),U={emitConstructId:r((e,t)=>M(t.type)?m(e,t.type):e,"emitConstructId"),locateCandidates:r(e=>[e,...N.map(t=>m(e,t))],"locateCandidates")},$=c(W),z=c(F),J=c(h),H=c(S),K=c(u);function d(e,t){return x({kind:"SemanticQueryError",reason:`StatementTypeEntry.${e} for ${t} is not wired; existing types dispatch through the shared locator/generator.`})}r(d,"notWiredError");function X(e){return{factoryIdentifier:e,findByShape:r(()=>d("locator.findByShape",e),"findByShape"),validateContext:r(()=>d("locator.validateContext",e),"validateContext")}}r(X,"createLocator");function Z(e){return{build:r(()=>{const t=d("generator.build",e);throw new Error(t.success?"unreachable":t.error.reason)},"build")}}r(Z,"createGenerator");const ee=[{property:"peerAppName",refuseWhen:b("peerAppName"),reason:"`peerAppName` is required: it is the SSM prefix every remote lookup is built from, and omitting it does NOT fail \u2014 synth succeeds and the app deploys a peering connection pointed at `/fjall/default/undefined/vpc-id`. Pass `--peerAppName <remote app>`."},{property:"peerAccountId",refuseWhen:b("peerAccountId"),reason:"`peerAccountId` is required: omitting it does NOT fail, it deploys a VPC peering connection with no `PeerOwnerId`. Pass `--peerAccountId <12-digit account>`."}];function o(e,t,a={}){return{factoryIdentifier:e,locator:X(e),generator:Z(e),schemaFragment:t,...a}}r(o,"createEntry");const i={database:o(n.database,j,{emitWrapper:{appMethod:"addDatabase"},addContract:p(y)}),storage:o(n.storage,B,{emitWrapper:{appMethod:"addStorage"},addContract:p(C)}),compute:o(n.compute,V,{emitWrapper:{appMethod:"addCompute"},addContract:D}),messaging:o(n.messaging,Y,{emitWrapper:{appMethod:"addMessaging"},addContract:p(f)}),cdn:o(n.cdn,G,{emitWrapper:{appMethod:"addCdn"},addContract:p(l)}),network:o(n.network,L,{emitWrapper:{appMethod:"addNetwork"},addContract:p(P)}),pattern:o(n.pattern,q,{emitWrapper:{appMethod:"addPattern"},addContract:Q,statementIdentity:U}),"vpc-peer":o(n["vpc-peer"],$,{emitWrapper:{appMethod:"addVpcPeer"},emitGuard:ee}),"vpc-peer-accepter":o(n["vpc-peer-accepter"],z,{emitWrapper:{appMethod:"addVpcPeerAccepter"},addContract:p(F)}),"cross-plan-connection":o(n["cross-plan-connection"],J,{addContract:p(h)}),organisation:o(n.organisation,H,{addContract:p(S)}),buildkite:o(n.buildkite,K,{emitWrapper:{appMethod:"addBuildkite",propsOverloadConstructId:"Buildkite"},addContract:p(u)})},le=Object.keys(i);function ge(e,t,a){return i[e].statementIdentity?.emitConstructId(t,a)??t}r(ge,"constructIdFor");function he(e,t){return i[e].statementIdentity?.locateCandidates(t)??[t]}r(he,"locateNamesFor");function ye(e){const t=Object.keys(i);for(const a of t)if(i[a].factoryIdentifier===e)return a}r(ye,"findTypeByIdentifier");export{n as FACTORY_IDENTIFIERS,le as REGISTERED_STATEMENT_TYPES,i as STATEMENT_REGISTRY,ge as constructIdFor,ye as findTypeByIdentifier,he as locateNamesFor};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var N=Object.defineProperty;var d=(r,t)=>N(r,"name",{value:t,configurable:!0});import{failure as c,success as p}from"../../../types/Result.js";import{isProjectableType as v,TYPE_PROJECTIONS as k}from"../../../projection/index.js";import{extractProgramBody as O}from"../../_internal.js";import{findConfigObject as w}from"../../drift/snapshot.js";import{bodyCarriesSibling as E,siblingCallPropsObject as K}from"../../edits/addResource/siblingEmission.js";import{astToLiteral as S,isNodeShape as T,NON_LITERAL as x,readKeyName as j}from"../../edits/modifyResource/literalConversion.js";import{parse as M}from"../../fileRewriter/parse.js";import{constructIdFor as C,STATEMENT_REGISTRY as L}from"../../registry.js";import{locateByShape as R}from"../../semanticIndex/locateByShape.js";function _(r){if(!v(r))return[];const t=k[r].keys??{};return Object.entries(t).flatMap(([e,i])=>i.kind==="live"?[{planKey:e,constructKey:i.as??e,reason:i.reason,wants:"live binding"}]:i.kind==="structured"?[{planKey:e,constructKey:i.as??e,reason:i.reason,wants:"structured CDK expression"}]:[])}d(_,"shapeCheckedKeys");function u(r){return p({action:"reject",diagnostics:r})}d(u,"rejectOutcome");function A(r,t){if(r.plan.op!=="modify"||t?.expansion===void 0)return;const e=t.expansion;if(!e.keys.some(f=>r.plan.properties[f]!==void 0))return;const i=e.derive(r.plan.properties,{resourceName:r.plan.name,editingExisting:!0}),[o]=i.unprojectable;if(o!==void 0)return c({kind:"InvalidPropertyError",property:o.key,reason:o.reason})}d(A,"expansionModifyParity");const W={id:"projection",run(r){const{type:t,name:e,op:i}=r.plan,o=v(t)?k[t]:void 0,f=A(r,o);if(f!==void 0)return f;const I=o?.siblings!==void 0?o.siblings.keys.filter(n=>r.plan.properties[n]!==void 0):[];let y=[];if(I.length>0&&o?.siblings!==void 0){const n=o.siblings.derive(r.plan.properties,{resourceName:e}),[s]=n.unprojectable;if(s!==void 0)return c({kind:"InvalidPropertyError",property:s.key,reason:s.reason});const[a]=n.siblings;if(i!=="add"&&a!==void 0)return c({kind:"InvalidPropertyError",property:a.planKey,reason:`\`${a.planKey}\` expands into its own \`app.${a.appMethod}("${a.constructId}", \u2026)\` statement, and a modify edits exactly one statement \u2014 the deterministic lane refuses this edit and the fallback lane holds the same line.`});y=n.siblings}const m=_(t),h=i==="add"&&L[t].statementIdentity!==void 0;if(m.length===0&&!h&&y.length===0)return p({action:"proceed"});const l=B(r);if(!l.success)return l;if(l.data===void 0)return u(`could not resolve the emitted config object for ${t} "${e}"; the output cannot be verified against the projection contract`);const{symbolName:b,configObject:g,body:$}=l.data;for(const n of m){const s=P(g,n.constructKey);if(s!==void 0&&(s.type==="StringLiteral"||s.type==="TemplateLiteral"))return c({kind:"InvalidPropertyError",property:n.constructKey,reason:`the ${t} construct reads a ${n.wants} here and the output wrote a ${s.type==="StringLiteral"?"string":"template"} literal; ${n.reason}`})}for(const n of y){if(!E($,n))return u(`the \`${n.planKey}\` key expands into a second statement \`app.${n.appMethod}("${n.constructId}", \u2026)\` and the output does not carry it \u2014 the primary resource would deploy with the expansion silently missing`);if(n.props.length===0)continue;const s=K($,n);if(s===void 0)return u(`the \`${n.planKey}\` expansion statement \`app.${n.appMethod}("${n.constructId}", \u2026)\` carries no readable props object, so it cannot be verified against the props the projection derives (${n.props.map(a=>`\`${a.key}\``).join(", ")})`);for(const a of n.props)if(P(s,a.key)===void 0)return u(`the \`${n.planKey}\` expansion statement \`app.${n.appMethod}("${n.constructId}", \u2026)\` omits the derived prop \`${a.key}\` \u2014 the deterministic lane always emits it, and without it the expansion deploys wrong or incomplete infrastructure`)}if(h){const n=G(g),s=C(t,e,n);if(b!==s)return u(`output writes construct id "${b}" where the ${t} identity derivation for "${e}" requires "${s}" \u2014 an id the deterministic lane never emits (the type declares an identity precisely because non-derived ids collide or go unaddressable at synth)`)}return p({action:"proceed"})}};function B(r){const t=R(r.content,{type:r.plan.type,name:r.plan.name});if(!t.success)return c(t.error);if(t.data===void 0)return p(void 0);const e=M(r.content,t.data.filePath);if(!e.success)return c(e.error);const i=O(e.data);if(i===void 0)return p(void 0);const o=w(i,{start:t.data.start,length:t.data.length});return o===void 0?p(void 0):p({symbolName:t.data.symbolName,configObject:o,body:i})}d(B,"locateEmittedStatement");function P(r,t){for(const e of r.properties)if(!(e.type!=="Property"&&e.type!=="ObjectProperty")&&!(e.shorthand===!0||e.computed===!0)&&j(e.key)===t&&e.value!==void 0&&T(e.value))return e.value}d(P,"readPropertyValueNode");function G(r){const t={};for(const e of r.properties){if(e.type!=="Property"&&e.type!=="ObjectProperty"||e.shorthand===!0||e.computed===!0)continue;const i=j(e.key);if(i===void 0||e.value===void 0)continue;const o=S(e.value);o!==x&&(t[i]=o)}return t}d(G,"literalPropertiesOf");export{W as projectionGate};
|