@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/dist/index.d.ts
CHANGED
|
@@ -951,7 +951,7 @@ declare function attrsFor(path: string, kind: string, props?: AttrBinding[], sco
|
|
|
951
951
|
declare function propsAttribute(props: AttrBinding[]): string;
|
|
952
952
|
|
|
953
953
|
/** Bumped whenever the emitted source changes. `isKnownHelper` upgrades anything older. */
|
|
954
|
-
declare const HELPER_VERSION =
|
|
954
|
+
declare const HELPER_VERSION = 9;
|
|
955
955
|
/** Where each dialect's helper lives. Null = this dialect reads nothing at build time. */
|
|
956
956
|
declare const HELPER_PATH: Record<Dialect, string | null>;
|
|
957
957
|
/** The directory the snapshots live in, at the repository root. */
|
package/dist/index.js
CHANGED
|
@@ -4187,7 +4187,7 @@ async function bindImages(ctx, targets) {
|
|
|
4187
4187
|
|
|
4188
4188
|
// src/helper.ts
|
|
4189
4189
|
import { createHash as createHash2 } from "crypto";
|
|
4190
|
-
var HELPER_VERSION =
|
|
4190
|
+
var HELPER_VERSION = 9;
|
|
4191
4191
|
var HEADER = "// @bettercms-ai/convert helper v";
|
|
4192
4192
|
var HELPER_PATH = Object.fromEntries(
|
|
4193
4193
|
Object.keys(DIALECT_RULES).map((d) => [d, DIALECT_RULES[d].helper])
|
|
@@ -4352,9 +4352,19 @@ export function bcmsImage<T>(page: unknown, path: string, fallback: T, slug?: st
|
|
|
4352
4352
|
* the fallback the template shipped with \u2014 which is why a section renders correctly against the
|
|
4353
4353
|
* committed \`{}\` stub.
|
|
4354
4354
|
*/
|
|
4355
|
-
export function bcmsSection(
|
|
4355
|
+
export function bcmsSection(
|
|
4356
|
+
page: unknown,
|
|
4357
|
+
bind?: string,
|
|
4358
|
+
overrides?: unknown,
|
|
4359
|
+
bindPaths?: Record<string, string>,
|
|
4360
|
+
): Record<string, unknown> {
|
|
4356
4361
|
const group = bind ? readPath(page, bind) : undefined;
|
|
4357
4362
|
const base: Record<string, unknown> = isRecord(group) ? { ...group } : {};
|
|
4363
|
+
// A locale copy on its twin's component spells its fields its own way: each prop's copy is
|
|
4364
|
+
// read from the path the placement names for it.
|
|
4365
|
+
if (bind && isRecord(bindPaths)) {
|
|
4366
|
+
for (const [key, path] of Object.entries(bindPaths)) base[key] = readPath(page, path);
|
|
4367
|
+
}
|
|
4358
4368
|
if (!isRecord(overrides)) return base;
|
|
4359
4369
|
for (const key of Object.keys(overrides)) {
|
|
4360
4370
|
const value = overrides[key];
|
|
@@ -4417,21 +4427,25 @@ export function bcmsSectionPaths(
|
|
|
4417
4427
|
overrides: unknown,
|
|
4418
4428
|
prefix: string,
|
|
4419
4429
|
map: BcmsPathMap,
|
|
4430
|
+
bindPaths?: Record<string, string>,
|
|
4420
4431
|
): Record<string, unknown> {
|
|
4421
4432
|
const out: Record<string, unknown> = isRecord(page) ? { ...page } : {};
|
|
4422
4433
|
const own = isRecord(overrides) ? overrides : {};
|
|
4423
4434
|
const separator = prefix.slice(-1);
|
|
4424
|
-
|
|
4425
|
-
|
|
4435
|
+
// A re-keyed locale copy names each prop's path on its own page; any other placement re-bases.
|
|
4436
|
+
const fromPage = (path: string, key: string): unknown =>
|
|
4437
|
+
!bind ? undefined
|
|
4438
|
+
: isRecord(bindPaths) && typeof bindPaths[key] === "string" ? readPath(page, bindPaths[key])
|
|
4439
|
+
: readPath(page, bind + separator + path.slice(prefix.length));
|
|
4426
4440
|
for (const [path, key] of Object.entries(map.scalars ?? {})) {
|
|
4427
4441
|
const value = own[key];
|
|
4428
|
-
out[path] = value !== undefined && value !== null ? value : fromPage(path);
|
|
4442
|
+
out[path] = value !== undefined && value !== null ? value : fromPage(path, key);
|
|
4429
4443
|
}
|
|
4430
4444
|
for (const [path, table] of Object.entries(map.tables ?? {})) {
|
|
4431
4445
|
const held = own[table.key];
|
|
4432
4446
|
const rows = isRecord(held) && Array.isArray(held.rows) ? held.rows : held;
|
|
4433
4447
|
if (!Array.isArray(rows)) {
|
|
4434
|
-
out[path] = fromPage(path);
|
|
4448
|
+
out[path] = fromPage(path, table.key);
|
|
4435
4449
|
continue;
|
|
4436
4450
|
}
|
|
4437
4451
|
const pageColumn = new Map(Object.entries(table.columns).map(([column, key]) => [key, column]));
|
|
@@ -4446,12 +4460,17 @@ export function bcmsSectionPaths(
|
|
|
4446
4460
|
}
|
|
4447
4461
|
|
|
4448
4462
|
export function bcmsFields(
|
|
4449
|
-
placement: { blockId?: string; bind?: string; overrides?: unknown },
|
|
4463
|
+
placement: { blockId?: string; bind?: string; overrides?: unknown; bindPaths?: Record<string, string> },
|
|
4450
4464
|
pathPrefix: string,
|
|
4451
4465
|
map?: BcmsPathMap,
|
|
4452
4466
|
): (path: string) => string {
|
|
4453
4467
|
const id = placement.blockId;
|
|
4454
4468
|
const own = typeof id === "string" && id !== "" && !placement.bind && isRecord(placement.overrides);
|
|
4469
|
+
/** A re-keyed locale copy's own path for a prop, with whatever follows the prop kept. */
|
|
4470
|
+
const moved = (key: string | undefined, rest: string): string | undefined => {
|
|
4471
|
+
const paths = placement.bind && isRecord(placement.bindPaths) ? placement.bindPaths : undefined;
|
|
4472
|
+
return key !== undefined && paths && typeof paths[key] === "string" ? paths[key] + rest : undefined;
|
|
4473
|
+
};
|
|
4455
4474
|
/**
|
|
4456
4475
|
* What replaces the prefix the markup was cut with, or null for "leave every path alone".
|
|
4457
4476
|
*
|
|
@@ -4470,11 +4489,14 @@ export function bcmsFields(
|
|
|
4470
4489
|
const separator = pathPrefix.slice(-1);
|
|
4471
4490
|
return (path: string): string => {
|
|
4472
4491
|
if (!path.startsWith(pathPrefix) || !(own || placement.bind)) return path;
|
|
4473
|
-
if (!own) return placement.bind + separator + path.slice(pathPrefix.length);
|
|
4474
4492
|
const scalar = map.scalars?.[path];
|
|
4475
|
-
if (scalar !== undefined) return id + "__overrides." + scalar;
|
|
4476
4493
|
const row = /^([^[]+)\\[(\\d+)\\]\\.(.+)$/.exec(path);
|
|
4477
4494
|
const table = row ? map.tables?.[row[1]] : undefined;
|
|
4495
|
+
if (!own) {
|
|
4496
|
+
return moved(scalar, "") ?? moved(table?.key, row ? "[" + row[2] + "]." + row[3] : "")
|
|
4497
|
+
?? placement.bind + separator + path.slice(pathPrefix.length);
|
|
4498
|
+
}
|
|
4499
|
+
if (scalar !== undefined) return id + "__overrides." + scalar;
|
|
4478
4500
|
const column = row && table ? table.columns[row[3]] : undefined;
|
|
4479
4501
|
return table && column !== undefined ? id + "__overrides." + table.key + "[" + row![2] + "]." + column : path;
|
|
4480
4502
|
};
|
|
@@ -4484,7 +4506,9 @@ export function bcmsFields(
|
|
|
4484
4506
|
// it names a key the instance does not hold and a group this placement is not bound to.
|
|
4485
4507
|
// (An EMPTY prefix is a plan saying the prop key IS the page path, and matches everything.)
|
|
4486
4508
|
if (lane === null || !path.startsWith(pathPrefix)) return path;
|
|
4487
|
-
|
|
4509
|
+
const rest = path.slice(pathPrefix.length);
|
|
4510
|
+
const key = /^[^.[]+/.exec(rest)?.[0];
|
|
4511
|
+
return (own ? undefined : moved(key, rest.slice(key?.length ?? 0))) ?? lane + rest;
|
|
4488
4512
|
};
|
|
4489
4513
|
}
|
|
4490
4514
|
`;
|
|
@@ -4497,7 +4521,8 @@ var HISTORICAL = {
|
|
|
4497
4521
|
4: "a5742f64dacb1b26ee6dd5e1469a54871487934c71bc8267df19e3a80e417595",
|
|
4498
4522
|
5: "0472fe3ffdcfa49e719c7b9da9cb63b6eba637cc22783bb00c3c2cadd3d800da",
|
|
4499
4523
|
6: "c907e7245578d947c6541b1ab2c5c6659ea7789a1519e895b4a4aed122c6f649",
|
|
4500
|
-
7: "f22514ef48c50230985e605bea6cf9bf41756384a7dc80603e347baba9b65d93"
|
|
4524
|
+
7: "f22514ef48c50230985e605bea6cf9bf41756384a7dc80603e347baba9b65d93",
|
|
4525
|
+
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9"
|
|
4501
4526
|
},
|
|
4502
4527
|
"src/lib/bcms-content.ts": {
|
|
4503
4528
|
1: "ae72ae14d706943d481c880d70da5789b4816ba1ba319a10fbc63ded4d0b42f2",
|
|
@@ -4506,7 +4531,8 @@ var HISTORICAL = {
|
|
|
4506
4531
|
4: "0146d027a727ecd3c9e3fc336fcf1299b59ddf75b04091c05703f3f983ec28af",
|
|
4507
4532
|
5: "c8c93655320fa65664611ba84541f3fa7bfa292cc9a2fd655373440b99049fba",
|
|
4508
4533
|
6: "63f1fa29e47e70c5193b81ee24addb238ba100247124d55bc17713102d587df5",
|
|
4509
|
-
7: "ed92fb88de953d9951abbe6a1edae1d048f4050eaf6fb607ac08167f94d8bcc7"
|
|
4534
|
+
7: "ed92fb88de953d9951abbe6a1edae1d048f4050eaf6fb607ac08167f94d8bcc7",
|
|
4535
|
+
8: "1a6f669d76d42effe77f082436e9d21c0efa6fc499e919e3d116bc3a27a7f3d5"
|
|
4510
4536
|
},
|
|
4511
4537
|
"composables/bcms-content.ts": {
|
|
4512
4538
|
1: "c272412532efed7db64b6cf313b2bed4291f9951430412289c8a588b7f565407",
|
|
@@ -4515,7 +4541,8 @@ var HISTORICAL = {
|
|
|
4515
4541
|
4: "a5742f64dacb1b26ee6dd5e1469a54871487934c71bc8267df19e3a80e417595",
|
|
4516
4542
|
5: "0472fe3ffdcfa49e719c7b9da9cb63b6eba637cc22783bb00c3c2cadd3d800da",
|
|
4517
4543
|
6: "c907e7245578d947c6541b1ab2c5c6659ea7789a1519e895b4a4aed122c6f649",
|
|
4518
|
-
7: "f22514ef48c50230985e605bea6cf9bf41756384a7dc80603e347baba9b65d93"
|
|
4544
|
+
7: "f22514ef48c50230985e605bea6cf9bf41756384a7dc80603e347baba9b65d93",
|
|
4545
|
+
8: "484e72852d2b496e016a1f2a2b1a77bb993f8a163b290781522d6114b6519bb9"
|
|
4519
4546
|
}
|
|
4520
4547
|
};
|
|
4521
4548
|
var sha256 = (value) => createHash2("sha256").update(value, "utf8").digest("hex");
|
|
@@ -6498,7 +6525,7 @@ function* formsIn(nodes, chain = []) {
|
|
|
6498
6525
|
}
|
|
6499
6526
|
}
|
|
6500
6527
|
var isComponentTag = (dialect, tag) => dialect !== "html" && /^[A-Z]/.test(tag);
|
|
6501
|
-
function candidateOf(file, dialect, form, imported, landmark) {
|
|
6528
|
+
function candidateOf(file, dialect, form, imported, landmark, content) {
|
|
6502
6529
|
const controls = /* @__PURE__ */ new Map();
|
|
6503
6530
|
const wrapper = /* @__PURE__ */ new Map();
|
|
6504
6531
|
const foreign = /* @__PURE__ */ new Set();
|
|
@@ -6535,7 +6562,11 @@ function candidateOf(file, dialect, form, imported, landmark) {
|
|
|
6535
6562
|
const id = attrOf(control, "id")?.value;
|
|
6536
6563
|
if (id && !controls.has(id)) controls.set(id, control);
|
|
6537
6564
|
}
|
|
6538
|
-
|
|
6565
|
+
const computed = (attr) => !!attr?.expression && !!attr.expressionRange && /[A-Za-z_$]/.test(
|
|
6566
|
+
content.slice(attr.expressionRange.start, attr.expressionRange.end).replace(/\/\*[\s\S]*?\*\/|\/\/[^\n]*|"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'|`(?:[^`\\$]|\\.|\$(?!\{))*`/g, "")
|
|
6567
|
+
);
|
|
6568
|
+
const dynamic = all.some((control) => !foreign.has(control) && computed(attrOf(control, "name")));
|
|
6569
|
+
return { file, dialect, el: form, controls, wrapper, foreign, landmark, dynamic };
|
|
6539
6570
|
}
|
|
6540
6571
|
async function importedControls(source, parsed, dialect, project, cache) {
|
|
6541
6572
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -6629,11 +6660,12 @@ async function wireForms(briefIn, sources, options_ = {}) {
|
|
|
6629
6660
|
}
|
|
6630
6661
|
const imported = dialect === "html" ? /* @__PURE__ */ new Map() : await importedControls(source, parsed, dialect, project, componentFiles);
|
|
6631
6662
|
for (const { el, landmark } of formsIn(parsed.roots)) {
|
|
6632
|
-
candidates.push(candidateOf(source.path, dialect, el, imported, landmark));
|
|
6663
|
+
candidates.push(candidateOf(source.path, dialect, el, imported, landmark, source.content));
|
|
6633
6664
|
}
|
|
6634
6665
|
}
|
|
6635
6666
|
const holds = (c, f) => f.fields.filter((field) => c.controls.has(field.key)).length;
|
|
6636
|
-
const
|
|
6667
|
+
const wiredTo = (c, f) => attrOf(c.el, "data-bcms-form")?.value === f.id;
|
|
6668
|
+
const covers2 = (c, f) => c.dynamic && wiredTo(c, f) || f.fields.length > 0 && holds(c, f) === f.fields.length;
|
|
6637
6669
|
const samePath = (a, b) => a.replace(/\\/g, "/").replace(/^\.\//, "") === b.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
6638
6670
|
const options = new Map(forms.map((f) => [f.id, candidates.filter((c) => covers2(c, f))]));
|
|
6639
6671
|
const pinned = /* @__PURE__ */ new Map();
|
|
@@ -6716,6 +6748,11 @@ async function wireForms(briefIn, sources, options_ = {}) {
|
|
|
6716
6748
|
continue;
|
|
6717
6749
|
}
|
|
6718
6750
|
const candidate = list[0];
|
|
6751
|
+
if (wiredTo(candidate, form)) {
|
|
6752
|
+
alreadyWired++;
|
|
6753
|
+
onSite.push({ form, file: candidate.file });
|
|
6754
|
+
continue;
|
|
6755
|
+
}
|
|
6719
6756
|
if (attrOf(candidate.el, "action")?.expression) {
|
|
6720
6757
|
pend2(form, "ACTION_IS_EXPRESSION", candidate.file, "its action is an expression, so this run will not replace it.");
|
|
6721
6758
|
continue;
|
|
@@ -6728,11 +6765,6 @@ async function wireForms(briefIn, sources, options_ = {}) {
|
|
|
6728
6765
|
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.`);
|
|
6729
6766
|
continue;
|
|
6730
6767
|
}
|
|
6731
|
-
if (attrOf(candidate.el, "data-bcms-form")?.value === form.id) {
|
|
6732
|
-
alreadyWired++;
|
|
6733
|
-
onSite.push({ form, file: candidate.file });
|
|
6734
|
-
continue;
|
|
6735
|
-
}
|
|
6736
6768
|
matched.push({ form, candidate });
|
|
6737
6769
|
onSite.push({ form, file: candidate.file });
|
|
6738
6770
|
}
|
|
@@ -6853,7 +6885,8 @@ var TEMPLATE_DIRS = /* @__PURE__ */ new Set([
|
|
|
6853
6885
|
"_includes",
|
|
6854
6886
|
"_layouts"
|
|
6855
6887
|
]);
|
|
6856
|
-
var
|
|
6888
|
+
var READ_CONFIG = /^astro\.config\.[^./]+$/;
|
|
6889
|
+
var isAboutTheSite = (lower) => /\.(test|spec)\.[^./]+$/.test(lower) || /^[^/]*\.config\.[^./]+$/.test(lower) && !READ_CONFIG.test(lower);
|
|
6857
6890
|
function isSourceCandidate(path) {
|
|
6858
6891
|
const lower = path.toLowerCase();
|
|
6859
6892
|
if (SKIP_DIRS.some((dir) => lower === dir.slice(0, -1) || lower.startsWith(dir) || lower.includes(`/${dir}`)))
|
|
@@ -6900,7 +6933,7 @@ function measureUnaddressable(html) {
|
|
|
6900
6933
|
let visible = 0;
|
|
6901
6934
|
let unaddressable = 0;
|
|
6902
6935
|
const buckets = /* @__PURE__ */ new Map();
|
|
6903
|
-
const visit = (node, tag, context, bound) => {
|
|
6936
|
+
const visit = (node, tag, context, bound, inForm = false) => {
|
|
6904
6937
|
if (node.type === "text") {
|
|
6905
6938
|
const text = flat2(node.value);
|
|
6906
6939
|
if (isDecorativeGlyph(text) || PLATFORM_BADGE.test(text)) return;
|
|
@@ -6920,9 +6953,10 @@ function measureUnaddressable(html) {
|
|
|
6920
6953
|
if (attrs.has("hidden") || attrs.get("aria-hidden") === "true" || /display\s*:\s*none/i.test(attrs.get("style") ?? "") || isSkipLink(node, attrs)) {
|
|
6921
6954
|
return;
|
|
6922
6955
|
}
|
|
6923
|
-
const
|
|
6956
|
+
const form = inForm || attrs.has("data-bcms-form");
|
|
6957
|
+
const owned = bound || BOUND_ATTRS.some((name) => attrs.has(name)) || form && attrs.has("data-bcms-form-part");
|
|
6924
6958
|
const chain = CONTEXT_TAGS.has(node.tag) ? context === "body" ? node.tag : `${context}>${node.tag}` : context;
|
|
6925
|
-
for (const child of node.children) visit(child, node.tag, chain, owned);
|
|
6959
|
+
for (const child of node.children) visit(child, node.tag, chain, owned, form);
|
|
6926
6960
|
};
|
|
6927
6961
|
for (const root of parsed.roots) visit(root, "body", "body", false);
|
|
6928
6962
|
return {
|
|
@@ -8124,6 +8158,7 @@ function componentFile(dialect, path, fromFile, content, parsed, resolved, pathP
|
|
|
8124
8158
|
provided: [
|
|
8125
8159
|
"blockId",
|
|
8126
8160
|
"bind",
|
|
8161
|
+
"bindPaths",
|
|
8127
8162
|
"overrides",
|
|
8128
8163
|
"page",
|
|
8129
8164
|
fieldName,
|
|
@@ -8138,8 +8173,8 @@ function componentFile(dialect, path, fromFile, content, parsed, resolved, pathP
|
|
|
8138
8173
|
const key = /^[A-Za-z_$][\w$]*$/.test(groupKey) ? groupKey : JSON.stringify(groupKey);
|
|
8139
8174
|
const carriedDeclarations = carry.declarations.length > 0 ? `${carry.declarations.join("\n")}
|
|
8140
8175
|
` : "";
|
|
8141
|
-
const copy = !snapshot ? "" : flat3 ? `const ${snapshot} = bcmsSectionPaths(page, bind, overrides, ${JSON.stringify(pathPrefix)}, ${JSON.stringify(pathMap)});` : `const ${snapshot} = { ${key}: bcmsSection(page, bind, overrides) };`;
|
|
8142
|
-
const field = bound > 0 ? `const ${fieldName} = ${fieldsName}({ blockId, bind, overrides }, ${JSON.stringify(pathPrefix)}${flat3 ? `, ${JSON.stringify(pathMap)}` : ""});` : "";
|
|
8176
|
+
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) };`;
|
|
8177
|
+
const field = bound > 0 ? `const ${fieldName} = ${fieldsName}({ blockId, bind, bindPaths, overrides }, ${JSON.stringify(pathPrefix)}${flat3 ? `, ${JSON.stringify(pathMap)}` : ""});` : "";
|
|
8143
8178
|
const declared = [copy, field].filter(Boolean).join("\n");
|
|
8144
8179
|
const styles = dialect === "astro" ? carriedStyles(content) : "";
|
|
8145
8180
|
if (dialect === "astro") {
|
|
@@ -8152,12 +8187,14 @@ interface Props {
|
|
|
8152
8187
|
blockId?: string;
|
|
8153
8188
|
/** The page field group this placement renders \u2014 Phase A keeps the copy where P2 put it. */
|
|
8154
8189
|
bind?: string;
|
|
8190
|
+
/** A locale copy's own field path for each prop, when its keys differ from this component's. */
|
|
8191
|
+
bindPaths?: Record<string, string>;
|
|
8155
8192
|
/** The instance's own copy, when an editor gave it any. Wins over the bound group. */
|
|
8156
8193
|
overrides?: Record<string, unknown>;
|
|
8157
8194
|
/** The page snapshot, so one component can serve every page whose group has this shape. */
|
|
8158
8195
|
page?: unknown;
|
|
8159
8196
|
}
|
|
8160
|
-
const { blockId, bind, overrides, page } = Astro.props;
|
|
8197
|
+
const { blockId, bind, bindPaths, overrides, page } = Astro.props;
|
|
8161
8198
|
${carriedDeclarations}${declared}
|
|
8162
8199
|
---
|
|
8163
8200
|
${markup}
|
|
@@ -8169,7 +8206,7 @@ ${styles}
|
|
|
8169
8206
|
${[...carried, `import { ${helpers.join(", ")} } from "${helperSpecifier}";`, `import type { BcmsSectionProps } from "${relativeImport(path, SECTIONS_LIB).replace(/\.tsx?$/, "")}";`].join("\n")}
|
|
8170
8207
|
${carriedDeclarations === "" ? "" : `
|
|
8171
8208
|
${carriedDeclarations}`}
|
|
8172
|
-
export default function ${resolved.name}({ blockId, bind, overrides, page }: BcmsSectionProps) {
|
|
8209
|
+
export default function ${resolved.name}({ blockId, bind, bindPaths, overrides, page }: BcmsSectionProps) {
|
|
8173
8210
|
${declared.split("\n").join("\n ")}
|
|
8174
8211
|
return (
|
|
8175
8212
|
${markup}
|
|
@@ -8531,6 +8568,7 @@ const isRecord = (v: unknown): v is Record<string, unknown> =>
|
|
|
8531
8568
|
export interface BcmsSectionProps {
|
|
8532
8569
|
blockId?: string;
|
|
8533
8570
|
bind?: string;
|
|
8571
|
+
bindPaths?: Record<string, string>;
|
|
8534
8572
|
overrides?: Record<string, unknown>;
|
|
8535
8573
|
page?: unknown;
|
|
8536
8574
|
}
|
|
@@ -8540,6 +8578,8 @@ export interface BcmsPlacement {
|
|
|
8540
8578
|
blockId?: string;
|
|
8541
8579
|
slug: string;
|
|
8542
8580
|
bind?: string;
|
|
8581
|
+
/** A locale copy's own field path for each prop, when its keys differ from the component's. */
|
|
8582
|
+
bindPaths?: Record<string, string>;
|
|
8543
8583
|
overrides?: Record<string, unknown>;
|
|
8544
8584
|
}
|
|
8545
8585
|
|
|
@@ -8600,6 +8640,7 @@ export function pageSections(pageSlug: string): BcmsPlacement[] {
|
|
|
8600
8640
|
blockId: typeof block.id === "string" ? block.id : undefined,
|
|
8601
8641
|
slug,
|
|
8602
8642
|
bind: typeof props.bind === "string" ? props.bind : undefined,
|
|
8643
|
+
bindPaths: isRecord(props.bindPaths) ? (props.bindPaths as Record<string, string>) : undefined,
|
|
8603
8644
|
overrides: isRecord(props.overrides) ? props.overrides : undefined,
|
|
8604
8645
|
});
|
|
8605
8646
|
}
|
|
@@ -8665,6 +8706,7 @@ const snapshot = pageSnapshot(page);
|
|
|
8665
8706
|
<Component
|
|
8666
8707
|
blockId={placement.blockId}
|
|
8667
8708
|
bind={placement.bind}
|
|
8709
|
+
bindPaths={placement.bindPaths}
|
|
8668
8710
|
overrides={placement.overrides}
|
|
8669
8711
|
page={snapshot}
|
|
8670
8712
|
/>
|
|
@@ -8687,6 +8729,7 @@ export default function Sections({ page }: { page: string }) {
|
|
|
8687
8729
|
key={placement.blockId ?? \`\${placement.slug}-\${i}\`}
|
|
8688
8730
|
blockId={placement.blockId}
|
|
8689
8731
|
bind={placement.bind}
|
|
8732
|
+
bindPaths={placement.bindPaths}
|
|
8690
8733
|
overrides={placement.overrides}
|
|
8691
8734
|
page={snapshot}
|
|
8692
8735
|
/>
|
|
@@ -9420,7 +9463,23 @@ async function plan(file, content, dialect, targets, sites, importAt, outcomes,
|
|
|
9420
9463
|
continue;
|
|
9421
9464
|
}
|
|
9422
9465
|
const resolved = sharing.length === 1 ? { assigned: /* @__PURE__ */ new Map([[sharing[0].key, forLiteral]]), ambiguous: /* @__PURE__ */ new Set() } : resolvePositionally(sharing, forLiteral);
|
|
9466
|
+
const exactly = new Map(
|
|
9467
|
+
sharing.length > 1 ? sharing.flatMap((target) => {
|
|
9468
|
+
const own = forLiteral.filter(
|
|
9469
|
+
(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)
|
|
9470
|
+
);
|
|
9471
|
+
return own.length > 0 ? [[target.key, own]] : [];
|
|
9472
|
+
}) : []
|
|
9473
|
+
);
|
|
9474
|
+
const unmarked = forLiteral.filter((site) => ![...exactly.values()].some((own) => own.includes(site)));
|
|
9475
|
+
const settled = unmarked.length <= sharing.length - exactly.size ? exactly : /* @__PURE__ */ new Map();
|
|
9423
9476
|
for (const target of sharing) {
|
|
9477
|
+
const own = settled.get(target.key);
|
|
9478
|
+
if (own) {
|
|
9479
|
+
outcomes.set(target.key, "declared");
|
|
9480
|
+
located += own.length;
|
|
9481
|
+
continue;
|
|
9482
|
+
}
|
|
9424
9483
|
if (resolved.ambiguous.has(target.key)) {
|
|
9425
9484
|
outcomes.set(target.key, "AMBIGUOUS_LITERAL");
|
|
9426
9485
|
continue;
|