@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/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");
@@ -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
- return { file, dialect, el: form, controls, wrapper, foreign, landmark };
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 covers2 = (c, f) => f.fields.length > 0 && holds(c, f) === f.fields.length;
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 isAboutTheSite = (lower) => /\.(test|spec)\.[^./]+$/.test(lower) || /^[^/]*\.config\.[^./]+$/.test(lower);
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 owned = bound || BOUND_ATTRS.some((name) => attrs.has(name));
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;