@bettercms-ai/convert 0.3.0 → 0.5.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/index.d.ts CHANGED
@@ -164,7 +164,9 @@ declare function locate(brief: BriefLike, sources: SourceFile[], options?: Locat
164
164
  * sentence appears in three files" and "this field is bound" are different questions — and a path
165
165
  * is only `rewritten` when EVERY located occurrence of it was.
166
166
  */
167
- type PendingReason = "NO_ORIGINAL" | "NOT_IN_SOURCE" | "DIALECT_UNSUPPORTED" | "IN_EXPRESSION" | "IN_SCRIPT_OR_COMMENT" | "IN_DATA_FILE" | "AMBIGUOUS_LITERAL" | "KIND_MISMATCH" | "SUBSTRING_ONLY" | "PROP_TARGET_NOT_FOUND" | "PROP_DRILLED_DEEP" | "REPEATER_FIXED_LENGTH" | "DYNAMIC_PARAMS_UNAVAILABLE" | "BRIEF_META_UNPLACED" | "PARSE_ERROR" | "TIER3_UNVERIFIABLE";
167
+ type PendingReason = "NO_ORIGINAL" | "NOT_IN_SOURCE" | "DIALECT_UNSUPPORTED" | "IN_EXPRESSION" | "IN_SCRIPT_OR_COMMENT" | "IN_DATA_FILE" | "AMBIGUOUS_LITERAL" | "KIND_MISMATCH" | "SUBSTRING_ONLY" | "PROP_TARGET_NOT_FOUND" | "PROP_DRILLED_DEEP" | "REPEATER_FIXED_LENGTH" | "DYNAMIC_PARAMS_UNAVAILABLE" | "BRIEF_META_UNPLACED" | "PARSE_ERROR" | "TIER3_UNVERIFIABLE"
168
+ /** @see CANVAS_REASONS — these two are about the SITE's live-preview lane, not a brief path. */
169
+ | "CANVAS_BRIDGE_MANUAL" | "SSR_DRAFT_ROUTE";
168
170
  interface PendingPath {
169
171
  route: string;
170
172
  scope: "page" | "layout";
@@ -174,6 +176,10 @@ interface PendingPath {
174
176
  file?: string;
175
177
  reason: PendingReason;
176
178
  message?: string;
179
+ /** 1-based line in `file`, when the reason points at one place a human has to go. */
180
+ line?: number;
181
+ /** What to do about it, in prose — a recipe, not a diagnosis. @see message */
182
+ hint?: string;
177
183
  }
178
184
  /**
179
185
  * One path that was already DECLARED before this run — and how honestly.
@@ -237,6 +243,14 @@ interface ConversionReceipt {
237
243
  dynamicBindings: DynamicBinding[];
238
244
  /** Facts about the repository that shaped this run. OPTIONAL: an older receipt carries none. */
239
245
  notes?: ReceiptNote[];
246
+ /**
247
+ * Can the visual editor push drafts to this site? OPTIONAL: an older receipt carries none, and a
248
+ * reader must treat absent as unknown rather than as `"pending"`.
249
+ */
250
+ canvas?: {
251
+ lane: "bridge" | "pending";
252
+ files?: string[];
253
+ };
240
254
  }
241
255
  /**
242
256
  * One binding whose `data-bcms-field` is an expression, and where its value is written literally.
@@ -698,7 +712,7 @@ declare function attrsFor(path: string, kind: string, props?: AttrBinding[], sco
698
712
  declare function propsAttribute(props: AttrBinding[]): string;
699
713
 
700
714
  /** Bumped whenever the emitted source changes. `isKnownHelper` upgrades anything older. */
701
- declare const HELPER_VERSION = 3;
715
+ declare const HELPER_VERSION = 4;
702
716
  /** Where each dialect's helper lives. Null = this dialect reads nothing at build time. */
703
717
  declare const HELPER_PATH: Record<Dialect, string | null>;
704
718
  /** The directory the snapshots live in, at the repository root. */
@@ -725,6 +739,35 @@ declare function helperSource(dialect: Dialect): string;
725
739
  */
726
740
  declare function isKnownHelper(content: string, dialect: Dialect): number | null;
727
741
 
742
+ /** The recipe an Astro site needs instead — never auto-migrate a site to SSR. */
743
+ declare const SSR_DRAFT_RECIPE: string;
744
+ interface CanvasSource {
745
+ path: string;
746
+ content: string;
747
+ /** The babel AST from `parseFile("jsx", …)`. Absent for every non-jsx dialect. */
748
+ ast?: unknown;
749
+ }
750
+ interface CanvasResult {
751
+ lane: "bridge" | "pending";
752
+ /** Files the bridge was installed in. */
753
+ files: string[];
754
+ /** Rewritten contents, by path. Empty when the lane is pending. */
755
+ edits: Map<string, string>;
756
+ pending: PendingPath[];
757
+ }
758
+ /**
759
+ * The one row every Astro conversion carries. Exported so a test names it instead of restating it.
760
+ */
761
+ declare const ASTRO_LANE_PENDING: PendingPath;
762
+ /**
763
+ * Install the draft bridge, or say why not.
764
+ *
765
+ * `routes` maps a brief route (`/about`) to its slug, so a route written as a literal in the page
766
+ * can name itself. An Astro project is refused wholesale: bridging it needs a server render, which
767
+ * is a deploy-shaped decision and never a codemod's.
768
+ */
769
+ declare function canvasBridge(sources: CanvasSource[], routes: Map<string, string>): CanvasResult;
770
+
728
771
  /**
729
772
  * Which files in a repository can possibly render a page's copy.
730
773
  *
@@ -979,6 +1022,15 @@ interface ComponentizePlanSection {
979
1022
  componentId?: string;
980
1023
  proposedSlug?: string;
981
1024
  };
1025
+ /**
1026
+ * WHERE THIS PLACEMENT'S COPY LIVES — Phase B's one new field.
1027
+ *
1028
+ * `"instance"` says the server moved the group's values onto the instance's `overrides`, so the
1029
+ * placement carries no `bind` and its elements declare the BLOCK lane. ABSENT MEANS `"bind"`:
1030
+ * a plan written by a Phase A server says nothing here, and a codemod that required the field
1031
+ * would refuse every plan older than itself. @see readPlan
1032
+ */
1033
+ copy?: string;
982
1034
  /** The SERVER already decided it cannot place this one. Not this codemod's to extract. */
983
1035
  pending?: {
984
1036
  reason?: string;
@@ -1024,10 +1076,21 @@ interface ComponentizePlan {
1024
1076
  * `DIALECT_UNSUPPORTED` the page is svelte / vue / html; nothing is written for it.
1025
1077
  * `HELPER_CONFLICT` `src/bcms-content.ts` is a module this package did not write.
1026
1078
  * `SNAPSHOT_INVALID` `bcms-content/<page>.json` is not JSON this can add `blocks` to.
1079
+ * `COPY_MODE_MISMATCH` `--copy instance` was asked of a plan whose placements are all
1080
+ * still bound to page field groups. @see ComponentizeOptions
1081
+ * `PROP_MAP_INCONSISTENT` the plan's `fields[].path` is not `<one prefix> + fields[].key`,
1082
+ * so a page path cannot be turned into a prop key losslessly.
1083
+ * `DUPLICATE_FIELD_BINDING` one element in the section carries more than one
1084
+ * `data-bcms-field`, and there is no single address to rewrite.
1085
+ * `INLINE_NEEDS_INSTANCE` the page cannot be looped, and the in-place call site the codemod
1086
+ * would write carries no `blockId`/`overrides` — so a placement
1087
+ * whose copy has MOVED could neither render nor address it.
1088
+ * `SECTION_UNMIGRATABLE` an OLDER generated component at this section's path cannot be
1089
+ * upgraded to the current format. @see migrateSections
1027
1090
  * `NOT_IN_SOURCE` no file we were given renders the group, or the route names no
1028
1091
  * page file this package can find.
1029
1092
  */
1030
- type SectionPendingReason = "SECTION_ROOT_AMBIGUOUS" | "SECTION_NOT_CONTIGUOUS" | "SECTION_FREE_IDENTIFIERS" | "COMPONENT_CONFLICT" | "REGISTRY_CONFLICT" | "REGISTRY_UNREADABLE" | "ROUTE_FILE_AMBIGUOUS" | "DIALECT_UNSUPPORTED" | "HELPER_CONFLICT" | "SNAPSHOT_INVALID" | "NOT_IN_SOURCE";
1093
+ type SectionPendingReason = "SECTION_ROOT_AMBIGUOUS" | "SECTION_NOT_CONTIGUOUS" | "SECTION_FREE_IDENTIFIERS" | "COMPONENT_CONFLICT" | "REGISTRY_CONFLICT" | "REGISTRY_UNREADABLE" | "ROUTE_FILE_AMBIGUOUS" | "DIALECT_UNSUPPORTED" | "HELPER_CONFLICT" | "SNAPSHOT_INVALID" | "COPY_MODE_MISMATCH" | "PROP_MAP_INCONSISTENT" | "DUPLICATE_FIELD_BINDING" | "INLINE_NEEDS_INSTANCE" | "SECTION_UNMIGRATABLE" | "NOT_IN_SOURCE";
1031
1094
  interface PendingSection {
1032
1095
  route: string;
1033
1096
  groupKey: string;
@@ -1070,6 +1133,15 @@ interface SectionsReceipt {
1070
1133
  interface ComponentizeReceipt {
1071
1134
  /** The plan this run was made against, carried so a receipt can be matched to one. */
1072
1135
  planDigest: string;
1136
+ /**
1137
+ * Which copy model this run was asked for — the same word the server's receipt carries.
1138
+ *
1139
+ * It does NOT change the bytes of an extracted component: the lane an element declares is
1140
+ * decided at render time from the placement's own props, so one file serves both. What it
1141
+ * changes is what the run will accept — `"instance"` against a plan that moved no copy is
1142
+ * `COPY_MODE_MISMATCH` — and what the registry's shipped fallback binds. @see bcmsFields
1143
+ */
1144
+ copy: "bind" | "instance";
1073
1145
  sections: SectionsReceipt;
1074
1146
  /** The component slugs this run wrote a file for, sorted. */
1075
1147
  components: string[];
@@ -1106,9 +1178,27 @@ declare function assertSections(total: number, sections: SectionsReceipt): Secti
1106
1178
  interface ComponentizeOptions {
1107
1179
  /** Replace a helper module this package did not write, instead of refusing. The CLI's flag. */
1108
1180
  overwriteHelper?: boolean;
1181
+ /**
1182
+ * WHICH COPY MODEL THE OPERATOR MEANT — `"bind"` (Phase A, the default) or `"instance"`.
1183
+ *
1184
+ * 🔴 AN ASSERTION, NOT A SWITCH. The extracted files are identical either way, so this flag
1185
+ * exists to catch the order-of-operations mistake that would otherwise be silent: running
1186
+ * `--copy instance` in the repository BEFORE the server has moved the copy leaves a tree that
1187
+ * looks converted and renders every section out of page fields the dashboard is about to hide.
1188
+ * A plan whose placements are all still bound says so, and the run refuses by name.
1189
+ */
1190
+ copy?: "bind" | "instance";
1109
1191
  }
1110
- /** The marker that says a file is OURS. Idempotence is decided on it, never on a path. */
1111
- declare const SECTION_MARKER = "// @bettercms-ai/convert section v1";
1192
+ /**
1193
+ * The marker that says a file is OURS — and WHICH FORMAT it is in.
1194
+ *
1195
+ * 🔴 THE VERSION IS LOAD-BEARING, NOT DECORATION. Idempotence is decided on this marker, so a v1
1196
+ * component (0.3: page-path bindings, no render-time lane) read as "already ours, nothing to do"
1197
+ * was skipped forever — every repository converted before Phase B stayed on the page lane, and
1198
+ * `--copy instance` there reported five sections done and moved no address at all. A format change
1199
+ * bumps the version, and anything older is MIGRATED before it is called done. @see migrateSections
1200
+ */
1201
+ declare const SECTION_MARKER = "// @bettercms-ai/convert section v2";
1112
1202
  /** The same, for the two modules that hold the registry rather than a section. */
1113
1203
  declare const REGISTRY_MARKER = "// @bettercms-ai/convert sections v1";
1114
1204
  /** Where the generated components live. Fixed, so a second run knows its own output on sight. */
@@ -1202,4 +1292,4 @@ declare function convertSources(briefIn: Brief, sources: SourceFile[], options?:
1202
1292
  receipt: ConversionReceipt;
1203
1293
  }>;
1204
1294
 
1205
- export { type AstNode, type AttrBinding, type Brief, type BriefPage, type BriefPath, COMPONENT_DIR, CONTENT_DIR, type Carried, type ComponentizeOptions, type ComponentizePlan, type ComponentizePlanComponent, type ComponentizePlanField, type ComponentizePlanPage, type ComponentizePlanSection, type ComponentizeReceipt, type ConversionReceipt, ConvertError, type ConvertErrorCode, type ConvertOptions, DIALECT_RULES, type DeclaredPath, type Dialect, type DynamicBinding, type FileDeclaration, type FindSitesResult, HELPER_PATH, HELPER_VERSION, type ImportedFrom, type LlmFallback, type LocatedPath, type Node, PARSE_FILE, type ParsedFile, type ParserError, type PathLocator, type PendingPath, type PendingReason, type PendingSection, type PlanFile, REGISTRY_MARKER, type ReceiptFile, ReceiptInvariantError, type ReceiptNote, type Rewrite, SECTIONS_LIB, SECTION_MARKER, SKIP_DIRS, SKIP_FILES, SOURCE_EXTENSIONS, STUB_CONTENT, SectionInvariantError, type SectionPendingReason, type SectionsReceipt, type Site, type SiteWhere, type SourceFile, type Splice, type TargetIdentity, type UnlocatedPath, type ValidationCode, ValidationError, aliasesFrom, assertReceipt, assertSections, attrsFor, briefDigest, carryFor, componentizeSources, convertSources, convertedHere, coverageOf, declaringElements, dialectOf, exportedFunction, findSites, findSitesTolerant, flat, helperSource, importsIn, isDynamicRoute, isKnownHelper, isSourceCandidate, locate, overlapping, pageFilesFor, parseFile, propsAttribute, readBrief, readComponentizePlan, readDeclarations, readExpr, readPlan, relativeImport, resolveSpecifier, rewriteFile, routeOfFile, stripTags, unreadableConfigs, walkAst };
1295
+ export { ASTRO_LANE_PENDING, type AstNode, type AttrBinding, type Brief, type BriefPage, type BriefPath, COMPONENT_DIR, CONTENT_DIR, type CanvasResult, type CanvasSource, type Carried, type ComponentizeOptions, type ComponentizePlan, type ComponentizePlanComponent, type ComponentizePlanField, type ComponentizePlanPage, type ComponentizePlanSection, type ComponentizeReceipt, type ConversionReceipt, ConvertError, type ConvertErrorCode, type ConvertOptions, DIALECT_RULES, type DeclaredPath, type Dialect, type DynamicBinding, type FileDeclaration, type FindSitesResult, HELPER_PATH, HELPER_VERSION, type ImportedFrom, type LlmFallback, type LocatedPath, type Node, PARSE_FILE, type ParsedFile, type ParserError, type PathLocator, type PendingPath, type PendingReason, type PendingSection, type PlanFile, REGISTRY_MARKER, type ReceiptFile, ReceiptInvariantError, type ReceiptNote, type Rewrite, SECTIONS_LIB, SECTION_MARKER, SKIP_DIRS, SKIP_FILES, SOURCE_EXTENSIONS, SSR_DRAFT_RECIPE, STUB_CONTENT, SectionInvariantError, type SectionPendingReason, type SectionsReceipt, type Site, type SiteWhere, type SourceFile, type Splice, type TargetIdentity, type UnlocatedPath, type ValidationCode, ValidationError, aliasesFrom, assertReceipt, assertSections, attrsFor, briefDigest, canvasBridge, carryFor, componentizeSources, convertSources, convertedHere, coverageOf, declaringElements, dialectOf, exportedFunction, findSites, findSitesTolerant, flat, helperSource, importsIn, isDynamicRoute, isKnownHelper, isSourceCandidate, locate, overlapping, pageFilesFor, parseFile, propsAttribute, readBrief, readComponentizePlan, readDeclarations, readExpr, readPlan, relativeImport, resolveSpecifier, rewriteFile, routeOfFile, stripTags, unreadableConfigs, walkAst };