@bettercms-ai/convert 0.12.1 → 0.14.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 +21 -0
- package/dist/cli.js +42 -9
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +30 -4
- package/dist/index.js +41 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @bettercms-ai/convert
|
|
2
2
|
|
|
3
|
+
## 0.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- df570ef: Receipt and brief shapes a consumer reads:
|
|
8
|
+
- `BriefPath.kind` is typed `BindingKind` rather than `BindingKind | ""` — the brief always names a kind, and the empty case only forced callers to handle a value it never sends.
|
|
9
|
+
- New `PendingReason` `"DOCUMENT_DECLARE_ONLY"`: a `document` path is never located and never rewritten, because its `original` is only the body's FIRST block and declaring the paragraph that renders it is what publish refuses. The row's fix names the wrapper to declare instead.
|
|
10
|
+
- `PendingFix.kind` (`"document" | "richtext"`, optional) accompanies a `declare-richtext` action to say WHICH container is meant.
|
|
11
|
+
|
|
12
|
+
## 0.13.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- 0b05aa6: The forms receipt names the file each wired form is in
|
|
17
|
+
|
|
18
|
+
`receipt.forms.wiredForms` lists `{ id, file }` for every form on the site after a
|
|
19
|
+
`--forms` run — wired now or by an earlier one. The server matches the file to the
|
|
20
|
+
component recorded as its owner, so the Forms tab and a component's form prop can say
|
|
21
|
+
which component renders each form. Additive: `wired` is still a number, and a server
|
|
22
|
+
that has never heard of the list accepts the receipt unchanged.
|
|
23
|
+
|
|
3
24
|
## 0.12.1
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
package/dist/cli.js
CHANGED
|
@@ -2562,7 +2562,11 @@ var IMAGE_SOURCES = {
|
|
|
2562
2562
|
video: ["poster"]
|
|
2563
2563
|
};
|
|
2564
2564
|
var isImageSource = (site) => site.where === "attr" && (IMAGE_SOURCES[site.tag.toLowerCase()] ?? []).includes(site.attr ?? "");
|
|
2565
|
-
var ownsSubtree = (kind, site, inline) =>
|
|
2565
|
+
var ownsSubtree = (kind, site, inline) => (
|
|
2566
|
+
// A `document` is the same claim at article scale: the element renders EVERY block of the Body,
|
|
2567
|
+
// so its children come from the stored value and nothing else may be bound inside it.
|
|
2568
|
+
(kind === "richtext" || kind === "document") && (inline === true ? !site.nonHtml : !(site.mixed && site.textRange !== null))
|
|
2569
|
+
);
|
|
2566
2570
|
var norm = (value) => decodeEntities(value.normalize("NFC")).replace(/\s+/g, " ").trim();
|
|
2567
2571
|
var BCMS_ATTRS = [
|
|
2568
2572
|
"data-bcms-field",
|
|
@@ -5363,7 +5367,7 @@ function actionFor(reason, input, file, inData) {
|
|
|
5363
5367
|
return chosen;
|
|
5364
5368
|
}
|
|
5365
5369
|
function reasonAction(reason, input, file, inData) {
|
|
5366
|
-
const richtext = input.kind === "richtext" || input.inline === true;
|
|
5370
|
+
const richtext = input.kind === "richtext" || input.kind === "document" || input.inline === true;
|
|
5367
5371
|
switch (reason) {
|
|
5368
5372
|
case "AMBIGUOUS_LITERAL":
|
|
5369
5373
|
if (input.routes > 1) {
|
|
@@ -5414,6 +5418,11 @@ function reasonAction(reason, input, file, inData) {
|
|
|
5414
5418
|
return { action: "wrap-span", why: "Only part of the element's text is this value \u2014 give it its own span." };
|
|
5415
5419
|
case "SUBTREE_NOT_HTML":
|
|
5416
5420
|
return { action: "declare-richtext", why: "The value is the element's whole subtree \u2014 bind it as richtext." };
|
|
5421
|
+
case "DOCUMENT_DECLARE_ONLY":
|
|
5422
|
+
return {
|
|
5423
|
+
action: "declare-richtext",
|
|
5424
|
+
why: 'This is a Body: bind the ONE element that renders every block of it \u2014 an article, a main or a div \u2014 with the richtext helper and data-bcms-kind="document". Never the paragraph holding its first block: that is where the whole article would be published.'
|
|
5425
|
+
};
|
|
5417
5426
|
default:
|
|
5418
5427
|
return { action: "manual", why: `${reason} \u2014 see the receipt's message for what blocked this path.` };
|
|
5419
5428
|
}
|
|
@@ -5430,7 +5439,10 @@ function fixFor(row, input) {
|
|
|
5430
5439
|
...place.col !== void 0 ? { col: place.col } : {},
|
|
5431
5440
|
snippet: place.snippet,
|
|
5432
5441
|
action,
|
|
5433
|
-
...why ? { why } : {}
|
|
5442
|
+
...why ? { why } : {},
|
|
5443
|
+
// Only `declare-richtext` carries it, and only to say WHICH container is meant: one element
|
|
5444
|
+
// for a rich-text value, the whole Body's wrapper for a document.
|
|
5445
|
+
...action === "declare-richtext" && (input.kind === "document" || input.kind === "richtext") ? { kind: input.kind } : {}
|
|
5434
5446
|
};
|
|
5435
5447
|
}
|
|
5436
5448
|
function routeCounts(pending) {
|
|
@@ -6511,11 +6523,11 @@ async function wireForms(briefIn, sources) {
|
|
|
6511
6523
|
}
|
|
6512
6524
|
if (attrOf(candidate.el, "data-bcms-form")) {
|
|
6513
6525
|
alreadyWired++;
|
|
6514
|
-
onSite.push(form);
|
|
6526
|
+
onSite.push({ form, file: candidate.file });
|
|
6515
6527
|
continue;
|
|
6516
6528
|
}
|
|
6517
6529
|
matched.push({ form, candidate });
|
|
6518
|
-
onSite.push(form);
|
|
6530
|
+
onSite.push({ form, file: candidate.file });
|
|
6519
6531
|
}
|
|
6520
6532
|
const contents = new Map(sources.map((s) => [s.path, s.content]));
|
|
6521
6533
|
const byFile = /* @__PURE__ */ new Map();
|
|
@@ -6533,7 +6545,7 @@ ${indent}${scriptFor(last.candidate.dialect)}`);
|
|
|
6533
6545
|
}
|
|
6534
6546
|
files.push({ path, operation: "modify", content: source.toString() });
|
|
6535
6547
|
}
|
|
6536
|
-
const notes = onSite.filter((
|
|
6548
|
+
const notes = onSite.filter(({ form }) => form.status === "draft").map(({ form }) => `publish form ${form.name} in the Forms tab \u2014 a draft form rejects every submission with 403.`);
|
|
6537
6549
|
return {
|
|
6538
6550
|
files,
|
|
6539
6551
|
receipt: {
|
|
@@ -6550,7 +6562,9 @@ ${indent}${scriptFor(last.candidate.dialect)}`);
|
|
|
6550
6562
|
wired: matched.length,
|
|
6551
6563
|
alreadyWired,
|
|
6552
6564
|
pending,
|
|
6553
|
-
...notes.length > 0 ? { notes } : {}
|
|
6565
|
+
...notes.length > 0 ? { notes } : {},
|
|
6566
|
+
// Always, even empty: a run where every form went pending must retire the files an earlier one named.
|
|
6567
|
+
wiredForms: onSite.map(({ form, file }) => ({ id: form.id, file }))
|
|
6554
6568
|
})
|
|
6555
6569
|
}
|
|
6556
6570
|
};
|
|
@@ -8769,10 +8783,28 @@ async function convertSources(briefIn, sources, options) {
|
|
|
8769
8783
|
}
|
|
8770
8784
|
pend2(target, miss.reason === "no-original" ? "NO_ORIGINAL" : "NOT_IN_SOURCE");
|
|
8771
8785
|
}
|
|
8786
|
+
const documents = /* @__PURE__ */ new Set();
|
|
8787
|
+
for (const [key, hit] of locatedByKey) {
|
|
8788
|
+
const target = targets.get(key);
|
|
8789
|
+
if (!target || target.kind !== "document") continue;
|
|
8790
|
+
documents.add(key);
|
|
8791
|
+
const byHand = declaredByHand(target, hit.files);
|
|
8792
|
+
if (byHand !== null) {
|
|
8793
|
+
declaredOnly++;
|
|
8794
|
+
declaredRow(target, false, byHand);
|
|
8795
|
+
continue;
|
|
8796
|
+
}
|
|
8797
|
+
pend2(
|
|
8798
|
+
target,
|
|
8799
|
+
"DOCUMENT_DECLARE_ONLY",
|
|
8800
|
+
hit.files[0],
|
|
8801
|
+
"A Body is bound by declaring the one element that renders every block of it, never the paragraph that happens to hold its first block."
|
|
8802
|
+
);
|
|
8803
|
+
}
|
|
8772
8804
|
const byFile = /* @__PURE__ */ new Map();
|
|
8773
8805
|
for (const [key, hit] of locatedByKey) {
|
|
8774
8806
|
const target = targets.get(key);
|
|
8775
|
-
if (!target) continue;
|
|
8807
|
+
if (!target || documents.has(key)) continue;
|
|
8776
8808
|
for (const file of hit.files) byFile.set(file, [...byFile.get(file) ?? [], target]);
|
|
8777
8809
|
}
|
|
8778
8810
|
const drill = {
|
|
@@ -8821,6 +8853,7 @@ async function convertSources(briefIn, sources, options) {
|
|
|
8821
8853
|
let rewritten = 0;
|
|
8822
8854
|
let alreadyDeclared = declaredOnly;
|
|
8823
8855
|
for (const [key, hit] of locatedByKey) {
|
|
8856
|
+
if (documents.has(key)) continue;
|
|
8824
8857
|
const target = targets.get(key);
|
|
8825
8858
|
const outcomes = hit.files.map((file) => results.get(file)?.get(target.key) ?? "NOT_IN_SOURCE");
|
|
8826
8859
|
const worst = outcomes.find((o) => o !== "rewritten" && o !== "declared");
|
|
@@ -9605,7 +9638,7 @@ function emitStubs2(dialects, slugs, contents, out) {
|
|
|
9605
9638
|
// package.json
|
|
9606
9639
|
var package_default = {
|
|
9607
9640
|
name: "@bettercms-ai/convert",
|
|
9608
|
-
version: "0.
|
|
9641
|
+
version: "0.14.0",
|
|
9609
9642
|
type: "module",
|
|
9610
9643
|
description: "Deterministic codemod that turns an imported site's text-matched bindings into declared ones \u2014 parser offsets in, one magic-string pass out, plus a receipt of everything it could not do.",
|
|
9611
9644
|
bin: {
|