@bettercms-ai/convert 0.18.1 → 0.19.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 +93 -33
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +89 -30
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @bettercms-ai/convert
|
|
2
2
|
|
|
3
|
+
## 0.19.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3d022b0: A locale copy placed on its default-locale twin's section component now carries `props.bindPaths` (`{ <propKey>: "<this page's field path>" }`) beside `bind`, because its own field keys differ from the component's. `ComponentProps.bindPaths` is new in types; the convert helper (v9) and the extracted section components and registry read a prop's copy and declare its address through it, so `/fr` renders and edits its own words instead of a field it does not have. Older readers ignore it.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [12b2d62]
|
|
12
|
+
- Updated dependencies [3d022b0]
|
|
13
|
+
- Updated dependencies [a0a6ad9]
|
|
14
|
+
- Updated dependencies [621a70e]
|
|
15
|
+
- Updated dependencies [2729e58]
|
|
16
|
+
- @bettercms-ai/types@1.25.0
|
|
17
|
+
|
|
18
|
+
## 0.18.2
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- b201770: Rebuild before publishing. 1.22.1 / 0.18.1 shipped a stale dist/ that predated their own changes; this release carries the built fixes.
|
|
23
|
+
|
|
3
24
|
## 0.18.1
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
package/dist/cli.js
CHANGED
|
@@ -4190,7 +4190,7 @@ async function bindImages(ctx, targets) {
|
|
|
4190
4190
|
|
|
4191
4191
|
// src/helper.ts
|
|
4192
4192
|
import { createHash as createHash2 } from "crypto";
|
|
4193
|
-
var HELPER_VERSION =
|
|
4193
|
+
var HELPER_VERSION = 9;
|
|
4194
4194
|
var HEADER = "// @bettercms-ai/convert helper v";
|
|
4195
4195
|
var HELPER_PATH = Object.fromEntries(
|
|
4196
4196
|
Object.keys(DIALECT_RULES).map((d) => [d, DIALECT_RULES[d].helper])
|
|
@@ -4355,9 +4355,19 @@ export function bcmsImage<T>(page: unknown, path: string, fallback: T, slug?: st
|
|
|
4355
4355
|
* the fallback the template shipped with \u2014 which is why a section renders correctly against the
|
|
4356
4356
|
* committed \`{}\` stub.
|
|
4357
4357
|
*/
|
|
4358
|
-
export function bcmsSection(
|
|
4358
|
+
export function bcmsSection(
|
|
4359
|
+
page: unknown,
|
|
4360
|
+
bind?: string,
|
|
4361
|
+
overrides?: unknown,
|
|
4362
|
+
bindPaths?: Record<string, string>,
|
|
4363
|
+
): Record<string, unknown> {
|
|
4359
4364
|
const group = bind ? readPath(page, bind) : undefined;
|
|
4360
4365
|
const base: Record<string, unknown> = isRecord(group) ? { ...group } : {};
|
|
4366
|
+
// A locale copy on its twin's component spells its fields its own way: each prop's copy is
|
|
4367
|
+
// read from the path the placement names for it.
|
|
4368
|
+
if (bind && isRecord(bindPaths)) {
|
|
4369
|
+
for (const [key, path] of Object.entries(bindPaths)) base[key] = readPath(page, path);
|
|
4370
|
+
}
|
|
4361
4371
|
if (!isRecord(overrides)) return base;
|
|
4362
4372
|
for (const key of Object.keys(overrides)) {
|
|
4363
4373
|
const value = overrides[key];
|
|
@@ -4420,21 +4430,25 @@ export function bcmsSectionPaths(
|
|
|
4420
4430
|
overrides: unknown,
|
|
4421
4431
|
prefix: string,
|
|
4422
4432
|
map: BcmsPathMap,
|
|
4433
|
+
bindPaths?: Record<string, string>,
|
|
4423
4434
|
): Record<string, unknown> {
|
|
4424
4435
|
const out: Record<string, unknown> = isRecord(page) ? { ...page } : {};
|
|
4425
4436
|
const own = isRecord(overrides) ? overrides : {};
|
|
4426
4437
|
const separator = prefix.slice(-1);
|
|
4427
|
-
|
|
4428
|
-
|
|
4438
|
+
// A re-keyed locale copy names each prop's path on its own page; any other placement re-bases.
|
|
4439
|
+
const fromPage = (path: string, key: string): unknown =>
|
|
4440
|
+
!bind ? undefined
|
|
4441
|
+
: isRecord(bindPaths) && typeof bindPaths[key] === "string" ? readPath(page, bindPaths[key])
|
|
4442
|
+
: readPath(page, bind + separator + path.slice(prefix.length));
|
|
4429
4443
|
for (const [path, key] of Object.entries(map.scalars ?? {})) {
|
|
4430
4444
|
const value = own[key];
|
|
4431
|
-
out[path] = value !== undefined && value !== null ? value : fromPage(path);
|
|
4445
|
+
out[path] = value !== undefined && value !== null ? value : fromPage(path, key);
|
|
4432
4446
|
}
|
|
4433
4447
|
for (const [path, table] of Object.entries(map.tables ?? {})) {
|
|
4434
4448
|
const held = own[table.key];
|
|
4435
4449
|
const rows = isRecord(held) && Array.isArray(held.rows) ? held.rows : held;
|
|
4436
4450
|
if (!Array.isArray(rows)) {
|
|
4437
|
-
out[path] = fromPage(path);
|
|
4451
|
+
out[path] = fromPage(path, table.key);
|
|
4438
4452
|
continue;
|
|
4439
4453
|
}
|
|
4440
4454
|
const pageColumn = new Map(Object.entries(table.columns).map(([column, key]) => [key, column]));
|
|
@@ -4449,12 +4463,17 @@ export function bcmsSectionPaths(
|
|
|
4449
4463
|
}
|
|
4450
4464
|
|
|
4451
4465
|
export function bcmsFields(
|
|
4452
|
-
placement: { blockId?: string; bind?: string; overrides?: unknown },
|
|
4466
|
+
placement: { blockId?: string; bind?: string; overrides?: unknown; bindPaths?: Record<string, string> },
|
|
4453
4467
|
pathPrefix: string,
|
|
4454
4468
|
map?: BcmsPathMap,
|
|
4455
4469
|
): (path: string) => string {
|
|
4456
4470
|
const id = placement.blockId;
|
|
4457
4471
|
const own = typeof id === "string" && id !== "" && !placement.bind && isRecord(placement.overrides);
|
|
4472
|
+
/** A re-keyed locale copy's own path for a prop, with whatever follows the prop kept. */
|
|
4473
|
+
const moved = (key: string | undefined, rest: string): string | undefined => {
|
|
4474
|
+
const paths = placement.bind && isRecord(placement.bindPaths) ? placement.bindPaths : undefined;
|
|
4475
|
+
return key !== undefined && paths && typeof paths[key] === "string" ? paths[key] + rest : undefined;
|
|
4476
|
+
};
|
|
4458
4477
|
/**
|
|
4459
4478
|
* What replaces the prefix the markup was cut with, or null for "leave every path alone".
|
|
4460
4479
|
*
|
|
@@ -4473,11 +4492,14 @@ export function bcmsFields(
|
|
|
4473
4492
|
const separator = pathPrefix.slice(-1);
|
|
4474
4493
|
return (path: string): string => {
|
|
4475
4494
|
if (!path.startsWith(pathPrefix) || !(own || placement.bind)) return path;
|
|
4476
|
-
if (!own) return placement.bind + separator + path.slice(pathPrefix.length);
|
|
4477
4495
|
const scalar = map.scalars?.[path];
|
|
4478
|
-
if (scalar !== undefined) return id + "__overrides." + scalar;
|
|
4479
4496
|
const row = /^([^[]+)\\[(\\d+)\\]\\.(.+)$/.exec(path);
|
|
4480
4497
|
const table = row ? map.tables?.[row[1]] : undefined;
|
|
4498
|
+
if (!own) {
|
|
4499
|
+
return moved(scalar, "") ?? moved(table?.key, row ? "[" + row[2] + "]." + row[3] : "")
|
|
4500
|
+
?? placement.bind + separator + path.slice(pathPrefix.length);
|
|
4501
|
+
}
|
|
4502
|
+
if (scalar !== undefined) return id + "__overrides." + scalar;
|
|
4481
4503
|
const column = row && table ? table.columns[row[3]] : undefined;
|
|
4482
4504
|
return table && column !== undefined ? id + "__overrides." + table.key + "[" + row![2] + "]." + column : path;
|
|
4483
4505
|
};
|
|
@@ -4487,7 +4509,9 @@ export function bcmsFields(
|
|
|
4487
4509
|
// it names a key the instance does not hold and a group this placement is not bound to.
|
|
4488
4510
|
// (An EMPTY prefix is a plan saying the prop key IS the page path, and matches everything.)
|
|
4489
4511
|
if (lane === null || !path.startsWith(pathPrefix)) return path;
|
|
4490
|
-
|
|
4512
|
+
const rest = path.slice(pathPrefix.length);
|
|
4513
|
+
const key = /^[^.[]+/.exec(rest)?.[0];
|
|
4514
|
+
return (own ? undefined : moved(key, rest.slice(key?.length ?? 0))) ?? lane + rest;
|
|
4491
4515
|
};
|
|
4492
4516
|
}
|
|
4493
4517
|
`;
|
|
@@ -4500,7 +4524,8 @@ var HISTORICAL = {
|
|
|
4500
4524
|
4: "a5742f64dacb1b26ee6dd5e1469a54871487934c71bc8267df19e3a80e417595",
|
|
4501
4525
|
5: "0472fe3ffdcfa49e719c7b9da9cb63b6eba637cc22783bb00c3c2cadd3d800da",
|
|
4502
4526
|
6: "c907e7245578d947c6541b1ab2c5c6659ea7789a1519e895b4a4aed122c6f649",
|
|
4503
|
-
7: "f22514ef48c50230985e605bea6cf9bf41756384a7dc80603e347baba9b65d93"
|
|
4527
|
+
7: "f22514ef48c50230985e605bea6cf9bf41756384a7dc80603e347baba9b65d93",
|
|
4528
|
+
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9"
|
|
4504
4529
|
},
|
|
4505
4530
|
"src/lib/bcms-content.ts": {
|
|
4506
4531
|
1: "ae72ae14d706943d481c880d70da5789b4816ba1ba319a10fbc63ded4d0b42f2",
|
|
@@ -4509,7 +4534,8 @@ var HISTORICAL = {
|
|
|
4509
4534
|
4: "0146d027a727ecd3c9e3fc336fcf1299b59ddf75b04091c05703f3f983ec28af",
|
|
4510
4535
|
5: "c8c93655320fa65664611ba84541f3fa7bfa292cc9a2fd655373440b99049fba",
|
|
4511
4536
|
6: "63f1fa29e47e70c5193b81ee24addb238ba100247124d55bc17713102d587df5",
|
|
4512
|
-
7: "ed92fb88de953d9951abbe6a1edae1d048f4050eaf6fb607ac08167f94d8bcc7"
|
|
4537
|
+
7: "ed92fb88de953d9951abbe6a1edae1d048f4050eaf6fb607ac08167f94d8bcc7",
|
|
4538
|
+
8: "1a6f669d76d42effe77f082436e9d21c0efa6fc499e919e3d116bc3a27a7f3d5"
|
|
4513
4539
|
},
|
|
4514
4540
|
"composables/bcms-content.ts": {
|
|
4515
4541
|
1: "c272412532efed7db64b6cf313b2bed4291f9951430412289c8a588b7f565407",
|
|
@@ -4518,7 +4544,8 @@ var HISTORICAL = {
|
|
|
4518
4544
|
4: "a5742f64dacb1b26ee6dd5e1469a54871487934c71bc8267df19e3a80e417595",
|
|
4519
4545
|
5: "0472fe3ffdcfa49e719c7b9da9cb63b6eba637cc22783bb00c3c2cadd3d800da",
|
|
4520
4546
|
6: "c907e7245578d947c6541b1ab2c5c6659ea7789a1519e895b4a4aed122c6f649",
|
|
4521
|
-
7: "f22514ef48c50230985e605bea6cf9bf41756384a7dc80603e347baba9b65d93"
|
|
4547
|
+
7: "f22514ef48c50230985e605bea6cf9bf41756384a7dc80603e347baba9b65d93",
|
|
4548
|
+
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9"
|
|
4522
4549
|
}
|
|
4523
4550
|
};
|
|
4524
4551
|
var sha256 = (value) => createHash2("sha256").update(value, "utf8").digest("hex");
|
|
@@ -6489,7 +6516,7 @@ function* formsIn(nodes, chain = []) {
|
|
|
6489
6516
|
}
|
|
6490
6517
|
}
|
|
6491
6518
|
var isComponentTag = (dialect, tag) => dialect !== "html" && /^[A-Z]/.test(tag);
|
|
6492
|
-
function candidateOf(file, dialect, form, imported, landmark) {
|
|
6519
|
+
function candidateOf(file, dialect, form, imported, landmark, content) {
|
|
6493
6520
|
const controls = /* @__PURE__ */ new Map();
|
|
6494
6521
|
const wrapper = /* @__PURE__ */ new Map();
|
|
6495
6522
|
const foreign = /* @__PURE__ */ new Set();
|
|
@@ -6526,7 +6553,11 @@ function candidateOf(file, dialect, form, imported, landmark) {
|
|
|
6526
6553
|
const id = attrOf(control, "id")?.value;
|
|
6527
6554
|
if (id && !controls.has(id)) controls.set(id, control);
|
|
6528
6555
|
}
|
|
6529
|
-
|
|
6556
|
+
const computed = (attr) => !!attr?.expression && !!attr.expressionRange && /[A-Za-z_$]/.test(
|
|
6557
|
+
content.slice(attr.expressionRange.start, attr.expressionRange.end).replace(/\/\*[\s\S]*?\*\/|\/\/[^\n]*|"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'|`(?:[^`\\$]|\\.|\$(?!\{))*`/g, "")
|
|
6558
|
+
);
|
|
6559
|
+
const dynamic = all.some((control) => !foreign.has(control) && computed(attrOf(control, "name")));
|
|
6560
|
+
return { file, dialect, el: form, controls, wrapper, foreign, landmark, dynamic };
|
|
6530
6561
|
}
|
|
6531
6562
|
async function importedControls(source, parsed, dialect, project, cache) {
|
|
6532
6563
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -6620,11 +6651,12 @@ async function wireForms(briefIn, sources, options_ = {}) {
|
|
|
6620
6651
|
}
|
|
6621
6652
|
const imported = dialect === "html" ? /* @__PURE__ */ new Map() : await importedControls(source, parsed, dialect, project, componentFiles);
|
|
6622
6653
|
for (const { el, landmark } of formsIn(parsed.roots)) {
|
|
6623
|
-
candidates.push(candidateOf(source.path, dialect, el, imported, landmark));
|
|
6654
|
+
candidates.push(candidateOf(source.path, dialect, el, imported, landmark, source.content));
|
|
6624
6655
|
}
|
|
6625
6656
|
}
|
|
6626
6657
|
const holds = (c, f) => f.fields.filter((field) => c.controls.has(field.key)).length;
|
|
6627
|
-
const
|
|
6658
|
+
const wiredTo = (c, f) => attrOf(c.el, "data-bcms-form")?.value === f.id;
|
|
6659
|
+
const covers2 = (c, f) => c.dynamic && wiredTo(c, f) || f.fields.length > 0 && holds(c, f) === f.fields.length;
|
|
6628
6660
|
const samePath = (a, b) => a.replace(/\\/g, "/").replace(/^\.\//, "") === b.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
6629
6661
|
const options = new Map(forms.map((f) => [f.id, candidates.filter((c) => covers2(c, f))]));
|
|
6630
6662
|
const pinned = /* @__PURE__ */ new Map();
|
|
@@ -6707,6 +6739,11 @@ async function wireForms(briefIn, sources, options_ = {}) {
|
|
|
6707
6739
|
continue;
|
|
6708
6740
|
}
|
|
6709
6741
|
const candidate = list[0];
|
|
6742
|
+
if (wiredTo(candidate, form)) {
|
|
6743
|
+
alreadyWired++;
|
|
6744
|
+
onSite.push({ form, file: candidate.file });
|
|
6745
|
+
continue;
|
|
6746
|
+
}
|
|
6710
6747
|
if (attrOf(candidate.el, "action")?.expression) {
|
|
6711
6748
|
pend2(form, "ACTION_IS_EXPRESSION", candidate.file, "its action is an expression, so this run will not replace it.");
|
|
6712
6749
|
continue;
|
|
@@ -6719,11 +6756,6 @@ async function wireForms(briefIn, sources, options_ = {}) {
|
|
|
6719
6756
|
pend2(form, "FIELD_UNMATCHED", candidate.file, `the control for ${misnamed.key} posts under an expression, so its name cannot be set to the CMS key.`);
|
|
6720
6757
|
continue;
|
|
6721
6758
|
}
|
|
6722
|
-
if (attrOf(candidate.el, "data-bcms-form")?.value === form.id) {
|
|
6723
|
-
alreadyWired++;
|
|
6724
|
-
onSite.push({ form, file: candidate.file });
|
|
6725
|
-
continue;
|
|
6726
|
-
}
|
|
6727
6759
|
matched.push({ form, candidate });
|
|
6728
6760
|
onSite.push({ form, file: candidate.file });
|
|
6729
6761
|
}
|
|
@@ -6844,7 +6876,8 @@ var TEMPLATE_DIRS = /* @__PURE__ */ new Set([
|
|
|
6844
6876
|
"_includes",
|
|
6845
6877
|
"_layouts"
|
|
6846
6878
|
]);
|
|
6847
|
-
var
|
|
6879
|
+
var READ_CONFIG = /^astro\.config\.[^./]+$/;
|
|
6880
|
+
var isAboutTheSite = (lower) => /\.(test|spec)\.[^./]+$/.test(lower) || /^[^/]*\.config\.[^./]+$/.test(lower) && !READ_CONFIG.test(lower);
|
|
6848
6881
|
function isSourceCandidate(path) {
|
|
6849
6882
|
const lower = path.toLowerCase();
|
|
6850
6883
|
if (SKIP_DIRS.some((dir) => lower === dir.slice(0, -1) || lower.startsWith(dir) || lower.includes(`/${dir}`)))
|
|
@@ -6891,7 +6924,7 @@ function measureUnaddressable(html) {
|
|
|
6891
6924
|
let visible = 0;
|
|
6892
6925
|
let unaddressable = 0;
|
|
6893
6926
|
const buckets = /* @__PURE__ */ new Map();
|
|
6894
|
-
const visit = (node, tag, context, bound) => {
|
|
6927
|
+
const visit = (node, tag, context, bound, inForm = false) => {
|
|
6895
6928
|
if (node.type === "text") {
|
|
6896
6929
|
const text = flat2(node.value);
|
|
6897
6930
|
if (isDecorativeGlyph(text) || PLATFORM_BADGE.test(text)) return;
|
|
@@ -6911,9 +6944,10 @@ function measureUnaddressable(html) {
|
|
|
6911
6944
|
if (attrs.has("hidden") || attrs.get("aria-hidden") === "true" || /display\s*:\s*none/i.test(attrs.get("style") ?? "") || isSkipLink(node, attrs)) {
|
|
6912
6945
|
return;
|
|
6913
6946
|
}
|
|
6914
|
-
const
|
|
6947
|
+
const form = inForm || attrs.has("data-bcms-form");
|
|
6948
|
+
const owned = bound || BOUND_ATTRS.some((name) => attrs.has(name)) || form && attrs.has("data-bcms-form-part");
|
|
6915
6949
|
const chain = CONTEXT_TAGS.has(node.tag) ? context === "body" ? node.tag : `${context}>${node.tag}` : context;
|
|
6916
|
-
for (const child of node.children) visit(child, node.tag, chain, owned);
|
|
6950
|
+
for (const child of node.children) visit(child, node.tag, chain, owned, form);
|
|
6917
6951
|
};
|
|
6918
6952
|
for (const root of parsed.roots) visit(root, "body", "body", false);
|
|
6919
6953
|
return {
|
|
@@ -8107,6 +8141,7 @@ function componentFile(dialect, path, fromFile, content, parsed, resolved, pathP
|
|
|
8107
8141
|
provided: [
|
|
8108
8142
|
"blockId",
|
|
8109
8143
|
"bind",
|
|
8144
|
+
"bindPaths",
|
|
8110
8145
|
"overrides",
|
|
8111
8146
|
"page",
|
|
8112
8147
|
fieldName,
|
|
@@ -8121,8 +8156,8 @@ function componentFile(dialect, path, fromFile, content, parsed, resolved, pathP
|
|
|
8121
8156
|
const key = /^[A-Za-z_$][\w$]*$/.test(groupKey) ? groupKey : JSON.stringify(groupKey);
|
|
8122
8157
|
const carriedDeclarations = carry.declarations.length > 0 ? `${carry.declarations.join("\n")}
|
|
8123
8158
|
` : "";
|
|
8124
|
-
const copy = !snapshot ? "" : flat3 ? `const ${snapshot} = bcmsSectionPaths(page, bind, overrides, ${JSON.stringify(pathPrefix)}, ${JSON.stringify(pathMap)});` : `const ${snapshot} = { ${key}: bcmsSection(page, bind, overrides) };`;
|
|
8125
|
-
const field = bound > 0 ? `const ${fieldName} = ${fieldsName}({ blockId, bind, overrides }, ${JSON.stringify(pathPrefix)}${flat3 ? `, ${JSON.stringify(pathMap)}` : ""});` : "";
|
|
8159
|
+
const copy = !snapshot ? "" : flat3 ? `const ${snapshot} = bcmsSectionPaths(page, bind, overrides, ${JSON.stringify(pathPrefix)}, ${JSON.stringify(pathMap)}, bindPaths);` : `const ${snapshot} = { ${key}: bcmsSection(page, bind, overrides, bindPaths) };`;
|
|
8160
|
+
const field = bound > 0 ? `const ${fieldName} = ${fieldsName}({ blockId, bind, bindPaths, overrides }, ${JSON.stringify(pathPrefix)}${flat3 ? `, ${JSON.stringify(pathMap)}` : ""});` : "";
|
|
8126
8161
|
const declared = [copy, field].filter(Boolean).join("\n");
|
|
8127
8162
|
const styles = dialect === "astro" ? carriedStyles(content) : "";
|
|
8128
8163
|
if (dialect === "astro") {
|
|
@@ -8135,12 +8170,14 @@ interface Props {
|
|
|
8135
8170
|
blockId?: string;
|
|
8136
8171
|
/** The page field group this placement renders \u2014 Phase A keeps the copy where P2 put it. */
|
|
8137
8172
|
bind?: string;
|
|
8173
|
+
/** A locale copy's own field path for each prop, when its keys differ from this component's. */
|
|
8174
|
+
bindPaths?: Record<string, string>;
|
|
8138
8175
|
/** The instance's own copy, when an editor gave it any. Wins over the bound group. */
|
|
8139
8176
|
overrides?: Record<string, unknown>;
|
|
8140
8177
|
/** The page snapshot, so one component can serve every page whose group has this shape. */
|
|
8141
8178
|
page?: unknown;
|
|
8142
8179
|
}
|
|
8143
|
-
const { blockId, bind, overrides, page } = Astro.props;
|
|
8180
|
+
const { blockId, bind, bindPaths, overrides, page } = Astro.props;
|
|
8144
8181
|
${carriedDeclarations}${declared}
|
|
8145
8182
|
---
|
|
8146
8183
|
${markup}
|
|
@@ -8152,7 +8189,7 @@ ${styles}
|
|
|
8152
8189
|
${[...carried, `import { ${helpers.join(", ")} } from "${helperSpecifier}";`, `import type { BcmsSectionProps } from "${relativeImport(path, SECTIONS_LIB).replace(/\.tsx?$/, "")}";`].join("\n")}
|
|
8153
8190
|
${carriedDeclarations === "" ? "" : `
|
|
8154
8191
|
${carriedDeclarations}`}
|
|
8155
|
-
export default function ${resolved.name}({ blockId, bind, overrides, page }: BcmsSectionProps) {
|
|
8192
|
+
export default function ${resolved.name}({ blockId, bind, bindPaths, overrides, page }: BcmsSectionProps) {
|
|
8156
8193
|
${declared.split("\n").join("\n ")}
|
|
8157
8194
|
return (
|
|
8158
8195
|
${markup}
|
|
@@ -8514,6 +8551,7 @@ const isRecord = (v: unknown): v is Record<string, unknown> =>
|
|
|
8514
8551
|
export interface BcmsSectionProps {
|
|
8515
8552
|
blockId?: string;
|
|
8516
8553
|
bind?: string;
|
|
8554
|
+
bindPaths?: Record<string, string>;
|
|
8517
8555
|
overrides?: Record<string, unknown>;
|
|
8518
8556
|
page?: unknown;
|
|
8519
8557
|
}
|
|
@@ -8523,6 +8561,8 @@ export interface BcmsPlacement {
|
|
|
8523
8561
|
blockId?: string;
|
|
8524
8562
|
slug: string;
|
|
8525
8563
|
bind?: string;
|
|
8564
|
+
/** A locale copy's own field path for each prop, when its keys differ from the component's. */
|
|
8565
|
+
bindPaths?: Record<string, string>;
|
|
8526
8566
|
overrides?: Record<string, unknown>;
|
|
8527
8567
|
}
|
|
8528
8568
|
|
|
@@ -8583,6 +8623,7 @@ export function pageSections(pageSlug: string): BcmsPlacement[] {
|
|
|
8583
8623
|
blockId: typeof block.id === "string" ? block.id : undefined,
|
|
8584
8624
|
slug,
|
|
8585
8625
|
bind: typeof props.bind === "string" ? props.bind : undefined,
|
|
8626
|
+
bindPaths: isRecord(props.bindPaths) ? (props.bindPaths as Record<string, string>) : undefined,
|
|
8586
8627
|
overrides: isRecord(props.overrides) ? props.overrides : undefined,
|
|
8587
8628
|
});
|
|
8588
8629
|
}
|
|
@@ -8648,6 +8689,7 @@ const snapshot = pageSnapshot(page);
|
|
|
8648
8689
|
<Component
|
|
8649
8690
|
blockId={placement.blockId}
|
|
8650
8691
|
bind={placement.bind}
|
|
8692
|
+
bindPaths={placement.bindPaths}
|
|
8651
8693
|
overrides={placement.overrides}
|
|
8652
8694
|
page={snapshot}
|
|
8653
8695
|
/>
|
|
@@ -8670,6 +8712,7 @@ export default function Sections({ page }: { page: string }) {
|
|
|
8670
8712
|
key={placement.blockId ?? \`\${placement.slug}-\${i}\`}
|
|
8671
8713
|
blockId={placement.blockId}
|
|
8672
8714
|
bind={placement.bind}
|
|
8715
|
+
bindPaths={placement.bindPaths}
|
|
8673
8716
|
overrides={placement.overrides}
|
|
8674
8717
|
page={snapshot}
|
|
8675
8718
|
/>
|
|
@@ -9403,7 +9446,23 @@ async function plan(file, content, dialect, targets, sites, importAt, outcomes,
|
|
|
9403
9446
|
continue;
|
|
9404
9447
|
}
|
|
9405
9448
|
const resolved = sharing.length === 1 ? { assigned: /* @__PURE__ */ new Map([[sharing[0].key, forLiteral]]), ambiguous: /* @__PURE__ */ new Set() } : resolvePositionally(sharing, forLiteral);
|
|
9449
|
+
const exactly = new Map(
|
|
9450
|
+
sharing.length > 1 ? sharing.flatMap((target) => {
|
|
9451
|
+
const own = forLiteral.filter(
|
|
9452
|
+
(site) => site.where === "text" && !site.partial && !site.mixed && isIntrinsic(site.tag) && declarations.some((d) => d.scope === target.scope && d.path === target.path && d.at === site.attrInsertAt)
|
|
9453
|
+
);
|
|
9454
|
+
return own.length > 0 ? [[target.key, own]] : [];
|
|
9455
|
+
}) : []
|
|
9456
|
+
);
|
|
9457
|
+
const unmarked = forLiteral.filter((site) => ![...exactly.values()].some((own) => own.includes(site)));
|
|
9458
|
+
const settled = unmarked.length <= sharing.length - exactly.size ? exactly : /* @__PURE__ */ new Map();
|
|
9406
9459
|
for (const target of sharing) {
|
|
9460
|
+
const own = settled.get(target.key);
|
|
9461
|
+
if (own) {
|
|
9462
|
+
outcomes.set(target.key, "declared");
|
|
9463
|
+
located += own.length;
|
|
9464
|
+
continue;
|
|
9465
|
+
}
|
|
9407
9466
|
if (resolved.ambiguous.has(target.key)) {
|
|
9408
9467
|
outcomes.set(target.key, "AMBIGUOUS_LITERAL");
|
|
9409
9468
|
continue;
|
|
@@ -9929,7 +9988,7 @@ function styleEdits(before, after) {
|
|
|
9929
9988
|
// package.json
|
|
9930
9989
|
var package_default = {
|
|
9931
9990
|
name: "@bettercms-ai/convert",
|
|
9932
|
-
version: "0.
|
|
9991
|
+
version: "0.19.0",
|
|
9933
9992
|
type: "module",
|
|
9934
9993
|
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.",
|
|
9935
9994
|
bin: {
|
|
@@ -9956,12 +10015,13 @@ var package_default = {
|
|
|
9956
10015
|
build: "tsup",
|
|
9957
10016
|
test: "vitest run",
|
|
9958
10017
|
"test:watch": "vitest",
|
|
9959
|
-
briefs: "bun --conditions=development scripts/build-briefs.ts"
|
|
10018
|
+
briefs: "bun --conditions=development scripts/build-briefs.ts",
|
|
10019
|
+
prepublishOnly: "bun run build"
|
|
9960
10020
|
},
|
|
9961
10021
|
dependencies: {
|
|
9962
10022
|
"@astrojs/compiler": "^2.13.1",
|
|
9963
10023
|
"@babel/parser": "^7.29.2",
|
|
9964
|
-
"@bettercms-ai/types": "^1.
|
|
10024
|
+
"@bettercms-ai/types": "^1.25.0",
|
|
9965
10025
|
"@vue/compiler-sfc": "^3.5.0",
|
|
9966
10026
|
"magic-string": "^0.30.21",
|
|
9967
10027
|
parse5: "^7.3.0",
|