@bettercms-ai/convert 0.6.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,13 @@
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
+
3
11
  ## 0.6.0
4
12
 
5
13
  ### Minor Changes
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).