@thallylabs/migrate 0.2.30 → 0.2.32

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.js CHANGED
@@ -278,9 +278,9 @@ function collectRefs(root) {
278
278
  return;
279
279
  }
280
280
  if (ts.isAwaitExpression(node) && !inAsync) awaitOutsideAsync = true;
281
- const target = ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment ? node.left : (ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) && (node.operator === ts.SyntaxKind.PlusPlusToken || node.operator === ts.SyntaxKind.MinusMinusToken) ? node.operand : void 0;
282
- if (target) {
283
- let base = target;
281
+ const target2 = ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment ? node.left : (ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) && (node.operator === ts.SyntaxKind.PlusPlusToken || node.operator === ts.SyntaxKind.MinusMinusToken) ? node.operand : void 0;
282
+ if (target2) {
283
+ let base = target2;
284
284
  while (ts.isPropertyAccessExpression(base) || ts.isElementAccessExpression(base)) base = base.expression;
285
285
  if (ts.isIdentifier(base) && !bound(base.text, scopes)) assigned.push(base.text);
286
286
  }
@@ -484,8 +484,8 @@ function planInlineExtraction(input) {
484
484
  const dependencies = (unit) => {
485
485
  const found = /* @__PURE__ */ new Set();
486
486
  for (const { name } of unit.refs) {
487
- const target = owner.get(name);
488
- if (target !== void 0 && target !== unit.index) found.add(target);
487
+ const target2 = owner.get(name);
488
+ if (target2 !== void 0 && target2 !== unit.index) found.add(target2);
489
489
  }
490
490
  return found;
491
491
  };
@@ -540,8 +540,8 @@ function planInlineExtraction(input) {
540
540
  if (clientSide.has(index)) continue;
541
541
  const unit = units[index];
542
542
  const callsClient = unit.refs.some(({ name, kind }) => {
543
- const target = owner.get(name);
544
- return target !== void 0 && clientSide.has(target) && kind !== "tag" && kind !== "prop";
543
+ const target2 = owner.get(name);
544
+ return target2 !== void 0 && clientSide.has(target2) && kind !== "tag" && kind !== "prop";
545
545
  });
546
546
  if (callsClient) {
547
547
  clientSide.add(index);
@@ -702,9 +702,9 @@ function hasOnlySafeMemberAccess(root) {
702
702
  } else if (ts.isBindingElement(node)) {
703
703
  if (ts.isObjectBindingPattern(node.parent) && !safeKey(node.propertyName ?? (ts.isIdentifier(node.name) ? node.name : void 0), false)) safe = false;
704
704
  } else if (ts.isObjectLiteralExpression(node)) {
705
- const target = isAssignmentTarget(node);
705
+ const target2 = isAssignmentTarget(node);
706
706
  for (const property of node.properties) {
707
- if ((ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property)) && !safeKey(property.name, !target)) safe = false;
707
+ if ((ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property)) && !safeKey(property.name, !target2)) safe = false;
708
708
  }
709
709
  }
710
710
  ts.forEachChild(node, visit);
@@ -722,8 +722,8 @@ function pageScopeNames(esmSources) {
722
722
  for (const statement of parse(source).statements) {
723
723
  for (const local of importLocals(statement.getText())) names.add(local);
724
724
  if (ts.isImportDeclaration(statement)) continue;
725
- const target = ts.isExportDeclaration(statement) || ts.isExportAssignment(statement) ? void 0 : statement;
726
- if (target) for (const name of declaredNames(target).names) names.add(name);
725
+ const target2 = ts.isExportDeclaration(statement) || ts.isExportAssignment(statement) ? void 0 : statement;
726
+ if (target2) for (const name of declaredNames(target2).names) names.add(name);
727
727
  }
728
728
  }
729
729
  return names;
@@ -872,12 +872,12 @@ function resolveWithinRoot(baseDir, candidate, confineRoot) {
872
872
  if (isAbsolute(candidate) || candidate.includes("\0")) {
873
873
  throw new Error(`Unsafe migration path: ${candidate}`);
874
874
  }
875
- const target = resolve(baseDir, candidate);
876
- const fromRoot = relative(resolve(confineRoot), target);
875
+ const target2 = resolve(baseDir, candidate);
876
+ const fromRoot = relative(resolve(confineRoot), target2);
877
877
  if (fromRoot === ".." || fromRoot.startsWith(`..${sep}`) || isAbsolute(fromRoot)) {
878
878
  throw new Error(`Migration path escapes its root: ${candidate}`);
879
879
  }
880
- return target;
880
+ return target2;
881
881
  }
882
882
  function normalizeAssetPath(value) {
883
883
  const normalized = value.replace(/\\/g, "/").replace(/^\/+/, "");
@@ -1315,14 +1315,14 @@ ${trimmed.slice(0, marker).trimEnd()}`;
1315
1315
  function headingIdMarker(id) {
1316
1316
  return `{/* #${id} */}`;
1317
1317
  }
1318
- function mintlifyHeadingSlug(text2) {
1319
- return text2.replace(/\u200b/g, "").normalize("NFC").trim().toLowerCase().replace(/[.\s]+/g, "-").replace(/-{2,}/g, "-").replace(/^-|-$/g, "").replace(/[^\p{L}\p{M}\p{N}_\-+&/\u2019\u201c\u201d\u2014\u2013\u2192]/gu, "");
1318
+ function mintlifyHeadingSlug(text3) {
1319
+ return text3.replace(/\u200b/g, "").normalize("NFC").trim().toLowerCase().replace(/[.\s]+/g, "-").replace(/-{2,}/g, "-").replace(/^-|-$/g, "").replace(/[^\p{L}\p{M}\p{N}_\-+&/\u2019\u201c\u201d\u2014\u2013\u2192]/gu, "");
1320
1320
  }
1321
- function thallyHeadingSlug(text2) {
1322
- return text2.normalize("NFC").toLowerCase().replace(/[^\p{L}\p{M}\p{N}]+/gu, "-").replace(/(^-|-$)/g, "");
1321
+ function thallyHeadingSlug(text3) {
1322
+ return text3.normalize("NFC").toLowerCase().replace(/[^\p{L}\p{M}\p{N}]+/gu, "-").replace(/(^-|-$)/g, "");
1323
1323
  }
1324
- function typesetQuotes(text2) {
1325
- return text2.split(/(`[^`]*`|<[^>]*>|\]\([^)]*\))/).map((part, index) => {
1324
+ function typesetQuotes(text3) {
1325
+ return text3.split(/(`[^`]*`|<[^>]*>|\]\([^)]*\))/).map((part, index) => {
1326
1326
  if (index % 2) return part;
1327
1327
  return part.replace(/(^|[\s([{\u2014\u2013])"/g, "$1\u201C").replace(/"/g, "\u201D").replace(/(^|[\s([{\u2014\u2013\u201c])'(?=\S)/g, "$1\u2018").replace(/'/g, "\u2019");
1328
1328
  }).join("");
@@ -1345,9 +1345,9 @@ function markMintlifyHeadings(body) {
1345
1345
  const explicit = heading[2].match(/^(.*?)([ \t]*\{\/\*[ \t]*#\S+[ \t]*\*\/\})$/);
1346
1346
  const source = typesetQuotes(explicit ? explicit[1] : heading[2]);
1347
1347
  if (explicit) return `${heading[1]}${source}${explicit[2]}`;
1348
- const text2 = plainHeadingText(source);
1349
- const id = mintlifyHeadingSlug(text2);
1350
- return `${heading[1]}${source}${id && id !== thallyHeadingSlug(text2) ? ` ${headingIdMarker(id)}` : ""}`;
1348
+ const text3 = plainHeadingText(source);
1349
+ const id = mintlifyHeadingSlug(text3);
1350
+ return `${heading[1]}${source}${id && id !== thallyHeadingSlug(text3) ? ` ${headingIdMarker(id)}` : ""}`;
1351
1351
  }).join("\n");
1352
1352
  }
1353
1353
  var GLOBAL_DOCUSARUS_COMPONENTS = /* @__PURE__ */ new Set([
@@ -1417,7 +1417,7 @@ function bindSnippetProps(body, properties) {
1417
1417
  for (const child of node.children ?? []) visit(child);
1418
1418
  };
1419
1419
  visit(tree);
1420
- return edits.sort((a, b) => b.start - a.start).reduce((text2, edit) => text2.slice(0, edit.start) + edit.value + text2.slice(edit.end), body);
1420
+ return edits.sort((a, b) => b.start - a.start).reduce((text3, edit) => text3.slice(0, edit.start) + edit.value + text3.slice(edit.end), body);
1421
1421
  }
1422
1422
  function leadingPageHeading(body) {
1423
1423
  if (!/^ {0,3}(?:#(?:[ \t]|$)|=+[ \t\r]*$)/m.test(body)) return void 0;
@@ -1425,8 +1425,8 @@ function leadingPageHeading(body) {
1425
1425
  const root = descriptionParser.parse(body);
1426
1426
  const first = root.children?.find((node) => node.type !== "mdxjsEsm" && node.type !== "html" && !(node.type === "mdxFlowExpression" && node.data?.estree?.body.length === 0));
1427
1427
  if (first?.type !== "heading" || first.depth !== 1) return void 0;
1428
- const text2 = (node) => node.type === "mdxTextExpression" || node.type === "mdxFlowExpression" ? "" : node.value ?? (node.children ?? []).map(text2).join("");
1429
- const title = text2(first).replace(/\s+/g, " ").trim();
1428
+ const text3 = (node) => node.type === "mdxTextExpression" || node.type === "mdxFlowExpression" ? "" : node.value ?? (node.children ?? []).map(text3).join("");
1429
+ const title = text3(first).replace(/\s+/g, " ").trim();
1430
1430
  const start = first.position?.start.offset;
1431
1431
  const end = first.position?.end.offset;
1432
1432
  return title && start !== void 0 && end !== void 0 ? { title, start, end } : void 0;
@@ -1505,16 +1505,16 @@ function collectEsmBindingsByPattern(source, declared) {
1505
1505
  var FENCE_OPEN = /^(`{3,}|~{3,})/;
1506
1506
  function maskInlineSpansForMath(line) {
1507
1507
  const blocks = [];
1508
- const stash = (text2) => {
1509
- blocks.push(text2);
1508
+ const stash = (text3) => {
1509
+ blocks.push(text3);
1510
1510
  return `\0${blocks.length - 1}\0`;
1511
1511
  };
1512
1512
  const codeMasked = line.split(/(`[^`]*`)/).map((segment, index) => index % 2 === 1 ? stash(segment) : segment).join("");
1513
1513
  const tagMasked = codeMasked.replace(/<\/?[a-zA-Z][^<>]*>/g, stash);
1514
- const masked = [tagMasked, tagMasked].reduce((text2) => text2.replace(/(?<!\$)\{[^{}]*\}/g, stash), tagMasked);
1514
+ const masked = [tagMasked, tagMasked].reduce((text3) => text3.replace(/(?<!\$)\{[^{}]*\}/g, stash), tagMasked);
1515
1515
  return {
1516
1516
  masked,
1517
- unmask: (text2) => text2.replace(/\u0000(\d+)\u0000/g, (_match, index) => blocks[Number(index)])
1517
+ unmask: (text3) => text3.replace(/\u0000(\d+)\u0000/g, (_match, index) => blocks[Number(index)])
1518
1518
  };
1519
1519
  }
1520
1520
  var TEX_SIGNAL = /\\[a-zA-Z]|[\^_{]/;
@@ -1670,11 +1670,11 @@ function splitFrontmatterBlock(raw) {
1670
1670
  return { front: bom + source.slice(0, end), body: source.slice(end) };
1671
1671
  }
1672
1672
  var MIGRATED_COMPONENT_TAG = /^Migrated[0-9a-f]{12}$/;
1673
- function isSelfClosingJsx(text2) {
1674
- return /\/>\s*$/.test(text2);
1673
+ function isSelfClosingJsx(text3) {
1674
+ return /\/>\s*$/.test(text3);
1675
1675
  }
1676
- function renameTagOccurrences(text2, name, newName) {
1677
- let result = text2;
1676
+ function renameTagOccurrences(text3, name, newName) {
1677
+ let result = text3;
1678
1678
  const openIndex = result.indexOf(`<${name}`);
1679
1679
  if (openIndex >= 0) result = `${result.slice(0, openIndex + 1)}${newName}${result.slice(openIndex + 1 + name.length)}`;
1680
1680
  const closeIndex = result.lastIndexOf(`</${name}`);
@@ -1720,9 +1720,9 @@ function replaceUnknownComponents(raw, warn, options = {}) {
1720
1720
  if (start === void 0 || end === void 0) return "";
1721
1721
  const isJsx = node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement";
1722
1722
  const tagRoot = node.name ? node.name.split(".")[0] : void 0;
1723
- const text2 = body.slice(start, end);
1723
+ const text3 = body.slice(start, end);
1724
1724
  if (isJsx && tagRoot === "Link" && !declared.has("Link")) {
1725
- if (isSelfClosingJsx(text2) || !node.children?.length) return renameTagOccurrences(text2, node.name, "a");
1725
+ if (isSelfClosingJsx(text3) || !node.children?.length) return renameTagOccurrences(text3, node.name, "a");
1726
1726
  const openEnd = node.children[0].position?.start.offset ?? start;
1727
1727
  const closeStart = node.children.at(-1).position?.end.offset ?? end;
1728
1728
  return renameTagOccurrences(body.slice(start, openEnd), node.name, "a") + renderChildrenSpan(node.children, openEnd, closeStart, body, renderNode) + renameTagOccurrences(body.slice(closeStart, end), node.name, "a");
@@ -1732,7 +1732,7 @@ function replaceUnknownComponents(raw, warn, options = {}) {
1732
1732
  warned.add(node.name);
1733
1733
  warn(node.name);
1734
1734
  }
1735
- if (isSelfClosingJsx(text2)) return "";
1735
+ if (isSelfClosingJsx(text3)) return "";
1736
1736
  if (!node.children?.length) return "<div></div>";
1737
1737
  const openEnd = node.children[0].position?.start.offset ?? start;
1738
1738
  const closeStart = node.children.at(-1).position?.end.offset ?? end;
@@ -1743,7 +1743,7 @@ ${children}
1743
1743
 
1744
1744
  </div>` : `<div>${children}</div>`;
1745
1745
  }
1746
- if (!node.children?.length) return text2;
1746
+ if (!node.children?.length) return text3;
1747
1747
  return renderChildrenSpan(node.children, start, end, body, renderNode);
1748
1748
  };
1749
1749
  return front + renderNode(root);
@@ -1751,8 +1751,8 @@ ${children}
1751
1751
  function maskCode(body) {
1752
1752
  const source = body.replace(/\u0000/g, "");
1753
1753
  const blocks = [];
1754
- const stash = (text2) => {
1755
- blocks.push(text2);
1754
+ const stash = (text3) => {
1755
+ blocks.push(text3);
1756
1756
  return `\0${blocks.length - 1}\0`;
1757
1757
  };
1758
1758
  const lines = [];
@@ -1779,7 +1779,7 @@ function maskCode(body) {
1779
1779
  if (fenceBuffer.length) lines.push(stash(fenceBuffer.join("\n")));
1780
1780
  return {
1781
1781
  masked: lines.join("\n"),
1782
- unmask: (text2) => text2.replace(/\u0000(\d+)\u0000/g, (_match, index) => blocks[Number(index)]),
1782
+ unmask: (text3) => text3.replace(/\u0000(\d+)\u0000/g, (_match, index) => blocks[Number(index)]),
1783
1783
  openFence: codeFence
1784
1784
  };
1785
1785
  }
@@ -1792,8 +1792,8 @@ function replaceOutsideCode(body, transform) {
1792
1792
  const { masked, unmask } = maskCode(body);
1793
1793
  return unmask(transform(masked));
1794
1794
  }
1795
- function mdxComment(text2) {
1796
- return `{/*${text2.replace(/\*\//g, "* /")}*/}`;
1795
+ function mdxComment(text3) {
1796
+ return `{/*${text3.replace(/\*\//g, "* /")}*/}`;
1797
1797
  }
1798
1798
  function replaceOutsideCodeAndComments(body, transform) {
1799
1799
  return replaceOutsideCode(body, (masked) => {
@@ -1824,26 +1824,26 @@ function replaceOutsideCodeAndComments(body, transform) {
1824
1824
  });
1825
1825
  }
1826
1826
  function rewriteFernRelativePageLinks(body, currentSourcePath, routesBySourcePath) {
1827
- const rewrite = (target) => {
1828
- if (!target || target.startsWith("/") || target.startsWith("#") || target.startsWith("?") || target.includes("\\") || /[\u0000-\u001f\u007f]/.test(target) || /^[A-Za-z][A-Za-z\d+.-]*:/.test(target)) return target;
1829
- const suffixAt = target.search(/[?#]/);
1830
- const pathname = suffixAt < 0 ? target : target.slice(0, suffixAt);
1831
- const suffix = suffixAt < 0 ? "" : target.slice(suffixAt);
1832
- if (!pathname || pathname.startsWith("//") || pathname.split("/").some((part) => /%2f|%5c/i.test(part))) return target;
1827
+ const rewrite = (target2) => {
1828
+ if (!target2 || target2.startsWith("/") || target2.startsWith("#") || target2.startsWith("?") || target2.includes("\\") || /[\u0000-\u001f\u007f]/.test(target2) || /^[A-Za-z][A-Za-z\d+.-]*:/.test(target2)) return target2;
1829
+ const suffixAt = target2.search(/[?#]/);
1830
+ const pathname = suffixAt < 0 ? target2 : target2.slice(0, suffixAt);
1831
+ const suffix = suffixAt < 0 ? "" : target2.slice(suffixAt);
1832
+ if (!pathname || pathname.startsWith("//") || pathname.split("/").some((part) => /%2f|%5c/i.test(part))) return target2;
1833
1833
  const source = posix.normalize(posix.join(posix.dirname(currentSourcePath.replace(/\\/g, "/")), pathname));
1834
1834
  const candidates = /\.mdx?$/i.test(source) ? [source] : [source, `${source}.mdx`, `${source}.md`, `${source}/index.mdx`, `${source}/index.md`];
1835
1835
  const route = candidates.map((candidate) => routesBySourcePath.get(candidate)).find(Boolean);
1836
- return route ? `/${route.replace(/^\/+/, "")}${suffix}` : target;
1836
+ return route ? `/${route.replace(/^\/+/, "")}${suffix}` : target2;
1837
1837
  };
1838
- return replaceOutsideCode(body, (text2) => text2.replace(
1838
+ return replaceOutsideCode(body, (text3) => text3.replace(
1839
1839
  /(\]\()(<[^>\n]+>|[^\s)]+)(?=\s|\))/g,
1840
- (_match, opening, target) => `${opening}${target.startsWith("<") && target.endsWith(">") ? `<${rewrite(target.slice(1, -1))}>` : rewrite(target)}`
1840
+ (_match, opening, target2) => `${opening}${target2.startsWith("<") && target2.endsWith(">") ? `<${rewrite(target2.slice(1, -1))}>` : rewrite(target2)}`
1841
1841
  ).replace(
1842
1842
  /(\b(?:href|to)\s*=\s*)(["'])([^"'\n]+)\2/g,
1843
- (_match, opening, quote, target) => `${opening}${quote}${rewrite(target)}${quote}`
1843
+ (_match, opening, quote, target2) => `${opening}${quote}${rewrite(target2)}${quote}`
1844
1844
  ).replace(
1845
1845
  /(\b(?:href|to)\s*=\s*\{\s*)(["'])([^"'\n]+)\2(?=\s*\})/g,
1846
- (_match, opening, quote, target) => `${opening}${quote}${rewrite(target)}${quote}`
1846
+ (_match, opening, quote, target2) => `${opening}${quote}${rewrite(target2)}${quote}`
1847
1847
  ));
1848
1848
  }
1849
1849
  function normalizeFernFileTrees(body) {
@@ -2302,12 +2302,12 @@ function maskCodeRegions(body) {
2302
2302
  }).join("\n");
2303
2303
  }
2304
2304
  var UNTERMINATED = "unterminated";
2305
- function readTagEnd(text2, from) {
2306
- if (from < text2.length && !/[\s/>]/.test(text2[from])) return null;
2305
+ function readTagEnd(text3, from) {
2306
+ if (from < text3.length && !/[\s/>]/.test(text3[from])) return null;
2307
2307
  let depth = 0;
2308
2308
  let quote = "";
2309
- for (let i = from; i < text2.length; i++) {
2310
- const char = text2[i];
2309
+ for (let i = from; i < text3.length; i++) {
2310
+ const char = text3[i];
2311
2311
  if (quote) {
2312
2312
  if (char === "\\" && depth > 0) i++;
2313
2313
  else if (char === quote) quote = "";
@@ -2320,8 +2320,8 @@ function readTagEnd(text2, from) {
2320
2320
  } else if (depth === 0) {
2321
2321
  if (char === "<") return null;
2322
2322
  if (char === ">") {
2323
- const selfClosing = text2[i - 1] === "/" && i > from;
2324
- return { end: i + 1, selfClosing, attributes: text2.slice(from, selfClosing ? i - 1 : i) };
2323
+ const selfClosing = text3[i - 1] === "/" && i > from;
2324
+ return { end: i + 1, selfClosing, attributes: text3.slice(from, selfClosing ? i - 1 : i) };
2325
2325
  }
2326
2326
  }
2327
2327
  }
@@ -2467,7 +2467,7 @@ function removeUndefinedExpressions(body, warn) {
2467
2467
  visit(tree);
2468
2468
  if (edits.length === 0) return body;
2469
2469
  warn?.(`Expressions that use ${[...removed].map((name) => `"${name}"`).join(", ")} were removed so the page builds: ${removed.size === 1 ? "the name is" : "the names are"} not defined on this page. Define ${removed.size === 1 ? "the name" : "the names"} or escape the braces as \\{ \\} to show the text.`);
2470
- return edits.sort((a, b) => b.start - a.start).reduce((text2, edit) => text2.slice(0, edit.start) + text2.slice(edit.end), body);
2470
+ return edits.sort((a, b) => b.start - a.start).reduce((text3, edit) => text3.slice(0, edit.start) + text3.slice(edit.end), body);
2471
2471
  }
2472
2472
  function normalizeFlowParagraphContainers(body) {
2473
2473
  if (!body.includes("<p")) return body;
@@ -2493,7 +2493,7 @@ function normalizeFlowParagraphContainers(body) {
2493
2493
  for (const child of node.children ?? []) visit(child);
2494
2494
  }
2495
2495
  visit(tree);
2496
- return edits.sort((a, b) => b.offset - a.offset).reduce((text2, edit) => text2.slice(0, edit.offset) + edit.value + text2.slice(edit.offset + 1), body);
2496
+ return edits.sort((a, b) => b.offset - a.offset).reduce((text3, edit) => text3.slice(0, edit.offset) + edit.value + text3.slice(edit.offset + 1), body);
2497
2497
  }
2498
2498
  function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
2499
2499
  const runFern = platform === "fern";
@@ -2895,7 +2895,7 @@ const MintlifyComponents = {
2895
2895
  }
2896
2896
  function applyReplacements(source, replacements) {
2897
2897
  return replacements.sort((a, b) => b.start - a.start).reduce(
2898
- (text2, edit) => text2.slice(0, edit.start) + edit.value + text2.slice(edit.end),
2898
+ (text3, edit) => text3.slice(0, edit.start) + edit.value + text3.slice(edit.end),
2899
2899
  source
2900
2900
  );
2901
2901
  }
@@ -3301,14 +3301,14 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
3301
3301
  }
3302
3302
  return;
3303
3303
  }
3304
- const text2 = content.toString("utf8");
3305
- const syntax = ts2.transpileModule(text2, {
3304
+ const text3 = content.toString("utf8");
3305
+ const syntax = ts2.transpileModule(text3, {
3306
3306
  fileName: path.replace(/\.d\.ts$/, ".ts"),
3307
3307
  reportDiagnostics: true,
3308
3308
  compilerOptions: { jsx: ts2.JsxEmit.Preserve, target: ts2.ScriptTarget.ESNext, module: ts2.ModuleKind.ESNext }
3309
3309
  });
3310
3310
  if (syntax.diagnostics?.some((diagnostic) => diagnostic.category === ts2.DiagnosticCategory.Error)) throw new Error("component source contains unsupported JavaScript or TypeScript syntax");
3311
- const ast = sourceFile(text2, path);
3311
+ const ast = sourceFile(text3, path);
3312
3312
  if (ast.statements.some((statement) => ts2.isExpressionStatement(statement) && ts2.isStringLiteral(statement.expression) && statement.expression.text === "use server")) throw new Error("server-only component modules require manual migration");
3313
3313
  const edits = [];
3314
3314
  const dependencies = [];
@@ -3346,10 +3346,10 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
3346
3346
  if (!specifier.startsWith(".") && !specifier.startsWith("/")) {
3347
3347
  throw new Error(specifier.startsWith("@/") ? `path alias ${specifier} points to source-site code the migration does not copy` : `external package ${specifier} requires manual installation and review`);
3348
3348
  }
3349
- const target = resolveDependency(specifier, path);
3350
- visit(target);
3351
- dependencies.push(outputPath(target));
3352
- const nextPath = relative2(dirname(destination), outputPath(target)).replace(/\\/g, "/");
3349
+ const target2 = resolveDependency(specifier, path);
3350
+ visit(target2);
3351
+ dependencies.push(outputPath(target2));
3352
+ const nextPath = relative2(dirname(destination), outputPath(target2)).replace(/\\/g, "/");
3353
3353
  edits.push({ start: literal.getStart(ast), end: literal.end, value: JSON.stringify(portableSpecifier(nextPath.startsWith(".") ? nextPath : `./${nextPath}`)) });
3354
3354
  }
3355
3355
  function inspect(node) {
@@ -3364,7 +3364,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
3364
3364
  ts2.forEachChild(node, inspect);
3365
3365
  }
3366
3366
  inspect(ast);
3367
- const replaced = applyReplacements(text2, edits);
3367
+ const replaced = applyReplacements(text3, edits);
3368
3368
  const shebangMatch = /^#!.*\r?\n/.exec(replaced);
3369
3369
  modules.set(destination, {
3370
3370
  local: needsClientBoundary(ast),
@@ -3915,10 +3915,10 @@ ${inlineSource}` });
3915
3915
  const start = node.position.start.offset;
3916
3916
  const end = node.position.end.offset;
3917
3917
  if (extracted.some((item) => start >= item.node.position.start.offset && end <= item.node.position.end.offset)) return;
3918
- const text2 = content.slice(start, end);
3919
- const opening = text2.indexOf(`<${node.name}`);
3918
+ const text3 = content.slice(start, end);
3919
+ const opening = text3.indexOf(`<${node.name}`);
3920
3920
  if (opening >= 0) edits.push({ start: start + opening + 1, end: start + opening + 1 + node.name.length, value: replacement });
3921
- const closing = text2.lastIndexOf(`</${node.name}`);
3921
+ const closing = text3.lastIndexOf(`</${node.name}`);
3922
3922
  if (closing >= 0) edits.push({ start: start + closing + 2, end: start + closing + 2 + node.name.length, value: replacement });
3923
3923
  });
3924
3924
  walk(tree, (node) => {
@@ -4210,8 +4210,8 @@ function cssBrandVars(css) {
4210
4210
  if (prelude.startsWith("@")) continue;
4211
4211
  for (const selector of prelude.split(",")) {
4212
4212
  const name = selector.trim().toLowerCase();
4213
- const target = name === ":root" || name === "html" ? root : name === ".dark" || name === "html.dark" || name === ":root.dark" ? dark : void 0;
4214
- if (target) declarations(source.slice(open + 1, close - 1), target);
4213
+ const target2 = name === ":root" || name === "html" ? root : name === ".dark" || name === "html.dark" || name === ":root.dark" ? dark : void 0;
4214
+ if (target2) declarations(source.slice(open + 1, close - 1), target2);
4215
4215
  }
4216
4216
  }
4217
4217
  return { root, dark };
@@ -4379,9 +4379,9 @@ function jsonPointer(root, pointer) {
4379
4379
  const index = Number(token);
4380
4380
  return Number.isSafeInteger(index) && index >= 0 ? current[index] : void 0;
4381
4381
  }
4382
- const object = objectValue2(current);
4383
- if (!object) return void 0;
4384
- return object[token.replace(/~1/g, "/").replace(/~0/g, "~")];
4382
+ const object2 = objectValue2(current);
4383
+ if (!object2) return void 0;
4384
+ return object2[token.replace(/~1/g, "/").replace(/~0/g, "~")];
4385
4385
  }, root);
4386
4386
  }
4387
4387
  function readMintlifyJson(path, repositoryRoot) {
@@ -4400,22 +4400,22 @@ function resolveJsonReferences(value, currentFile, repositoryRoot, stack) {
4400
4400
  if (Array.isArray(value)) {
4401
4401
  return value.map((entry) => resolveJsonReferences(entry, currentFile, repositoryRoot, stack));
4402
4402
  }
4403
- const object = objectValue2(value);
4404
- if (!object) return value;
4405
- if (typeof object.$ref === "string") {
4406
- const [filePart, pointer = ""] = object.$ref.split("#", 2);
4403
+ const object2 = objectValue2(value);
4404
+ if (!object2) return value;
4405
+ if (typeof object2.$ref === "string") {
4406
+ const [filePart, pointer = ""] = object2.$ref.split("#", 2);
4407
4407
  const referencedFile = filePart ? resolveWithin(dirname2(currentFile), filePart) : currentFile;
4408
4408
  const relativePath = relative3(repositoryRoot, referencedFile);
4409
4409
  resolveWithin(repositoryRoot, relativePath);
4410
4410
  const stackKey = `${referencedFile}#${pointer}`;
4411
- if (stack.has(stackKey)) throw new Error(`Circular Mintlify $ref: ${object.$ref}`);
4411
+ if (stack.has(stackKey)) throw new Error(`Circular Mintlify $ref: ${object2.$ref}`);
4412
4412
  stack.add(stackKey);
4413
4413
  const referencedRoot = readMintlifyJson(referencedFile, repositoryRoot);
4414
4414
  const referenced = jsonPointer(referencedRoot, pointer ? `#${pointer}` : "");
4415
4415
  const resolved = resolveJsonReferences(referenced, referencedFile, repositoryRoot, stack);
4416
4416
  stack.delete(stackKey);
4417
4417
  const siblings = Object.fromEntries(
4418
- Object.entries(object).filter(([key]) => key !== "$ref").map(([key, entry]) => [
4418
+ Object.entries(object2).filter(([key]) => key !== "$ref").map(([key, entry]) => [
4419
4419
  key,
4420
4420
  resolveJsonReferences(entry, currentFile, repositoryRoot, stack)
4421
4421
  ])
@@ -4423,7 +4423,7 @@ function resolveJsonReferences(value, currentFile, repositoryRoot, stack) {
4423
4423
  return objectValue2(resolved) ? { ...resolved, ...siblings } : resolved;
4424
4424
  }
4425
4425
  return Object.fromEntries(
4426
- Object.entries(object).map(([key, entry]) => [
4426
+ Object.entries(object2).map(([key, entry]) => [
4427
4427
  key,
4428
4428
  resolveJsonReferences(entry, currentFile, repositoryRoot, stack)
4429
4429
  ])
@@ -4473,9 +4473,9 @@ function mintlifyNavigationApiReferences(config) {
4473
4473
  const entries = node[key];
4474
4474
  if (!Array.isArray(entries)) continue;
4475
4475
  for (const entry of entries) {
4476
- const object = objectValue2(entry);
4477
- if (!object) continue;
4478
- visit(object, labelFor(object, tabLabel ?? "Documentation"));
4476
+ const object2 = objectValue2(entry);
4477
+ if (!object2) continue;
4478
+ visit(object2, labelFor(object2, tabLabel ?? "Documentation"));
4479
4479
  }
4480
4480
  }
4481
4481
  for (const key of nestedKeys) {
@@ -4483,15 +4483,15 @@ function mintlifyNavigationApiReferences(config) {
4483
4483
  if (!Array.isArray(entries)) continue;
4484
4484
  for (const entry of entries) {
4485
4485
  if (typeof entry === "string") continue;
4486
- const object = objectValue2(entry);
4487
- if (object) visit(object, tabLabel);
4486
+ const object2 = objectValue2(entry);
4487
+ if (object2) visit(object2, tabLabel);
4488
4488
  }
4489
4489
  }
4490
4490
  if (Array.isArray(node.menu)) {
4491
4491
  const tab = tabLabel ?? "Documentation";
4492
4492
  const items = node.menu.flatMap((entry) => {
4493
- const object = objectValue2(entry);
4494
- return object ? [object] : [];
4493
+ const object2 = objectValue2(entry);
4494
+ return object2 ? [object2] : [];
4495
4495
  });
4496
4496
  const apiItems = items.filter((item) => specSource(item.openapi) || specSource(item.asyncapi));
4497
4497
  const soleContent = apiItems.length === 1 && !hasNavigationChildren(node) && !items.some(hasNavigationChildren);
@@ -4546,11 +4546,11 @@ function collectGatedSourceRefs(node, gate, out, limits, depth = 0) {
4546
4546
  for (const item of node) collectGatedSourceRefs(item, gate, out, limits, depth + 1);
4547
4547
  return;
4548
4548
  }
4549
- const object = objectValue2(node);
4550
- if (!object) return;
4551
- const reason = gate ?? navigationGateReason(object);
4552
- if (reason && typeof object.sourceRef === "string") out.set(object, reason);
4553
- for (const value of Object.values(object)) collectGatedSourceRefs(value, reason, out, limits, depth + 1);
4549
+ const object2 = objectValue2(node);
4550
+ if (!object2) return;
4551
+ const reason = gate ?? navigationGateReason(object2);
4552
+ if (reason && typeof object2.sourceRef === "string") out.set(object2, reason);
4553
+ for (const value of Object.values(object2)) collectGatedSourceRefs(value, reason, out, limits, depth + 1);
4554
4554
  }
4555
4555
  function collectReferenceAccess(node, access, pathPrefix, out, depth = 0) {
4556
4556
  if (depth > SWEEP_DEPTH_LIMIT) return;
@@ -4558,20 +4558,20 @@ function collectReferenceAccess(node, access, pathPrefix, out, depth = 0) {
4558
4558
  for (const item of node) collectReferenceAccess(item, access, pathPrefix, out, depth + 1);
4559
4559
  return;
4560
4560
  }
4561
- const object = objectValue2(node);
4562
- if (!object) return;
4563
- const nested = descendNavigationAccess(access, navigationAccess(object));
4561
+ const object2 = objectValue2(node);
4562
+ if (!object2) return;
4563
+ const nested = descendNavigationAccess(access, navigationAccess(object2));
4564
4564
  if (hasNavigationRules(nested)) {
4565
- const refs = [object.page, object.root, object.href, ...Array.isArray(object.pages) ? object.pages : []];
4565
+ const refs = [object2.page, object2.root, object2.href, ...Array.isArray(object2.pages) ? object2.pages : []];
4566
4566
  for (const ref of refs) {
4567
4567
  if (typeof ref === "string" && normalizePageRef(ref, pathPrefix)) out.push({ ref, access: nested });
4568
4568
  }
4569
4569
  }
4570
- for (const value of Object.values(object)) collectReferenceAccess(value, nested, pathPrefix, out, depth + 1);
4570
+ for (const value of Object.values(object2)) collectReferenceAccess(value, nested, pathPrefix, out, depth + 1);
4571
4571
  }
4572
- function withContainerAccess(object, context, walk2) {
4572
+ function withContainerAccess(object2, context, walk2) {
4573
4573
  const outer = context.access;
4574
- context.access = descendNavigationAccess(outer, navigationAccess(object));
4574
+ context.access = descendNavigationAccess(outer, navigationAccess(object2));
4575
4575
  try {
4576
4576
  return walk2();
4577
4577
  } finally {
@@ -4624,9 +4624,9 @@ function convertPage(value, context) {
4624
4624
  }
4625
4625
  return registerReference(value, context);
4626
4626
  }
4627
- const object = objectValue2(value);
4628
- if (!object) return null;
4629
- return withContainerAccess(object, context, () => convertPageObject(object, context));
4627
+ const object2 = objectValue2(value);
4628
+ if (!object2) return null;
4629
+ return withContainerAccess(object2, context, () => convertPageObject(object2, context));
4630
4630
  }
4631
4631
  function gatedSourceRef(repo, context) {
4632
4632
  if (!context.gatedSourceRefs.includes(repo)) context.gatedSourceRefs.push(repo);
@@ -4637,10 +4637,10 @@ function gatedSourceRef(repo, context) {
4637
4637
  );
4638
4638
  return null;
4639
4639
  }
4640
- function convertPageObject(object, context) {
4641
- if (typeof object.page === "string") return registerReference(object.page, context);
4642
- const href = projectedHref(object.href);
4643
- if (href && !object.pages && !object.groups) {
4640
+ function convertPageObject(object2, context) {
4641
+ if (typeof object2.page === "string") return registerReference(object2.page, context);
4642
+ const href = projectedHref(object2.href);
4643
+ if (href && !object2.pages && !object2.groups) {
4644
4644
  const page = registerReference(href, context);
4645
4645
  if (page) return page;
4646
4646
  warnOnce(
@@ -4650,25 +4650,25 @@ function convertPageObject(object, context) {
4650
4650
  );
4651
4651
  return null;
4652
4652
  }
4653
- if (typeof object.sourceRef === "string") {
4654
- if (isNavigationRestricted(context.access) || context.gatedNodes.has(object) || context.limits.tooDeep) return gatedSourceRef(object.sourceRef, context);
4655
- const imported = context.resolveSourceRef?.(object.sourceRef);
4656
- if (imported) return { group: object.sourceRef.split("/").pop() ?? object.sourceRef, pages: imported };
4653
+ if (typeof object2.sourceRef === "string") {
4654
+ if (isNavigationRestricted(context.access) || context.gatedNodes.has(object2) || context.limits.tooDeep) return gatedSourceRef(object2.sourceRef, context);
4655
+ const imported = context.resolveSourceRef?.(object2.sourceRef);
4656
+ if (imported) return { group: object2.sourceRef.split("/").pop() ?? object2.sourceRef, pages: imported };
4657
4657
  const where = context.groupLabel ? `the "${context.groupLabel}" navigation group` : "the navigation";
4658
4658
  warnOnce(
4659
4659
  context,
4660
- `source-ref:${context.groupLabel ?? ""}:${object.sourceRef}`,
4661
- `Navigation in ${where} mounts the docs of the repository ${object.sourceRef} (sourceRef). Those pages were not migrated; pass --source-ref ${object.sourceRef}=<path> to import them.`
4660
+ `source-ref:${context.groupLabel ?? ""}:${object2.sourceRef}`,
4661
+ `Navigation in ${where} mounts the docs of the repository ${object2.sourceRef} (sourceRef). Those pages were not migrated; pass --source-ref ${object2.sourceRef}=<path> to import them.`
4662
4662
  );
4663
4663
  return null;
4664
4664
  }
4665
- const pages = Array.isArray(object.pages) ? object.pages : [];
4666
- if ("group" in object || pages.length > 0) {
4665
+ const pages = Array.isArray(object2.pages) ? object2.pages : [];
4666
+ if ("group" in object2 || pages.length > 0) {
4667
4667
  const children = [];
4668
4668
  const outerGroupLabel = context.groupLabel;
4669
- context.groupLabel = labelFor(object, "Documentation");
4670
- if (typeof object.root === "string") {
4671
- const root = registerReference(object.root, context);
4669
+ context.groupLabel = labelFor(object2, "Documentation");
4670
+ if (typeof object2.root === "string") {
4671
+ const root = registerReference(object2.root, context);
4672
4672
  if (root) children.push(root);
4673
4673
  }
4674
4674
  try {
@@ -4688,9 +4688,9 @@ function convertPageObject(object, context) {
4688
4688
  }
4689
4689
  if (children.length === 0) return null;
4690
4690
  return {
4691
- group: labelFor(object, "Documentation"),
4692
- ...iconName(object.icon) ? { icon: iconName(object.icon) } : {},
4693
- ...object.hidden === true ? { hidden: true } : {},
4691
+ group: labelFor(object2, "Documentation"),
4692
+ ...iconName(object2.icon) ? { icon: iconName(object2.icon) } : {},
4693
+ ...object2.hidden === true ? { hidden: true } : {},
4694
4694
  pages: children
4695
4695
  };
4696
4696
  }
@@ -4780,37 +4780,37 @@ function convertContainerToTabs(containerValue, context, fallbackTab, trace, dep
4780
4780
  entries.sort((left, right) => Number(objectValue2(right)?.default === true) - Number(objectValue2(left)?.default === true));
4781
4781
  }
4782
4782
  const tabs = entries.flatMap((value, index) => {
4783
- const object = objectValue2(value);
4784
- if (!object) return [];
4785
- const tab = labelFor(object, `${fallbackTab} ${index + 1}`);
4786
- const href = projectedHref(object.href);
4787
- const hasNestedContainers = [...containerKeys, "menu"].some((containerKey) => Array.isArray(object[containerKey]));
4788
- if (href && !object.pages && !object.groups && !hasNestedContainers) {
4783
+ const object2 = objectValue2(value);
4784
+ if (!object2) return [];
4785
+ const tab = labelFor(object2, `${fallbackTab} ${index + 1}`);
4786
+ const href = projectedHref(object2.href);
4787
+ const hasNestedContainers = [...containerKeys, "menu"].some((containerKey) => Array.isArray(object2[containerKey]));
4788
+ if (href && !object2.pages && !object2.groups && !hasNestedContainers) {
4789
4789
  return [{
4790
4790
  tab,
4791
4791
  href,
4792
- ...containerPresentation(object),
4793
- ...object.hidden === true ? { hidden: true } : {}
4792
+ ...containerPresentation(object2),
4793
+ ...object2.hidden === true ? { hidden: true } : {}
4794
4794
  }];
4795
4795
  }
4796
- const nested = withContainerAccess(object, context, () => convertContainerToTabs(object, context, tab, trace, depth + 1));
4796
+ const nested = withContainerAccess(object2, context, () => convertContainerToTabs(object2, context, tab, trace, depth + 1));
4797
4797
  if (nested.length > 0) {
4798
4798
  if (nested.length === 1) {
4799
4799
  return [{
4800
4800
  ...nested[0],
4801
4801
  tab,
4802
- ...containerPresentation(object),
4802
+ ...containerPresentation(object2),
4803
4803
  ...href ? { href } : {},
4804
- ...object.hidden === true ? { hidden: true } : {}
4804
+ ...object2.hidden === true ? { hidden: true } : {}
4805
4805
  }];
4806
4806
  }
4807
- const presentation = containerPresentation(object);
4807
+ const presentation = containerPresentation(object2);
4808
4808
  return nested.map((item, childIndex) => ({
4809
4809
  ...presentation,
4810
4810
  ...item,
4811
4811
  tab: `${tab}: ${item.tab}`,
4812
4812
  ...childIndex === 0 && href && !item.href ? { href } : {},
4813
- ...object.hidden === true ? { hidden: true } : {}
4813
+ ...object2.hidden === true ? { hidden: true } : {}
4814
4814
  }));
4815
4815
  }
4816
4816
  return [];
@@ -5497,9 +5497,9 @@ function announcementMarkdown(message) {
5497
5497
  links.set(marker, destination && label ? `[${escapeText(label)}](${destination})` : escapeText(label));
5498
5498
  document(element).replaceWith(marker);
5499
5499
  });
5500
- let text2 = escapeText(document("body").text());
5501
- for (const [marker, link] of links) text2 = text2.replaceAll(marker, link);
5502
- return text2.trim();
5500
+ let text3 = escapeText(document("body").text());
5501
+ for (const [marker, link] of links) text3 = text3.replaceAll(marker, link);
5502
+ return text3.trim();
5503
5503
  }
5504
5504
  function objectValue3(value) {
5505
5505
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -5595,8 +5595,8 @@ function registerPageAt(rawPath, base, context, navTitle, hidden = false) {
5595
5595
  context.sourcePathToNavigationId.set(sourcePath, navigationId);
5596
5596
  return navigationId;
5597
5597
  }
5598
- function registerFolder(object, parentSegments, context) {
5599
- const rawPath = String(object.folder).trim();
5598
+ function registerFolder(object2, parentSegments, context) {
5599
+ const rawPath = String(object2.folder).trim();
5600
5600
  let folder;
5601
5601
  try {
5602
5602
  folder = withinRealRoot(resolveWithinRoot(
@@ -5612,8 +5612,8 @@ function registerFolder(object, parentSegments, context) {
5612
5612
  warnOnce2(context, `fern-missing-folder-${rawPath}`, `Fern folder "${rawPath}" does not exist and was skipped.`);
5613
5613
  return null;
5614
5614
  }
5615
- const label = typeof object.title === "string" && object.title.trim() ? object.title.trim() : titleCase2(basename2(folder));
5616
- const segment = typeof object.slug === "string" || object["skip-slug"] === true ? segmentFor(object, label, context) : fernBasicSlug(basename2(folder));
5615
+ const label = typeof object2.title === "string" && object2.title.trim() ? object2.title.trim() : titleCase2(basename2(folder));
5616
+ const segment = typeof object2.slug === "string" || object2["skip-slug"] === true ? segmentFor(object2, label, context) : fernBasicSlug(basename2(folder));
5617
5617
  const segments = segment ? [...parentSegments, segment] : parentSegments;
5618
5618
  const visit = (directory, routeSegments, depth) => {
5619
5619
  if (depth > 12 || context.descriptors.length >= 5e3) {
@@ -5646,17 +5646,17 @@ function registerFolder(object, parentSegments, context) {
5646
5646
  addBareRouteRedirect(segments, pages, context);
5647
5647
  return { group: label, pages };
5648
5648
  }
5649
- function registerPage(object, parentSegments, context) {
5650
- if (typeof object.path !== "string" || !object.path.trim()) return null;
5651
- const label = typeof object.page === "string" && object.page.trim() ? object.page.trim() : "Untitled";
5652
- const segment = segmentFor(object, label, context);
5649
+ function registerPage(object2, parentSegments, context) {
5650
+ if (typeof object2.path !== "string" || !object2.path.trim()) return null;
5651
+ const label = typeof object2.page === "string" && object2.page.trim() ? object2.page.trim() : "Untitled";
5652
+ const segment = segmentFor(object2, label, context);
5653
5653
  const base = [...parentSegments, segment].filter(Boolean).join("/");
5654
- return registerPageAt(object.path, base, context, label, object.hidden === true) || null;
5654
+ return registerPageAt(object2.path, base, context, label, object2.hidden === true) || null;
5655
5655
  }
5656
- function isRestrictedNode(object) {
5657
- const viewers = object.viewers;
5656
+ function isRestrictedNode(object2) {
5657
+ const viewers = object2.viewers;
5658
5658
  if (Array.isArray(viewers) ? viewers.length > 0 : typeof viewers === "string" ? viewers.trim() !== "" : viewers !== void 0 && viewers !== null && viewers !== false) return true;
5659
- const authed = object.authed;
5659
+ const authed = object2.authed;
5660
5660
  return authed !== void 0 && authed !== null && authed !== false && !(typeof authed === "string" && ["", "false"].includes(authed.trim().toLowerCase()));
5661
5661
  }
5662
5662
  function restrictionMark(context) {
@@ -5667,67 +5667,67 @@ function markRestricted(context, mark) {
5667
5667
  context.restrictedApiSections.push(...context.apiSections.splice(mark.apis));
5668
5668
  }
5669
5669
  function convertNode(node, parentSegments, context) {
5670
- const object = objectValue3(node);
5671
- if (!object) return null;
5670
+ const object2 = objectValue3(node);
5671
+ if (!object2) return null;
5672
5672
  const walk2 = context.navigationWalk;
5673
- const reason = walk2.active.has(object) ? "cyclic section" : walk2.active.size >= 64 ? "section depth exceeds 64" : walk2.visits >= 5e3 ? "node budget exceeds 5000" : void 0;
5673
+ const reason = walk2.active.has(object2) ? "cyclic section" : walk2.active.size >= 64 ? "section depth exceeds 64" : walk2.visits >= 5e3 ? "node budget exceeds 5000" : void 0;
5674
5674
  if (reason) {
5675
5675
  walk2.incomplete = true;
5676
5676
  warnOnce2(context, `navigation-${reason}`, `Fern navigation was skipped: ${reason}.`);
5677
5677
  return null;
5678
5678
  }
5679
5679
  walk2.visits++;
5680
- walk2.active.add(object);
5680
+ walk2.active.add(object2);
5681
5681
  try {
5682
- if (isRestrictedNode(object)) {
5682
+ if (isRestrictedNode(object2)) {
5683
5683
  const before = restrictionMark(context);
5684
- convertNodeContents({ ...object, viewers: void 0, authed: void 0 }, parentSegments, context);
5684
+ convertNodeContents({ ...object2, viewers: void 0, authed: void 0 }, parentSegments, context);
5685
5685
  markRestricted(context, before);
5686
5686
  return null;
5687
5687
  }
5688
- return convertNodeContents(object, parentSegments, context);
5688
+ return convertNodeContents(object2, parentSegments, context);
5689
5689
  } finally {
5690
- walk2.active.delete(object);
5690
+ walk2.active.delete(object2);
5691
5691
  }
5692
5692
  }
5693
- function convertNodeContents(object, parentSegments, context) {
5694
- if (typeof object.page === "string") {
5695
- const page = registerPage(object, parentSegments, context);
5696
- return object.hidden === true || context.hiddenInherited ? null : page;
5693
+ function convertNodeContents(object2, parentSegments, context) {
5694
+ if (typeof object2.page === "string") {
5695
+ const page = registerPage(object2, parentSegments, context);
5696
+ return object2.hidden === true || context.hiddenInherited ? null : page;
5697
5697
  }
5698
- if (typeof object.folder === "string") {
5699
- const folder = registerFolder(object, parentSegments, object.hidden === true ? { ...context, hiddenInherited: true } : context);
5700
- return object.hidden === true || context.hiddenInherited ? null : folder;
5698
+ if (typeof object2.folder === "string") {
5699
+ const folder = registerFolder(object2, parentSegments, object2.hidden === true ? { ...context, hiddenInherited: true } : context);
5700
+ return object2.hidden === true || context.hiddenInherited ? null : folder;
5701
5701
  }
5702
- if (typeof object.section === "string") {
5703
- const label = object.section;
5704
- const segment = segmentFor(object, label, context);
5702
+ if (typeof object2.section === "string") {
5703
+ const label = object2.section;
5704
+ const segment = segmentFor(object2, label, context);
5705
5705
  const segments = segment ? [...parentSegments, segment] : parentSegments;
5706
- const contents = Array.isArray(object.contents) ? object.contents : [];
5706
+ const contents = Array.isArray(object2.contents) ? object2.contents : [];
5707
5707
  const pages = [];
5708
- const hasOwnPath = typeof object.path === "string" && object.path.trim().length > 0;
5708
+ const hasOwnPath = typeof object2.path === "string" && object2.path.trim().length > 0;
5709
5709
  if (hasOwnPath) {
5710
- const registered = registerPageAt(object.path, segments.join("/"), context, label, object.hidden === true);
5710
+ const registered = registerPageAt(object2.path, segments.join("/"), context, label, object2.hidden === true);
5711
5711
  if (registered) pages.push(registered);
5712
5712
  }
5713
5713
  for (const child of contents) {
5714
- const converted = convertNode(child, segments, object.hidden === true ? { ...context, hiddenInherited: true } : context);
5714
+ const converted = convertNode(child, segments, object2.hidden === true ? { ...context, hiddenInherited: true } : context);
5715
5715
  if (converted) pages.push(converted);
5716
5716
  }
5717
5717
  if (pages.length === 0) return null;
5718
5718
  if (!hasOwnPath && segment) addBareRouteRedirect(segments, pages, context);
5719
- if (object.hidden === true || context.hiddenInherited) return null;
5719
+ if (object2.hidden === true || context.hiddenInherited) return null;
5720
5720
  return {
5721
5721
  group: label,
5722
- ...["open-by-default", "closed-by-default", true, false].includes(object.collapsed) ? { defaultOpen: object.collapsed === "open-by-default" || object.collapsed === false } : {},
5723
- ...typeof object.icon === "string" ? { icon: object.icon } : {},
5724
- ...object.hidden === true ? { hidden: true } : {},
5722
+ ...["open-by-default", "closed-by-default", true, false].includes(object2.collapsed) ? { defaultOpen: object2.collapsed === "open-by-default" || object2.collapsed === false } : {},
5723
+ ...typeof object2.icon === "string" ? { icon: object2.icon } : {},
5724
+ ...object2.hidden === true ? { hidden: true } : {},
5725
5725
  pages
5726
5726
  };
5727
5727
  }
5728
- if (typeof object.link === "string") {
5729
- const label = object.link.trim();
5730
- const rawHref = typeof object.href === "string" ? object.href.trim() : "";
5728
+ if (typeof object2.link === "string") {
5729
+ const label = object2.link.trim();
5730
+ const rawHref = typeof object2.href === "string" ? object2.href.trim() : "";
5731
5731
  let href;
5732
5732
  if (/^https?:\/\//i.test(rawHref) && !/[\\\u0000-\u0020\u007f]/.test(rawHref)) {
5733
5733
  try {
@@ -5736,26 +5736,26 @@ function convertNodeContents(object, parentSegments, context) {
5736
5736
  } catch {
5737
5737
  }
5738
5738
  }
5739
- if (label && href && object.hidden !== true && !context.hiddenInherited) {
5739
+ if (label && href && object2.hidden !== true && !context.hiddenInherited) {
5740
5740
  if (!context.externalLinks.some((link) => link.label === label && link.href === href)) {
5741
5741
  context.externalLinks.push({ label, href });
5742
5742
  }
5743
- } else if (!href && object.hidden !== true && !context.hiddenInherited) {
5743
+ } else if (!href && object2.hidden !== true && !context.hiddenInherited) {
5744
5744
  warnOnce2(context, `fern-link-${rawHref}`, `Fern navigation link "${label}" has an unsafe or invalid external URL and was skipped.`);
5745
5745
  }
5746
5746
  return null;
5747
5747
  }
5748
- if (typeof object.api === "string") {
5749
- const ownSegment = segmentFor(object, object.api, context);
5748
+ if (typeof object2.api === "string") {
5749
+ const ownSegment = segmentFor(object2, object2.api, context);
5750
5750
  context.apiSections.push({
5751
- name: typeof object["api-name"] === "string" ? object["api-name"] : object.api,
5752
- nameExplicit: typeof object["api-name"] === "string",
5751
+ name: typeof object2["api-name"] === "string" ? object2["api-name"] : object2.api,
5752
+ nameExplicit: typeof object2["api-name"] === "string",
5753
5753
  routeSegments: ownSegment ? [...parentSegments, ownSegment] : parentSegments
5754
5754
  });
5755
5755
  return null;
5756
5756
  }
5757
- if (typeof object.changelog === "string") {
5758
- return registerFolder({ folder: object.changelog, title: "Changelog", "skip-slug": true }, parentSegments, context);
5757
+ if (typeof object2.changelog === "string") {
5758
+ return registerFolder({ folder: object2.changelog, title: "Changelog", "skip-slug": true }, parentSegments, context);
5759
5759
  }
5760
5760
  return null;
5761
5761
  }
@@ -6258,8 +6258,8 @@ function expandDocusaurusDocCardLists(pages, config, sourceRoutes) {
6258
6258
  const cards = group.pages.flatMap((item) => {
6259
6259
  if (typeof item === "string") {
6260
6260
  if (item === page.navigationId) return [];
6261
- const target = pageByRoute.get(item);
6262
- return [{ title: target?.title ?? item.split("/").at(-1) ?? item, route: item }];
6261
+ const target2 = pageByRoute.get(item);
6262
+ return [{ title: target2?.title ?? item.split("/").at(-1) ?? item, route: item }];
6263
6263
  }
6264
6264
  const slug2 = slugifySegment(item.group);
6265
6265
  const routes = [...item.pages].flatMap((child) => typeof child === "string" ? [child] : []);
@@ -6284,23 +6284,23 @@ function rewriteDocusaurusLinks(body, current, descriptors, options = {}) {
6284
6284
  if (sourceRoute) routes.set(sourceRoute, descriptor.navigationId);
6285
6285
  }
6286
6286
  const currentDirectory = posix3.dirname(sourceReferenceKey(current.sourcePath));
6287
- function copiedAssetTarget(target) {
6288
- if (!target.startsWith("/") || target.startsWith("//") || target.includes("\\")) return null;
6289
- const suffixIndex = target.search(/[?#]/);
6290
- const path = suffixIndex >= 0 ? target.slice(0, suffixIndex) : target;
6291
- const suffix = suffixIndex >= 0 ? target.slice(suffixIndex) : "";
6287
+ function copiedAssetTarget(target2) {
6288
+ if (!target2.startsWith("/") || target2.startsWith("//") || target2.includes("\\")) return null;
6289
+ const suffixIndex = target2.search(/[?#]/);
6290
+ const path = suffixIndex >= 0 ? target2.slice(0, suffixIndex) : target2;
6291
+ const suffix = suffixIndex >= 0 ? target2.slice(suffixIndex) : "";
6292
6292
  if (path.startsWith("/docs/") && options.assetPaths?.has(path.slice("/docs/".length))) {
6293
6293
  return `/${path.slice("/docs/".length)}${suffix}`;
6294
6294
  }
6295
- return options.assetPaths?.has(path.slice(1)) ? target : null;
6295
+ return options.assetPaths?.has(path.slice(1)) ? target2 : null;
6296
6296
  }
6297
- function rewriteTarget(target) {
6298
- if (!target || /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(target)) return target;
6299
- if (target.startsWith("#")) return target;
6300
- const suffixIndex = target.search(/[?#]/);
6301
- const path = suffixIndex >= 0 ? target.slice(0, suffixIndex) : target;
6302
- const suffix = suffixIndex >= 0 ? target.slice(suffixIndex) : "";
6303
- const copiedAsset = copiedAssetTarget(target);
6297
+ function rewriteTarget(target2) {
6298
+ if (!target2 || /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(target2)) return target2;
6299
+ if (target2.startsWith("#")) return target2;
6300
+ const suffixIndex = target2.search(/[?#]/);
6301
+ const path = suffixIndex >= 0 ? target2.slice(0, suffixIndex) : target2;
6302
+ const suffix = suffixIndex >= 0 ? target2.slice(suffixIndex) : "";
6303
+ const copiedAsset = copiedAssetTarget(target2);
6304
6304
  if (copiedAsset) return copiedAsset;
6305
6305
  const candidates = path.startsWith("/") ? [
6306
6306
  sourceReferenceKey(path),
@@ -6313,10 +6313,10 @@ function rewriteDocusaurusLinks(body, current, descriptors, options = {}) {
6313
6313
  const route = candidates.map((candidate) => routes.get(candidate)).find(Boolean);
6314
6314
  if (!route) {
6315
6315
  if (path.startsWith("/") && path !== "/" && options.sourceOrigin) {
6316
- options.onExternalLink?.(target);
6317
- return new URL(target, options.sourceOrigin).toString();
6316
+ options.onExternalLink?.(target2);
6317
+ return new URL(target2, options.sourceOrigin).toString();
6318
6318
  }
6319
- return target;
6319
+ return target2;
6320
6320
  }
6321
6321
  return `${route === "introduction" ? "/" : `/${route}`}${suffix}`;
6322
6322
  }
@@ -6329,10 +6329,10 @@ function rewriteDocusaurusLinks(body, current, descriptors, options = {}) {
6329
6329
  return line;
6330
6330
  }
6331
6331
  if (codeFence) return line;
6332
- return line.replace(/(\]\()([^\s)]+)(?=[\s)]|$)/g, (_match, prefix, target) => `${prefix}${rewriteTarget(target)}`).replace(/(\bhref=")([^"]+)(")/g, (_match, prefix, target, suffix) => `${prefix}${rewriteTarget(target)}${suffix}`).replace(/(\bsrc=")([^"]+)(")/g, (_match, prefix, target, suffix) => `${prefix}${copiedAssetTarget(target) ?? target}${suffix}`).replace(/^(\s{0,3}\[[^\]]+\]:\s*)(<[^>]+>|\S+)/, (_match, prefix, destination) => {
6332
+ return line.replace(/(\]\()([^\s)]+)(?=[\s)]|$)/g, (_match, prefix, target2) => `${prefix}${rewriteTarget(target2)}`).replace(/(\bhref=")([^"]+)(")/g, (_match, prefix, target2, suffix) => `${prefix}${rewriteTarget(target2)}${suffix}`).replace(/(\bsrc=")([^"]+)(")/g, (_match, prefix, target2, suffix) => `${prefix}${copiedAssetTarget(target2) ?? target2}${suffix}`).replace(/^(\s{0,3}\[[^\]]+\]:\s*)(<[^>]+>|\S+)/, (_match, prefix, destination) => {
6333
6333
  const bracketed = destination.startsWith("<") && destination.endsWith(">");
6334
- const target = bracketed ? destination.slice(1, -1) : destination;
6335
- const rewritten = rewriteTarget(target);
6334
+ const target2 = bracketed ? destination.slice(1, -1) : destination;
6335
+ const rewritten = rewriteTarget(target2);
6336
6336
  return `${prefix}${bracketed ? `<${rewritten}>` : rewritten}`;
6337
6337
  });
6338
6338
  }).join("\n");
@@ -6418,14 +6418,14 @@ function parseStaticSidebarModule(source) {
6418
6418
  literal
6419
6419
  );
6420
6420
  const parsed = JSON5.parse(substituted);
6421
- const object = objectValue4(parsed);
6422
- if (!object) continue;
6421
+ const object2 = objectValue4(parsed);
6422
+ if (!object2) continue;
6423
6423
  const bindingName = candidate[0].match(/\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)/)?.[1];
6424
6424
  if (bindingName) {
6425
- bindings.set(bindingName, object);
6425
+ bindings.set(bindingName, object2);
6426
6426
  continue;
6427
6427
  }
6428
- return object;
6428
+ return object2;
6429
6429
  } catch (error) {
6430
6430
  const message = error instanceof Error ? error.message : String(error);
6431
6431
  const line = Number(message.match(/at (\d+):/)?.[1] ?? 0);
@@ -6514,8 +6514,8 @@ function configuredSidebarPath(repositoryRoot) {
6514
6514
  if (!existsSync4(path)) continue;
6515
6515
  const source = readBoundedText(path);
6516
6516
  for (const docs of source.matchAll(/\bdocs\s*:\s*/g)) {
6517
- const object = matchingObjectLiteral(source, (docs.index ?? 0) + docs[0].length);
6518
- const candidate2 = object && staticStringField(object, "sidebarPath")?.replace(/^\.\//, "");
6517
+ const object2 = matchingObjectLiteral(source, (docs.index ?? 0) + docs[0].length);
6518
+ const candidate2 = object2 && staticStringField(object2, "sidebarPath")?.replace(/^\.\//, "");
6519
6519
  if (candidate2) {
6520
6520
  const resolved2 = withinRealRoot(resolveWithin(repositoryRoot, candidate2), repositoryRoot);
6521
6521
  if (existsSync4(resolved2) && lstatSync4(resolved2).isFile()) return candidate2;
@@ -6626,12 +6626,12 @@ function readCategoryMetadata(contentRoot, directory) {
6626
6626
  try {
6627
6627
  const raw = readBoundedText(path);
6628
6628
  const parsed = filename.endsWith(".json") ? JSON5.parse(raw) : parseYaml3(raw);
6629
- const object = objectValue4(parsed);
6630
- if (!object) return {};
6629
+ const object2 = objectValue4(parsed);
6630
+ if (!object2) return {};
6631
6631
  return {
6632
- ...typeof object.label === "string" ? { label: object.label } : {},
6633
- ...typeof object.position === "number" ? { position: object.position } : {},
6634
- ..."link" in object ? { link: object.link } : {}
6632
+ ...typeof object2.label === "string" ? { label: object2.label } : {},
6633
+ ...typeof object2.position === "number" ? { position: object2.position } : {},
6634
+ ..."link" in object2 ? { link: object2.link } : {}
6635
6635
  };
6636
6636
  } catch {
6637
6637
  return {};
@@ -6815,7 +6815,7 @@ function readDocusaurusSiteSettings(repositoryRoot) {
6815
6815
  const source = readBoundedText(configPath);
6816
6816
  const bindings = staticStringBindings(source);
6817
6817
  const presets = staticArrayField(source, "presets");
6818
- const classicDocs = presets && [...presets.matchAll(/["']?docs["']?\s*:\s*/g)].map((match) => matchingObjectLiteral(presets, (match.index ?? 0) + match[0].length)).find((object) => Boolean(object));
6818
+ const classicDocs = presets && [...presets.matchAll(/["']?docs["']?\s*:\s*/g)].map((match) => matchingObjectLiteral(presets, (match.index ?? 0) + match[0].length)).find((object2) => Boolean(object2));
6819
6819
  const docsRouteBasePath = classicDocs && staticStringField(classicDocs, "routeBasePath") || "docs";
6820
6820
  const themeStart = propertyStart(source, "themeConfig");
6821
6821
  const theme = themeStart < 0 ? null : matchingObjectLiteral(source, themeStart);
@@ -6938,24 +6938,24 @@ function convertItems(value, context) {
6938
6938
  return page ? [page] : [];
6939
6939
  }
6940
6940
  if (Array.isArray(value)) return value.flatMap((entry) => convertItems(entry, context));
6941
- const object = objectValue4(value);
6942
- if (!object) return [];
6943
- if (object.type === "doc" || object.type === "ref") {
6944
- const page = typeof object.id === "string" ? registerDoc(object.id, context) : null;
6941
+ const object2 = objectValue4(value);
6942
+ if (!object2) return [];
6943
+ if (object2.type === "doc" || object2.type === "ref") {
6944
+ const page = typeof object2.id === "string" ? registerDoc(object2.id, context) : null;
6945
6945
  return page ? [page] : [];
6946
6946
  }
6947
- if (object.type === "autogenerated") {
6948
- return autogeneratedItems(typeof object.dirName === "string" ? object.dirName : ".", context);
6947
+ if (object2.type === "autogenerated") {
6948
+ return autogeneratedItems(typeof object2.dirName === "string" ? object2.dirName : ".", context);
6949
6949
  }
6950
- if (object.type === "category") {
6951
- const label = typeof object.label === "string" ? object.label : "Documentation";
6952
- const pages = convertItems(object.items, context);
6953
- const landing = generatedIndexPage(label, object.link, context);
6950
+ if (object2.type === "category") {
6951
+ const label = typeof object2.label === "string" ? object2.label : "Documentation";
6952
+ const pages = convertItems(object2.items, context);
6953
+ const landing = generatedIndexPage(label, object2.link, context);
6954
6954
  if (landing && !pages.includes(landing)) pages.unshift(landing);
6955
6955
  return pages.length > 0 ? [{ group: label, pages }] : [];
6956
6956
  }
6957
- if (object.type === "link" || object.type === "html") return [];
6958
- return Object.entries(object).flatMap(([label, items]) => {
6957
+ if (object2.type === "link" || object2.type === "html") return [];
6958
+ return Object.entries(object2).flatMap(([label, items]) => {
6959
6959
  const pages = convertItems(items, context);
6960
6960
  return pages.length > 0 ? [{ group: label, pages }] : [];
6961
6961
  });
@@ -7047,9 +7047,9 @@ function readDocusaurusPresentation(repositoryRoot) {
7047
7047
  if (rule.parent?.type !== "root") return;
7048
7048
  for (const selector of rule.selector.split(",")) {
7049
7049
  const key = selector.trim();
7050
- const target = key === ":root" || key === "html" || /^(?:html)?\[data-theme=['"]?light['"]?\]$/.test(key) ? modes.light : /^(?:html)?\[data-theme=['"]?dark['"]?\]$/.test(key) || key === ".dark" ? modes.dark : void 0;
7051
- if (target) rule.walkDecls((decl) => {
7052
- if (decl.prop.startsWith("--ifm-")) target.set(decl.prop, decl.value);
7050
+ const target2 = key === ":root" || key === "html" || /^(?:html)?\[data-theme=['"]?light['"]?\]$/.test(key) ? modes.light : /^(?:html)?\[data-theme=['"]?dark['"]?\]$/.test(key) || key === ".dark" ? modes.dark : void 0;
7051
+ if (target2) rule.walkDecls((decl) => {
7052
+ if (decl.prop.startsWith("--ifm-")) target2.set(decl.prop, decl.value);
7053
7053
  });
7054
7054
  const banner = key === ".theme-announcement-bar" ? banners.light : /^(?:html)?\[data-theme=['"]?dark['"]?\] \.theme-announcement-bar$/.test(key) ? banners.dark : void 0;
7055
7055
  if (banner) rule.walkDecls((decl) => {
@@ -7072,9 +7072,9 @@ function readDocusaurusPresentation(repositoryRoot) {
7072
7072
  return raw ? cssColorToHex(raw) : void 0;
7073
7073
  };
7074
7074
  const mapped = { "--docs-bg": "--ifm-background-color", "--docs-ink": "--ifm-font-color-base", "--docs-ink-2": "--ifm-font-color-base", "--docs-accent": "--ifm-link-color" };
7075
- const declarations2 = (mode) => Object.entries(mapped).flatMap(([target, source]) => {
7075
+ const declarations2 = (mode) => Object.entries(mapped).flatMap(([target2, source]) => {
7076
7076
  const hex = color(source, mode);
7077
- return hex ? [`${target}:${hex}`] : [];
7077
+ return hex ? [`${target2}:${hex}`] : [];
7078
7078
  }).join(";");
7079
7079
  const heading = value("--ifm-heading-font-family", "light")?.trim();
7080
7080
  const headingFont = heading && /^[\w -]{1,80}$/.test(heading) ? heading : void 0;
@@ -7114,9 +7114,9 @@ function readDocusaurusPresentation(repositoryRoot) {
7114
7114
  const theme = literal ? JSON5.parse(literal) : null;
7115
7115
  const tokenNames = { keyword: "keyword", string: "string", comment: "comment", function: "function", property: "property", constant: "constant", punctuation: "punctuation", parameter: "parameter" };
7116
7116
  const colors = /* @__PURE__ */ new Map();
7117
- for (const [target, raw] of [["--shiki-color-text", theme?.plain?.color], ["--docs-code-bg", theme?.plain?.backgroundColor]]) {
7117
+ for (const [target2, raw] of [["--shiki-color-text", theme?.plain?.color], ["--docs-code-bg", theme?.plain?.backgroundColor]]) {
7118
7118
  const hex = typeof raw === "string" ? cssColorToHex(raw) : void 0;
7119
- if (hex && target) colors.set(target, hex);
7119
+ if (hex && target2) colors.set(target2, hex);
7120
7120
  }
7121
7121
  for (const style of theme?.styles ?? []) for (const type of Array.isArray(style.types) ? style.types : []) {
7122
7122
  const hex = typeof style.style?.color === "string" ? cssColorToHex(style.style.color) : void 0;
@@ -7209,10 +7209,10 @@ function withheldOperationKeys(spec, withheldRefs, keptRefs) {
7209
7209
  function markExcluded(content, operationKeys, keptKeys = []) {
7210
7210
  const untouched = { content, excluded: [] };
7211
7211
  if (operationKeys.length === 0) return untouched;
7212
- const text2 = content.toString("utf8");
7212
+ const text3 = content.toString("utf8");
7213
7213
  let doc;
7214
7214
  try {
7215
- doc = parseYaml4(text2);
7215
+ doc = parseYaml4(text3);
7216
7216
  } catch {
7217
7217
  return untouched;
7218
7218
  }
@@ -7231,14 +7231,14 @@ function markExcluded(content, operationKeys, keptKeys = []) {
7231
7231
  }
7232
7232
  const entry = doc.paths?.[name];
7233
7233
  if (!entry || typeof entry !== "object") continue;
7234
- const target = typeof entry.$ref === "string" ? keptKeys.some((k) => k.slice(k.indexOf(" ") + 1) === name) ? void 0 : entry : entry[method];
7235
- if (target && typeof target === "object") {
7236
- target["x-excluded"] = true;
7234
+ const target2 = typeof entry.$ref === "string" ? keptKeys.some((k) => k.slice(k.indexOf(" ") + 1) === name) ? void 0 : entry : entry[method];
7235
+ if (target2 && typeof target2 === "object") {
7236
+ target2["x-excluded"] = true;
7237
7237
  excluded.push(`${method.toUpperCase()} ${name}`);
7238
7238
  }
7239
7239
  }
7240
7240
  if (excluded.length === 0) return untouched;
7241
- const out = text2.trimStart().startsWith("{") ? `${JSON.stringify(doc, null, 2)}
7241
+ const out = text3.trimStart().startsWith("{") ? `${JSON.stringify(doc, null, 2)}
7242
7242
  ` : stringifyYaml(doc);
7243
7243
  return { content: Buffer.from(out), excluded };
7244
7244
  }
@@ -7580,7 +7580,12 @@ var LOCALE_CODES = /* @__PURE__ */ new Set([
7580
7580
  ]);
7581
7581
  var PORTABLE_URL_PROPS = "href|src|img|primaryHref|secondaryHref";
7582
7582
  var PORTABLE_URL_PROP_NAMES = new Set(PORTABLE_URL_PROPS.split("|"));
7583
+ var MINTLIFY_ARTICLE_LABELS = [
7584
+ { baseUrl: "Select base URL", permalink: "Navigate to header" },
7585
+ { baseUrl: "\u9009\u62E9\u57FA\u7840URL", permalink: "\u5BFC\u822A\u5230\u6807\u9898" }
7586
+ ];
7583
7587
  var remoteMarkdownParser = unified3().use(remarkParse3).use(remarkMdx3);
7588
+ var embeddedOpenApiParser = unified3().use(remarkParse3);
7584
7589
  function validateMigrationUrl(value) {
7585
7590
  let url;
7586
7591
  try {
@@ -7875,6 +7880,43 @@ function escapeMarkdownText(value, escapeTableSeparator = false) {
7875
7880
  }
7876
7881
  return escaped;
7877
7882
  }
7883
+ function portableMarkdownTableCell(value) {
7884
+ let output = "";
7885
+ let hasOddBackslashes = false;
7886
+ for (let index = 0; index < value.length; index += 1) {
7887
+ const character = value[index];
7888
+ if (character === "\\") {
7889
+ output += character;
7890
+ hasOddBackslashes = !hasOddBackslashes;
7891
+ continue;
7892
+ }
7893
+ if (character === "|" && !hasOddBackslashes) output += "\\";
7894
+ if (character === "\r" || character === "\n") {
7895
+ output += " ";
7896
+ if (character === "\r" && value[index + 1] === "\n") index += 1;
7897
+ } else output += character;
7898
+ hasOddBackslashes = false;
7899
+ }
7900
+ return output.trim();
7901
+ }
7902
+ function needsLiteralTableCode(value) {
7903
+ let hasOddBackslashes = false;
7904
+ for (const character of value) {
7905
+ if (character === "\\") hasOddBackslashes = !hasOddBackslashes;
7906
+ else {
7907
+ if (character === "|" && hasOddBackslashes) return true;
7908
+ hasOddBackslashes = false;
7909
+ }
7910
+ }
7911
+ return false;
7912
+ }
7913
+ function literalMdxCodeText(value) {
7914
+ let output = "";
7915
+ for (const character of value) {
7916
+ output += /[A-Za-z0-9 ]/.test(character) ? character : `&#${character.codePointAt(0)};`;
7917
+ }
7918
+ return output;
7919
+ }
7878
7920
  function markdownLinkDestination(value) {
7879
7921
  try {
7880
7922
  return encodeURI(value).replace(/\(/g, "%28").replace(/\)/g, "%29").replace(/&/g, "&amp;");
@@ -7962,6 +8004,11 @@ function sanitizeMarkdownUrls(value) {
7962
8004
  return;
7963
8005
  }
7964
8006
  if (node.type === "mdxJsxTextElement" || node.type === "mdxJsxFlowElement") {
8007
+ const isLiteralCode = node.type === "mdxJsxTextElement" && node.name === "code" && !node.attributes?.length && (node.children ?? []).every((child) => child.type === "text");
8008
+ if (!isLiteralCode && (!node.name || !PORTABLE_MDX_COMPONENTS.has(node.name))) {
8009
+ hasUnsafeMdxSyntax = true;
8010
+ return;
8011
+ }
7965
8012
  for (const attribute of node.attributes ?? []) {
7966
8013
  if (attribute.type !== "mdxJsxAttribute" || !attribute.name || /^on[A-Z]/.test(attribute.name)) {
7967
8014
  hasUnsafeMdxSyntax = true;
@@ -8122,22 +8169,18 @@ function sanitizeRemoteMarkdown(body) {
8122
8169
  }
8123
8170
  }).replace(/\\[{}]/g, "");
8124
8171
  if (hasUnsafeExpression || /[{}]/.test(withoutStaticProps) || /\bon[A-Z][A-Za-z]*\s*=/g.test(withoutStaticProps) || hasUnsafePortableUrlProp(executable)) return null;
8125
- for (const match of withoutStaticProps.matchAll(/<\/?([A-Za-z][A-Za-z0-9.]*)(?:\s|>|\/)/g)) {
8126
- const component = match[1].split(".", 1)[0];
8127
- if (!PORTABLE_MDX_COMPONENTS.has(component)) return null;
8128
- }
8129
8172
  return urlSafeMarkdown;
8130
8173
  }
8131
8174
  function migratedHref(href, currentUrl, source, scopePath, importedIds, sourceHomePageId) {
8132
8175
  if (/^(?:javascript|data|vbscript):/i.test(href)) return "#";
8133
8176
  if (href.startsWith("#") || /^(?:mailto|tel):/i.test(href)) return href;
8134
8177
  try {
8135
- const target = new URL(href, currentUrl);
8136
- if (target.origin !== source.origin) return href;
8137
- if (scopePath === "/" && candidateIdentity(target) === candidateIdentity(source)) {
8138
- return `/${target.search}${target.hash}`;
8178
+ const target2 = new URL(href, currentUrl);
8179
+ if (target2.origin !== source.origin) return href;
8180
+ if (scopePath === "/" && candidateIdentity(target2) === candidateIdentity(source)) {
8181
+ return `/${target2.search}${target2.hash}`;
8139
8182
  }
8140
- let path = target.pathname;
8183
+ let path = target2.pathname;
8141
8184
  if (scopePath !== "/" && (path === scopePath || path.startsWith(`${scopePath}/`))) {
8142
8185
  path = path.slice(scopePath.length);
8143
8186
  }
@@ -8150,9 +8193,9 @@ function migratedHref(href, currentUrl, source, scopePath, importedIds, sourceHo
8150
8193
  }
8151
8194
  if (importedDestinationId) {
8152
8195
  const destination = importedDestinationId === "introduction" ? "/" : `/${importedDestinationId}`;
8153
- return `${destination}${target.search}${target.hash}`;
8196
+ return `${destination}${target2.search}${target2.hash}`;
8154
8197
  }
8155
- return target.toString();
8198
+ return target2.toString();
8156
8199
  } catch {
8157
8200
  return href;
8158
8201
  }
@@ -8206,22 +8249,45 @@ function stripMintlifyDocumentationIndex(body) {
8206
8249
  return lines.slice(index).join("\n");
8207
8250
  }
8208
8251
  function extractEmbeddedOpenApi(content) {
8209
- const fencePattern = /^\s{0,3}(`{3,}|~{3,})(?:yaml|yml|json)\s+(\S+\.(?:yaml|yml|json))\s+(delete|get|head|options|patch|post|put|trace)\s+(\/\S+)\s*\r?\n([\s\S]*?)^\s{0,3}\1\s*$/im;
8210
- const match = fencePattern.exec(content);
8211
- if (!match) return { content };
8252
+ if (Buffer.byteLength(content, "utf8") > MAX_LOCAL_RESPONSE_BYTES) return { content };
8212
8253
  try {
8213
- const parsed = parseYaml5(match[5], { maxAliasCount: 50 });
8254
+ const root = embeddedOpenApiParser.parse(content);
8255
+ const candidates = (root.children ?? []).flatMap((node2) => {
8256
+ if (node2.type !== "code" || !/^(?:yaml|yml|json)$/i.test(node2.lang ?? "")) return [];
8257
+ const metadata = node2.meta?.match(/^(?:(\S+\.(?:yaml|yml|json))\s+)?(delete|get|head|options|patch|post|put|trace)\s+(\/\S+)\s*$/i);
8258
+ return metadata ? [{ node: node2, method: metadata[2].toUpperCase(), path: metadata[3] }] : [];
8259
+ });
8260
+ if (candidates.length !== 1) return { content };
8261
+ const { node, method, path } = candidates[0];
8262
+ const start = node.position?.start.offset;
8263
+ const end = node.position?.end.offset;
8264
+ if (start === void 0 || end === void 0) return { content };
8265
+ const lines = content.slice(start, end).split(/\r?\n/);
8266
+ const opening = lines[0].match(/^ {0,3}(`{3,}|~{3,})/);
8267
+ const closing = lines.at(-1)?.match(/^ {0,3}(`{3,}|~{3,})[\t ]*$/);
8268
+ if (!opening || !closing || opening[1][0] !== closing[1][0] || closing[1].length < opening[1].length) return { content };
8269
+ const parsed = parseYaml5(node.value ?? "", { maxAliasCount: 50 });
8214
8270
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return { content };
8215
8271
  const document = parsed;
8216
8272
  if (typeof document.openapi !== "string" && typeof document.swagger !== "string") return { content };
8217
- const method = match[3].toUpperCase();
8218
- const path = match[4];
8219
8273
  const paths = document.paths;
8220
8274
  if (!paths || typeof paths !== "object" || Array.isArray(paths)) return { content };
8275
+ if (!Object.prototype.hasOwnProperty.call(paths, path)) return { content };
8221
8276
  const pathItem = paths[path];
8222
- if (!pathItem || typeof pathItem !== "object" || Array.isArray(pathItem) || !(match[3].toLowerCase() in pathItem)) return { content };
8223
- const before = content.slice(0, match.index).replace(/(?:^|\n)##\s+OpenAPI\s*\n\s*$/i, "\n");
8224
- const after = content.slice(match.index + match[0].length);
8277
+ if (!pathItem || typeof pathItem !== "object" || Array.isArray(pathItem) || !Object.prototype.hasOwnProperty.call(pathItem, method.toLowerCase())) return { content };
8278
+ const operation = pathItem[method.toLowerCase()];
8279
+ if (!operation || typeof operation !== "object" || Array.isArray(operation)) return { content };
8280
+ let values = 0;
8281
+ let textLength = 0;
8282
+ const serialized = JSON.stringify(document, (_key, value) => {
8283
+ values += 1;
8284
+ if (typeof value === "string") textLength += value.length;
8285
+ if (values > 1e5 || textLength > MAX_LOCAL_RESPONSE_BYTES || typeof value === "number" && !Number.isFinite(value)) throw new Error("OpenAPI document exceeds portable data limits.");
8286
+ return value;
8287
+ });
8288
+ if (Buffer.byteLength(serialized, "utf8") > MAX_LOCAL_RESPONSE_BYTES) return { content };
8289
+ const before = content.slice(0, start).replace(/(?:^|\n)##\s+OpenAPI\s*\n\s*$/i, "\n");
8290
+ const after = content.slice(end);
8225
8291
  return {
8226
8292
  content: `${before}${after}`.trim(),
8227
8293
  openapi: `${method} ${path}`,
@@ -8272,15 +8338,15 @@ function markdownPage(document, id, platform, warn) {
8272
8338
  openApiFragment: embeddedOpenApi.fragment
8273
8339
  };
8274
8340
  }
8275
- function mergeRecord(target, source) {
8341
+ function mergeRecord(target2, source) {
8276
8342
  if (!source || typeof source !== "object" || Array.isArray(source)) return;
8277
8343
  for (const [key, value] of Object.entries(source)) {
8278
8344
  if (["__proto__", "constructor", "prototype"].includes(key)) continue;
8279
- if (!Object.prototype.hasOwnProperty.call(target, key)) {
8280
- target[key] = value;
8345
+ if (!Object.prototype.hasOwnProperty.call(target2, key)) {
8346
+ target2[key] = value;
8281
8347
  continue;
8282
8348
  }
8283
- const current = target[key];
8349
+ const current = target2[key];
8284
8350
  if (current && value && typeof current === "object" && typeof value === "object" && !Array.isArray(current) && !Array.isArray(value)) {
8285
8351
  mergeRecord(current, value);
8286
8352
  }
@@ -8326,14 +8392,74 @@ function mergeEmbeddedOpenApi(fragments) {
8326
8392
  if (tags.size > 0) combined.tags = [...tags.values()];
8327
8393
  return new TextEncoder().encode(stringifyYaml2(combined));
8328
8394
  }
8395
+ function migrationHtmlArticle(body) {
8396
+ const $ = load2(body);
8397
+ const root = ["main article", "article", "main", '[role="main"]', "body"].map((selector) => $(selector).first()).find((candidate) => candidate.length);
8398
+ root.find([
8399
+ "script",
8400
+ "style",
8401
+ "noscript",
8402
+ "nav",
8403
+ "footer",
8404
+ "aside",
8405
+ ".theme-doc-version-badge",
8406
+ ".theme-doc-breadcrumbs",
8407
+ ".theme-doc-toc-mobile",
8408
+ ".table-of-contents",
8409
+ ".chat-assistant-floating-input",
8410
+ ".chat-assistant-sheet",
8411
+ "#chat-assistant-sheet",
8412
+ "#chat-assistant-textarea"
8413
+ ].join(",")).remove();
8414
+ const permalinkSelectors = MINTLIFY_ARTICLE_LABELS.map((labels) => `a[aria-label="${labels.permalink}"]`);
8415
+ root.find([...permalinkSelectors, "h1 .hash-link", "h2 .hash-link", "h3 .hash-link", "h4 .hash-link", "h5 .hash-link", "h6 .hash-link"].join(",")).each((_index, link) => {
8416
+ const parent = $(link).parent();
8417
+ $(link).remove();
8418
+ if (parent.is("div") && !parent.text().trim() && parent.children().length === 0) parent.remove();
8419
+ });
8420
+ root.find('svg.lucide-chevrons-up-down,summary[data-component-part="expandable-button"] svg[data-component-part="icon-svg"]').remove();
8421
+ root.find('li.task-list-item > input[type="checkbox"][disabled]').each((_index, element) => {
8422
+ const isChecked = $(element).attr("checked") !== void 0;
8423
+ $(element).replaceWith($("<span></span>").attr("data-thally-static-task-checkbox", isChecked ? "checked" : "unchecked").text(isChecked ? "[x] " : "[ ] "));
8424
+ });
8425
+ root.find(MINTLIFY_ARTICLE_LABELS.map((labels) => `select[aria-label="${labels.baseUrl}"]`).join(",")).each((_index, element) => {
8426
+ const select = $(element);
8427
+ const options = select.children("option").toArray();
8428
+ if (!options.length || options.length !== select.children().length) return;
8429
+ const urls = [];
8430
+ for (const option of options) {
8431
+ if ($(option).children().length) return;
8432
+ const label = $(option).text().trim();
8433
+ if (!/^https:\/\//i.test(label) || /[\s\u0000-\u001f\u007f]/.test(label)) return;
8434
+ try {
8435
+ const url = new URL(label);
8436
+ if (url.protocol !== "https:" || url.username || url.password) return;
8437
+ urls.push({ label, href: url.href, isSelected: $(option).attr("selected") !== void 0 });
8438
+ } catch {
8439
+ return;
8440
+ }
8441
+ }
8442
+ const projection = $("<div data-thally-static-base-urls></div>");
8443
+ const sourceId = select.attr("id");
8444
+ if (sourceId) projection.attr("id", sourceId);
8445
+ projection.append($("<p></p>").text(select.attr("aria-label")));
8446
+ const list = $("<ul></ul>");
8447
+ for (const url of urls) {
8448
+ const item = $("<li></li>").append($("<a></a>").attr("href", url.href).text(url.label));
8449
+ if (url.isSelected) item.append(" (selected)");
8450
+ list.append(item);
8451
+ }
8452
+ projection.append(list);
8453
+ select.replaceWith(projection);
8454
+ });
8455
+ return { $, root };
8456
+ }
8329
8457
  function htmlPage(document, id, options = {}) {
8330
- const $ = load2(document.body);
8331
- const links = $('nav a[href], main a[href], article a[href], [role="main"] a[href]').map((_index, element) => $(element).attr("href") ?? "").get().filter(Boolean);
8332
- const scopedTitle = options.omitDocumentHeading ? $('main article, article, main, [role="main"]').first().find("h1").first().text().trim() : "";
8458
+ const { $, root } = migrationHtmlArticle(document.body);
8459
+ const links = root.find("a[href]").map((_index, element) => $(element).attr("href") ?? "").get().filter(Boolean);
8460
+ const scopedTitle = options.omitDocumentHeading ? root.find("h1").first().text().trim() : "";
8333
8461
  const title = scopedTitle || $("main h1, article h1, h1").first().text().trim() || $('meta[property="og:title"]').attr("content")?.trim() || $("title").text().split("|")[0].trim();
8334
8462
  const description = $('meta[name="description"]').attr("content")?.trim() || $('meta[property="og:description"]').attr("content")?.trim();
8335
- const content = $('main article, article, main, [role="main"]').first();
8336
- const root = content.length ? content : $("body");
8337
8463
  let documentHeadingAnchor = "";
8338
8464
  const excludedElements = options.omitDocumentHeading ? "script,style,noscript,nav,footer,aside,form,button,svg,iframe,object,embed,link,meta" : "script,style,noscript,nav,header,footer,aside,form,button,svg,iframe,object,embed,link,meta";
8339
8465
  root.find(excludedElements).remove();
@@ -8347,6 +8473,9 @@ function htmlPage(document, id, options = {}) {
8347
8473
  `;
8348
8474
  heading.remove();
8349
8475
  }
8476
+ root.find("h1").each((_index, element) => {
8477
+ element.name = "h2";
8478
+ });
8350
8479
  }
8351
8480
  root.find("a[href]").each((_index, element) => {
8352
8481
  const href = $(element).attr("href");
@@ -8376,8 +8505,20 @@ function htmlPage(document, id, options = {}) {
8376
8505
  $(element).removeAttr("src");
8377
8506
  }
8378
8507
  });
8379
- const turndown = new TurndownService({ codeBlockStyle: "fenced", emDelimiter: "_", headingStyle: "atx" });
8508
+ const turndown = new TurndownService({ codeBlockStyle: "fenced", emDelimiter: "_", headingStyle: "atx", preformattedCode: true });
8509
+ let isConvertingTableCell = false;
8380
8510
  turndown.remove(["script", "style", "noscript"]);
8511
+ turndown.addRule("migration-literal-table-code", {
8512
+ filter: (node) => isConvertingTableCell && node.nodeName === "CODE" && node.parentNode?.nodeName !== "PRE" && needsLiteralTableCode(node.textContent ?? ""),
8513
+ // A strict, attribute-free text leaf preserves the payload that GFM's
8514
+ // escaped-pipe code-span grammar cannot represent without changing it.
8515
+ replacement: (_content, node) => `<code>${literalMdxCodeText(node.textContent ?? "")}</code>`
8516
+ });
8517
+ turndown.addRule("migration-static-task-checkbox", {
8518
+ filter: (node) => node.nodeName === "SPAN" && ["checked", "unchecked"].includes(node.getAttribute("data-thally-static-task-checkbox") ?? ""),
8519
+ // Emit literal task-list syntax rather than escaping its brackets as copy.
8520
+ replacement: (_content, node) => node.getAttribute("data-thally-static-task-checkbox") === "checked" ? "[x] " : "[ ] "
8521
+ });
8381
8522
  const anchor = (element) => {
8382
8523
  const value = element.getAttribute("id");
8383
8524
  return options.preserveAnchors && value ? `<a id="${value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/\{/g, "&#123;")}" />
@@ -8386,12 +8527,12 @@ function htmlPage(document, id, options = {}) {
8386
8527
  };
8387
8528
  if (options.preserveAnchors) turndown.addRule("migration-source-anchor", {
8388
8529
  filter: (node) => node.hasAttribute("id") && node.nodeName !== "PRE",
8389
- replacement: (content2, node) => {
8530
+ replacement: (content, node) => {
8390
8531
  const element = node;
8391
8532
  const heading = element.nodeName.match(/^H([1-6])$/);
8392
8533
  return `
8393
8534
 
8394
- ${anchor(element)}${heading ? `${"#".repeat(Number(heading[1]))} ` : ""}${content2}
8535
+ ${anchor(element)}${heading ? `${"#".repeat(Number(heading[1]))} ${content.trim()}` : content}
8395
8536
 
8396
8537
  `;
8397
8538
  }
@@ -8416,10 +8557,10 @@ ${anchor(element)}${heading ? `${"#".repeat(Number(heading[1]))} ` : ""}${conten
8416
8557
  });
8417
8558
  turndown.addRule("migration-responsive-picture", {
8418
8559
  filter: "picture",
8419
- replacement: (content2) => `
8560
+ replacement: (content) => `
8420
8561
 
8421
8562
  <picture>
8422
- ${content2.trim()}
8563
+ ${content.trim()}
8423
8564
  </picture>
8424
8565
 
8425
8566
  `
@@ -8481,10 +8622,15 @@ ${tabs.join("\n\n")}
8481
8622
  filter: "table",
8482
8623
  replacement: (_content, node) => {
8483
8624
  const fragment = load2(node.outerHTML);
8484
- const rows = fragment("tr").toArray().map((row) => fragment(row).children("th,td").toArray().map((cell) => escapeMarkdownText(
8485
- fragment(cell).text().replace(/\s+/g, " ").trim(),
8486
- true
8487
- ))).filter((row) => row.length > 0);
8625
+ const rows = fragment("tr").toArray().map((row) => fragment(row).children("th,td").toArray().map((cell) => {
8626
+ const wasConvertingTableCell = isConvertingTableCell;
8627
+ isConvertingTableCell = true;
8628
+ try {
8629
+ return portableMarkdownTableCell(turndown.turndown(fragment(cell).html() ?? ""));
8630
+ } finally {
8631
+ isConvertingTableCell = wasConvertingTableCell;
8632
+ }
8633
+ })).filter((row) => row.length > 0);
8488
8634
  if (rows.length === 0) return "";
8489
8635
  const width = Math.max(...rows.map((row) => row.length));
8490
8636
  const normalized = rows.map((row) => [...row, ...Array(width - row.length).fill("")]);
@@ -8517,7 +8663,7 @@ ${fence}
8517
8663
  }
8518
8664
  });
8519
8665
  const escape = turndown.escape.bind(turndown);
8520
- turndown.escape = (text2) => escape(text2).replace(/[<{}]/g, (match) => `\\${match}`);
8666
+ turndown.escape = (text3) => isConvertingTableCell ? escape(text3.replace(/[<>{}]/g, (character) => ({ "<": "&lt;", ">": "&gt;", "{": "&#123;", "}": "&#125;" })[character])) : escape(text3).replace(/[<{}]/g, (match) => `\\${match}`);
8521
8667
  const body = `${documentHeadingAnchor}${turndown.turndown(root.html() ?? "").trim()}`;
8522
8668
  if (!title || body.length < 40 && $("article").length === 0) return { page: null, links };
8523
8669
  return {
@@ -8602,9 +8748,9 @@ function deriveDocusaurusScope(source, document, submittedScopePath) {
8602
8748
  const href = $(element).attr("href");
8603
8749
  if (!href) return [];
8604
8750
  try {
8605
- const target = new URL(href, document.finalUrl);
8606
- if (target.origin !== source.origin || !isInScope(target, source, scopePath)) return [];
8607
- const relativePath = target.pathname.slice(scopePath.length).replace(/^\/+/, "");
8751
+ const target2 = new URL(href, document.finalUrl);
8752
+ if (target2.origin !== source.origin || !isInScope(target2, source, scopePath)) return [];
8753
+ const relativePath = target2.pathname.slice(scopePath.length).replace(/^\/+/, "");
8608
8754
  const version = relativePath.split("/", 1)[0];
8609
8755
  if (!/^(?:legacy|next|v\d[\w.-]*)$/i.test(version)) return [];
8610
8756
  return [`${scopePath}/${version}`];
@@ -8645,11 +8791,11 @@ function docusaurusNavigationFromSnapshots(snapshots, pages, scopePath) {
8645
8791
  snapshot
8646
8792
  ])).values()];
8647
8793
  const mergedSnapshots = [];
8648
- function mergeItems(target, incoming) {
8794
+ function mergeItems(target2, incoming) {
8649
8795
  for (const item of incoming) {
8650
- const existing = target.find((candidate) => candidate.label === item.label && (candidate.items || item.items)) ?? target.find((candidate) => candidate.label === item.label && candidate.href === item.href);
8796
+ const existing = target2.find((candidate) => candidate.label === item.label && (candidate.items || item.items)) ?? target2.find((candidate) => candidate.label === item.label && candidate.href === item.href);
8651
8797
  if (!existing) {
8652
- target.push(structuredClone(item));
8798
+ target2.push(structuredClone(item));
8653
8799
  continue;
8654
8800
  }
8655
8801
  if (!existing.href && item.href) existing.href = item.href;
@@ -8720,10 +8866,10 @@ function htmlTopLevelNavigation(document, source, scopePath) {
8720
8866
  const href = $(element).attr("href");
8721
8867
  if (!label || !href) return;
8722
8868
  try {
8723
- const target = new URL(href, document.finalUrl);
8724
- if (!isInScope(target, source, scopePath)) return;
8869
+ const target2 = new URL(href, document.finalUrl);
8870
+ if (!isInScope(target2, source, scopePath)) return;
8725
8871
  anchorCount += 1;
8726
- const targetId = canonicalLocalizedPageId(pageIdForUrl(target, scopePath) ?? "");
8872
+ const targetId = canonicalLocalizedPageId(pageIdForUrl(target2, scopePath) ?? "");
8727
8873
  const pageId = targetId;
8728
8874
  const section = targetId.split("/", 1)[0] || "introduction";
8729
8875
  if (!pageId || seenSections.has(section)) return;
@@ -9137,8 +9283,8 @@ var SOURCE_REF_MAX_BYTES = 5e7;
9137
9283
  var SOURCE_REF_MAX_REPOSITORY_KB = 2e5;
9138
9284
  var DOCS_JSON_MAX_BYTES = 1e6;
9139
9285
  var MAX_FORWARDED_WARNINGS = 50;
9140
- function stripControlCharacters(text2) {
9141
- return text2.replace(/\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07\x1b]*(?:\x07|\x1b\\)?|.)?/g, "").replace(/[\x00-\x08\x0b-\x1f\x7f]/g, "");
9286
+ function stripControlCharacters(text3) {
9287
+ return text3.replace(/\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07\x1b]*(?:\x07|\x1b\\)?|.)?/g, "").replace(/[\x00-\x08\x0b-\x1f\x7f]/g, "");
9142
9288
  }
9143
9289
  var REPO_PATTERN = /^[A-Za-z0-9-]{1,39}\/[A-Za-z0-9._-]{1,100}$/;
9144
9290
  var MOUNT_PATTERN = /^[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9][a-z0-9._-]*)*$/;
@@ -9240,8 +9386,8 @@ function sanitizeAndMeasure(root) {
9240
9386
  }
9241
9387
  return { removedLinks };
9242
9388
  }
9243
- function mainSiteLinkTarget(target, mountPath, index, unresolved) {
9244
- const [, base, tail] = /^([^?#]*)([\s\S]*)$/.exec(target);
9389
+ function mainSiteLinkTarget(target2, mountPath, index, unresolved) {
9390
+ const [, base, tail] = /^([^?#]*)([\s\S]*)$/.exec(target2);
9245
9391
  const key = base.replace(/^\/+|\/+$/g, "");
9246
9392
  if (!key) return void 0;
9247
9393
  const has = (set, id) => set.has(id) || set.has(`${id}/index`);
@@ -9254,14 +9400,14 @@ function mainSiteLinkTarget(target, mountPath, index, unresolved) {
9254
9400
  const rest = key.slice(slash + 1);
9255
9401
  if (has(index.main, rest) && !index.sections.has(first)) return found(rest);
9256
9402
  }
9257
- unresolved.push(target);
9403
+ unresolved.push(target2);
9258
9404
  return void 0;
9259
9405
  }
9260
9406
  function prefixRootLinks(body, mountPath, resolve4, markdown = true) {
9261
9407
  const mounted = `/${mountPath}`;
9262
- const alreadyMounted = (target) => target === mounted || ["/", "?", "#"].some((next) => target.startsWith(mounted + next));
9263
- const fix = (target) => alreadyMounted(target) ? target : resolve4?.(target) ?? `${mounted}${target}`;
9264
- return replaceOutsideCodeAndComments(body, (text2) => text2.replace(markdown ? /(\]\(<?)(\/(?!\/)[^\s)>]*)/g : /(?!)/g, (_match, before, target) => `${before}${fix(target)}`).replace(/(\b(?:href|src|to|poster)=(['"]))(\/(?!\/)[^'"\n]*)\2/g, (_match, before, quote, target) => `${before}${fix(target)}${quote}`).replace(/(\b(?:href|src|to|poster)=\{\s*(['"]))(\/(?!\/)[^'"\n]*)\2(\s*\})/g, (_match, before, quote, target, after) => `${before}${fix(target)}${quote}${after}`).replace(markdown ? /^(\[[^\]\n]+\]:[ \t]*<?)(\/(?!\/)\S*)/gm : /(?!)/g, (_match, before, target) => `${before}${fix(target)}`));
9408
+ const alreadyMounted = (target2) => target2 === mounted || ["/", "?", "#"].some((next) => target2.startsWith(mounted + next));
9409
+ const fix = (target2) => alreadyMounted(target2) ? target2 : resolve4?.(target2) ?? `${mounted}${target2}`;
9410
+ return replaceOutsideCodeAndComments(body, (text3) => text3.replace(markdown ? /(\]\(<?)(\/(?!\/)[^\s)>]*)/g : /(?!)/g, (_match, before, target2) => `${before}${fix(target2)}`).replace(/(\b(?:href|src|to|poster)=(['"]))(\/(?!\/)[^'"\n]*)\2/g, (_match, before, quote, target2) => `${before}${fix(target2)}${quote}`).replace(/(\b(?:href|src|to|poster)=\{\s*(['"]))(\/(?!\/)[^'"\n]*)\2(\s*\})/g, (_match, before, quote, target2, after) => `${before}${fix(target2)}${quote}${after}`).replace(markdown ? /^(\[[^\]\n]+\]:[ \t]*<?)(\/(?!\/)\S*)/gm : /(?!)/g, (_match, before, target2) => `${before}${fix(target2)}`));
9265
9411
  }
9266
9412
  function prefixNavigation(entries, mountPath) {
9267
9413
  return entries.map((entry) => typeof entry === "string" ? `${mountPath}/${entry}` : { ...entry, pages: prefixNavigation(entry.pages, mountPath) });
@@ -9320,8 +9466,8 @@ function importSourceRef(mapping, repositoryDir) {
9320
9466
  return { ...mapping, pages, assets, ...bundle.componentFiles?.length ? { componentFiles: bundle.componentFiles } : {}, navigation: prefixNavigation(flattenTabs(bundle.docsConfig), mapping.mountPath), warnings };
9321
9467
  }
9322
9468
  function sourceRefMountCollides(siteRoot, mountPath) {
9323
- const target = resolve3(siteRoot, mountPath);
9324
- return [target, `${target}.md`, `${target}.mdx`].some((candidate) => {
9469
+ const target2 = resolve3(siteRoot, mountPath);
9470
+ return [target2, `${target2}.md`, `${target2}.mdx`].some((candidate) => {
9325
9471
  try {
9326
9472
  lstatSync5(candidate);
9327
9473
  return true;
@@ -10050,14 +10196,14 @@ function scanFiles(root, confinementRoot = root, warnings, rank, budget = MAX_SO
10050
10196
  }
10051
10197
  const withinConfinement = real === confinementReal || real.startsWith(`${confinementReal}${sep3}`);
10052
10198
  if (!withinConfinement) continue;
10053
- let target;
10199
+ let target2;
10054
10200
  try {
10055
- target = statSync(real);
10201
+ target2 = statSync(real);
10056
10202
  } catch {
10057
10203
  continue;
10058
10204
  }
10059
- if (target.isDirectory()) visit(real, logicalPath);
10060
- else if (target.isFile()) files.push({ absolutePath: real, relativePath: relative6(root, logicalPath).replace(/\\/g, "/") });
10205
+ if (target2.isDirectory()) visit(real, logicalPath);
10206
+ else if (target2.isFile()) files.push({ absolutePath: real, relativePath: relative6(root, logicalPath).replace(/\\/g, "/") });
10061
10207
  continue;
10062
10208
  }
10063
10209
  if (entry.isDirectory()) visit(path, logicalPath);
@@ -10171,8 +10317,8 @@ var PATH_SEPARATORS = /[\s"'()<>[\]{}=,;:|\\`*!?#&]+/;
10171
10317
  function publicAssetKey(repoRelative) {
10172
10318
  return repoRelative.split("/", 1)[0].toLowerCase() === "public" ? repoRelative.slice("public/".length) : repoRelative;
10173
10319
  }
10174
- function addPathReferences(text2, baseDir, exact, loose, docusaurus) {
10175
- for (const word of text2.split(PATH_SEPARATORS)) {
10320
+ function addPathReferences(text3, baseDir, exact, loose, docusaurus) {
10321
+ for (const word of text3.split(PATH_SEPARATORS)) {
10176
10322
  let token = word.replace(/\.+$/, "");
10177
10323
  if (!/\.[a-z0-9]{2,5}$/i.test(token) || token.startsWith("//")) continue;
10178
10324
  if (token.includes("%")) {
@@ -10240,8 +10386,8 @@ function classifyApiSpec(path) {
10240
10386
  } catch {
10241
10387
  return "unknown";
10242
10388
  }
10243
- const text2 = buffer.toString("utf8", 0, bytesRead);
10244
- const topLevel = text2.match(/^(?:openapi|swagger|asyncapi)\s*:/m)?.[0] ?? text2.match(/^\s*\{\s*"(?:openapi|swagger|asyncapi)"\s*:/m)?.[0];
10389
+ const text3 = buffer.toString("utf8", 0, bytesRead);
10390
+ const topLevel = text3.match(/^(?:openapi|swagger|asyncapi)\s*:/m)?.[0] ?? text3.match(/^\s*\{\s*"(?:openapi|swagger|asyncapi)"\s*:/m)?.[0];
10245
10391
  if (!topLevel) return "unknown";
10246
10392
  return /asyncapi/i.test(topLevel) ? "asyncapi" : "openapi";
10247
10393
  }
@@ -10507,22 +10653,22 @@ function rewriteApiOperationLinks(body, linkMap, prefixLandings, unmatched) {
10507
10653
  return line;
10508
10654
  }
10509
10655
  if (codeFence) return line;
10510
- const rewriteTarget = (target) => {
10511
- const suffixIndex = target.search(/[?#]/);
10512
- const path = (suffixIndex >= 0 ? target.slice(0, suffixIndex) : target).replace(/^\/+/, "").toLowerCase();
10513
- const suffix = suffixIndex >= 0 ? target.slice(suffixIndex) : "";
10656
+ const rewriteTarget = (target2) => {
10657
+ const suffixIndex = target2.search(/[?#]/);
10658
+ const path = (suffixIndex >= 0 ? target2.slice(0, suffixIndex) : target2).replace(/^\/+/, "").toLowerCase();
10659
+ const suffix = suffixIndex >= 0 ? target2.slice(suffixIndex) : "";
10514
10660
  const mapped = linkMap.get(path);
10515
10661
  if (mapped) return `${mapped}${suffix}`;
10516
10662
  for (const [prefix, landing] of orderedPrefixes) {
10517
10663
  if (path === prefix) return `${landing}${suffix}`;
10518
10664
  if (path.startsWith(`${prefix}/`)) {
10519
- unmatched.add(target);
10665
+ unmatched.add(target2);
10520
10666
  return `${landing}${suffix}`;
10521
10667
  }
10522
10668
  }
10523
- return target;
10669
+ return target2;
10524
10670
  };
10525
- return line.replace(/(\]\()\/([^\s)]+)(?=[\s)]|$)/g, (_match, prefix, target) => `${prefix}${rewriteTarget(`/${target}`)}`).replace(/(\bhref=")\/([^"]+)(")/g, (_match, prefix, target, suffix) => `${prefix}${rewriteTarget(`/${target}`)}${suffix}`);
10671
+ return line.replace(/(\]\()\/([^\s)]+)(?=[\s)]|$)/g, (_match, prefix, target2) => `${prefix}${rewriteTarget(`/${target2}`)}`).replace(/(\bhref=")\/([^"]+)(")/g, (_match, prefix, target2, suffix) => `${prefix}${rewriteTarget(`/${target2}`)}${suffix}`);
10526
10672
  }).join("\n");
10527
10673
  }
10528
10674
  var MAX_FERN_GENERATORS_BYTES = 2e6;
@@ -10683,10 +10829,10 @@ function withoutFencedCode3(raw) {
10683
10829
  }).join("\n");
10684
10830
  }
10685
10831
  function fernIfRolesReason(raw) {
10686
- const text2 = withoutFencedCode3(raw).replace(/(`{1,3})[^`\n]*\1/g, "");
10832
+ const text3 = withoutFencedCode3(raw).replace(/(`{1,3})[^`\n]*\1/g, "");
10687
10833
  const marker = /<If(?![\w$.-])/g;
10688
- for (let match = marker.exec(text2); match; match = marker.exec(text2)) {
10689
- const tag = scanJsxOpeningTag(text2, match.index, "If");
10834
+ for (let match = marker.exec(text3); match; match = marker.exec(text3)) {
10835
+ const tag = scanJsxOpeningTag(text3, match.index, "If");
10690
10836
  marker.lastIndex = tag.next;
10691
10837
  if (tag.attributes.includes("...")) {
10692
10838
  return "it contains `<If>` spread props whose access rules cannot be resolved safely";
@@ -10899,70 +11045,70 @@ function fernSourceSiteUrl(config) {
10899
11045
  }
10900
11046
  }
10901
11047
  function externalizeMissingFernLinks(body, pageIds, sourceSiteUrl, externalized) {
10902
- const rewrite = (target) => {
10903
- const path = target.split(/[?#]/, 1)[0].replace(/^\//, "").replace(/\/$/, "");
10904
- if (!path || pageIds.has(path) || ASSET_EXTENSIONS.has(extname6(path).toLowerCase())) return target;
11048
+ const rewrite = (target2) => {
11049
+ const path = target2.split(/[?#]/, 1)[0].replace(/^\//, "").replace(/\/$/, "");
11050
+ if (!path || pageIds.has(path) || ASSET_EXTENSIONS.has(extname6(path).toLowerCase())) return target2;
10905
11051
  try {
10906
11052
  const base = new URL(`${sourceSiteUrl}/`);
10907
- const sourceLinkUrl = new URL(target.slice(1), base);
10908
- if (sourceLinkUrl.origin !== base.origin) return target;
11053
+ const sourceLinkUrl = new URL(target2.slice(1), base);
11054
+ if (sourceLinkUrl.origin !== base.origin) return target2;
10909
11055
  const sourceLink = sourceLinkUrl.toString();
10910
- externalized.add(target);
11056
+ externalized.add(target2);
10911
11057
  return sourceLink;
10912
11058
  } catch {
10913
- return target;
11059
+ return target2;
10914
11060
  }
10915
11061
  };
10916
- return replaceOutsideCode(body, (text2) => text2.replace(/(\]\()\/(?!\/)([^\s)]+)(\))/g, (_match, before, target, after) => `${before}${rewrite(`/${target}`)}${after}`).replace(/(\b(?:href|to)=(['"]))\/(?!\/)([^'"\n]+)\2/g, (_match, before, quote, target) => `${before}${rewrite(`/${target}`)}${quote}`));
11062
+ return replaceOutsideCode(body, (text3) => text3.replace(/(\]\()\/(?!\/)([^\s)]+)(\))/g, (_match, before, target2, after) => `${before}${rewrite(`/${target2}`)}${after}`).replace(/(\b(?:href|to)=(['"]))\/(?!\/)([^'"\n]+)\2/g, (_match, before, quote, target2) => `${before}${rewrite(`/${target2}`)}${quote}`));
10917
11063
  }
10918
11064
  function stripFernBasePathFromLinks(body, basePath) {
10919
11065
  if (!basePath) return body;
10920
11066
  const escaped = basePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10921
- return replaceOutsideCode(body, (text2) => text2.replace(new RegExp(`(\\]\\()${escaped}(?=\\/|[)#?])`, "g"), (match, prefix, offset, source) => prefix + (source[offset + match.length] === "/" ? "" : "/")).replace(new RegExp(`(\\b(?:href|to)=["'])${escaped}(?=\\/|["'#?])`, "g"), (match, prefix, offset, source) => prefix + (source[offset + match.length] === "/" ? "" : "/")));
11067
+ return replaceOutsideCode(body, (text3) => text3.replace(new RegExp(`(\\]\\()${escaped}(?=\\/|[)#?])`, "g"), (match, prefix, offset, source) => prefix + (source[offset + match.length] === "/" ? "" : "/")).replace(new RegExp(`(\\b(?:href|to)=["'])${escaped}(?=\\/|["'#?])`, "g"), (match, prefix, offset, source) => prefix + (source[offset + match.length] === "/" ? "" : "/")));
10922
11068
  }
10923
11069
  function rewriteMintlifyMountedLinks(body, pageIds) {
10924
- const rewrite = (target) => {
10925
- const suffixAt = target.search(/[?#]/);
10926
- const pathname = suffixAt < 0 ? target : target.slice(0, suffixAt);
10927
- const suffix = suffixAt < 0 ? "" : target.slice(suffixAt);
10928
- if (!pathname.startsWith("/") || pathname.startsWith("//") || pathname.includes("\\")) return target;
11070
+ const rewrite = (target2) => {
11071
+ const suffixAt = target2.search(/[?#]/);
11072
+ const pathname = suffixAt < 0 ? target2 : target2.slice(0, suffixAt);
11073
+ const suffix = suffixAt < 0 ? "" : target2.slice(suffixAt);
11074
+ if (!pathname.startsWith("/") || pathname.startsWith("//") || pathname.includes("\\")) return target2;
10929
11075
  const segments = pathname.slice(1).split("/");
10930
- if (segments.some((segment) => !segment || segment === "." || segment === "..")) return target;
10931
- if (pageIds.has(segments.join("/"))) return target;
11076
+ if (segments.some((segment) => !segment || segment === "." || segment === "..")) return target2;
11077
+ if (pageIds.has(segments.join("/"))) return target2;
10932
11078
  for (let count = 1; count < segments.length && count <= 3; count++) {
10933
11079
  const candidate = segments.slice(count).join("/");
10934
11080
  if (pageIds.has(candidate)) return `/${candidate}${suffix}`;
10935
11081
  }
10936
- return target;
11082
+ return target2;
10937
11083
  };
10938
- return replaceOutsideCode(body, (text2) => text2.replace(/(\]\()(\/[^\s)]+)(\))/g, (_match, before, target, after) => `${before}${rewrite(target)}${after}`).replace(/(\b(?:href|to)=(['"]))(\/[^'"\n]+)\2/g, (_match, before, quote, target) => `${before}${rewrite(target)}${quote}`));
11084
+ return replaceOutsideCode(body, (text3) => text3.replace(/(\]\()(\/[^\s)]+)(\))/g, (_match, before, target2, after) => `${before}${rewrite(target2)}${after}`).replace(/(\b(?:href|to)=(['"]))(\/[^'"\n]+)\2/g, (_match, before, quote, target2) => `${before}${rewrite(target2)}${quote}`));
10939
11085
  }
10940
11086
  function preserveLinkedAnchors(pages) {
10941
11087
  const pageById = new Map(pages.map((page) => [page.id, page]));
10942
11088
  const requested = /* @__PURE__ */ new Map();
10943
11089
  const crossPageRequests = /* @__PURE__ */ new Set();
10944
- const addTarget = (target, currentId) => {
10945
- const hash3 = target.indexOf("#");
11090
+ const addTarget = (target2, currentId) => {
11091
+ const hash3 = target2.indexOf("#");
10946
11092
  if (hash3 < 0) return;
10947
11093
  let fragment;
10948
11094
  try {
10949
- fragment = decodeURIComponent(target.slice(hash3 + 1));
11095
+ fragment = decodeURIComponent(target2.slice(hash3 + 1));
10950
11096
  } catch {
10951
11097
  return;
10952
11098
  }
10953
11099
  if (!/^[\p{L}\p{N}_.:$-]{1,120}$/u.test(fragment)) return;
10954
- const path = target.slice(0, hash3).split("?")[0];
10955
- const id = target.startsWith("#") ? currentId : path.startsWith("/") && !path.startsWith("//") ? path.replace(/^\//, "").replace(/\/$/, "") || "introduction" : "";
11100
+ const path = target2.slice(0, hash3).split("?")[0];
11101
+ const id = target2.startsWith("#") ? currentId : path.startsWith("/") && !path.startsWith("//") ? path.replace(/^\//, "").replace(/\/$/, "") || "introduction" : "";
10956
11102
  if (!pageById.has(id)) return;
10957
11103
  if (!requested.has(id)) requested.set(id, /* @__PURE__ */ new Set());
10958
11104
  requested.get(id).add(fragment);
10959
11105
  if (id !== currentId) crossPageRequests.add(`${id}#${fragment}`);
10960
11106
  };
10961
11107
  for (const page of pages) {
10962
- replaceOutsideCode(page.body, (text2) => {
10963
- for (const match of text2.matchAll(/\]\(([^)\s]+)\)/g)) addTarget(match[1], page.id);
10964
- for (const match of text2.matchAll(/\b(?:href|to)=(['"])([^'"\n]+)\1/g)) addTarget(match[2], page.id);
10965
- return text2;
11108
+ replaceOutsideCode(page.body, (text3) => {
11109
+ for (const match of text3.matchAll(/\]\(([^)\s]+)\)/g)) addTarget(match[1], page.id);
11110
+ for (const match of text3.matchAll(/\b(?:href|to)=(['"])([^'"\n]+)\1/g)) addTarget(match[2], page.id);
11111
+ return text3;
10966
11112
  });
10967
11113
  }
10968
11114
  const comparable = (value) => value.replace(/&(?:lt|gt|amp|quot);/g, " ").toLowerCase().replace(/[^\p{L}\p{N}]+/gu, "");
@@ -10970,12 +11116,12 @@ function preserveLinkedAnchors(pages) {
10970
11116
  const fragments = requested.get(page.id);
10971
11117
  if (!fragments?.size) continue;
10972
11118
  const definitions = /* @__PURE__ */ new Map();
10973
- replaceOutsideCodeAndComments(page.body, (text2) => {
10974
- for (const match of text2.matchAll(/^ {0,3}\[([^\]\n]+)\]:[^\n]*$/gm)) {
11119
+ replaceOutsideCodeAndComments(page.body, (text3) => {
11120
+ for (const match of text3.matchAll(/^ {0,3}\[([^\]\n]+)\]:[^\n]*$/gm)) {
10975
11121
  const label = match[1].trim().replace(/\s+/g, " ").toLowerCase();
10976
11122
  if (!definitions.has(label)) definitions.set(label, match[0]);
10977
11123
  }
10978
- return text2;
11124
+ return text3;
10979
11125
  });
10980
11126
  const lines = page.body.split("\n");
10981
11127
  let fence;
@@ -10994,10 +11140,10 @@ function preserveLinkedAnchors(pages) {
10994
11140
  return match ? { index, text: mdxVisibleText(match[1].replace(/\s*\{\/\*\s*#\S+?\s*\*\/\}$/, ""), definitions) } : null;
10995
11141
  }).filter((entry) => entry !== null);
10996
11142
  const existing = /* @__PURE__ */ new Set();
10997
- replaceOutsideCode(page.body, (text2) => {
10998
- for (const match of text2.matchAll(/\bid=(?:"([^"]+)"|'([^']+)')/g)) existing.add(match[1] ?? match[2]);
10999
- for (const match of text2.matchAll(/\{\/\*\s*#(\S+?)\s*\*\/\}/g)) existing.add(match[1]);
11000
- return text2;
11143
+ replaceOutsideCode(page.body, (text3) => {
11144
+ for (const match of text3.matchAll(/\bid=(?:"([^"]+)"|'([^']+)')/g)) existing.add(match[1] ?? match[2]);
11145
+ for (const match of text3.matchAll(/\{\/\*\s*#(\S+?)\s*\*\/\}/g)) existing.add(match[1]);
11146
+ return text3;
11001
11147
  });
11002
11148
  const candidateIndexes = /* @__PURE__ */ new Map();
11003
11149
  for (const heading of headings) {
@@ -11283,15 +11429,15 @@ function repositoryAssetHref(value, currentFile, siteRoot, onReferenced, onRootF
11283
11429
  }
11284
11430
  }
11285
11431
  function rewriteFernIdRenameLinks(body, renames) {
11286
- return replaceOutsideCode(body, (text2) => {
11287
- const rewriteTarget = (target) => {
11288
- const suffixIndex = target.search(/[?#]/);
11289
- const path = (suffixIndex >= 0 ? target.slice(0, suffixIndex) : target).replace(/^\/+/, "");
11290
- const suffix = suffixIndex >= 0 ? target.slice(suffixIndex) : "";
11432
+ return replaceOutsideCode(body, (text3) => {
11433
+ const rewriteTarget = (target2) => {
11434
+ const suffixIndex = target2.search(/[?#]/);
11435
+ const path = (suffixIndex >= 0 ? target2.slice(0, suffixIndex) : target2).replace(/^\/+/, "");
11436
+ const suffix = suffixIndex >= 0 ? target2.slice(suffixIndex) : "";
11291
11437
  const renamed = renames.get(path);
11292
- return renamed ? `/${renamed}${suffix}` : target;
11438
+ return renamed ? `/${renamed}${suffix}` : target2;
11293
11439
  };
11294
- return text2.replace(/(\]\()\/([^\s)]+)(?=[\s)]|$)/g, (_match, prefix, target) => `${prefix}${rewriteTarget(`/${target}`)}`).replace(/(\bhref=")\/([^"]+)(")/g, (_match, prefix, target, suffix) => `${prefix}${rewriteTarget(`/${target}`)}${suffix}`);
11440
+ return text3.replace(/(\]\()\/([^\s)]+)(?=[\s)]|$)/g, (_match, prefix, target2) => `${prefix}${rewriteTarget(`/${target2}`)}`).replace(/(\bhref=")\/([^"]+)(")/g, (_match, prefix, target2, suffix) => `${prefix}${rewriteTarget(`/${target2}`)}${suffix}`);
11295
11441
  });
11296
11442
  }
11297
11443
  function rewriteRepositoryAssetLinks(body, currentFile, siteRoot, onReferenced, onRootFallback) {
@@ -12737,7 +12883,7 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
12737
12883
  const descriptor = descriptorByNavigationId.get(page.navigationId);
12738
12884
  if (descriptor) page.body = rewriteDocusaurusLinks(page.body, descriptor, docusaurusDescriptors, {
12739
12885
  sourceOrigin,
12740
- onExternalLink: (target) => externalizedLinks.add(target),
12886
+ onExternalLink: (target2) => externalizedLinks.add(target2),
12741
12887
  assetPaths: new Set(assets.map((asset) => asset.path))
12742
12888
  });
12743
12889
  }
@@ -12777,7 +12923,7 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
12777
12923
  }
12778
12924
  if (platform === "fern" && fernSourceLinkAliases.size > 0) {
12779
12925
  const imported = new Set(pages.map((page) => page.id));
12780
- const aliases = new Map([...fernSourceLinkAliases].map(([source, target]) => [source, fernIdRenames.get(target) ?? target]).filter(([, target]) => imported.has(target)));
12926
+ const aliases = new Map([...fernSourceLinkAliases].map(([source, target2]) => [source, fernIdRenames.get(target2) ?? target2]).filter(([, target2]) => imported.has(target2)));
12781
12927
  for (const page of pages) page.body = rewriteFernIdRenameLinks(page.body, aliases);
12782
12928
  }
12783
12929
  if (docsConfig.tabs.length === 0) docsConfig = buildNavigationFromPages(pages);
@@ -13104,7 +13250,7 @@ ${body}`;
13104
13250
  let count = 0;
13105
13251
  const unresolvedLinks = [];
13106
13252
  const linkIndex = rootLinkIndex();
13107
- const resolveLink = (target) => mainSiteLinkTarget(target, ref.mountPath, linkIndex, unresolvedLinks);
13253
+ const resolveLink = (target2) => mainSiteLinkTarget(target2, ref.mountPath, linkIndex, unresolvedLinks);
13108
13254
  for (const sourcePage of ref.pages) {
13109
13255
  const page = { ...sourcePage, body: prefixRootLinks(sourcePage.body, ref.mountPath, resolveLink) };
13110
13256
  if (taken.has(page.id)) {
@@ -13124,7 +13270,7 @@ ${body}`;
13124
13270
  if (unresolved.length > 0) {
13125
13271
  warnings.push({
13126
13272
  code: "unsupported-config",
13127
- message: `[${ref.repo}] ${unresolved.length} root-absolute link target${unresolved.length === 1 ? "" : "s"} match no page in the sub-site or the main site and were kept under "${ref.mountPath}": ${unresolved.slice(0, 10).map((target) => stripControlCharacters(target)).join(", ")}${unresolved.length > 10 ? ", \u2026" : ""}.`
13273
+ message: `[${ref.repo}] ${unresolved.length} root-absolute link target${unresolved.length === 1 ? "" : "s"} match no page in the sub-site or the main site and were kept under "${ref.mountPath}": ${unresolved.slice(0, 10).map((target2) => stripControlCharacters(target2)).join(", ")}${unresolved.length > 10 ? ", \u2026" : ""}.`
13128
13274
  });
13129
13275
  }
13130
13276
  }
@@ -13508,18 +13654,18 @@ function mergeMigrationConfig(existing, incoming) {
13508
13654
  names.add(tab.tab.toLowerCase());
13509
13655
  continue;
13510
13656
  }
13511
- const target = tabs.find((item) => item.tab.toLowerCase() === tab.tab.toLowerCase());
13512
- if (!target) continue;
13657
+ const target2 = tabs.find((item) => item.tab.toLowerCase() === tab.tab.toLowerCase());
13658
+ if (!target2) continue;
13513
13659
  const incomingRootNodes = [
13514
13660
  ...uniqueTab.pages ?? [],
13515
13661
  ...uniqueTab.groups ?? []
13516
13662
  ];
13517
13663
  if (uniqueTab.pages?.length) {
13518
- target.pages = [...target.pages ?? target.groups ?? [], ...incomingRootNodes];
13519
- delete target.groups;
13664
+ target2.pages = [...target2.pages ?? target2.groups ?? [], ...incomingRootNodes];
13665
+ delete target2.groups;
13520
13666
  } else if (uniqueTab.groups?.length) {
13521
- if (target.pages) target.pages = [...target.pages, ...uniqueTab.groups];
13522
- else target.groups = [...target.groups ?? [], ...uniqueTab.groups];
13667
+ if (target2.pages) target2.pages = [...target2.pages, ...uniqueTab.groups];
13668
+ else target2.groups = [...target2.groups ?? [], ...uniqueTab.groups];
13523
13669
  }
13524
13670
  }
13525
13671
  const changelog = existing.tabs.find((tab) => tab.tab.toLowerCase() === "changelog") ?? incoming.tabs.find((tab) => tab.tab.toLowerCase() === "changelog");
@@ -13566,7 +13712,7 @@ function renderMigrationFiles(bundle, options = {}) {
13566
13712
 
13567
13713
  // src/url-run.ts
13568
13714
  import { createHash as createHash3 } from "crypto";
13569
- import { load as load3 } from "cheerio";
13715
+ import { load as load4 } from "cheerio";
13570
13716
  import remarkParse4 from "remark-parse";
13571
13717
  import remarkMdx4 from "remark-mdx";
13572
13718
  import { unified as unified4 } from "unified";
@@ -13803,20 +13949,20 @@ function utf8SvgText(content) {
13803
13949
  if (body[0] === 254 && body[1] === 255 || body[0] === 255 && body[1] === 254 || body[0] === 0 && body[1] === 0 || body.includes(0)) {
13804
13950
  return null;
13805
13951
  }
13806
- const text2 = body.toString("utf8");
13807
- if (text2.includes("\uFFFD")) return null;
13808
- const declaration = /^<\?xml\b[^>]*\?>/iu.exec(text2);
13952
+ const text3 = body.toString("utf8");
13953
+ if (text3.includes("\uFFFD")) return null;
13954
+ const declaration = /^<\?xml\b[^>]*\?>/iu.exec(text3);
13809
13955
  if (declaration) {
13810
13956
  const encoding = /\bencoding\s*=\s*["']([^"']*)["']/iu.exec(declaration[0]);
13811
13957
  if (encoding && !/^utf-?8$/iu.test(encoding[1].trim())) return null;
13812
- } else if (/<\?xml\b/iu.test(text2)) {
13958
+ } else if (/<\?xml\b/iu.test(text3)) {
13813
13959
  return null;
13814
13960
  }
13815
- return text2;
13961
+ return text3;
13816
13962
  }
13817
13963
  function isPassiveSvg(content) {
13818
- const text2 = utf8SvgText(Buffer.from(content.buffer, content.byteOffset, content.byteLength));
13819
- if (text2 === null) return false;
13964
+ const text3 = utf8SvgText(Buffer.from(content.buffer, content.byteOffset, content.byteLength));
13965
+ if (text3 === null) return false;
13820
13966
  let isPassive = true;
13821
13967
  let depth = 0;
13822
13968
  let sawRoot = false;
@@ -13868,7 +14014,7 @@ function isPassiveSvg(content) {
13868
14014
  { xmlMode: true, decodeEntities: true, recognizeSelfClosing: true }
13869
14015
  );
13870
14016
  try {
13871
- parser3.write(text2);
14017
+ parser3.write(text3);
13872
14018
  parser3.end();
13873
14019
  } catch {
13874
14020
  return false;
@@ -13943,8 +14089,276 @@ function cloneUrlMigrationCheckpoint(checkpoint) {
13943
14089
  return clone(checkpoint);
13944
14090
  }
13945
14091
 
14092
+ // src/url-navigation.ts
14093
+ import { load as load3 } from "cheerio";
14094
+ var MAX_CAPTURE_BYTES = 8e6;
14095
+ var MAX_JSON_BYTES = 2e6;
14096
+ var MAX_NODES = 1e4;
14097
+ var MAX_DEPTH = 32;
14098
+ var MAX_STRING_LENGTH = 8192;
14099
+ function object(value) {
14100
+ return value !== null && typeof value === "object" && !Array.isArray(value);
14101
+ }
14102
+ function text2(value) {
14103
+ return typeof value === "string" && value.length <= MAX_STRING_LENGTH && value.trim() ? value.trim() : void 0;
14104
+ }
14105
+ function target(value, base) {
14106
+ const reference = text2(value);
14107
+ if (!reference) return void 0;
14108
+ try {
14109
+ const url = new URL(reference, base);
14110
+ return ["https:", "http:"].includes(url.protocol) && !url.username && !url.password ? url.toString() : void 0;
14111
+ } catch {
14112
+ return void 0;
14113
+ }
14114
+ }
14115
+ function readJson(value) {
14116
+ if (Buffer.byteLength(value) > MAX_JSON_BYTES) return void 0;
14117
+ let depth = 0;
14118
+ let quoted = false;
14119
+ let escaped = false;
14120
+ for (const char of value) {
14121
+ if (quoted) {
14122
+ if (escaped) escaped = false;
14123
+ else if (char === "\\") escaped = true;
14124
+ else if (char === '"') quoted = false;
14125
+ } else if (char === '"') quoted = true;
14126
+ else if (char === "[" || char === "{") {
14127
+ if (++depth > 96) return void 0;
14128
+ } else if (char === "]" || char === "}") depth--;
14129
+ }
14130
+ try {
14131
+ return JSON.parse(value);
14132
+ } catch {
14133
+ return void 0;
14134
+ }
14135
+ }
14136
+ function flightRecords(stream) {
14137
+ const bytes = Buffer.from(stream);
14138
+ const records = [];
14139
+ let cursor = 0;
14140
+ while (cursor < bytes.length) {
14141
+ const colon = bytes.indexOf(58, cursor);
14142
+ if (colon < 0 || colon - cursor > 16 || !/^[a-f\d]*$/i.test(bytes.toString("utf8", cursor, colon))) break;
14143
+ cursor = colon + 1;
14144
+ if (bytes[cursor] === 84) {
14145
+ const comma = bytes.indexOf(44, cursor + 1);
14146
+ const length = comma < 0 ? "" : bytes.toString("utf8", cursor + 1, comma);
14147
+ if (!/^[a-f\d]{1,8}$/i.test(length)) break;
14148
+ const end2 = comma + 1 + Number.parseInt(length, 16);
14149
+ if (end2 > bytes.length) break;
14150
+ cursor = end2;
14151
+ continue;
14152
+ }
14153
+ const newline = bytes.indexOf(10, cursor);
14154
+ const end = newline < 0 ? bytes.length : newline;
14155
+ if (bytes[cursor] === 91 || bytes[cursor] === 123) records.push(readJson(bytes.toString("utf8", cursor, end)));
14156
+ cursor = end + 1;
14157
+ }
14158
+ return records;
14159
+ }
14160
+ function mintlifyNavigation(body, base, locale) {
14161
+ const $ = load3(body);
14162
+ let stream = "";
14163
+ const records = [];
14164
+ $("script").each((_index, script) => {
14165
+ const source = $(script).text();
14166
+ const call = /^\s*self\.__next_f\.push\(\s*(\[[\s\S]*\])\s*\)\s*;?\s*$/.exec(source);
14167
+ if (call) {
14168
+ const value = readJson(call[1]);
14169
+ if (Array.isArray(value) && value[0] === 1 && typeof value[1] === "string") stream += value[1];
14170
+ } else if ($(script).attr("type") === "application/json") {
14171
+ records.push(readJson(source));
14172
+ }
14173
+ });
14174
+ records.push(...flightRecords(stream));
14175
+ const candidates = [];
14176
+ let visited = 0;
14177
+ const visit = (value, depth = 0) => {
14178
+ if (++visited > MAX_NODES * 5 || depth > 96) return;
14179
+ if (Array.isArray(value)) {
14180
+ for (const child of value) visit(child, depth + 1);
14181
+ } else if (object(value)) {
14182
+ for (const key of ["scopedNav", "docsNavWithMetadata", "anonymizedNav"]) {
14183
+ if (object(value[key])) candidates.push({ value: value[key], rank: key === "scopedNav" ? 3 : 2 });
14184
+ }
14185
+ if (object(value.docsConfig) && object(value.docsConfig.navigation)) {
14186
+ candidates.push({ value: value.docsConfig.navigation, rank: 1 });
14187
+ }
14188
+ for (const child of Object.values(value)) visit(child, depth + 1);
14189
+ }
14190
+ };
14191
+ records.forEach((record) => visit(record));
14192
+ const language = locale ?? text2($("html").attr("lang"));
14193
+ for (const candidate of candidates.sort((a, b) => b.rank - a.rank)) {
14194
+ let count = 0;
14195
+ const walk2 = (value, depth = 0, activeLocale) => {
14196
+ if (depth > MAX_DEPTH || ++count > MAX_NODES) throw new Error("Source navigation exceeds its safety bound.");
14197
+ if (typeof value === "string") {
14198
+ const url2 = target(value, new URL("/", base));
14199
+ return url2 ? [{ kind: "page", label: value, url: url2 }] : [];
14200
+ }
14201
+ if (Array.isArray(value)) return value.flatMap((child) => walk2(child, depth + 1, activeLocale));
14202
+ if (!object(value)) return [];
14203
+ if (Array.isArray(value.languages)) {
14204
+ const languages = value.languages.filter(object);
14205
+ const current = new URL(base);
14206
+ current.hash = "";
14207
+ const routeScore = (item) => {
14208
+ let visited2 = 0;
14209
+ let matches = false;
14210
+ let populated = 0;
14211
+ const scan = (node, depth2 = 0) => {
14212
+ if (++visited2 > MAX_NODES || depth2 > MAX_DEPTH) return;
14213
+ if (Array.isArray(node)) {
14214
+ for (const child of node) scan(child, depth2 + 1);
14215
+ return;
14216
+ }
14217
+ if (!object(node)) return;
14218
+ const href = target(node.href, base);
14219
+ if (href) {
14220
+ populated++;
14221
+ const url2 = new URL(href);
14222
+ url2.hash = "";
14223
+ if (url2.toString() === current.toString()) matches = true;
14224
+ }
14225
+ for (const key of ["tabs", "groups", "pages", "dropdowns", "anchors", "versions"]) {
14226
+ if (Array.isArray(node[key])) scan(node[key], depth2 + 1);
14227
+ }
14228
+ };
14229
+ scan(item);
14230
+ return matches ? populated : 0;
14231
+ };
14232
+ const matching = languages.map((item) => ({ item, score: routeScore(item) })).filter((candidate2) => candidate2.score > 0).sort((a, b) => b.score - a.score);
14233
+ const selected = matching[0]?.item ?? languages.find((item) => text2(item.language)?.toLowerCase() === language?.toLowerCase()) ?? languages.find((item) => text2(item.language)?.toLowerCase() === "en") ?? languages[0];
14234
+ return selected ? walk2({ ...selected, languages: void 0 }, depth + 1, text2(selected.language)) : [];
14235
+ }
14236
+ const label = text2(value.tab) ?? text2(value.group) ?? text2(value.title) ?? text2(value.label);
14237
+ const kind = text2(value.tab) ? "tab" : text2(value.group) ? "group" : "page";
14238
+ const children = ["tabs", "groups", "pages", "dropdowns", "anchors", "versions"].flatMap((key) => Array.isArray(value[key]) ? walk2(value[key], depth + 1, activeLocale) : []);
14239
+ const url = target(value.href, base);
14240
+ if (!label) return children;
14241
+ if (!url && !children.length) return [];
14242
+ return [{
14243
+ kind,
14244
+ label,
14245
+ ...url ? { url } : {},
14246
+ ...children.length ? { children } : {},
14247
+ ...kind === "tab" && activeLocale ? { locale: activeLocale } : {}
14248
+ }];
14249
+ };
14250
+ try {
14251
+ const nodes = walk2(candidate.value);
14252
+ if (nodes.length) return nodes;
14253
+ } catch {
14254
+ }
14255
+ }
14256
+ return [];
14257
+ }
14258
+ function resolveNavigation(nodes, base) {
14259
+ let count = 0;
14260
+ const walk2 = (items, depth = 0) => {
14261
+ if (depth > MAX_DEPTH || !Array.isArray(items)) throw new Error("Invalid source navigation.");
14262
+ return items.flatMap((node) => {
14263
+ if (++count > MAX_NODES || !object(node)) throw new Error("Source navigation exceeds its safety bound.");
14264
+ const label = text2(node.label);
14265
+ if (!label) return [];
14266
+ const url = target(node.url, base);
14267
+ const children = node.children ? walk2(node.children, depth + 1) : [];
14268
+ return [{
14269
+ label,
14270
+ ...url ? { url } : {},
14271
+ ...children.length ? { children } : {},
14272
+ ...["tab", "group", "page"].includes(node.kind ?? "") ? { kind: node.kind } : {},
14273
+ ...text2(node.locale) ? { locale: text2(node.locale) } : {}
14274
+ }];
14275
+ });
14276
+ };
14277
+ return walk2(nodes);
14278
+ }
14279
+ function extractSourceNavigation(capture) {
14280
+ if (capture.navigation) return resolveNavigation(capture.navigation, capture.finalUrl);
14281
+ if (!/html/i.test(capture.contentType) || Buffer.byteLength(capture.body) > MAX_CAPTURE_BYTES) return [];
14282
+ const mintlify = mintlifyNavigation(capture.body, capture.finalUrl, capture.locale);
14283
+ if (mintlify.length) return mintlify;
14284
+ const $ = load3(capture.body);
14285
+ const candidates = ['.theme-doc-sidebar-menu,[aria-label*="sidebar" i]', "aside", '[role="navigation"],nav'];
14286
+ const root = candidates.map((selector) => $(selector).filter((_index, node) => $(node).find("a[href]").length > 0 && $(node).closest("header").length === 0).first()).find((candidate) => candidate.length);
14287
+ if (!root) return [];
14288
+ let count = 0;
14289
+ const walk2 = (element, excluded, depth = 0) => {
14290
+ if (depth > MAX_DEPTH) throw new Error("Source navigation exceeds its safety bound.");
14291
+ const result = [];
14292
+ $(element).children().each((_index, node) => {
14293
+ if (++count > MAX_NODES) throw new Error("Source navigation exceeds its safety bound.");
14294
+ if (node === excluded) return;
14295
+ const item = $(node);
14296
+ if (item.is("a[href]")) {
14297
+ const label = item.text().replace(/\s+/g, " ").trim();
14298
+ const url = target(item.attr("href"), capture.finalUrl);
14299
+ if (label && url) result.push({ label, url });
14300
+ } else if (item.is("li,details") || item.attr("data-migration-group") !== void 0 || item.children("h2,h3,h4,h5,h6").length > 0) {
14301
+ const directLink = item.children("a[href]").first();
14302
+ const direct = directLink.length ? directLink : item.children("div").children("a[href]").first();
14303
+ const label = direct.text().trim() || item.children("summary,button,span,h2,h3,h4,h5,h6").first().text().trim();
14304
+ const children = walk2(node, direct[0], depth + 1);
14305
+ const url = target(direct.attr("href"), capture.finalUrl);
14306
+ if (label && (url || children.length)) result.push({ label, ...url ? { url } : {}, ...children.length ? { children } : {} });
14307
+ else result.push(...children);
14308
+ } else result.push(...walk2(node, excluded, depth + 1));
14309
+ });
14310
+ return result;
14311
+ };
14312
+ try {
14313
+ return walk2(root);
14314
+ } catch {
14315
+ return [];
14316
+ }
14317
+ }
14318
+ function placeholder(node) {
14319
+ const children = node.children ?? [];
14320
+ return node.kind === "tab" && children.length === 1 && children[0].kind === "page" && children[0].label === node.label && !children[0].children?.length;
14321
+ }
14322
+ function mergeSourceNavigation(existing, incoming) {
14323
+ let count = 0;
14324
+ const merge = (left, right, depth = 0) => {
14325
+ if (depth > MAX_DEPTH || (count += left.length + right.length) > MAX_NODES * 4) throw new Error("Source navigation exceeds its safety bound.");
14326
+ const result = left.map((node) => ({ ...node }));
14327
+ const identity = (node) => JSON.stringify([
14328
+ node.kind,
14329
+ node.label,
14330
+ node.locale,
14331
+ node.kind === "tab" || node.kind === "group" ? void 0 : node.url
14332
+ ]);
14333
+ const positions = /* @__PURE__ */ new Map();
14334
+ result.forEach((node, index) => {
14335
+ const key = identity(node);
14336
+ const siblings = positions.get(key) ?? [];
14337
+ siblings.push(index);
14338
+ positions.set(key, siblings);
14339
+ });
14340
+ const offsets = /* @__PURE__ */ new Map();
14341
+ for (const next of right) {
14342
+ const key = identity(next);
14343
+ const offset = offsets.get(key) ?? 0;
14344
+ const index = positions.get(key)?.[offset];
14345
+ offsets.set(key, offset + 1);
14346
+ if (index === void 0) {
14347
+ result.push({ ...next });
14348
+ continue;
14349
+ }
14350
+ const previous = result[index];
14351
+ if (placeholder(previous) && !placeholder(next)) result[index] = { ...next };
14352
+ else if (!placeholder(previous) && placeholder(next)) continue;
14353
+ else result[index] = { ...previous, ...next, ...previous.children || next.children ? { children: merge(previous.children ?? [], next.children ?? [], depth + 1) } : {} };
14354
+ }
14355
+ return result;
14356
+ };
14357
+ return merge(existing, incoming);
14358
+ }
14359
+
13946
14360
  // src/url-run.ts
13947
- var CONVERTER_VERSION = "url-evidence-v2";
14361
+ var CONVERTER_VERSION = "url-evidence-v4";
13948
14362
  var parser2 = unified4().use(remarkParse4).use(remarkMdx4);
13949
14363
  var ACCEPT = "text/markdown,text/html,application/xhtml+xml;q=0.9";
13950
14364
  var MAX_RESPONSE_BYTES = 8e6;
@@ -13954,9 +14368,12 @@ var LOCALES = /* @__PURE__ */ new Set(["ar", "cs", "da", "de", "el", "en", "es",
13954
14368
  function hash2(value) {
13955
14369
  return createHash3("sha256").update(value).digest("hex");
13956
14370
  }
14371
+ function canonicalJson(value) {
14372
+ const canonical2 = (value2) => Array.isArray(value2) ? value2.map(canonical2) : value2 !== null && typeof value2 === "object" ? Object.fromEntries(Object.entries(value2).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, field]) => [key, canonical2(field)])) : value2;
14373
+ return JSON.stringify(canonical2(value));
14374
+ }
13957
14375
  function pageHash(page) {
13958
- const canonical2 = (value) => Array.isArray(value) ? value.map(canonical2) : value !== null && typeof value === "object" ? Object.fromEntries(Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, field]) => [key, canonical2(field)])) : value;
13959
- return hash2(JSON.stringify(canonical2(page)));
14376
+ return hash2(canonicalJson(page));
13960
14377
  }
13961
14378
  function inScope(url, source, scope) {
13962
14379
  return url.origin === source.origin && !url.username && !url.password && (scope === "/" || url.pathname === scope || url.pathname.startsWith(`${scope}/`));
@@ -13975,7 +14392,7 @@ function canonical(value, base) {
13975
14392
  }
13976
14393
  function classifyMigrationResponse(document) {
13977
14394
  if (document.status && document.status >= 400) return "unsupported";
13978
- if (/\/(?:llms(?:-full)?|robots)\.txt$|\/sitemap[^/]*\.xml$|\/search(?:\.html)?$/i.test(document.finalUrl.pathname) || /(?:xml|json)/i.test(document.contentType)) return "index";
14395
+ if (/\/(?:llms(?:-full)?|robots)\.txt$|\/sitemap[^/]*\.xml$|\/search(?:\.html)?$/i.test(document.finalUrl.pathname) || /\.(?:json|ya?ml)$/i.test(document.finalUrl.pathname) || /(?:xml|json)/i.test(document.contentType)) return "index";
13979
14396
  if (/^(?:image|audio|video)\//i.test(document.contentType) || /\.(?:pdf|zip|png|jpe?g|webp|gif|svg|ico|mp4|webm)$/i.test(document.finalUrl.pathname)) return "asset";
13980
14397
  return /(?:html|markdown|text\/plain)/i.test(document.contentType) || /\.mdx?$/i.test(document.finalUrl.pathname) ? "page" : "unsupported";
13981
14398
  }
@@ -13997,14 +14414,14 @@ function alternativeBlocks(body, baseline) {
13997
14414
  return blocks(body).filter((block) => !originals.has(block)).join("\n\n");
13998
14415
  }
13999
14416
  function linksOf(document) {
14417
+ if (/json|ya?ml/i.test(document.contentType) || /\.(?:json|ya?ml)$/i.test(document.finalUrl.pathname)) return [];
14000
14418
  if (/html/i.test(document.contentType)) {
14001
- const $ = load3(document.body);
14002
- const root = $('main article,article,main,[role="main"]').first();
14419
+ const { $, root } = migrationHtmlArticle(document.body);
14003
14420
  root.find("nav,footer,aside").remove();
14004
14421
  return [...root.find("a[href]").toArray(), ...$('link[rel="sitemap"][href],link[rel="alternate"][href]').toArray()].map((node) => $(node).attr("href")).filter(Boolean);
14005
14422
  }
14006
14423
  if (/xml/i.test(document.contentType) || /<urlset|<sitemapindex/i.test(document.body)) {
14007
- const $ = load3(document.body, { xmlMode: true });
14424
+ const $ = load4(document.body, { xmlMode: true });
14008
14425
  return $("loc").toArray().map((node) => $(node).text().trim());
14009
14426
  }
14010
14427
  return [
@@ -14013,8 +14430,7 @@ function linksOf(document) {
14013
14430
  ];
14014
14431
  }
14015
14432
  function htmlEvidence(document) {
14016
- const $ = load3(document.body);
14017
- const root = $('main article,article,main,[role="main"]').first();
14433
+ const { $, root } = migrationHtmlArticle(document.body);
14018
14434
  const article = root.length ? root : $("body");
14019
14435
  article.find("nav,footer,aside,form,script,style").remove();
14020
14436
  return {
@@ -14041,55 +14457,35 @@ function evidenceOf(capture) {
14041
14457
  function markdownHeadingAnchors(body) {
14042
14458
  const seen = /* @__PURE__ */ new Map();
14043
14459
  return markdownNodes(body).filter((node) => node.type === "heading").map((node) => {
14044
- const text2 = (value) => value.value ?? (value.children ?? []).map(text2).join("");
14045
- const base = text2(node).toLowerCase().replace(/[^\p{L}\p{N}\s_-]/gu, "").replace(/\s/g, "-");
14460
+ const text3 = (value) => value.value ?? (value.children ?? []).map(text3).join("");
14461
+ const base = text3(node).toLowerCase().replace(/[^\p{L}\p{N}\s_-]/gu, "").replace(/\s/g, "-");
14046
14462
  const occurrence = seen.get(base) ?? 0;
14047
14463
  seen.set(base, occurrence + 1);
14048
14464
  return occurrence ? `${base}-${occurrence}` : base;
14049
14465
  });
14050
14466
  }
14051
14467
  function sourceNavigation(capture) {
14052
- if (capture.navigation) {
14053
- const resolve4 = (nodes, depth = 0) => {
14054
- if (depth > 32 || nodes.length > 1e4) throw new Error("Source navigation exceeds its depth or width safety bound.");
14055
- return nodes.map((node) => ({ label: node.label, ...node.url ? { url: new URL(node.url, capture.finalUrl).toString() } : {}, ...node.children ? { children: resolve4(node.children, depth + 1) } : {} }));
14056
- };
14057
- return resolve4(capture.navigation);
14058
- }
14059
- if (!/html/i.test(capture.contentType)) return [];
14060
- const $ = load3(capture.body);
14061
- const candidates = ['.theme-doc-sidebar-menu,[aria-label*="sidebar" i]', "aside", '[role="navigation"],nav'];
14062
- const root = candidates.map((selector) => $(selector).filter((_index, node) => $(node).find("a[href]").length > 0 && $(node).closest("header").length === 0).first()).find((candidate) => candidate.length) ?? $("aside").first();
14063
- if (!root.length) return [];
14064
- const walk2 = (element, excluded) => {
14065
- const result = [];
14066
- $(element).children().each((_index, node) => {
14067
- if (node === excluded) return;
14068
- const item = $(node);
14069
- if (item.is("a[href]")) {
14070
- result.push({ label: item.text().replace(/\s+/g, " ").trim(), url: new URL(item.attr("href"), capture.finalUrl).toString() });
14071
- } else if (item.is("li,details") || item.attr("data-migration-group") !== void 0 || item.children("h2,h3,h4,h5,h6").length > 0) {
14072
- const directLink = item.children("a[href]").first();
14073
- const direct = directLink.length ? directLink : item.children("div").children("a[href]").first();
14074
- const label = direct.text().trim() || item.children("summary,button,span,h2,h3,h4,h5,h6").first().text().trim();
14075
- const children = walk2(node, direct[0]);
14076
- if (label) result.push({ label, ...direct.length ? { url: new URL(direct.attr("href"), capture.finalUrl).toString() } : {}, ...children.length ? { children } : {} });
14077
- else result.push(...children);
14078
- } else result.push(...walk2(node, excluded));
14079
- });
14080
- return result;
14081
- };
14082
- try {
14083
- return walk2(root);
14084
- } catch {
14085
- return [];
14086
- }
14468
+ return extractSourceNavigation(capture);
14087
14469
  }
14088
14470
  function idForUrl(url, scope) {
14089
14471
  const relative7 = scope === "/" ? url.pathname.slice(1) : url.pathname.slice(scope.length).replace(/^\//, "");
14090
14472
  const id = pageIdFromReference(relative7 || "introduction", true);
14091
14473
  return id && `${id}${url.search ? `--${hash2(url.search).slice(0, 12)}` : ""}`;
14092
14474
  }
14475
+ function articleIdentity(document) {
14476
+ if (!/html/i.test(document.contentType)) return document.finalUrl;
14477
+ const $ = load4(document.body);
14478
+ const reference = $('link[rel="canonical"][href]').first().attr("href");
14479
+ if (!reference) return document.finalUrl;
14480
+ try {
14481
+ const target2 = new URL(reference, document.finalUrl);
14482
+ const source = document.finalUrl;
14483
+ const directory = (path) => path.replace(/\/index\/?$/i, "").replace(/\/$/, "");
14484
+ return target2.origin === source.origin && !target2.username && !target2.password && target2.search === source.search && directory(target2.pathname) === directory(source.pathname) ? target2 : source;
14485
+ } catch {
14486
+ return document.finalUrl;
14487
+ }
14488
+ }
14093
14489
  function convert(document, id) {
14094
14490
  if (/html/i.test(document.contentType)) {
14095
14491
  const technical = htmlEvidence(document);
@@ -14107,9 +14503,20 @@ function convert(document, id) {
14107
14503
  const info = original.split("\n", 1)[0].replace(/^`+|^~+/, "");
14108
14504
  const code = technical.code[index];
14109
14505
  const fence = "`".repeat(Math.max(3, ...[...code.matchAll(/`+/g)].map((match) => match[0].length + 1)));
14506
+ const lineStart = page.body.lastIndexOf("\n", start - 1) + 1;
14507
+ const prefix = page.body.slice(lineStart, start);
14508
+ let hasContainerPrefix = true;
14509
+ for (const character of prefix) {
14510
+ if (character !== " " && character !== " " && character !== ">") {
14511
+ hasContainerPrefix = false;
14512
+ break;
14513
+ }
14514
+ }
14515
+ const indent = hasContainerPrefix ? prefix : "";
14516
+ const payload = code.split("\n").map((line) => `${indent}${line}`).join("\n");
14110
14517
  page.body = `${page.body.slice(0, start)}${fence}${info}
14111
- ${code}
14112
- ${fence}${page.body.slice(end)}`;
14518
+ ${payload}
14519
+ ${indent}${fence}${page.body.slice(end)}`;
14113
14520
  }
14114
14521
  }
14115
14522
  return page;
@@ -14121,16 +14528,14 @@ function assetReferences(capture) {
14121
14528
  if (!/html/i.test(capture.contentType)) {
14122
14529
  return markdownNodes(capture.body).filter((node) => node.type === "image").flatMap((node) => node.url ? [node.url] : []);
14123
14530
  }
14124
- const $ = load3(capture.body);
14125
- const root = $('main article,article,main,[role="main"]').first();
14531
+ const { $, root } = migrationHtmlArticle(capture.body);
14126
14532
  return [
14127
14533
  ...root.find("img[src],video[poster],a[download][href]").toArray().map((node) => $(node).attr("src") ?? $(node).attr("poster") ?? $(node).attr("href")),
14128
14534
  ...root.find("[srcset]").toArray().flatMap((node) => migrationImageCandidates($(node).attr("srcset") ?? "", capture.finalUrl).map((candidate) => candidate.url))
14129
14535
  ].filter(Boolean);
14130
14536
  }
14131
- function unresolvedStaticControls(body) {
14132
- const $ = load3(body);
14133
- const root = $('main article,article,main,[role="main"]').first();
14537
+ function unresolvedStaticControls(body, hasApiSchema = false) {
14538
+ const { $, root } = migrationHtmlArticle(body);
14134
14539
  const tabs = root.find('[role="tab"]').toArray();
14135
14540
  for (const tab of tabs) {
14136
14541
  const controls = $(tab).attr("aria-controls");
@@ -14138,6 +14543,7 @@ function unresolvedStaticControls(body) {
14138
14543
  if (panels.length !== 1 || !panels.text().trim() && !panels.find("pre,img,table,svg").length || panels.find('[aria-busy="true"],[role="progressbar"]').length) return true;
14139
14544
  }
14140
14545
  return root.find("details:not([open])").toArray().some((node) => {
14546
+ if (hasApiSchema && $(node).is(".expandable") && $(node).children('summary[data-component-part="expandable-button"]').length) return false;
14141
14547
  const clone = $(node).clone();
14142
14548
  clone.children("summary").remove();
14143
14549
  return !clone.text().trim() && !clone.find("pre,img,table,svg").length;
@@ -14175,33 +14581,85 @@ function acceptedAsset(asset) {
14175
14581
  }
14176
14582
  function validRecord(record) {
14177
14583
  if (record.outcome !== "imported") return true;
14178
- return Boolean(record.page && record.pageSha256 === pageHash(record.page) && record.evidence && pageIdFromReference(record.page.id, true) === record.page.id && pageIdFromReference(record.page.navigationId, true) === record.page.navigationId && sanitizeRemoteMarkdown(record.page.body.replace(/^<a id="[^"<]*" \/>$/gm, "")) !== null && /^[a-f0-9]{64}$/.test(record.evidence.sha256) && record.assets?.every((asset) => /^migration-assets\/[a-f0-9]{64}\.[a-z0-9]+$/.test(asset.path) && hash2(Buffer.from(asset.base64, "base64")) === asset.sha256));
14584
+ return Boolean(record.page && record.pageSha256 === pageHash(record.page) && record.evidence && pageIdFromReference(record.page.id, true) === record.page.id && pageIdFromReference(record.page.navigationId, true) === record.page.navigationId && sanitizeRemoteMarkdown(record.page.body.replace(/^<a id="[^"<]*" \/>$/gm, "")) !== null && /^[a-f0-9]{64}$/.test(record.evidence.sha256) && (!record.apiSpecification || hasCompleteLocalApiSchema(record.apiSpecification.document) && record.apiSpecification.path === `openapi/migration-${record.apiSpecification.sha256}.json` && hash2(canonicalJson(record.apiSpecification.document)) === record.apiSpecification.sha256) && record.assets?.every((asset) => /^migration-assets\/[a-f0-9]{64}\.[a-z0-9]+$/.test(asset.path) && hash2(Buffer.from(asset.base64, "base64")) === asset.sha256));
14585
+ }
14586
+ function hasCompleteLocalApiSchema(document) {
14587
+ let visited = 0;
14588
+ const visit = (value, depth = 0) => {
14589
+ if (++visited > 1e5 || depth > 96) return false;
14590
+ if (typeof value === "number" && !Number.isFinite(value)) return false;
14591
+ if (!value || typeof value !== "object") return true;
14592
+ if (Array.isArray(value)) return value.every((child) => visit(child, depth + 1));
14593
+ const object2 = value;
14594
+ if (Object.prototype.hasOwnProperty.call(object2, "$ref")) {
14595
+ if (typeof object2.$ref !== "string" || !object2.$ref.startsWith("#/")) return false;
14596
+ let target2 = document;
14597
+ try {
14598
+ for (const encoded of object2.$ref.slice(2).split("/")) {
14599
+ const key = decodeURIComponent(encoded).replace(/~1/g, "/").replace(/~0/g, "~");
14600
+ if (!target2 || typeof target2 !== "object" || !Object.prototype.hasOwnProperty.call(target2, key)) return false;
14601
+ target2 = target2[key];
14602
+ }
14603
+ } catch {
14604
+ return false;
14605
+ }
14606
+ }
14607
+ return Object.values(object2).every((child) => visit(child, depth + 1));
14608
+ };
14609
+ return visit(document);
14179
14610
  }
14180
- function navigationConfig(navigation, records) {
14611
+ function resolveMigrationRecord(records, record) {
14612
+ const seen = /* @__PURE__ */ new Set();
14613
+ while (record?.outcome === "alias") {
14614
+ if (seen.has(record.url) || seen.size >= 32) return void 0;
14615
+ seen.add(record.url);
14616
+ record = records.get(record.aliasOf ?? "");
14617
+ }
14618
+ return record;
14619
+ }
14620
+ function navigationConfig(checkpoint, records) {
14621
+ const navigation = checkpoint.navigation;
14622
+ const projection = localeProjection(checkpoint);
14181
14623
  const project2 = (nodes) => nodes.flatMap((node) => {
14182
14624
  const record = node.url ? records.get(canonical(node.url, node.url) ?? "") : void 0;
14183
- const target = record?.outcome === "alias" ? records.get(record.aliasOf ?? "") : record;
14184
- const page = target?.page;
14625
+ const target2 = resolveMigrationRecord(records, record);
14626
+ const page = target2?.page;
14185
14627
  const children = project2(node.children ?? []);
14186
14628
  if (children.length) {
14187
- const contains = (entries) => entries.some((entry) => typeof entry === "string" ? entry === page?.navigationId : contains(entry.pages));
14188
- return [{ group: node.label || "Documentation", pages: [...page && !contains(children) ? [page.navigationId] : [], ...children] }];
14629
+ const contains = (entries) => entries.some((entry) => typeof entry === "string" ? entry === (page && projection.navigationId(page)) : contains(entry.pages));
14630
+ return [{ group: node.label || "Documentation", pages: [...page && !contains(children) ? [projection.navigationId(page)] : [], ...children] }];
14189
14631
  }
14190
- return page ? [page.navigationId] : [];
14632
+ return page ? [projection.navigationId(page)] : [];
14191
14633
  });
14634
+ const tabs = navigation.filter((node) => node.kind === "tab");
14635
+ if (tabs.length) {
14636
+ const locales = [...new Set(tabs.map((tab) => tab.locale ?? projection.defaultLocale))];
14637
+ const localizedTabs = (locale) => tabs.filter((tab) => (tab.locale ?? projection.defaultLocale) === locale).flatMap((tab) => {
14638
+ const pages2 = project2(tab.children ?? []);
14639
+ return pages2.length || tab.url ? [{ tab: tab.label, ...pages2.length ? { pages: pages2 } : {}, ...tab.url ? { href: tab.url } : {} }] : [];
14640
+ });
14641
+ const primary = localizedTabs(projection.defaultLocale);
14642
+ return { tabs: primary.length ? primary : localizedTabs(locales[0]), ...locales.length > 1 ? {
14643
+ i18n: {
14644
+ defaultLocale: projection.defaultLocale,
14645
+ locales: locales.map((code) => ({ code, label: code === "en" ? "English" : code })),
14646
+ navigation: Object.fromEntries(locales.map((locale) => [locale, localizedTabs(locale)]))
14647
+ }
14648
+ } : {} };
14649
+ }
14192
14650
  const pages = project2(navigation);
14193
14651
  return pages.length ? { tabs: [{ tab: "Documentation", pages }] } : null;
14194
14652
  }
14653
+ function canonicalLanguage(value) {
14654
+ if (!/^[a-z]{2,3}(?:-[a-z0-9]{2,8}){0,4}$/i.test(value)) return void 0;
14655
+ try {
14656
+ return Intl.getCanonicalLocales(value)[0];
14657
+ } catch {
14658
+ return void 0;
14659
+ }
14660
+ }
14195
14661
  function observedLocale(document, id, scopePath) {
14196
14662
  const issues = [];
14197
- const canonicalLanguage = (value) => {
14198
- if (!/^[a-z]{2,3}(?:-[a-z0-9]{2,8}){0,4}$/i.test(value)) return void 0;
14199
- try {
14200
- return Intl.getCanonicalLocales(value)[0];
14201
- } catch {
14202
- return void 0;
14203
- }
14204
- };
14205
14663
  const candidates = [];
14206
14664
  if (document.locale) {
14207
14665
  const locale = canonicalLanguage(document.locale);
@@ -14210,7 +14668,7 @@ function observedLocale(document, id, scopePath) {
14210
14668
  }
14211
14669
  const urlLocale = [id.split("/", 1)[0], ...scopePath.split("/"), document.finalUrl.pathname.split("/").filter(Boolean)[0]].find((segment) => segment && LOCALES.has(segment.toLowerCase()));
14212
14670
  if (urlLocale) candidates.push({ source: "URL", value: canonicalLanguage(urlLocale) });
14213
- const declared = /html/i.test(document.contentType) ? load3(document.body)("html").attr("lang")?.trim() : void 0;
14671
+ const declared = /html/i.test(document.contentType) ? load4(document.body)("html").attr("lang")?.trim() : void 0;
14214
14672
  if (declared) {
14215
14673
  const locale = canonicalLanguage(declared);
14216
14674
  if (locale) candidates.push({ source: "html lang", value: locale });
@@ -14223,37 +14681,73 @@ function observedLocale(document, id, scopePath) {
14223
14681
  }
14224
14682
  function localeProjection(checkpoint) {
14225
14683
  const pages = checkpoint.records.flatMap((record) => record.page ? [record.page] : []);
14226
- const canonicalLocale = (page) => {
14684
+ const declaredLocale = (page) => {
14227
14685
  try {
14228
14686
  return page.locale ? Intl.getCanonicalLocales(page.locale)[0] : void 0;
14229
14687
  } catch {
14230
14688
  return void 0;
14231
14689
  }
14232
14690
  };
14691
+ const declaredLocales = [...new Set(pages.map(declaredLocale).filter((locale) => Boolean(locale)))];
14692
+ const defaultLocale = pages.some((page) => !page.locale) || declaredLocales.includes("en") ? "en" : declaredLocales[0] ?? "en";
14693
+ const records = new Map(checkpoint.records.map((record) => [record.url, record]));
14694
+ const memberships = /* @__PURE__ */ new Map();
14695
+ const observe = (nodes, parentLocale) => {
14696
+ for (const node of nodes) {
14697
+ const locale = node.locale ? canonicalLanguage(node.locale) : parentLocale;
14698
+ const entry = node.url ? records.get(canonical(node.url, checkpoint.sourceUrl) ?? "") : void 0;
14699
+ const page = resolveMigrationRecord(records, entry)?.page;
14700
+ if (page && locale) {
14701
+ const languages = memberships.get(page) ?? /* @__PURE__ */ new Set();
14702
+ languages.add(locale);
14703
+ memberships.set(page, languages);
14704
+ }
14705
+ observe(node.children ?? [], locale);
14706
+ }
14707
+ };
14708
+ observe(checkpoint.navigation);
14709
+ const primaryIds = new Set(pages.filter((page) => !declaredLocale(page) || declaredLocale(page) === defaultLocale).filter((page) => memberships.get(page)?.has(defaultLocale)).map((page) => page.navigationId));
14710
+ const remapped = /* @__PURE__ */ new Map();
14711
+ for (const page of pages) {
14712
+ const languages = memberships.get(page);
14713
+ if (languages?.size !== 1) continue;
14714
+ const locale = [...languages][0];
14715
+ const prefix = `${locale.toLowerCase()}-`;
14716
+ if (locale === defaultLocale || !page.navigationId.toLowerCase().startsWith(prefix)) continue;
14717
+ const navigationId2 = page.navigationId.slice(prefix.length);
14718
+ if (primaryIds.has(navigationId2)) remapped.set(page, { locale, navigationId: navigationId2 });
14719
+ }
14720
+ const canonicalLocale = (page) => remapped.get(page)?.locale ?? declaredLocale(page);
14721
+ const navigationId = (page) => remapped.get(page)?.navigationId ?? page.navigationId;
14233
14722
  const locales = [...new Set(pages.map(canonicalLocale).filter((locale) => Boolean(locale)))];
14234
- const defaultLocale = pages.some((page) => !page.locale) || locales.includes("en") ? "en" : locales[0] ?? "en";
14235
14723
  const pageId = (page) => {
14236
14724
  const locale = canonicalLocale(page);
14237
- return locale ? `${locale === defaultLocale ? "" : `${locale}/`}${page.navigationId}` : page.id;
14725
+ return locale ? `${locale === defaultLocale ? "" : `${locale}/`}${navigationId(page)}` : page.id;
14238
14726
  };
14239
14727
  const route = (page) => {
14240
14728
  const locale = canonicalLocale(page);
14241
14729
  const prefix = locale && locale !== defaultLocale ? `/${locale}` : "";
14242
- return `${prefix}${page.navigationId === "introduction" ? "/" : `/${page.navigationId}`}`;
14730
+ return `${prefix}${navigationId(page) === "introduction" ? "/" : `/${navigationId(page)}`}`;
14243
14731
  };
14244
- return { canonicalLocale, locales, defaultLocale, pageId, route };
14732
+ const redirects = checkpoint.records.flatMap((record) => {
14733
+ if (!record.page || !remapped.has(record.page)) return [];
14734
+ const source = new URL(record.url);
14735
+ return source.search || !/^\/[A-Za-z0-9/_~.%+-]*$/.test(source.pathname) ? [] : [{ source: source.pathname, destination: route(record.page), permanent: true }];
14736
+ });
14737
+ return { canonicalLocale, navigationId, locales, defaultLocale, pageId, route, redirects };
14245
14738
  }
14246
14739
  function validateUrlMigration(checkpoint, cancelled = false) {
14247
14740
  const issues = [];
14741
+ const warnings = [];
14248
14742
  const counts = { pending: 0, imported: 0, excluded: 0, failed: 0, alias: 0 };
14249
14743
  const records = new Map(checkpoint.records.map((record) => [record.url, record]));
14250
14744
  const source = new URL(checkpoint.sourceUrl);
14251
14745
  const projection = localeProjection(checkpoint);
14252
- const primaryIds = new Set(checkpoint.records.flatMap((record) => record.page && (!record.page.locale || projection.canonicalLocale(record.page) === projection.defaultLocale) ? [record.page.navigationId] : []));
14746
+ const primaryIds = new Set(checkpoint.records.flatMap((record) => record.page && (!projection.canonicalLocale(record.page) || projection.canonicalLocale(record.page) === projection.defaultLocale) ? [projection.navigationId(record.page)] : []));
14253
14747
  const outputIds = /* @__PURE__ */ new Set();
14254
14748
  const resolve4 = (url) => {
14255
14749
  const record = records.get(canonical(url, checkpoint.sourceUrl) ?? "");
14256
- return record?.outcome === "alias" ? records.get(record.aliasOf ?? "") : record;
14750
+ return resolveMigrationRecord(records, record);
14257
14751
  };
14258
14752
  for (const record of checkpoint.records) {
14259
14753
  counts[record.outcome]++;
@@ -14263,8 +14757,8 @@ function validateUrlMigration(checkpoint, cancelled = false) {
14263
14757
  const outputId = projection.pageId(record.page);
14264
14758
  if (outputIds.has(outputId)) issues.push({ code: "collision", source: record.url, message: `Multiple source pages map to runtime path ${outputId}.` });
14265
14759
  outputIds.add(outputId);
14266
- if (record.page.locale && projection.canonicalLocale(record.page) !== projection.defaultLocale && !primaryIds.has(record.page.navigationId)) {
14267
- issues.push({ code: "missing-page", source: record.url, message: `Secondary locale ${record.page.locale} requires a primary ${projection.defaultLocale} page at ${record.page.navigationId}; the runtime cannot serve an orphan translation.` });
14760
+ if (projection.canonicalLocale(record.page) && projection.canonicalLocale(record.page) !== projection.defaultLocale && !primaryIds.has(projection.navigationId(record.page))) {
14761
+ issues.push({ code: "missing-page", source: record.url, message: `Secondary locale ${projection.canonicalLocale(record.page)} requires a primary ${projection.defaultLocale} page at ${projection.navigationId(record.page)}; the runtime cannot serve an orphan translation.` });
14268
14762
  }
14269
14763
  const actual = markdownCode(record.page.body);
14270
14764
  if (JSON.stringify(actual) !== JSON.stringify(record.evidence.code)) issues.push({ code: "code-mismatch", source: record.url, message: "Source code payloads differ from converted code payloads." });
@@ -14286,22 +14780,37 @@ function validateUrlMigration(checkpoint, cancelled = false) {
14286
14780
  anchor = decodeURIComponent(anchor);
14287
14781
  } catch {
14288
14782
  }
14289
- if (!destination.evidence?.anchors.includes(anchor)) issues.push({ code: "missing-anchor", source: record.url, message: `Missing source anchor: ${link}` });
14783
+ if (!destination.evidence?.anchors.includes(anchor)) {
14784
+ warnings.push({ code: "source-link-warning", source: record.url, message: `The original source link refers to an absent source anchor: ${link}` });
14785
+ } else if (destination.page) {
14786
+ const nodes = markdownNodes(destination.page.body);
14787
+ const explicit = nodes.flatMap((node) => node.name === "a" ? (node.attributes ?? []).flatMap((attribute) => attribute.name === "id" && typeof attribute.value === "string" ? [attribute.value] : []) : []);
14788
+ if (!explicit.includes(anchor) && !markdownHeadingAnchors(destination.page.body).includes(anchor)) {
14789
+ issues.push({ code: "missing-anchor", source: record.url, message: `Conversion lost a source anchor: ${link}` });
14790
+ }
14791
+ }
14290
14792
  }
14291
14793
  }
14292
14794
  }
14293
- const visit = (nodes) => {
14795
+ const visit = (nodes, parentLocale) => {
14294
14796
  for (const node of nodes) {
14797
+ const locale = node.locale ? canonicalLanguage(node.locale) : parentLocale;
14295
14798
  if (node.url) {
14296
14799
  const url = new URL(node.url, source);
14297
- if (inScope(url, source, checkpoint.scopePath) && !resolve4(url.toString())?.page) issues.push({ code: "navigation-missing", source: node.url, message: `Source navigation target ${node.label} was not imported.` });
14800
+ if (inScope(url, source, checkpoint.scopePath)) {
14801
+ const page = resolve4(url.toString())?.page;
14802
+ if (!page) issues.push({ code: "navigation-missing", source: node.url, message: `Source navigation target ${node.label} was not imported.` });
14803
+ else if (locale && locale !== projection.defaultLocale && !outputIds.has(`${locale}/${projection.navigationId(page)}`)) {
14804
+ issues.push({ code: "navigation-missing", source: node.url, message: `The ${locale} sidebar target ${node.label} has no authored localized runtime page.` });
14805
+ }
14806
+ }
14298
14807
  }
14299
- visit(node.children ?? []);
14808
+ visit(node.children ?? [], locale);
14300
14809
  }
14301
14810
  };
14302
14811
  visit(checkpoint.navigation);
14303
14812
  if (!counts.imported) issues.push({ code: "missing-page", source: checkpoint.sourceUrl, message: "No readable article pages were imported." });
14304
- return { status: cancelled ? "cancelled" : issues.length ? "partial" : "passed", issues, counts };
14813
+ return { status: cancelled ? "cancelled" : issues.length ? "partial" : "passed", issues, counts, ...warnings.length ? { warnings } : {} };
14305
14814
  }
14306
14815
  async function runUrlMigration(options) {
14307
14816
  const source = validateMigrationUrl(options.sourceUrl);
@@ -14331,6 +14840,11 @@ async function runUrlMigration(options) {
14331
14840
  delete record.pageSha256;
14332
14841
  delete record.evidence;
14333
14842
  delete record.assets;
14843
+ delete record.apiSpecification;
14844
+ delete record.version;
14845
+ delete record.issues;
14846
+ delete record.reason;
14847
+ delete record.aliasOf;
14334
14848
  }
14335
14849
  if (record.page && pageIdFromReference(record.page.id, true) !== record.page.id) throw new Error("Checkpoint contains an unsafe page path.");
14336
14850
  records.set(record.url, record);
@@ -14421,13 +14935,24 @@ async function runUrlMigration(options) {
14421
14935
  navigationChanged = false;
14422
14936
  };
14423
14937
  const process2 = async (record) => {
14424
- if (options.signal?.aborted) return;
14938
+ if (options.signal?.aborted || record.outcome !== "pending") return;
14939
+ let claimedId;
14940
+ let claimedFinal;
14941
+ let markdownRepresentation;
14425
14942
  try {
14426
14943
  delete record.reason;
14944
+ delete record.apiSpecification;
14945
+ const represented = resolveMigrationRecord(records, record.representationOf ? records.get(record.representationOf) : void 0);
14946
+ if (represented?.outcome === "imported") {
14947
+ record.outcome = "alias";
14948
+ record.aliasOf = represented.url;
14949
+ return;
14950
+ }
14427
14951
  const document = await capture({ url: new URL(record.url), signal: options.signal });
14428
14952
  if (options.signal?.aborted) return;
14429
14953
  if (Buffer.byteLength(document.body) > MAX_RESPONSE_BYTES) throw new Error("Captured response exceeds the 8 MB safety bound.");
14430
- const final = canonical(document.finalUrl.toString(), sourceUrl);
14954
+ const identity = articleIdentity(document);
14955
+ const final = canonical(identity.toString(), sourceUrl);
14431
14956
  const role = classifyMigrationResponse(document);
14432
14957
  if (!inScope(document.finalUrl, source, scopePath) && !(role === "index" && isDiscoveryIndex(document.finalUrl, source))) {
14433
14958
  record.outcome = "excluded";
@@ -14448,6 +14973,30 @@ async function runUrlMigration(options) {
14448
14973
  for (const link of links) enqueue(link, final, record.url);
14449
14974
  return;
14450
14975
  }
14976
+ if (/html/i.test(document.contentType)) {
14977
+ const $ = load4(document.body);
14978
+ $('link[rel="alternate"][type="text/markdown"][href]').each((_index, node) => {
14979
+ const alternate = canonical($(node).attr("href"), final);
14980
+ if (!alternate) return;
14981
+ const target2 = new URL(alternate), primary = new URL(final);
14982
+ const directory = (path) => path.replace(/\.mdx?$/i, "").replace(/\/index\/?$/i, "").replace(/\/$/, "");
14983
+ if (target2.origin !== primary.origin || target2.search !== primary.search || directory(target2.pathname) !== directory(primary.pathname) || !/\.mdx?$/i.test(target2.pathname)) return;
14984
+ enqueue(alternate, final, "declared-markdown-representation");
14985
+ const sibling = records.get(alternate);
14986
+ sibling.representationOf = record.url;
14987
+ markdownRepresentation ??= alternate;
14988
+ changed.push(sibling);
14989
+ });
14990
+ }
14991
+ const observedNavigation = sourceNavigation(document);
14992
+ if (observedNavigation.length && !(checkpoint.navigation.some((node) => node.kind === "tab") && !observedNavigation.some((node) => node.kind === "tab"))) {
14993
+ const merged = mergeSourceNavigation(checkpoint.navigation, observedNavigation);
14994
+ if (JSON.stringify(merged) !== JSON.stringify(checkpoint.navigation)) {
14995
+ checkpoint.navigation = merged;
14996
+ navigationChanged = true;
14997
+ }
14998
+ enqueueNavigation(observedNavigation, final);
14999
+ }
14451
15000
  if (imported >= maxPages) {
14452
15001
  record.outcome = "excluded";
14453
15002
  record.reason = "A discovery endpoint resolved to an article after the selected page limit.";
@@ -14460,14 +15009,20 @@ async function runUrlMigration(options) {
14460
15009
  return;
14461
15010
  }
14462
15011
  finalUrls.set(final, record.url);
14463
- const id = idForUrl(document.finalUrl, scopePath);
15012
+ claimedFinal = final;
15013
+ const id = idForUrl(identity, scopePath);
14464
15014
  if (!id) throw new Error("Source URL has no safe destination path.");
14465
- if (usedIds.has(id) && usedIds.get(id) !== record.url) {
15015
+ const language = observedLocale(document, id, scopePath);
15016
+ const locale = language.locale;
15017
+ const navigationId = locale ? id.split("/").filter((segment) => segment.toLowerCase() !== locale.toLowerCase()).join("/") || "introduction" : id;
15018
+ const identityId = locale ? `${locale}/${navigationId}` : id;
15019
+ if (usedIds.has(identityId) && usedIds.get(identityId) !== record.url) {
14466
15020
  record.outcome = "failed";
14467
- record.reason = `Destination collision for ${id}.`;
15021
+ record.reason = `Destination collision for ${identityId}.`;
14468
15022
  return;
14469
15023
  }
14470
- usedIds.set(id, record.url);
15024
+ usedIds.set(identityId, record.url);
15025
+ claimedId = identityId;
14471
15026
  const evidence = evidenceOf(document);
14472
15027
  const page = convert(document, id);
14473
15028
  if (!page) {
@@ -14475,6 +15030,23 @@ async function runUrlMigration(options) {
14475
15030
  record.reason = "Content could not be represented as safe inert MDX.";
14476
15031
  return;
14477
15032
  }
15033
+ const hasSchemaChoice = /html/i.test(document.contentType) && migrationHtmlArticle(document.body).root.find('select[aria-label="Select schema type"],select[aria-label="\u9009\u62E9\u67B6\u6784\u7C7B\u578B"]').length > 0;
15034
+ if (/html/i.test(document.contentType) && markdownRepresentation && (unresolvedStaticControls(document.body) || hasSchemaChoice)) {
15035
+ const schemaCapture = await capture({ url: new URL(markdownRepresentation), signal: options.signal });
15036
+ if (options.signal?.aborted) return;
15037
+ if (schemaCapture.status && schemaCapture.status >= 400 || !/text\/(?:markdown|plain)/i.test(schemaCapture.contentType)) throw new Error("API schema representation is not a successful Markdown response.");
15038
+ totalBytes += Buffer.byteLength(schemaCapture.body);
15039
+ if (Buffer.byteLength(schemaCapture.body) > MAX_RESPONSE_BYTES || totalBytes > (options.maxTotalBytes ?? 5e8)) throw new Error("API schema capture exceeds its content byte budget.");
15040
+ const expected = new URL(markdownRepresentation);
15041
+ if (schemaCapture.finalUrl.origin !== expected.origin || schemaCapture.finalUrl.pathname !== expected.pathname || schemaCapture.finalUrl.search !== expected.search) throw new Error("API schema representation escaped its declared identity.");
15042
+ const fragment = extractEmbeddedOpenApi(schemaCapture.body).fragment;
15043
+ if (fragment && hasCompleteLocalApiSchema(fragment.document)) {
15044
+ const sha256 = hash2(canonicalJson(fragment.document));
15045
+ const path = `openapi/migration-${sha256}.json`;
15046
+ record.apiSpecification = { path, sha256, document: fragment.document };
15047
+ page.openapi = `${path} ${fragment.method} ${fragment.path}`;
15048
+ }
15049
+ }
14478
15050
  const states = document.states ?? [];
14479
15051
  if (states.length > 64) throw new Error("Capture contains too many alternative states.");
14480
15052
  for (const state of states) {
@@ -14503,14 +15075,16 @@ ${difference}`;
14503
15075
  record.assets = [];
14504
15076
  record.issues = [];
14505
15077
  if (/html/i.test(document.contentType)) {
14506
- const $ = load3(document.body);
14507
- const root = $('main article,article,main,[role="main"]').first();
15078
+ const { $, root } = migrationHtmlArticle(document.body);
14508
15079
  root.find("nav,footer,aside,.theme-doc-breadcrumbs,.theme-doc-toc-mobile,.table-of-contents,.hash-link").remove();
14509
15080
  root.find('button svg,a.hash-link svg,[aria-hidden="true"] svg,svg[aria-hidden="true"],svg[data-lucide],svg[data-icon]').remove();
14510
- if (root.find("h1").length > 1) record.issues.push({ code: "unsupported-component", source: record.url, message: "The article contains multiple level-one headings; review their hierarchy." });
15081
+ if (record.apiSpecification) {
15082
+ root.find('select[aria-label="Select schema type"],select[aria-label="\u9009\u62E9\u67B6\u6784\u7C7B\u578B"]').remove();
15083
+ root.find('.option-dropdown svg[data-component-part="icon-svg"]').remove();
15084
+ }
14511
15085
  const unsupported = [...new Set(root.find("iframe,object,embed,canvas,svg,form,input,textarea,select,math,video,audio").toArray().map((node) => node.tagName))];
14512
15086
  if (unsupported.length) record.issues.push({ code: "unsupported-component", source: record.url, message: `Rendered content requires explicit review for: ${unsupported.join(", ")}.` });
14513
- if (!states.length && unresolvedStaticControls(document.body)) record.issues.push({ code: "unsupported-component", source: record.url, message: "An interactive alternative has no complete captured panel or disclosure content." });
15087
+ if (!states.length && unresolvedStaticControls(document.body, Boolean(record.apiSpecification))) record.issues.push({ code: "unsupported-component", source: record.url, message: "An interactive alternative has no complete captured panel or disclosure content." });
14514
15088
  }
14515
15089
  const suppliedAssets = new Map((document.assets ?? []).map((asset) => [canonical(asset.url, final), asset]));
14516
15090
  const assetUrls = [...new Set([...assetReferences(document), ...states.flatMap((state) => assetReferences(state.response))].map((url) => canonical(url, final)).filter((url) => Boolean(url)))];
@@ -14550,30 +15124,18 @@ ${difference}`;
14550
15124
  if (sanitizeRemoteMarkdown(page.body.replace(/^<a id="[^"<]*" \/>$/gm, "")) === null) throw new Error("Converted content did not pass inert MDX validation.");
14551
15125
  record.evidence = evidence;
14552
15126
  record.page = page;
14553
- const language = observedLocale(document, page.id, scopePath);
14554
15127
  record.issues.push(...language.issues);
14555
15128
  const canonicalLocale = language.locale;
14556
15129
  if (canonicalLocale) {
14557
15130
  page.locale = canonicalLocale;
14558
- const segments = page.id.split("/");
14559
- const localeIndex = segments.findIndex((segment) => segment.toLowerCase() === canonicalLocale.toLowerCase());
14560
- page.navigationId = segments.filter((_segment, index) => index !== localeIndex).join("/") || "introduction";
15131
+ page.navigationId = navigationId;
14561
15132
  page.id = `${canonicalLocale}/${page.navigationId}`;
14562
- if (usedIds.has(page.id) && usedIds.get(page.id) !== record.url) throw new Error(`Destination collision for locale page ${page.id}.`);
14563
- usedIds.delete(id);
14564
- usedIds.set(page.id, record.url);
14565
15133
  }
14566
15134
  record.version = document.version ?? [...page.id.split("/"), ...document.finalUrl.pathname.split("/")].find((segment) => /^v\d+(?:\.\d+)*$/i.test(segment));
14567
15135
  record.pageSha256 = pageHash(page);
14568
15136
  record.outcome = "imported";
14569
15137
  imported++;
14570
- const navigation = checkpoint.navigation.length ? [] : sourceNavigation(document);
14571
- if (!checkpoint.navigation.length && navigation.length) {
14572
- checkpoint.navigation = navigation;
14573
- navigationChanged = true;
14574
- }
14575
15138
  enqueueArticleLinks(evidence.links, final, record.url);
14576
- enqueueNavigation(navigation, final);
14577
15139
  } catch (error) {
14578
15140
  if (options.signal?.aborted) return;
14579
15141
  const wasImported = record.outcome === "imported";
@@ -14586,13 +15148,43 @@ ${difference}`;
14586
15148
  delete record.page;
14587
15149
  delete record.pageSha256;
14588
15150
  delete record.assets;
15151
+ delete record.apiSpecification;
14589
15152
  } finally {
15153
+ if (record.outcome !== "imported") {
15154
+ if (claimedId && usedIds.get(claimedId) === record.url) usedIds.delete(claimedId);
15155
+ if (claimedFinal && finalUrls.get(claimedFinal) === record.url) finalUrls.delete(claimedFinal);
15156
+ }
14590
15157
  if (record.outcome !== "pending") {
14591
15158
  if (options.onRecord) await options.onRecord(record);
14592
15159
  changed.push(record);
14593
15160
  }
14594
15161
  }
14595
15162
  };
15163
+ const settleRepresentations = () => {
15164
+ for (const record of records.values()) {
15165
+ if (!record.representationOf) continue;
15166
+ const primary = resolveMigrationRecord(records, records.get(record.representationOf));
15167
+ if (!primary) continue;
15168
+ const winner = primary.outcome === "imported" ? primary : record.outcome === "imported" && primary.outcome === "failed" ? record : void 0;
15169
+ if (!winner) continue;
15170
+ const alternate = winner === primary ? record : primary;
15171
+ if (alternate.outcome === "alias" && alternate.aliasOf === winner.url) continue;
15172
+ if (alternate.outcome === "imported") {
15173
+ imported--;
15174
+ if (alternate.page && usedIds.get(alternate.page.id) === alternate.url) usedIds.delete(alternate.page.id);
15175
+ }
15176
+ alternate.outcome = "alias";
15177
+ alternate.aliasOf = winner.url;
15178
+ delete alternate.reason;
15179
+ delete alternate.page;
15180
+ delete alternate.pageSha256;
15181
+ delete alternate.assets;
15182
+ delete alternate.issues;
15183
+ delete alternate.apiSpecification;
15184
+ changed.push(alternate);
15185
+ }
15186
+ };
15187
+ settleRepresentations();
14596
15188
  while (cursor < pending.length && !options.signal?.aborted && !budgetExhausted && cursor < (options.maxCaptures ?? Infinity)) {
14597
15189
  if (imported >= maxPages) {
14598
15190
  const index = pending.findIndex((record, position) => position >= cursor && isDiscoveryIndex(new URL(record.url), source));
@@ -14602,17 +15194,18 @@ ${difference}`;
14602
15194
  const batch = pending.slice(cursor, cursor + Math.min(concurrency, imported >= maxPages ? 1 : maxPages - imported, (options.maxCaptures ?? Infinity) - cursor));
14603
15195
  cursor += batch.length;
14604
15196
  await Promise.all(batch.map(process2));
15197
+ settleRepresentations();
14605
15198
  if (changed.length >= batchSize) await flush();
14606
15199
  }
14607
15200
  await flush();
14608
15201
  const projection = localeProjection(checkpoint);
14609
15202
  const routeMap = /* @__PURE__ */ new Map();
14610
15203
  for (const record of checkpoint.records) {
14611
- const target = record.outcome === "alias" ? records.get(record.aliasOf ?? "") : record;
14612
- if (target?.page) {
14613
- const route = projection.route(target.page);
15204
+ const target2 = resolveMigrationRecord(records, record);
15205
+ if (target2?.page) {
15206
+ const route = projection.route(target2.page);
14614
15207
  routeMap.set(record.url, route);
14615
- if (target.evidence) routeMap.set(canonical(target.evidence.finalUrl, sourceUrl), route);
15208
+ if (target2.evidence) routeMap.set(canonical(target2.evidence.finalUrl, sourceUrl), route);
14616
15209
  }
14617
15210
  }
14618
15211
  const navigationLabels = /* @__PURE__ */ new Map();
@@ -14620,17 +15213,17 @@ ${difference}`;
14620
15213
  const labelPages = (nodes) => {
14621
15214
  for (const node of nodes) {
14622
15215
  const entry = node.url ? records.get(canonical(node.url, sourceUrl) ?? "") : void 0;
14623
- const target = entry?.outcome === "alias" ? records.get(entry.aliasOf ?? "") : entry;
14624
- if (target?.page && node.label && !node.children?.length) {
14625
- const previous = navigationLabels.get(target.url);
14626
- if (previous && previous !== node.label) navigationIssues.push({ code: "unsupported-component", source: target.url, message: `This page has multiple source navigation labels (${previous}, ${node.label}); review the shared sidebar title.` });
14627
- else navigationLabels.set(target.url, node.label);
15216
+ const target2 = resolveMigrationRecord(records, entry);
15217
+ if (target2?.page && node.label && !node.children?.length) {
15218
+ const previous = navigationLabels.get(target2.url);
15219
+ if (previous && previous !== node.label) navigationIssues.push({ code: "unsupported-component", source: target2.url, message: `This page has multiple source navigation labels (${previous}, ${node.label}); review the shared sidebar title.` });
15220
+ else navigationLabels.set(target2.url, node.label);
14628
15221
  }
14629
15222
  labelPages(node.children ?? []);
14630
15223
  }
14631
15224
  };
14632
15225
  labelPages(checkpoint.navigation);
14633
- const pages = checkpoint.records.flatMap((record) => record.page ? [{ ...record.page, id: projection.pageId(record.page), ...record.page.locale ? { locale: projection.canonicalLocale(record.page) } : {}, ...navigationLabels.has(record.url) ? { navTitle: navigationLabels.get(record.url) } : {}, body: rewriteMarkdownDestinations(record.page.body, (value) => {
15226
+ const pages = checkpoint.records.flatMap((record) => record.page ? [{ ...record.page, id: projection.pageId(record.page), navigationId: projection.navigationId(record.page), ...projection.canonicalLocale(record.page) ? { locale: projection.canonicalLocale(record.page) } : {}, ...navigationLabels.has(record.url) ? { navTitle: navigationLabels.get(record.url) } : {}, body: rewriteMarkdownDestinations(record.page.body, (value) => {
14634
15227
  let url;
14635
15228
  try {
14636
15229
  url = new URL(value, record.evidence.finalUrl);
@@ -14650,20 +15243,28 @@ ${difference}`;
14650
15243
  assets.set(asset.path, { path: asset.path, content: Buffer.from(content.buffer, content.byteOffset, content.byteLength) });
14651
15244
  }
14652
15245
  }
15246
+ for (const record of checkpoint.records) if (record.page && record.apiSpecification) {
15247
+ const spec = record.apiSpecification;
15248
+ assets.set(spec.path, { path: spec.path, projectRelative: true, content: Buffer.from(canonicalJson(spec.document)) });
15249
+ }
14653
15250
  const bundle = {
14654
15251
  sourceUrl,
14655
15252
  sourceKind: "url",
14656
15253
  platform: options.platform ?? "generic",
14657
15254
  pages,
14658
15255
  assets: [...assets.values()],
14659
- docsConfig: navigationConfig(checkpoint.navigation, records) ?? buildNavigationFromPages(pages),
14660
- warnings: validation.issues.map((issue) => ({ code: issue.code === "missing-page" ? "missing-page" : "unsupported-config", message: issue.message, source: issue.source })),
15256
+ docsConfig: navigationConfig(checkpoint, records) ?? buildNavigationFromPages(pages),
15257
+ warnings: [...validation.issues, ...validation.warnings ?? []].map((issue) => ({ code: issue.code === "missing-page" ? "missing-page" : "unsupported-config", message: issue.message, source: issue.source })),
14661
15258
  urlMigrationValidation: validation,
14662
15259
  stats: { discovered: records.size, imported: pages.length, skipped: records.size - pages.length }
14663
15260
  };
15261
+ if (projection.redirects.length) bundle.docsConfig.redirects = projection.redirects;
14664
15262
  if (projection.locales.length) {
14665
15263
  const locales = [.../* @__PURE__ */ new Set([projection.defaultLocale, ...projection.locales])];
14666
- bundle.docsConfig.i18n = { defaultLocale: projection.defaultLocale, locales: locales.map((code) => ({ code, label: code === "en" ? "English" : code })) };
15264
+ bundle.docsConfig.i18n = { ...bundle.docsConfig.i18n, defaultLocale: projection.defaultLocale, locales: locales.map((code) => ({ code, label: code === "en" ? "English" : code })) };
15265
+ }
15266
+ for (const spec of assets.values()) if (spec.projectRelative && spec.path.startsWith("openapi/")) {
15267
+ bundle.docsConfig.tabs.push({ tab: `Migration API ${spec.path.slice(-69, -5)}`, hidden: true, api: { source: spec.path, navigation: false } });
14667
15268
  }
14668
15269
  const stopReason = options.signal?.aborted ? "cancelled" : budgetExhausted ? "byte-limit" : cursor < pending.length && cursor >= (options.maxCaptures ?? Infinity) ? "capture-limit" : imported >= maxPages && cursor < pending.length ? "page-limit" : cursor < pending.length ? "capture-limit" : "complete";
14669
15270
  return { bundle, checkpoint, validation, stopReason };
@@ -14808,8 +15409,8 @@ async function downloadSpec(value, fetcher) {
14808
15409
  throw new Error("Remote OpenAPI spec redirected too many times.");
14809
15410
  }
14810
15411
  function parseOpenApi(content, extension) {
14811
- const text2 = content.toString("utf8");
14812
- const parsed = extension === "yaml" || !text2.trimStart().startsWith("{") ? parseYaml7(text2) : JSON.parse(text2);
15412
+ const text3 = content.toString("utf8");
15413
+ const parsed = extension === "yaml" || !text3.trimStart().startsWith("{") ? parseYaml7(text3) : JSON.parse(text3);
14813
15414
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("OpenAPI spec is not an object.");
14814
15415
  const document = parsed;
14815
15416
  if (typeof document.openapi !== "string" || !/^3\./.test(document.openapi)) {