@bettercms-ai/convert 0.18.2 → 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/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 = 8;
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 = 8;
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(page: unknown, bind?: string, overrides?: unknown): Record<string, unknown> {
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
- const fromPage = (path: string): unknown =>
4425
- bind ? readPath(page, bind + separator + path.slice(prefix.length)) : undefined;
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
- return lane + path.slice(pathPrefix.length);
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");
@@ -8131,6 +8158,7 @@ function componentFile(dialect, path, fromFile, content, parsed, resolved, pathP
8131
8158
  provided: [
8132
8159
  "blockId",
8133
8160
  "bind",
8161
+ "bindPaths",
8134
8162
  "overrides",
8135
8163
  "page",
8136
8164
  fieldName,
@@ -8145,8 +8173,8 @@ function componentFile(dialect, path, fromFile, content, parsed, resolved, pathP
8145
8173
  const key = /^[A-Za-z_$][\w$]*$/.test(groupKey) ? groupKey : JSON.stringify(groupKey);
8146
8174
  const carriedDeclarations = carry.declarations.length > 0 ? `${carry.declarations.join("\n")}
8147
8175
  ` : "";
8148
- const copy = !snapshot ? "" : flat3 ? `const ${snapshot} = bcmsSectionPaths(page, bind, overrides, ${JSON.stringify(pathPrefix)}, ${JSON.stringify(pathMap)});` : `const ${snapshot} = { ${key}: bcmsSection(page, bind, overrides) };`;
8149
- 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)}` : ""});` : "";
8150
8178
  const declared = [copy, field].filter(Boolean).join("\n");
8151
8179
  const styles = dialect === "astro" ? carriedStyles(content) : "";
8152
8180
  if (dialect === "astro") {
@@ -8159,12 +8187,14 @@ interface Props {
8159
8187
  blockId?: string;
8160
8188
  /** The page field group this placement renders \u2014 Phase A keeps the copy where P2 put it. */
8161
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>;
8162
8192
  /** The instance's own copy, when an editor gave it any. Wins over the bound group. */
8163
8193
  overrides?: Record<string, unknown>;
8164
8194
  /** The page snapshot, so one component can serve every page whose group has this shape. */
8165
8195
  page?: unknown;
8166
8196
  }
8167
- const { blockId, bind, overrides, page } = Astro.props;
8197
+ const { blockId, bind, bindPaths, overrides, page } = Astro.props;
8168
8198
  ${carriedDeclarations}${declared}
8169
8199
  ---
8170
8200
  ${markup}
@@ -8176,7 +8206,7 @@ ${styles}
8176
8206
  ${[...carried, `import { ${helpers.join(", ")} } from "${helperSpecifier}";`, `import type { BcmsSectionProps } from "${relativeImport(path, SECTIONS_LIB).replace(/\.tsx?$/, "")}";`].join("\n")}
8177
8207
  ${carriedDeclarations === "" ? "" : `
8178
8208
  ${carriedDeclarations}`}
8179
- export default function ${resolved.name}({ blockId, bind, overrides, page }: BcmsSectionProps) {
8209
+ export default function ${resolved.name}({ blockId, bind, bindPaths, overrides, page }: BcmsSectionProps) {
8180
8210
  ${declared.split("\n").join("\n ")}
8181
8211
  return (
8182
8212
  ${markup}
@@ -8538,6 +8568,7 @@ const isRecord = (v: unknown): v is Record<string, unknown> =>
8538
8568
  export interface BcmsSectionProps {
8539
8569
  blockId?: string;
8540
8570
  bind?: string;
8571
+ bindPaths?: Record<string, string>;
8541
8572
  overrides?: Record<string, unknown>;
8542
8573
  page?: unknown;
8543
8574
  }
@@ -8547,6 +8578,8 @@ export interface BcmsPlacement {
8547
8578
  blockId?: string;
8548
8579
  slug: string;
8549
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>;
8550
8583
  overrides?: Record<string, unknown>;
8551
8584
  }
8552
8585
 
@@ -8607,6 +8640,7 @@ export function pageSections(pageSlug: string): BcmsPlacement[] {
8607
8640
  blockId: typeof block.id === "string" ? block.id : undefined,
8608
8641
  slug,
8609
8642
  bind: typeof props.bind === "string" ? props.bind : undefined,
8643
+ bindPaths: isRecord(props.bindPaths) ? (props.bindPaths as Record<string, string>) : undefined,
8610
8644
  overrides: isRecord(props.overrides) ? props.overrides : undefined,
8611
8645
  });
8612
8646
  }
@@ -8672,6 +8706,7 @@ const snapshot = pageSnapshot(page);
8672
8706
  <Component
8673
8707
  blockId={placement.blockId}
8674
8708
  bind={placement.bind}
8709
+ bindPaths={placement.bindPaths}
8675
8710
  overrides={placement.overrides}
8676
8711
  page={snapshot}
8677
8712
  />
@@ -8694,6 +8729,7 @@ export default function Sections({ page }: { page: string }) {
8694
8729
  key={placement.blockId ?? \`\${placement.slug}-\${i}\`}
8695
8730
  blockId={placement.blockId}
8696
8731
  bind={placement.bind}
8732
+ bindPaths={placement.bindPaths}
8697
8733
  overrides={placement.overrides}
8698
8734
  page={snapshot}
8699
8735
  />