@bettercms-ai/convert 0.5.0 β†’ 0.7.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @bettercms-ai/convert
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e8b5b1c: Convert the shapes real template sites are made of: data literals rendered through `.map`, headings whose copy is one text node of a mixed element, and images imported from `src/assets`. Root-level `.md` files are no longer read as templates, and a located-but-unplaced path now carries a reason that is true (`IN_EXPRESSION`, or `NOT_IN_SOURCE` with the file named).
8
+
9
+ New helper exports `bcmsRowsAs` and `bcmsImage` (helper v5), and two new pending reasons: `REPEATER_AMBIGUOUS` and `IMAGE_ASSET_UNRESOLVED`.
10
+
11
+ ## 0.6.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 5ad31fd: Astro SSR draft recipe now names `@astrojs/node` standalone, the auto-injected draft routes, and `loadPage` + `loadComponents`.
16
+
3
17
  ## 0.5.0
4
18
 
5
19
  ### Minor Changes
@@ -97,7 +111,7 @@ reject the checkout, which is what broke the migrator image on #616.
97
111
  has; a `bcmsField` the file demonstrably builds from our helper is left alone and only its
98
112
  bindings are wrapped; anything else is `SECTION_UNMIGRATABLE`.
99
113
 
100
- πŸ”΄ A NAME IS NOT A PROVENANCE. Reusing anything *called* `bcmsFields` trusted an import from
114
+ πŸ”΄ A NAME IS NOT A PROVENANCE. Reusing anything _called_ `bcmsFields` trusted an import from
101
115
  any module at all β€” `import { bcmsFields } from "./their-utils"` is a different function with
102
116
  the same name β€” and any coexisting `bcmsField` vouched for itself. The specifier must RESOLVE
103
117
  to the helper module this package writes (through the project's own aliases), and `bcmsField`
@@ -203,7 +217,7 @@ reject the checkout, which is what broke the migrator image on #616.
203
217
  catch, reached through the check itself. Two shapes are provable: a string literal and NOTHING
204
218
  else, and a template literal whose every interpolation is an INDEX (`[${i}]`, what a repeater
205
219
  writes, which cannot change the prefix). Everything else β€” `{computedPath}`, `{"a" + x}`,
206
- `` {`${prefix}.title`} `` β€” is opaque, and opaque is `PROP_MAP_INCONSISTENT`.
220
+ ``{`${prefix}.title`}`` β€” is opaque, and opaque is `PROP_MAP_INCONSISTENT`.
207
221
 
208
222
  - `COPY_MODE_MISMATCH` ignores sections the SERVER already refused.
209
223
 
@@ -224,7 +238,7 @@ reject the checkout, which is what broke the migrator image on #616.
224
238
 
225
239
  The in-place call site β€” `<Hero bind="hero" page={pageSnapshot("home")} />` β€” is written by
226
240
  the codemod from the plan and carries no `blockId` and no `overrides`; it never consults the
227
- CMS's blocks at all, which is exactly what makes the inline form componentisation *without*
241
+ CMS's blocks at all, which is exactly what makes the inline form componentisation _without_
228
242
  the page builder. Emitting it for a placement whose copy has MOVED rendered the page's field
229
243
  group and declared the page lane for an address that no longer holds anything. The component
230
244
  is still written; the page is left as its author wrote it.
@@ -294,7 +308,7 @@ reject the checkout, which is what broke the migrator image on #616.
294
308
  the dashboard renders. The committed helper needed nothing: `bcmsRows` already passes a
295
309
  nested array through untouched and `bcmsSection` hands a section its group whole.
296
310
 
297
- The bindings are `` data-bcms-field={`cards[${i}].items[${j}].label`} `` and the shape is
311
+ The bindings are ``data-bcms-field={`cards[${i}].items[${j}].label`}`` and the shape is
298
312
  `cards[*].items[*].label`; the loop now REPORTS the bindings it wrote, both loop variables
299
313
  included, instead of the caller re-deriving a literal the file does not contain. ONE level
300
314
  of nesting β€” what the plan mints and what the component prop validator accepts β€” so a leaf
package/README.md CHANGED
@@ -58,10 +58,52 @@ tolerant pass that will only place a literal occurring exactly once between a `>
58
58
  that, an injected `llmFallback` whose output is accepted only if it re-parses and declares exactly
59
59
  the paths that were asked for. The CLI injects none β€” the agent running it is tier 3.
60
60
 
61
- **Everything it will not do has a name.** `AMBIGUOUS_LITERAL` when two different paths share a
62
- sentence and position cannot separate them (both are skipped; the rest of the file still converts),
63
- `SUBSTRING_ONLY`, `IN_SCRIPT_OR_COMMENT`, `KIND_MISMATCH`, `NOT_IN_SOURCE`, `PARSE_ERROR` β€” and the
64
- receipt's arithmetic is checked, not hoped for:
61
+ **A prose file is a template only where a framework renders one.** `.md`, `.mdx`, `.njk`, `.hbs`,
62
+ `.ejs`, `.liquid`, `.erb` and `.twig` are opened under a directory named `pages`, `content`, `src`,
63
+ `app`, `routes`, `layouts`, `components`, `templates`, `views`, `_includes` or `_layouts` β€” and
64
+ never at the repository root or under `docs/`. A README quoting the hero line is documentation
65
+ ABOUT the site, and because a path counts as rewritten only when every located occurrence was, one
66
+ of them pended 176 of 735 paths on a real repository with a reason naming a file nobody would ever
67
+ want bound.
68
+
69
+ **A scalar module literal is converted too.** `const tagline = "…"` rendered as `{tagline}` becomes
70
+ `const tagline = bcms(page, "<path>", "…")`, with the declaration on the element that renders it β€”
71
+ a literal path, because there is no index to template. Refused as `IN_EXPRESSION` when the
72
+ identifier is rendered more than once, used in an attribute as well, or transformed on the way:
73
+ moving the declaration to a CMS read changes the value everywhere that identifier is used.
74
+
75
+ **Copy that lives in a data literal is converted too.** `deriveSchema` reads the BUILT page, so
76
+ four cards arrive as `cards[0..3]`; the repository renders ONE element from a frontmatter (astro)
77
+ or module-scope (jsx/tsx) array through `.map`. The declaration becomes
78
+
79
+ ```js
80
+ const features = bcmsRowsAs(bcmsHome, "cards", [ …the original array, verbatim… ],
81
+ { title: "h3-field", body: "p-field" });
82
+ ```
83
+
84
+ β€” the rows come from the CMS and are renamed onto the template's OWN property names, so
85
+ `feature.tone`, `feature.link` and every other property the brief never heard of keep rendering
86
+ (`bcmsRowsAs` merges each CMS row over the row the template shipped with, and a row an editor adds
87
+ inherits row 0's styling). Each row element then declares
88
+ `` data-bcms-field={`cards[${i}].<leaf>`} ``, and the callback gains an index parameter if it had
89
+ none. An imported data module stays `IN_DATA_FILE`.
90
+
91
+ **An image is bound through its import, not through its url.** An image's `original` is the name
92
+ the bundler minted (`/_astro/hero.do77EGgx_ZNfVA8.jpg`) β€” it exists in no file, and the asset
93
+ itself is not a source candidate, so a text search can never find it. What survives the build is
94
+ the BASE NAME, and the page says it itself: `import hero from "../assets/hero.jpg"`. The element
95
+ rendering that binding β€” `<img>`, `<source>`, `<video poster>`, or `<Image>`/`<Picture>` from
96
+ `astro:assets`, which forward unknown props to the `<img>` they render β€” gets
97
+ `src={bcmsImage(page, "<path>", hero)}` and the declaration beside it.
98
+
99
+ **Everything it will not do has a name, and the name is TRUE.** `AMBIGUOUS_LITERAL` when two
100
+ different paths share a sentence and position cannot separate them (both are skipped; the rest of
101
+ the file still converts), `SUBSTRING_ONLY`, `IN_SCRIPT_OR_COMMENT`, `KIND_MISMATCH`,
102
+ `REPEATER_AMBIGUOUS` (one array declaration, two loops over it β€” the row has two homes),
103
+ `IMAGE_ASSET_UNRESOLVED`, `PARSE_ERROR`. `NOT_IN_SOURCE` is reserved for what it says: a path
104
+ `locate` found in a file is `IN_EXPRESSION` when it sits in the module region or an expression
105
+ node, and where `NOT_IN_SOURCE` is still the answer the row names the file it was found in. And
106
+ the receipt's arithmetic is checked, not hoped for:
65
107
 
66
108
  ```
67
109
  paths.declared === paths.rewritten + paths.alreadyDeclared + paths.pending.length
@@ -428,6 +470,19 @@ and removing them would mean editing statements no section asked about.
428
470
 
429
471
  ## Not here yet
430
472
 
473
+ An array of PRIMITIVES β€” `const items = ["a", "b", "c"]`, or of tuples β€” whose elements the brief
474
+ gave a separate NON-indexed path each (`li-field`, `li-rtl`, …) rather than one repeater group.
475
+ There is no group to key and no constant to rewrite, so those stay `IN_EXPRESSION`; what would fix
476
+ them is the derive lane minting the group, not a third shape here. Svelte and vue data literals are
477
+ not converted either β€” both lanes are written against the two dialects that keep their module and
478
+ their markup in one file with an AST this package already holds.
479
+
480
+ SHARED CHROME the brief still calls page copy. A header rendered by one component that nine routes
481
+ each declare a `nav[0].label` for is nine targets on one element, and there is no honest binding: a
482
+ read names ONE route's snapshot. That is `promoteSharedChrome`'s job on the derive side β€” once the
483
+ field is `scope: "layout"` the codemod collapses the nine to one identity and binds it. Until then
484
+ those paths are `AMBIGUOUS_LITERAL`, which is true.
485
+
431
486
  `promoteSharedChrome`, and prop drilling through a svelte or vue component (both parse, and both
432
487
  bind their own copy; only `findPropTargets` is jsx/astro-only, so a drilled prop there is
433
488
  `PROP_TARGET_NOT_FOUND` rather than a wrong edit).