@thallylabs/migrate 0.2.29 → 0.2.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -8
- package/dist/index.js +1066 -494
- package/dist/index.js.map +1 -1
- package/dist/{url-migration-CDjLZVaN.d.ts → url-migration-Coy62q1L.d.ts} +15 -1
- package/dist/url-migration.d.ts +1 -1
- package/dist/url-migration.js +760 -188
- package/dist/url-migration.js.map +1 -1
- package/package.json +1 -1
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
|
|
282
|
-
if (
|
|
283
|
-
let base =
|
|
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
|
|
488
|
-
if (
|
|
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
|
|
544
|
-
return
|
|
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
|
|
705
|
+
const target2 = isAssignmentTarget(node);
|
|
706
706
|
for (const property of node.properties) {
|
|
707
|
-
if ((ts.isPropertyAssignment(property) || ts.isShorthandPropertyAssignment(property)) && !safeKey(property.name, !
|
|
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
|
|
726
|
-
if (
|
|
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
|
|
876
|
-
const fromRoot = relative(resolve(confineRoot),
|
|
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
|
|
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(
|
|
1319
|
-
return
|
|
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(
|
|
1322
|
-
return
|
|
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(
|
|
1325
|
-
return
|
|
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
|
|
1349
|
-
const id = mintlifyHeadingSlug(
|
|
1350
|
-
return `${heading[1]}${source}${id && id !== thallyHeadingSlug(
|
|
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((
|
|
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
|
|
1429
|
-
const title =
|
|
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 = (
|
|
1509
|
-
blocks.push(
|
|
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((
|
|
1514
|
+
const masked = [tagMasked, tagMasked].reduce((text3) => text3.replace(/(?<!\$)\{[^{}]*\}/g, stash), tagMasked);
|
|
1515
1515
|
return {
|
|
1516
1516
|
masked,
|
|
1517
|
-
unmask: (
|
|
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(
|
|
1674
|
-
return /\/>\s*$/.test(
|
|
1673
|
+
function isSelfClosingJsx(text3) {
|
|
1674
|
+
return /\/>\s*$/.test(text3);
|
|
1675
1675
|
}
|
|
1676
|
-
function renameTagOccurrences(
|
|
1677
|
-
let result =
|
|
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
|
|
1723
|
+
const text3 = body.slice(start, end);
|
|
1724
1724
|
if (isJsx && tagRoot === "Link" && !declared.has("Link")) {
|
|
1725
|
-
if (isSelfClosingJsx(
|
|
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(
|
|
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
|
|
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 = (
|
|
1755
|
-
blocks.push(
|
|
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: (
|
|
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(
|
|
1796
|
-
return `{/*${
|
|
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 = (
|
|
1828
|
-
if (!
|
|
1829
|
-
const suffixAt =
|
|
1830
|
-
const pathname = suffixAt < 0 ?
|
|
1831
|
-
const suffix = suffixAt < 0 ? "" :
|
|
1832
|
-
if (!pathname || pathname.startsWith("//") || pathname.split("/").some((part) => /%2f|%5c/i.test(part))) return
|
|
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}` :
|
|
1836
|
+
return route ? `/${route.replace(/^\/+/, "")}${suffix}` : target2;
|
|
1837
1837
|
};
|
|
1838
|
-
return replaceOutsideCode(body, (
|
|
1838
|
+
return replaceOutsideCode(body, (text3) => text3.replace(
|
|
1839
1839
|
/(\]\()(<[^>\n]+>|[^\s)]+)(?=\s|\))/g,
|
|
1840
|
-
(_match, opening,
|
|
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,
|
|
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,
|
|
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(
|
|
2306
|
-
if (from <
|
|
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 <
|
|
2310
|
-
const char =
|
|
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 =
|
|
2324
|
-
return { end: i + 1, selfClosing, attributes:
|
|
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((
|
|
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((
|
|
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
|
-
(
|
|
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
|
|
3305
|
-
const syntax = ts2.transpileModule(
|
|
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(
|
|
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
|
|
3350
|
-
visit(
|
|
3351
|
-
dependencies.push(outputPath(
|
|
3352
|
-
const nextPath = relative2(dirname(destination), outputPath(
|
|
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(
|
|
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
|
|
3919
|
-
const opening =
|
|
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 =
|
|
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
|
|
4214
|
-
if (
|
|
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
|
|
4383
|
-
if (!
|
|
4384
|
-
return
|
|
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
|
|
4404
|
-
if (!
|
|
4405
|
-
if (typeof
|
|
4406
|
-
const [filePart, pointer = ""] =
|
|
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: ${
|
|
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(
|
|
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(
|
|
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
|
|
4477
|
-
if (!
|
|
4478
|
-
visit(
|
|
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
|
|
4487
|
-
if (
|
|
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
|
|
4494
|
-
return
|
|
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
|
|
4550
|
-
if (!
|
|
4551
|
-
const reason = gate ?? navigationGateReason(
|
|
4552
|
-
if (reason && typeof
|
|
4553
|
-
for (const value of Object.values(
|
|
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
|
|
4562
|
-
if (!
|
|
4563
|
-
const nested = descendNavigationAccess(access, navigationAccess(
|
|
4561
|
+
const object2 = objectValue2(node);
|
|
4562
|
+
if (!object2) return;
|
|
4563
|
+
const nested = descendNavigationAccess(access, navigationAccess(object2));
|
|
4564
4564
|
if (hasNavigationRules(nested)) {
|
|
4565
|
-
const refs = [
|
|
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(
|
|
4570
|
+
for (const value of Object.values(object2)) collectReferenceAccess(value, nested, pathPrefix, out, depth + 1);
|
|
4571
4571
|
}
|
|
4572
|
-
function withContainerAccess(
|
|
4572
|
+
function withContainerAccess(object2, context, walk2) {
|
|
4573
4573
|
const outer = context.access;
|
|
4574
|
-
context.access = descendNavigationAccess(outer, navigationAccess(
|
|
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
|
|
4628
|
-
if (!
|
|
4629
|
-
return withContainerAccess(
|
|
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(
|
|
4641
|
-
if (typeof
|
|
4642
|
-
const href = projectedHref(
|
|
4643
|
-
if (href && !
|
|
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
|
|
4654
|
-
if (isNavigationRestricted(context.access) || context.gatedNodes.has(
|
|
4655
|
-
const imported = context.resolveSourceRef?.(
|
|
4656
|
-
if (imported) return { group:
|
|
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 ?? ""}:${
|
|
4661
|
-
`Navigation in ${where} mounts the docs of the repository ${
|
|
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(
|
|
4666
|
-
if ("group" in
|
|
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(
|
|
4670
|
-
if (typeof
|
|
4671
|
-
const root = registerReference(
|
|
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(
|
|
4692
|
-
...iconName(
|
|
4693
|
-
...
|
|
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
|
|
4784
|
-
if (!
|
|
4785
|
-
const tab = labelFor(
|
|
4786
|
-
const href = projectedHref(
|
|
4787
|
-
const hasNestedContainers = [...containerKeys, "menu"].some((containerKey) => Array.isArray(
|
|
4788
|
-
if (href && !
|
|
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(
|
|
4793
|
-
...
|
|
4792
|
+
...containerPresentation(object2),
|
|
4793
|
+
...object2.hidden === true ? { hidden: true } : {}
|
|
4794
4794
|
}];
|
|
4795
4795
|
}
|
|
4796
|
-
const nested = withContainerAccess(
|
|
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(
|
|
4802
|
+
...containerPresentation(object2),
|
|
4803
4803
|
...href ? { href } : {},
|
|
4804
|
-
...
|
|
4804
|
+
...object2.hidden === true ? { hidden: true } : {}
|
|
4805
4805
|
}];
|
|
4806
4806
|
}
|
|
4807
|
-
const presentation = containerPresentation(
|
|
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
|
-
...
|
|
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
|
|
5501
|
-
for (const [marker, link] of links)
|
|
5502
|
-
return
|
|
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(
|
|
5599
|
-
const rawPath = String(
|
|
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
|
|
5616
|
-
const segment = typeof
|
|
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(
|
|
5650
|
-
if (typeof
|
|
5651
|
-
const label = typeof
|
|
5652
|
-
const segment = segmentFor(
|
|
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(
|
|
5654
|
+
return registerPageAt(object2.path, base, context, label, object2.hidden === true) || null;
|
|
5655
5655
|
}
|
|
5656
|
-
function isRestrictedNode(
|
|
5657
|
-
const 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 =
|
|
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
|
|
5671
|
-
if (!
|
|
5670
|
+
const object2 = objectValue3(node);
|
|
5671
|
+
if (!object2) return null;
|
|
5672
5672
|
const walk2 = context.navigationWalk;
|
|
5673
|
-
const reason = walk2.active.has(
|
|
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(
|
|
5680
|
+
walk2.active.add(object2);
|
|
5681
5681
|
try {
|
|
5682
|
-
if (isRestrictedNode(
|
|
5682
|
+
if (isRestrictedNode(object2)) {
|
|
5683
5683
|
const before = restrictionMark(context);
|
|
5684
|
-
convertNodeContents({ ...
|
|
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(
|
|
5688
|
+
return convertNodeContents(object2, parentSegments, context);
|
|
5689
5689
|
} finally {
|
|
5690
|
-
walk2.active.delete(
|
|
5690
|
+
walk2.active.delete(object2);
|
|
5691
5691
|
}
|
|
5692
5692
|
}
|
|
5693
|
-
function convertNodeContents(
|
|
5694
|
-
if (typeof
|
|
5695
|
-
const page = registerPage(
|
|
5696
|
-
return
|
|
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
|
|
5699
|
-
const folder = registerFolder(
|
|
5700
|
-
return
|
|
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
|
|
5703
|
-
const label =
|
|
5704
|
-
const segment = segmentFor(
|
|
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(
|
|
5706
|
+
const contents = Array.isArray(object2.contents) ? object2.contents : [];
|
|
5707
5707
|
const pages = [];
|
|
5708
|
-
const hasOwnPath = typeof
|
|
5708
|
+
const hasOwnPath = typeof object2.path === "string" && object2.path.trim().length > 0;
|
|
5709
5709
|
if (hasOwnPath) {
|
|
5710
|
-
const registered = registerPageAt(
|
|
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,
|
|
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 (
|
|
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(
|
|
5723
|
-
...typeof
|
|
5724
|
-
...
|
|
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
|
|
5729
|
-
const label =
|
|
5730
|
-
const rawHref = typeof
|
|
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 &&
|
|
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 &&
|
|
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
|
|
5749
|
-
const ownSegment = segmentFor(
|
|
5748
|
+
if (typeof object2.api === "string") {
|
|
5749
|
+
const ownSegment = segmentFor(object2, object2.api, context);
|
|
5750
5750
|
context.apiSections.push({
|
|
5751
|
-
name: typeof
|
|
5752
|
-
nameExplicit: typeof
|
|
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
|
|
5758
|
-
return registerFolder({ folder:
|
|
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
|
|
6262
|
-
return [{ title:
|
|
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(
|
|
6288
|
-
if (!
|
|
6289
|
-
const suffixIndex =
|
|
6290
|
-
const path = suffixIndex >= 0 ?
|
|
6291
|
-
const suffix = suffixIndex >= 0 ?
|
|
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)) ?
|
|
6295
|
+
return options.assetPaths?.has(path.slice(1)) ? target2 : null;
|
|
6296
6296
|
}
|
|
6297
|
-
function rewriteTarget(
|
|
6298
|
-
if (!
|
|
6299
|
-
if (
|
|
6300
|
-
const suffixIndex =
|
|
6301
|
-
const path = suffixIndex >= 0 ?
|
|
6302
|
-
const suffix = suffixIndex >= 0 ?
|
|
6303
|
-
const copiedAsset = copiedAssetTarget(
|
|
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?.(
|
|
6317
|
-
return new URL(
|
|
6316
|
+
options.onExternalLink?.(target2);
|
|
6317
|
+
return new URL(target2, options.sourceOrigin).toString();
|
|
6318
6318
|
}
|
|
6319
|
-
return
|
|
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,
|
|
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
|
|
6335
|
-
const rewritten = rewriteTarget(
|
|
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
|
|
6422
|
-
if (!
|
|
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,
|
|
6425
|
+
bindings.set(bindingName, object2);
|
|
6426
6426
|
continue;
|
|
6427
6427
|
}
|
|
6428
|
-
return
|
|
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
|
|
6518
|
-
const candidate2 =
|
|
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
|
|
6630
|
-
if (!
|
|
6629
|
+
const object2 = objectValue4(parsed);
|
|
6630
|
+
if (!object2) return {};
|
|
6631
6631
|
return {
|
|
6632
|
-
...typeof
|
|
6633
|
-
...typeof
|
|
6634
|
-
..."link" in
|
|
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((
|
|
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
|
|
6942
|
-
if (!
|
|
6943
|
-
if (
|
|
6944
|
-
const page = typeof
|
|
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 (
|
|
6948
|
-
return autogeneratedItems(typeof
|
|
6947
|
+
if (object2.type === "autogenerated") {
|
|
6948
|
+
return autogeneratedItems(typeof object2.dirName === "string" ? object2.dirName : ".", context);
|
|
6949
6949
|
}
|
|
6950
|
-
if (
|
|
6951
|
-
const label = typeof
|
|
6952
|
-
const pages = convertItems(
|
|
6953
|
-
const landing = generatedIndexPage(label,
|
|
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 (
|
|
6958
|
-
return Object.entries(
|
|
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
|
|
7051
|
-
if (
|
|
7052
|
-
if (decl.prop.startsWith("--ifm-"))
|
|
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(([
|
|
7075
|
+
const declarations2 = (mode) => Object.entries(mapped).flatMap(([target2, source]) => {
|
|
7076
7076
|
const hex = color(source, mode);
|
|
7077
|
-
return 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 [
|
|
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 &&
|
|
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
|
|
7212
|
+
const text3 = content.toString("utf8");
|
|
7213
7213
|
let doc;
|
|
7214
7214
|
try {
|
|
7215
|
-
doc = parseYaml4(
|
|
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
|
|
7235
|
-
if (
|
|
7236
|
-
|
|
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 =
|
|
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, "&");
|
|
@@ -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
|
|
8136
|
-
if (
|
|
8137
|
-
if (scopePath === "/" && candidateIdentity(
|
|
8138
|
-
return `/${
|
|
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 =
|
|
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}${
|
|
8196
|
+
return `${destination}${target2.search}${target2.hash}`;
|
|
8154
8197
|
}
|
|
8155
|
-
return
|
|
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
|
-
|
|
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
|
|
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) || !(
|
|
8223
|
-
const
|
|
8224
|
-
|
|
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(
|
|
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(
|
|
8280
|
-
|
|
8345
|
+
if (!Object.prototype.hasOwnProperty.call(target2, key)) {
|
|
8346
|
+
target2[key] = value;
|
|
8281
8347
|
continue;
|
|
8282
8348
|
}
|
|
8283
|
-
const current =
|
|
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
|
|
8331
|
-
const links =
|
|
8332
|
-
const scopedTitle = options.omitDocumentHeading ?
|
|
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, "&").replace(/"/g, """).replace(/</g, "<").replace(/\{/g, "{")}" />
|
|
@@ -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: (
|
|
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]))} ` :
|
|
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: (
|
|
8560
|
+
replacement: (content) => `
|
|
8420
8561
|
|
|
8421
8562
|
<picture>
|
|
8422
|
-
${
|
|
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) =>
|
|
8485
|
-
|
|
8486
|
-
true
|
|
8487
|
-
|
|
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 = (
|
|
8666
|
+
turndown.escape = (text3) => isConvertingTableCell ? escape(text3.replace(/[<>{}]/g, (character) => ({ "<": "<", ">": ">", "{": "{", "}": "}" })[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
|
|
8606
|
-
if (
|
|
8607
|
-
const relativePath =
|
|
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(
|
|
8794
|
+
function mergeItems(target2, incoming) {
|
|
8649
8795
|
for (const item of incoming) {
|
|
8650
|
-
const existing =
|
|
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
|
-
|
|
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
|
|
8724
|
-
if (!isInScope(
|
|
8869
|
+
const target2 = new URL(href, document.finalUrl);
|
|
8870
|
+
if (!isInScope(target2, source, scopePath)) return;
|
|
8725
8871
|
anchorCount += 1;
|
|
8726
|
-
const targetId = canonicalLocalizedPageId(pageIdForUrl(
|
|
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(
|
|
9141
|
-
return
|
|
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(
|
|
9244
|
-
const [, base, tail] = /^([^?#]*)([\s\S]*)$/.exec(
|
|
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(
|
|
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 = (
|
|
9263
|
-
const fix = (
|
|
9264
|
-
return replaceOutsideCodeAndComments(body, (
|
|
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
|
|
9324
|
-
return [
|
|
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
|
|
10199
|
+
let target2;
|
|
10054
10200
|
try {
|
|
10055
|
-
|
|
10201
|
+
target2 = statSync(real);
|
|
10056
10202
|
} catch {
|
|
10057
10203
|
continue;
|
|
10058
10204
|
}
|
|
10059
|
-
if (
|
|
10060
|
-
else if (
|
|
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(
|
|
10175
|
-
for (const word of
|
|
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
|
|
10244
|
-
const topLevel =
|
|
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 = (
|
|
10511
|
-
const suffixIndex =
|
|
10512
|
-
const path = (suffixIndex >= 0 ?
|
|
10513
|
-
const suffix = suffixIndex >= 0 ?
|
|
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(
|
|
10665
|
+
unmatched.add(target2);
|
|
10520
10666
|
return `${landing}${suffix}`;
|
|
10521
10667
|
}
|
|
10522
10668
|
}
|
|
10523
|
-
return
|
|
10669
|
+
return target2;
|
|
10524
10670
|
};
|
|
10525
|
-
return line.replace(/(\]\()\/([^\s)]+)(?=[\s)]|$)/g, (_match, prefix,
|
|
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
|
|
10832
|
+
const text3 = withoutFencedCode3(raw).replace(/(`{1,3})[^`\n]*\1/g, "");
|
|
10687
10833
|
const marker = /<If(?![\w$.-])/g;
|
|
10688
|
-
for (let match = marker.exec(
|
|
10689
|
-
const tag = scanJsxOpeningTag(
|
|
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 = (
|
|
10903
|
-
const path =
|
|
10904
|
-
if (!path || pageIds.has(path) || ASSET_EXTENSIONS.has(extname6(path).toLowerCase())) return
|
|
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(
|
|
10908
|
-
if (sourceLinkUrl.origin !== base.origin) return
|
|
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(
|
|
11056
|
+
externalized.add(target2);
|
|
10911
11057
|
return sourceLink;
|
|
10912
11058
|
} catch {
|
|
10913
|
-
return
|
|
11059
|
+
return target2;
|
|
10914
11060
|
}
|
|
10915
11061
|
};
|
|
10916
|
-
return replaceOutsideCode(body, (
|
|
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, (
|
|
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 = (
|
|
10925
|
-
const suffixAt =
|
|
10926
|
-
const pathname = suffixAt < 0 ?
|
|
10927
|
-
const suffix = suffixAt < 0 ? "" :
|
|
10928
|
-
if (!pathname.startsWith("/") || pathname.startsWith("//") || pathname.includes("\\")) return
|
|
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
|
|
10931
|
-
if (pageIds.has(segments.join("/"))) return
|
|
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
|
|
11082
|
+
return target2;
|
|
10937
11083
|
};
|
|
10938
|
-
return replaceOutsideCode(body, (
|
|
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 = (
|
|
10945
|
-
const hash3 =
|
|
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(
|
|
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 =
|
|
10955
|
-
const id =
|
|
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, (
|
|
10963
|
-
for (const match of
|
|
10964
|
-
for (const match of
|
|
10965
|
-
return
|
|
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, (
|
|
10974
|
-
for (const match of
|
|
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
|
|
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, (
|
|
10998
|
-
for (const match of
|
|
10999
|
-
for (const match of
|
|
11000
|
-
return
|
|
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, (
|
|
11287
|
-
const rewriteTarget = (
|
|
11288
|
-
const suffixIndex =
|
|
11289
|
-
const path = (suffixIndex >= 0 ?
|
|
11290
|
-
const suffix = suffixIndex >= 0 ?
|
|
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}` :
|
|
11438
|
+
return renamed ? `/${renamed}${suffix}` : target2;
|
|
11293
11439
|
};
|
|
11294
|
-
return
|
|
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: (
|
|
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,
|
|
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 = (
|
|
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((
|
|
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
|
|
13512
|
-
if (!
|
|
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
|
-
|
|
13519
|
-
delete
|
|
13664
|
+
target2.pages = [...target2.pages ?? target2.groups ?? [], ...incomingRootNodes];
|
|
13665
|
+
delete target2.groups;
|
|
13520
13666
|
} else if (uniqueTab.groups?.length) {
|
|
13521
|
-
if (
|
|
13522
|
-
else
|
|
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
|
|
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
|
|
13807
|
-
if (
|
|
13808
|
-
const declaration = /^<\?xml\b[^>]*\?>/iu.exec(
|
|
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(
|
|
13958
|
+
} else if (/<\?xml\b/iu.test(text3)) {
|
|
13813
13959
|
return null;
|
|
13814
13960
|
}
|
|
13815
|
-
return
|
|
13961
|
+
return text3;
|
|
13816
13962
|
}
|
|
13817
13963
|
function isPassiveSvg(content) {
|
|
13818
|
-
const
|
|
13819
|
-
if (
|
|
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(
|
|
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-
|
|
14361
|
+
var CONVERTER_VERSION = "url-evidence-v3";
|
|
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
|
-
|
|
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
|
|
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 $ =
|
|
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
|
|
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
|
|
14045
|
-
const base =
|
|
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
|
-
|
|
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
|
-
${
|
|
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
|
|
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
|
|
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,13 +14581,47 @@ 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);
|
|
14610
|
+
}
|
|
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;
|
|
14179
14619
|
}
|
|
14180
14620
|
function navigationConfig(navigation, records) {
|
|
14181
14621
|
const project2 = (nodes) => nodes.flatMap((node) => {
|
|
14182
14622
|
const record = node.url ? records.get(canonical(node.url, node.url) ?? "") : void 0;
|
|
14183
|
-
const
|
|
14184
|
-
const page =
|
|
14623
|
+
const target2 = resolveMigrationRecord(records, record);
|
|
14624
|
+
const page = target2?.page;
|
|
14185
14625
|
const children = project2(node.children ?? []);
|
|
14186
14626
|
if (children.length) {
|
|
14187
14627
|
const contains = (entries) => entries.some((entry) => typeof entry === "string" ? entry === page?.navigationId : contains(entry.pages));
|
|
@@ -14189,6 +14629,23 @@ function navigationConfig(navigation, records) {
|
|
|
14189
14629
|
}
|
|
14190
14630
|
return page ? [page.navigationId] : [];
|
|
14191
14631
|
});
|
|
14632
|
+
const tabs = navigation.filter((node) => node.kind === "tab");
|
|
14633
|
+
if (tabs.length) {
|
|
14634
|
+
const projection = localeProjection({ records: [...records.values()] });
|
|
14635
|
+
const locales = [...new Set(tabs.map((tab) => tab.locale ?? projection.defaultLocale))];
|
|
14636
|
+
const localizedTabs = (locale) => tabs.filter((tab) => (tab.locale ?? projection.defaultLocale) === locale).flatMap((tab) => {
|
|
14637
|
+
const pages2 = project2(tab.children ?? []);
|
|
14638
|
+
return pages2.length || tab.url ? [{ tab: tab.label, ...pages2.length ? { pages: pages2 } : {}, ...tab.url ? { href: tab.url } : {} }] : [];
|
|
14639
|
+
});
|
|
14640
|
+
const primary = localizedTabs(projection.defaultLocale);
|
|
14641
|
+
return { tabs: primary.length ? primary : localizedTabs(locales[0]), ...locales.length > 1 ? {
|
|
14642
|
+
i18n: {
|
|
14643
|
+
defaultLocale: projection.defaultLocale,
|
|
14644
|
+
locales: locales.map((code) => ({ code, label: code === "en" ? "English" : code })),
|
|
14645
|
+
navigation: Object.fromEntries(locales.map((locale) => [locale, localizedTabs(locale)]))
|
|
14646
|
+
}
|
|
14647
|
+
} : {} };
|
|
14648
|
+
}
|
|
14192
14649
|
const pages = project2(navigation);
|
|
14193
14650
|
return pages.length ? { tabs: [{ tab: "Documentation", pages }] } : null;
|
|
14194
14651
|
}
|
|
@@ -14210,7 +14667,7 @@ function observedLocale(document, id, scopePath) {
|
|
|
14210
14667
|
}
|
|
14211
14668
|
const urlLocale = [id.split("/", 1)[0], ...scopePath.split("/"), document.finalUrl.pathname.split("/").filter(Boolean)[0]].find((segment) => segment && LOCALES.has(segment.toLowerCase()));
|
|
14212
14669
|
if (urlLocale) candidates.push({ source: "URL", value: canonicalLanguage(urlLocale) });
|
|
14213
|
-
const declared = /html/i.test(document.contentType) ?
|
|
14670
|
+
const declared = /html/i.test(document.contentType) ? load4(document.body)("html").attr("lang")?.trim() : void 0;
|
|
14214
14671
|
if (declared) {
|
|
14215
14672
|
const locale = canonicalLanguage(declared);
|
|
14216
14673
|
if (locale) candidates.push({ source: "html lang", value: locale });
|
|
@@ -14245,6 +14702,7 @@ function localeProjection(checkpoint) {
|
|
|
14245
14702
|
}
|
|
14246
14703
|
function validateUrlMigration(checkpoint, cancelled = false) {
|
|
14247
14704
|
const issues = [];
|
|
14705
|
+
const warnings = [];
|
|
14248
14706
|
const counts = { pending: 0, imported: 0, excluded: 0, failed: 0, alias: 0 };
|
|
14249
14707
|
const records = new Map(checkpoint.records.map((record) => [record.url, record]));
|
|
14250
14708
|
const source = new URL(checkpoint.sourceUrl);
|
|
@@ -14253,7 +14711,7 @@ function validateUrlMigration(checkpoint, cancelled = false) {
|
|
|
14253
14711
|
const outputIds = /* @__PURE__ */ new Set();
|
|
14254
14712
|
const resolve4 = (url) => {
|
|
14255
14713
|
const record = records.get(canonical(url, checkpoint.sourceUrl) ?? "");
|
|
14256
|
-
return
|
|
14714
|
+
return resolveMigrationRecord(records, record);
|
|
14257
14715
|
};
|
|
14258
14716
|
for (const record of checkpoint.records) {
|
|
14259
14717
|
counts[record.outcome]++;
|
|
@@ -14286,7 +14744,15 @@ function validateUrlMigration(checkpoint, cancelled = false) {
|
|
|
14286
14744
|
anchor = decodeURIComponent(anchor);
|
|
14287
14745
|
} catch {
|
|
14288
14746
|
}
|
|
14289
|
-
if (!destination.evidence?.anchors.includes(anchor))
|
|
14747
|
+
if (!destination.evidence?.anchors.includes(anchor)) {
|
|
14748
|
+
warnings.push({ code: "source-link-warning", source: record.url, message: `The original source link refers to an absent source anchor: ${link}` });
|
|
14749
|
+
} else if (destination.page) {
|
|
14750
|
+
const nodes = markdownNodes(destination.page.body);
|
|
14751
|
+
const explicit = nodes.flatMap((node) => node.name === "a" ? (node.attributes ?? []).flatMap((attribute) => attribute.name === "id" && typeof attribute.value === "string" ? [attribute.value] : []) : []);
|
|
14752
|
+
if (!explicit.includes(anchor) && !markdownHeadingAnchors(destination.page.body).includes(anchor)) {
|
|
14753
|
+
issues.push({ code: "missing-anchor", source: record.url, message: `Conversion lost a source anchor: ${link}` });
|
|
14754
|
+
}
|
|
14755
|
+
}
|
|
14290
14756
|
}
|
|
14291
14757
|
}
|
|
14292
14758
|
}
|
|
@@ -14301,7 +14767,7 @@ function validateUrlMigration(checkpoint, cancelled = false) {
|
|
|
14301
14767
|
};
|
|
14302
14768
|
visit(checkpoint.navigation);
|
|
14303
14769
|
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 };
|
|
14770
|
+
return { status: cancelled ? "cancelled" : issues.length ? "partial" : "passed", issues, counts, ...warnings.length ? { warnings } : {} };
|
|
14305
14771
|
}
|
|
14306
14772
|
async function runUrlMigration(options) {
|
|
14307
14773
|
const source = validateMigrationUrl(options.sourceUrl);
|
|
@@ -14331,6 +14797,11 @@ async function runUrlMigration(options) {
|
|
|
14331
14797
|
delete record.pageSha256;
|
|
14332
14798
|
delete record.evidence;
|
|
14333
14799
|
delete record.assets;
|
|
14800
|
+
delete record.apiSpecification;
|
|
14801
|
+
delete record.version;
|
|
14802
|
+
delete record.issues;
|
|
14803
|
+
delete record.reason;
|
|
14804
|
+
delete record.aliasOf;
|
|
14334
14805
|
}
|
|
14335
14806
|
if (record.page && pageIdFromReference(record.page.id, true) !== record.page.id) throw new Error("Checkpoint contains an unsafe page path.");
|
|
14336
14807
|
records.set(record.url, record);
|
|
@@ -14359,6 +14830,33 @@ async function runUrlMigration(options) {
|
|
|
14359
14830
|
enqueue(sourceUrl, sourceUrl, "submitted");
|
|
14360
14831
|
for (const path of ["llms.txt", "sitemap.xml", "robots.txt"]) enqueue(`${scopePath === "/" ? "" : scopePath}/${path}`, sourceUrl, "discovery-index");
|
|
14361
14832
|
if (scopePath !== "/") for (const path of ["llms.txt", "sitemap.xml", "robots.txt"]) enqueue(`/${path}`, sourceUrl, "discovery-index");
|
|
14833
|
+
const enqueueArticleLinks = (links, base, discoveredBy) => {
|
|
14834
|
+
for (const link of links) {
|
|
14835
|
+
try {
|
|
14836
|
+
const url = new URL(link, base);
|
|
14837
|
+
if (!/\.(?:png|jpe?g|gif|svg|webp|avif|pdf|zip|mp4|webm|css|js)$/i.test(url.pathname)) enqueue(link, base, discoveredBy);
|
|
14838
|
+
} catch {
|
|
14839
|
+
}
|
|
14840
|
+
}
|
|
14841
|
+
};
|
|
14842
|
+
const enqueueNavigation = (nodes, base) => {
|
|
14843
|
+
for (const node of nodes) {
|
|
14844
|
+
if (node.url) enqueue(node.url, base, "source-navigation");
|
|
14845
|
+
enqueueNavigation(node.children ?? [], base);
|
|
14846
|
+
}
|
|
14847
|
+
};
|
|
14848
|
+
for (const record of [...records.values()]) {
|
|
14849
|
+
if (!record.evidence) continue;
|
|
14850
|
+
const final = canonical(record.evidence.finalUrl, sourceUrl);
|
|
14851
|
+
if (!final) continue;
|
|
14852
|
+
if (record.outcome === "imported") enqueueArticleLinks(record.evidence.links, final, record.url);
|
|
14853
|
+
else if (record.outcome === "excluded") {
|
|
14854
|
+
if (classifyMigrationResponse({ finalUrl: new URL(final), contentType: record.evidence.contentType, body: "" }) === "index") {
|
|
14855
|
+
for (const link of record.evidence.links) enqueue(link, final, record.url);
|
|
14856
|
+
}
|
|
14857
|
+
}
|
|
14858
|
+
}
|
|
14859
|
+
enqueueNavigation(checkpoint.navigation, sourceUrl);
|
|
14362
14860
|
const fetcher = options.fetcher ?? defaultMigrationFetcher;
|
|
14363
14861
|
const capture = options.captureProvider?.capture.bind(options.captureProvider) ?? (async ({ url }) => fetcher(url, { accept: ACCEPT }));
|
|
14364
14862
|
const assetFetcher = options.assetFetcher ?? (!options.fetcher && !options.captureProvider ? defaultAssetFetcher : void 0);
|
|
@@ -14394,13 +14892,24 @@ async function runUrlMigration(options) {
|
|
|
14394
14892
|
navigationChanged = false;
|
|
14395
14893
|
};
|
|
14396
14894
|
const process2 = async (record) => {
|
|
14397
|
-
if (options.signal?.aborted) return;
|
|
14895
|
+
if (options.signal?.aborted || record.outcome !== "pending") return;
|
|
14896
|
+
let claimedId;
|
|
14897
|
+
let claimedFinal;
|
|
14898
|
+
let markdownRepresentation;
|
|
14398
14899
|
try {
|
|
14399
14900
|
delete record.reason;
|
|
14901
|
+
delete record.apiSpecification;
|
|
14902
|
+
const represented = resolveMigrationRecord(records, record.representationOf ? records.get(record.representationOf) : void 0);
|
|
14903
|
+
if (represented?.outcome === "imported") {
|
|
14904
|
+
record.outcome = "alias";
|
|
14905
|
+
record.aliasOf = represented.url;
|
|
14906
|
+
return;
|
|
14907
|
+
}
|
|
14400
14908
|
const document = await capture({ url: new URL(record.url), signal: options.signal });
|
|
14401
14909
|
if (options.signal?.aborted) return;
|
|
14402
14910
|
if (Buffer.byteLength(document.body) > MAX_RESPONSE_BYTES) throw new Error("Captured response exceeds the 8 MB safety bound.");
|
|
14403
|
-
const
|
|
14911
|
+
const identity = articleIdentity(document);
|
|
14912
|
+
const final = canonical(identity.toString(), sourceUrl);
|
|
14404
14913
|
const role = classifyMigrationResponse(document);
|
|
14405
14914
|
if (!inScope(document.finalUrl, source, scopePath) && !(role === "index" && isDiscoveryIndex(document.finalUrl, source))) {
|
|
14406
14915
|
record.outcome = "excluded";
|
|
@@ -14421,6 +14930,30 @@ async function runUrlMigration(options) {
|
|
|
14421
14930
|
for (const link of links) enqueue(link, final, record.url);
|
|
14422
14931
|
return;
|
|
14423
14932
|
}
|
|
14933
|
+
if (/html/i.test(document.contentType)) {
|
|
14934
|
+
const $ = load4(document.body);
|
|
14935
|
+
$('link[rel="alternate"][type="text/markdown"][href]').each((_index, node) => {
|
|
14936
|
+
const alternate = canonical($(node).attr("href"), final);
|
|
14937
|
+
if (!alternate) return;
|
|
14938
|
+
const target2 = new URL(alternate), primary = new URL(final);
|
|
14939
|
+
const directory = (path) => path.replace(/\.mdx?$/i, "").replace(/\/index\/?$/i, "").replace(/\/$/, "");
|
|
14940
|
+
if (target2.origin !== primary.origin || target2.search !== primary.search || directory(target2.pathname) !== directory(primary.pathname) || !/\.mdx?$/i.test(target2.pathname)) return;
|
|
14941
|
+
enqueue(alternate, final, "declared-markdown-representation");
|
|
14942
|
+
const sibling = records.get(alternate);
|
|
14943
|
+
sibling.representationOf = record.url;
|
|
14944
|
+
markdownRepresentation ??= alternate;
|
|
14945
|
+
changed.push(sibling);
|
|
14946
|
+
});
|
|
14947
|
+
}
|
|
14948
|
+
const observedNavigation = sourceNavigation(document);
|
|
14949
|
+
if (observedNavigation.length && !(checkpoint.navigation.some((node) => node.kind === "tab") && !observedNavigation.some((node) => node.kind === "tab"))) {
|
|
14950
|
+
const merged = mergeSourceNavigation(checkpoint.navigation, observedNavigation);
|
|
14951
|
+
if (JSON.stringify(merged) !== JSON.stringify(checkpoint.navigation)) {
|
|
14952
|
+
checkpoint.navigation = merged;
|
|
14953
|
+
navigationChanged = true;
|
|
14954
|
+
}
|
|
14955
|
+
enqueueNavigation(observedNavigation, final);
|
|
14956
|
+
}
|
|
14424
14957
|
if (imported >= maxPages) {
|
|
14425
14958
|
record.outcome = "excluded";
|
|
14426
14959
|
record.reason = "A discovery endpoint resolved to an article after the selected page limit.";
|
|
@@ -14433,14 +14966,20 @@ async function runUrlMigration(options) {
|
|
|
14433
14966
|
return;
|
|
14434
14967
|
}
|
|
14435
14968
|
finalUrls.set(final, record.url);
|
|
14436
|
-
|
|
14969
|
+
claimedFinal = final;
|
|
14970
|
+
const id = idForUrl(identity, scopePath);
|
|
14437
14971
|
if (!id) throw new Error("Source URL has no safe destination path.");
|
|
14438
|
-
|
|
14972
|
+
const language = observedLocale(document, id, scopePath);
|
|
14973
|
+
const locale = language.locale;
|
|
14974
|
+
const navigationId = locale ? id.split("/").filter((segment) => segment.toLowerCase() !== locale.toLowerCase()).join("/") || "introduction" : id;
|
|
14975
|
+
const identityId = locale ? `${locale}/${navigationId}` : id;
|
|
14976
|
+
if (usedIds.has(identityId) && usedIds.get(identityId) !== record.url) {
|
|
14439
14977
|
record.outcome = "failed";
|
|
14440
|
-
record.reason = `Destination collision for ${
|
|
14978
|
+
record.reason = `Destination collision for ${identityId}.`;
|
|
14441
14979
|
return;
|
|
14442
14980
|
}
|
|
14443
|
-
usedIds.set(
|
|
14981
|
+
usedIds.set(identityId, record.url);
|
|
14982
|
+
claimedId = identityId;
|
|
14444
14983
|
const evidence = evidenceOf(document);
|
|
14445
14984
|
const page = convert(document, id);
|
|
14446
14985
|
if (!page) {
|
|
@@ -14448,6 +14987,23 @@ async function runUrlMigration(options) {
|
|
|
14448
14987
|
record.reason = "Content could not be represented as safe inert MDX.";
|
|
14449
14988
|
return;
|
|
14450
14989
|
}
|
|
14990
|
+
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;
|
|
14991
|
+
if (/html/i.test(document.contentType) && markdownRepresentation && (unresolvedStaticControls(document.body) || hasSchemaChoice)) {
|
|
14992
|
+
const schemaCapture = await capture({ url: new URL(markdownRepresentation), signal: options.signal });
|
|
14993
|
+
if (options.signal?.aborted) return;
|
|
14994
|
+
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.");
|
|
14995
|
+
totalBytes += Buffer.byteLength(schemaCapture.body);
|
|
14996
|
+
if (Buffer.byteLength(schemaCapture.body) > MAX_RESPONSE_BYTES || totalBytes > (options.maxTotalBytes ?? 5e8)) throw new Error("API schema capture exceeds its content byte budget.");
|
|
14997
|
+
const expected = new URL(markdownRepresentation);
|
|
14998
|
+
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.");
|
|
14999
|
+
const fragment = extractEmbeddedOpenApi(schemaCapture.body).fragment;
|
|
15000
|
+
if (fragment && hasCompleteLocalApiSchema(fragment.document)) {
|
|
15001
|
+
const sha256 = hash2(canonicalJson(fragment.document));
|
|
15002
|
+
const path = `openapi/migration-${sha256}.json`;
|
|
15003
|
+
record.apiSpecification = { path, sha256, document: fragment.document };
|
|
15004
|
+
page.openapi = `${path} ${fragment.method} ${fragment.path}`;
|
|
15005
|
+
}
|
|
15006
|
+
}
|
|
14451
15007
|
const states = document.states ?? [];
|
|
14452
15008
|
if (states.length > 64) throw new Error("Capture contains too many alternative states.");
|
|
14453
15009
|
for (const state of states) {
|
|
@@ -14476,14 +15032,16 @@ ${difference}`;
|
|
|
14476
15032
|
record.assets = [];
|
|
14477
15033
|
record.issues = [];
|
|
14478
15034
|
if (/html/i.test(document.contentType)) {
|
|
14479
|
-
const
|
|
14480
|
-
const root = $('main article,article,main,[role="main"]').first();
|
|
15035
|
+
const { $, root } = migrationHtmlArticle(document.body);
|
|
14481
15036
|
root.find("nav,footer,aside,.theme-doc-breadcrumbs,.theme-doc-toc-mobile,.table-of-contents,.hash-link").remove();
|
|
14482
15037
|
root.find('button svg,a.hash-link svg,[aria-hidden="true"] svg,svg[aria-hidden="true"],svg[data-lucide],svg[data-icon]').remove();
|
|
14483
|
-
if (
|
|
15038
|
+
if (record.apiSpecification) {
|
|
15039
|
+
root.find('select[aria-label="Select schema type"],select[aria-label="\u9009\u62E9\u67B6\u6784\u7C7B\u578B"]').remove();
|
|
15040
|
+
root.find('.option-dropdown svg[data-component-part="icon-svg"]').remove();
|
|
15041
|
+
}
|
|
14484
15042
|
const unsupported = [...new Set(root.find("iframe,object,embed,canvas,svg,form,input,textarea,select,math,video,audio").toArray().map((node) => node.tagName))];
|
|
14485
15043
|
if (unsupported.length) record.issues.push({ code: "unsupported-component", source: record.url, message: `Rendered content requires explicit review for: ${unsupported.join(", ")}.` });
|
|
14486
|
-
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." });
|
|
15044
|
+
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." });
|
|
14487
15045
|
}
|
|
14488
15046
|
const suppliedAssets = new Map((document.assets ?? []).map((asset) => [canonical(asset.url, final), asset]));
|
|
14489
15047
|
const assetUrls = [...new Set([...assetReferences(document), ...states.flatMap((state) => assetReferences(state.response))].map((url) => canonical(url, final)).filter((url) => Boolean(url)))];
|
|
@@ -14523,42 +15081,18 @@ ${difference}`;
|
|
|
14523
15081
|
if (sanitizeRemoteMarkdown(page.body.replace(/^<a id="[^"<]*" \/>$/gm, "")) === null) throw new Error("Converted content did not pass inert MDX validation.");
|
|
14524
15082
|
record.evidence = evidence;
|
|
14525
15083
|
record.page = page;
|
|
14526
|
-
const language = observedLocale(document, page.id, scopePath);
|
|
14527
15084
|
record.issues.push(...language.issues);
|
|
14528
15085
|
const canonicalLocale = language.locale;
|
|
14529
15086
|
if (canonicalLocale) {
|
|
14530
15087
|
page.locale = canonicalLocale;
|
|
14531
|
-
|
|
14532
|
-
const localeIndex = segments.findIndex((segment) => segment.toLowerCase() === canonicalLocale.toLowerCase());
|
|
14533
|
-
page.navigationId = segments.filter((_segment, index) => index !== localeIndex).join("/") || "introduction";
|
|
15088
|
+
page.navigationId = navigationId;
|
|
14534
15089
|
page.id = `${canonicalLocale}/${page.navigationId}`;
|
|
14535
|
-
if (usedIds.has(page.id) && usedIds.get(page.id) !== record.url) throw new Error(`Destination collision for locale page ${page.id}.`);
|
|
14536
|
-
usedIds.delete(id);
|
|
14537
|
-
usedIds.set(page.id, record.url);
|
|
14538
15090
|
}
|
|
14539
15091
|
record.version = document.version ?? [...page.id.split("/"), ...document.finalUrl.pathname.split("/")].find((segment) => /^v\d+(?:\.\d+)*$/i.test(segment));
|
|
14540
15092
|
record.pageSha256 = pageHash(page);
|
|
14541
15093
|
record.outcome = "imported";
|
|
14542
15094
|
imported++;
|
|
14543
|
-
|
|
14544
|
-
if (!checkpoint.navigation.length && navigation.length) {
|
|
14545
|
-
checkpoint.navigation = navigation;
|
|
14546
|
-
navigationChanged = true;
|
|
14547
|
-
}
|
|
14548
|
-
for (const link of evidence.links) {
|
|
14549
|
-
try {
|
|
14550
|
-
const url = new URL(link, final);
|
|
14551
|
-
if (!/\.(?:png|jpe?g|gif|svg|webp|avif|pdf|zip|mp4|webm|css|js)$/i.test(url.pathname)) enqueue(link, final, record.url);
|
|
14552
|
-
} catch {
|
|
14553
|
-
}
|
|
14554
|
-
}
|
|
14555
|
-
const visit = (nodes) => {
|
|
14556
|
-
for (const node of nodes) {
|
|
14557
|
-
if (node.url) enqueue(node.url, final, "source-navigation");
|
|
14558
|
-
visit(node.children ?? []);
|
|
14559
|
-
}
|
|
14560
|
-
};
|
|
14561
|
-
visit(navigation);
|
|
15095
|
+
enqueueArticleLinks(evidence.links, final, record.url);
|
|
14562
15096
|
} catch (error) {
|
|
14563
15097
|
if (options.signal?.aborted) return;
|
|
14564
15098
|
const wasImported = record.outcome === "imported";
|
|
@@ -14571,13 +15105,43 @@ ${difference}`;
|
|
|
14571
15105
|
delete record.page;
|
|
14572
15106
|
delete record.pageSha256;
|
|
14573
15107
|
delete record.assets;
|
|
15108
|
+
delete record.apiSpecification;
|
|
14574
15109
|
} finally {
|
|
15110
|
+
if (record.outcome !== "imported") {
|
|
15111
|
+
if (claimedId && usedIds.get(claimedId) === record.url) usedIds.delete(claimedId);
|
|
15112
|
+
if (claimedFinal && finalUrls.get(claimedFinal) === record.url) finalUrls.delete(claimedFinal);
|
|
15113
|
+
}
|
|
14575
15114
|
if (record.outcome !== "pending") {
|
|
14576
15115
|
if (options.onRecord) await options.onRecord(record);
|
|
14577
15116
|
changed.push(record);
|
|
14578
15117
|
}
|
|
14579
15118
|
}
|
|
14580
15119
|
};
|
|
15120
|
+
const settleRepresentations = () => {
|
|
15121
|
+
for (const record of records.values()) {
|
|
15122
|
+
if (!record.representationOf) continue;
|
|
15123
|
+
const primary = resolveMigrationRecord(records, records.get(record.representationOf));
|
|
15124
|
+
if (!primary) continue;
|
|
15125
|
+
const winner = primary.outcome === "imported" ? primary : record.outcome === "imported" && primary.outcome === "failed" ? record : void 0;
|
|
15126
|
+
if (!winner) continue;
|
|
15127
|
+
const alternate = winner === primary ? record : primary;
|
|
15128
|
+
if (alternate.outcome === "alias" && alternate.aliasOf === winner.url) continue;
|
|
15129
|
+
if (alternate.outcome === "imported") {
|
|
15130
|
+
imported--;
|
|
15131
|
+
if (alternate.page && usedIds.get(alternate.page.id) === alternate.url) usedIds.delete(alternate.page.id);
|
|
15132
|
+
}
|
|
15133
|
+
alternate.outcome = "alias";
|
|
15134
|
+
alternate.aliasOf = winner.url;
|
|
15135
|
+
delete alternate.reason;
|
|
15136
|
+
delete alternate.page;
|
|
15137
|
+
delete alternate.pageSha256;
|
|
15138
|
+
delete alternate.assets;
|
|
15139
|
+
delete alternate.issues;
|
|
15140
|
+
delete alternate.apiSpecification;
|
|
15141
|
+
changed.push(alternate);
|
|
15142
|
+
}
|
|
15143
|
+
};
|
|
15144
|
+
settleRepresentations();
|
|
14581
15145
|
while (cursor < pending.length && !options.signal?.aborted && !budgetExhausted && cursor < (options.maxCaptures ?? Infinity)) {
|
|
14582
15146
|
if (imported >= maxPages) {
|
|
14583
15147
|
const index = pending.findIndex((record, position) => position >= cursor && isDiscoveryIndex(new URL(record.url), source));
|
|
@@ -14587,17 +15151,18 @@ ${difference}`;
|
|
|
14587
15151
|
const batch = pending.slice(cursor, cursor + Math.min(concurrency, imported >= maxPages ? 1 : maxPages - imported, (options.maxCaptures ?? Infinity) - cursor));
|
|
14588
15152
|
cursor += batch.length;
|
|
14589
15153
|
await Promise.all(batch.map(process2));
|
|
15154
|
+
settleRepresentations();
|
|
14590
15155
|
if (changed.length >= batchSize) await flush();
|
|
14591
15156
|
}
|
|
14592
15157
|
await flush();
|
|
14593
15158
|
const projection = localeProjection(checkpoint);
|
|
14594
15159
|
const routeMap = /* @__PURE__ */ new Map();
|
|
14595
15160
|
for (const record of checkpoint.records) {
|
|
14596
|
-
const
|
|
14597
|
-
if (
|
|
14598
|
-
const route = projection.route(
|
|
15161
|
+
const target2 = resolveMigrationRecord(records, record);
|
|
15162
|
+
if (target2?.page) {
|
|
15163
|
+
const route = projection.route(target2.page);
|
|
14599
15164
|
routeMap.set(record.url, route);
|
|
14600
|
-
if (
|
|
15165
|
+
if (target2.evidence) routeMap.set(canonical(target2.evidence.finalUrl, sourceUrl), route);
|
|
14601
15166
|
}
|
|
14602
15167
|
}
|
|
14603
15168
|
const navigationLabels = /* @__PURE__ */ new Map();
|
|
@@ -14605,11 +15170,11 @@ ${difference}`;
|
|
|
14605
15170
|
const labelPages = (nodes) => {
|
|
14606
15171
|
for (const node of nodes) {
|
|
14607
15172
|
const entry = node.url ? records.get(canonical(node.url, sourceUrl) ?? "") : void 0;
|
|
14608
|
-
const
|
|
14609
|
-
if (
|
|
14610
|
-
const previous = navigationLabels.get(
|
|
14611
|
-
if (previous && previous !== node.label) navigationIssues.push({ code: "unsupported-component", source:
|
|
14612
|
-
else navigationLabels.set(
|
|
15173
|
+
const target2 = resolveMigrationRecord(records, entry);
|
|
15174
|
+
if (target2?.page && node.label && !node.children?.length) {
|
|
15175
|
+
const previous = navigationLabels.get(target2.url);
|
|
15176
|
+
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.` });
|
|
15177
|
+
else navigationLabels.set(target2.url, node.label);
|
|
14613
15178
|
}
|
|
14614
15179
|
labelPages(node.children ?? []);
|
|
14615
15180
|
}
|
|
@@ -14635,6 +15200,10 @@ ${difference}`;
|
|
|
14635
15200
|
assets.set(asset.path, { path: asset.path, content: Buffer.from(content.buffer, content.byteOffset, content.byteLength) });
|
|
14636
15201
|
}
|
|
14637
15202
|
}
|
|
15203
|
+
for (const record of checkpoint.records) if (record.page && record.apiSpecification) {
|
|
15204
|
+
const spec = record.apiSpecification;
|
|
15205
|
+
assets.set(spec.path, { path: spec.path, projectRelative: true, content: Buffer.from(canonicalJson(spec.document)) });
|
|
15206
|
+
}
|
|
14638
15207
|
const bundle = {
|
|
14639
15208
|
sourceUrl,
|
|
14640
15209
|
sourceKind: "url",
|
|
@@ -14642,13 +15211,16 @@ ${difference}`;
|
|
|
14642
15211
|
pages,
|
|
14643
15212
|
assets: [...assets.values()],
|
|
14644
15213
|
docsConfig: navigationConfig(checkpoint.navigation, records) ?? buildNavigationFromPages(pages),
|
|
14645
|
-
warnings: validation.issues.map((issue) => ({ code: issue.code === "missing-page" ? "missing-page" : "unsupported-config", message: issue.message, source: issue.source })),
|
|
15214
|
+
warnings: [...validation.issues, ...validation.warnings ?? []].map((issue) => ({ code: issue.code === "missing-page" ? "missing-page" : "unsupported-config", message: issue.message, source: issue.source })),
|
|
14646
15215
|
urlMigrationValidation: validation,
|
|
14647
15216
|
stats: { discovered: records.size, imported: pages.length, skipped: records.size - pages.length }
|
|
14648
15217
|
};
|
|
14649
15218
|
if (projection.locales.length) {
|
|
14650
15219
|
const locales = [.../* @__PURE__ */ new Set([projection.defaultLocale, ...projection.locales])];
|
|
14651
|
-
bundle.docsConfig.i18n = { defaultLocale: projection.defaultLocale, locales: locales.map((code) => ({ code, label: code === "en" ? "English" : code })) };
|
|
15220
|
+
bundle.docsConfig.i18n = { ...bundle.docsConfig.i18n, defaultLocale: projection.defaultLocale, locales: locales.map((code) => ({ code, label: code === "en" ? "English" : code })) };
|
|
15221
|
+
}
|
|
15222
|
+
for (const spec of assets.values()) if (spec.projectRelative && spec.path.startsWith("openapi/")) {
|
|
15223
|
+
bundle.docsConfig.tabs.push({ tab: `Migration API ${spec.path.slice(-69, -5)}`, hidden: true, api: { source: spec.path, navigation: false } });
|
|
14652
15224
|
}
|
|
14653
15225
|
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";
|
|
14654
15226
|
return { bundle, checkpoint, validation, stopReason };
|
|
@@ -14793,8 +15365,8 @@ async function downloadSpec(value, fetcher) {
|
|
|
14793
15365
|
throw new Error("Remote OpenAPI spec redirected too many times.");
|
|
14794
15366
|
}
|
|
14795
15367
|
function parseOpenApi(content, extension) {
|
|
14796
|
-
const
|
|
14797
|
-
const parsed = extension === "yaml" || !
|
|
15368
|
+
const text3 = content.toString("utf8");
|
|
15369
|
+
const parsed = extension === "yaml" || !text3.trimStart().startsWith("{") ? parseYaml7(text3) : JSON.parse(text3);
|
|
14798
15370
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("OpenAPI spec is not an object.");
|
|
14799
15371
|
const document = parsed;
|
|
14800
15372
|
if (typeof document.openapi !== "string" || !/^3\./.test(document.openapi)) {
|