@thallylabs/migrate 0.2.40 → 0.2.42
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/README.md +72 -3
- package/dist/index.d.ts +10 -2
- package/dist/index.js +575 -82
- package/dist/index.js.map +1 -1
- package/dist/url-migration.d.ts +2 -2
- package/dist/url-migration.js +146 -29
- package/dist/url-migration.js.map +1 -1
- package/dist/{url-run-DFnoqEi-.d.ts → url-run-CPzQfjRW.d.ts} +35 -3
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1370,8 +1370,29 @@ ${trimmed.slice(0, marker).trimEnd()}`;
|
|
|
1370
1370
|
function headingIdMarker(id) {
|
|
1371
1371
|
return `{/* #${id} */}`;
|
|
1372
1372
|
}
|
|
1373
|
+
var HEADING_ID_WORD = /[\p{L}\p{M}\p{N}_+&/@\u2019\u201c\u201d\u2014\u2013\u2192]/u;
|
|
1373
1374
|
function mintlifyHeadingSlug(text3) {
|
|
1374
|
-
|
|
1375
|
+
const chars = [...text3.replace(/[\u200b*]/g, "").normalize("NFC").trim().toLowerCase()];
|
|
1376
|
+
const isWord = (char) => char !== void 0 && HEADING_ID_WORD.test(char);
|
|
1377
|
+
let id = "";
|
|
1378
|
+
let afterDash = false;
|
|
1379
|
+
let endsWithDash = false;
|
|
1380
|
+
chars.forEach((char, index) => {
|
|
1381
|
+
const before = chars[index - 1];
|
|
1382
|
+
const after = chars[index + 1];
|
|
1383
|
+
endsWithDash = false;
|
|
1384
|
+
if (isWord(char)) {
|
|
1385
|
+
id += char;
|
|
1386
|
+
afterDash = false;
|
|
1387
|
+
} else if (/[\s-]/.test(char) || char === "." && isWord(after) || char === "(" && isWord(before) && (isWord(after) || after === "{") || char === ")" && after !== void 0 && !/\s/.test(after)) {
|
|
1388
|
+
if (id && !afterDash) id += "-";
|
|
1389
|
+
afterDash = true;
|
|
1390
|
+
endsWithDash = true;
|
|
1391
|
+
} else if (char === "{" || char === ":" || char === '"') {
|
|
1392
|
+
afterDash = false;
|
|
1393
|
+
}
|
|
1394
|
+
});
|
|
1395
|
+
return endsWithDash ? id.replace(/-$/, "") : id;
|
|
1375
1396
|
}
|
|
1376
1397
|
function thallyHeadingSlug(text3) {
|
|
1377
1398
|
return text3.normalize("NFC").toLowerCase().replace(/[^\p{L}\p{M}\p{N}]+/gu, "-").replace(/(^-|-$)/g, "");
|
|
@@ -1383,7 +1404,7 @@ function typesetQuotes(text3) {
|
|
|
1383
1404
|
}).join("");
|
|
1384
1405
|
}
|
|
1385
1406
|
function plainHeadingText(source) {
|
|
1386
|
-
return source.replace(/\{\/\*[\s\S]*?\*\/\}/g, " ").replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/<\/?[A-Za-z][^>]*>/g, "").replace(/`([^`]*)`/g, "$1").replace(/(\*\*|__|~~|\*)/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/\\([\\`*_{}[\]()#+.!&<>|~-])/g, "$1");
|
|
1407
|
+
return source.replace(/\{\/\*[\s\S]*?\*\/\}/g, " ").replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/<\/?[A-Za-z][^>]*>/g, "").replace(/`([^`]*)`/g, "$1").replace(/(?<!\\)(\*\*|__|~~|\*)/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/\\([\\`*_{}[\]()#+.!&<>|~-])/g, "$1");
|
|
1387
1408
|
}
|
|
1388
1409
|
function markMintlifyHeadings(body) {
|
|
1389
1410
|
let fence;
|
|
@@ -2587,7 +2608,7 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
|
2587
2608
|
}
|
|
2588
2609
|
if (runMintlify) rewritten = normalizeMintlifyParameterAnchors(rewritten);
|
|
2589
2610
|
rewritten = replaceOutsideCode(rewritten, (segment) => {
|
|
2590
|
-
let result = convertHtmlStyleAttributes(segment).replace(/<!--([\s\S]*?)-->/g, (_match, content) => mdxComment(content)).replace(/<Danger(\s[^>]*)?>/g, "<Error$1>").replace(/<\/Danger>/g, "</Error>").replace(/<Warn(\s[^>]*)?>/g, "<Warning$1>").replace(/<\/Warn>/g, "</Warning>").replace(/<
|
|
2611
|
+
let result = convertHtmlStyleAttributes(segment).replace(/<!--([\s\S]*?)-->/g, (_match, content) => mdxComment(content)).replace(/<Danger(\s[^>]*)?>/g, "<Error$1>").replace(/<\/Danger>/g, "</Error>").replace(/<Warn(\s[^>]*)?>/g, "<Warning$1>").replace(/<\/Warn>/g, "</Warning>").replace(/<Tree\.Folder/g, "<Folder").replace(/<\/Tree\.Folder>/g, "</Folder>").replace(/<Tree\.File/g, "<File").replace(/<\/Tree\.File>/g, "</File>");
|
|
2591
2612
|
if (runDocusaurus) {
|
|
2592
2613
|
result = result.replace(/<TabItem\b([^<>]*)>/g, (_match, attributes) => {
|
|
2593
2614
|
const title = attributes.match(/\blabel=(?:"([^"]*)"|'([^']*)')/)?.slice(1).find(Boolean) ?? attributes.match(/\bvalue=(?:"([^"]*)"|'([^']*)')/)?.slice(1).find(Boolean) ?? "Tab";
|
|
@@ -2596,7 +2617,7 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
|
2596
2617
|
result = normalizeDocusaurusLinkTags(result).replace(/<(?:DocCardList|TOCInline)\b[^<>]*\/>/g, "");
|
|
2597
2618
|
}
|
|
2598
2619
|
if (runMintlify) {
|
|
2599
|
-
result = normalizeMintlifyUpdateLabels(result).replace(/<FileTree(\s[^>]*)?>/g, "<Tree$1>").replace(/<\/FileTree>/g, "</Tree>").replace(/<GitHub\.Repo/g, "<GitHub").replace(/<\/GitHub\.Repo>/g, "</GitHub>").replace(/<Column(\s[^>]*)?>/g, "<div$1>").replace(/<\/Column>/g, "</div>");
|
|
2620
|
+
result = normalizeMintlifyUpdateLabels(result).replace(/<FileTree(\s[^>]*)?>/g, "<Tree$1>").replace(/<\/FileTree>/g, "</Tree>").replace(/<GitHub\.Repo/g, "<GitHub").replace(/<\/GitHub\.Repo>/g, "</GitHub>").replace(/<Callout(\s[^<>]*)?>/g, (tag) => tag.replace(/(\s)type=(?:"[^"]*"|'[^']*'|\{[^{}]*\})/, '$1type="info"')).replace(/<Column(\s[^>]*)?>/g, "<div$1>").replace(/<\/Column>/g, "</div>");
|
|
2600
2621
|
result = pinStepsTitleSize(result);
|
|
2601
2622
|
}
|
|
2602
2623
|
if (runFern) {
|
|
@@ -2615,6 +2636,16 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
|
2615
2636
|
}
|
|
2616
2637
|
return normalizeFlowParagraphContainers(normalized);
|
|
2617
2638
|
}
|
|
2639
|
+
function externalPageUrl(value) {
|
|
2640
|
+
const url = typeof value === "string" ? value.trim() : "";
|
|
2641
|
+
if (!/^https?:\/\/[^\s]+$/i.test(url)) return void 0;
|
|
2642
|
+
try {
|
|
2643
|
+
new URL(url);
|
|
2644
|
+
return url;
|
|
2645
|
+
} catch {
|
|
2646
|
+
return void 0;
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2618
2649
|
function parseMarkdownPage(input) {
|
|
2619
2650
|
const parsed = parseFrontmatter(input.raw);
|
|
2620
2651
|
const fallbackIdentity = {
|
|
@@ -2639,6 +2670,7 @@ function parseMarkdownPage(input) {
|
|
|
2639
2670
|
const badge = typeof parsed.data.tag === "string" && parsed.data.tag.trim() ? parsed.data.tag.trim() : typeof parsed.data.badge === "string" && parsed.data.badge.trim() ? parsed.data.badge.trim() : void 0;
|
|
2640
2671
|
const sourceMode = typeof parsed.data.mode === "string" ? parsed.data.mode : void 0;
|
|
2641
2672
|
const mode = sourceMode === "frame" ? "wide" : ["default", "wide", "custom", "center", "home"].includes(sourceMode ?? "") ? sourceMode : void 0;
|
|
2673
|
+
const externalUrl = input.platform === "mintlify" ? externalPageUrl(parsed.data.url) : void 0;
|
|
2642
2674
|
const description = typeof parsed.data.description === "string" && parsed.data.description.trim() ? parsed.data.description.trim() : typeof parsed.data.openapi === "string" && parsed.data.openapi.trim() ? "" : firstParagraph(body);
|
|
2643
2675
|
const page = {
|
|
2644
2676
|
id: identity.id,
|
|
@@ -2654,7 +2686,9 @@ function parseMarkdownPage(input) {
|
|
|
2654
2686
|
keywords,
|
|
2655
2687
|
mode,
|
|
2656
2688
|
hidden: parsed.data.hidden === true ? true : void 0,
|
|
2657
|
-
|
|
2689
|
+
// The path of a page that links elsewhere redirects, so it has no business in a sitemap.
|
|
2690
|
+
noindex: parsed.data.noindex === true || parsed.data.noindex === "true" || externalUrl ? true : void 0,
|
|
2691
|
+
...externalUrl ? { externalUrl } : {},
|
|
2658
2692
|
...Object.keys(meta).length > 0 ? { meta } : {},
|
|
2659
2693
|
openapi: typeof parsed.data.openapi === "string" ? parsed.data.openapi.trim() : void 0,
|
|
2660
2694
|
...apiFrontmatter(parsed.data, input.warn),
|
|
@@ -4391,12 +4425,17 @@ function addMintlifyHomepageRedirects(config, pages) {
|
|
|
4391
4425
|
const homepage = config.tabs.filter((tab) => !tab.hidden).map((tab) => firstPage([...tab.pages ?? [], ...tab.groups ?? []])).find(Boolean);
|
|
4392
4426
|
if (!homepage) return config;
|
|
4393
4427
|
const redirects = [...config.redirects ?? []];
|
|
4394
|
-
const
|
|
4428
|
+
const routeKey = (route) => (route.split(/[?#]/, 1)[0].replace(/\/$/, "") || "/").toLowerCase();
|
|
4429
|
+
const sources = new Set(redirects.map((redirect) => routeKey(redirect.source)));
|
|
4395
4430
|
const roots = ["", ...(config.i18n?.locales ?? []).filter((locale) => locale.code !== config.i18n?.defaultLocale).filter((locale) => homepage !== "introduction" || pages.some((page) => page.locale === locale.code && page.navigationId === homepage)).map((locale) => locale.code)];
|
|
4431
|
+
const homeLinksElsewhere = pages.some((page) => page.id === "introduction" && page.externalUrl);
|
|
4396
4432
|
for (const locale of roots) {
|
|
4433
|
+
if (!locale && homeLinksElsewhere) continue;
|
|
4397
4434
|
const source = locale ? `/${locale}` : "/";
|
|
4398
4435
|
if (sources.has(source.toLowerCase())) continue;
|
|
4399
|
-
|
|
4436
|
+
const destination = `${locale ? `/${locale}` : ""}/${homepage}`;
|
|
4437
|
+
if (redirects.some((redirect) => routeKey(redirect.source) === destination.toLowerCase() && routeKey(redirect.destination) === source.toLowerCase())) continue;
|
|
4438
|
+
redirects.push({ source, destination, permanent: true });
|
|
4400
4439
|
}
|
|
4401
4440
|
return { ...config, redirects };
|
|
4402
4441
|
}
|
|
@@ -4593,7 +4632,7 @@ function mergeApiGroups(existing, incoming) {
|
|
|
4593
4632
|
return merged.length > 0 ? merged : void 0;
|
|
4594
4633
|
}
|
|
4595
4634
|
var hasNavigationChildren = (node) => ["groups", "pages"].some((key) => Array.isArray(node[key]) && node[key].length > 0);
|
|
4596
|
-
function mintlifyNavigationApiReferences(config) {
|
|
4635
|
+
function mintlifyNavigationApiReferences(config, tabFor) {
|
|
4597
4636
|
const navigation = objectValue2(config.navigation) ?? config;
|
|
4598
4637
|
const references = [];
|
|
4599
4638
|
const defaultLanguage = pickDefaultLanguage(
|
|
@@ -4617,7 +4656,7 @@ function mintlifyNavigationApiReferences(config) {
|
|
|
4617
4656
|
references.push({
|
|
4618
4657
|
value,
|
|
4619
4658
|
kind,
|
|
4620
|
-
tabLabel,
|
|
4659
|
+
tabLabel: tabFor?.(node) ?? tabLabel,
|
|
4621
4660
|
...sibling,
|
|
4622
4661
|
...typeof directory2 === "string" && directory2.trim() ? { directory: directory2.trim() } : {},
|
|
4623
4662
|
...operations.length > 0 ? { operations } : {},
|
|
@@ -4972,6 +5011,21 @@ function convertNavigationValues(values, context) {
|
|
|
4972
5011
|
return page ? [page] : [];
|
|
4973
5012
|
});
|
|
4974
5013
|
}
|
|
5014
|
+
var API_TAB_CONTAINER = /* @__PURE__ */ Symbol("apiTabContainer");
|
|
5015
|
+
function takeApiTabSlots(tabs) {
|
|
5016
|
+
const slots = [];
|
|
5017
|
+
const real = [];
|
|
5018
|
+
tabs.forEach((tab, index) => {
|
|
5019
|
+
const container = tab[API_TAB_CONTAINER];
|
|
5020
|
+
if (!container) {
|
|
5021
|
+
real.push(tab);
|
|
5022
|
+
return;
|
|
5023
|
+
}
|
|
5024
|
+
const template = Object.fromEntries(Object.entries(tab).filter(([key]) => key !== "groups"));
|
|
5025
|
+
slots.push({ container, slot: { tab: template, preceding: tabs.slice(0, index).map((earlier) => earlier.tab).reverse() } });
|
|
5026
|
+
});
|
|
5027
|
+
return { tabs: real, slots };
|
|
5028
|
+
}
|
|
4975
5029
|
function convertContainerToTabs(containerValue, context, fallbackTab, trace, depth = 0) {
|
|
4976
5030
|
const rawContainer = objectValue2(containerValue);
|
|
4977
5031
|
if (!rawContainer) return [];
|
|
@@ -5048,6 +5102,17 @@ function convertContainerToTabs(containerValue, context, fallbackTab, trace, dep
|
|
|
5048
5102
|
...convertNavigationValues(values, context),
|
|
5049
5103
|
...Array.isArray(container.menu) ? convertMenuItems(container.menu, context) : []
|
|
5050
5104
|
];
|
|
5105
|
+
if (children.length === 0 && depth > 0 && context.operationGroups && !context.otherLanguage && !context.operations.gated && !context.operations.hidden && specSource(rawContainer.openapi) && operationGroups(rawContainer).length > 0) {
|
|
5106
|
+
const placeholder2 = {
|
|
5107
|
+
tab: fallbackTab,
|
|
5108
|
+
groups: [],
|
|
5109
|
+
...containerPresentation(container),
|
|
5110
|
+
...projectedHref(container.href) ? { href: projectedHref(container.href) } : {},
|
|
5111
|
+
...container.hidden === true ? { hidden: true } : {},
|
|
5112
|
+
[API_TAB_CONTAINER]: rawContainer
|
|
5113
|
+
};
|
|
5114
|
+
return [placeholder2];
|
|
5115
|
+
}
|
|
5051
5116
|
return children.length > 0 ? [{
|
|
5052
5117
|
tab: fallbackTab,
|
|
5053
5118
|
...hasRootNodes ? { pages: children } : { groups: children },
|
|
@@ -5228,6 +5293,8 @@ function projectedCompatibleConfig(config, warnings) {
|
|
|
5228
5293
|
return {
|
|
5229
5294
|
// Mintlify pages show a group eyebrow above the title and no breadcrumb trail.
|
|
5230
5295
|
breadcrumbs: false,
|
|
5296
|
+
// Mintlify typesets straight quotes in prose as curly ones.
|
|
5297
|
+
smartQuotes: true,
|
|
5231
5298
|
// `styling.eyebrows: "breadcrumbs"` shows the whole group path; "section" (the default) shows the nearest group.
|
|
5232
5299
|
...objectValue2(config.styling)?.eyebrows === "breadcrumbs" ? { eyebrow: "path" } : {},
|
|
5233
5300
|
...projectedTheme(config.theme) ? { theme: projectedTheme(config.theme) } : {},
|
|
@@ -5479,6 +5546,9 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
5479
5546
|
}
|
|
5480
5547
|
}
|
|
5481
5548
|
}
|
|
5549
|
+
const taken = takeApiTabSlots(tabs);
|
|
5550
|
+
tabs = taken.tabs;
|
|
5551
|
+
const apiTabSlots = taken.slots;
|
|
5482
5552
|
if (tabs.length === 0) {
|
|
5483
5553
|
warnings.push({
|
|
5484
5554
|
code: "unsupported-config",
|
|
@@ -5524,6 +5594,7 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
5524
5594
|
}) : [];
|
|
5525
5595
|
if (versions.length > 1) {
|
|
5526
5596
|
tabs = annotateVersions(tabs);
|
|
5597
|
+
for (const entry of apiTabSlots) [entry.slot.tab] = annotateVersions([entry.slot.tab]);
|
|
5527
5598
|
for (const [locale, items] of Object.entries(localizedNavigation)) localizedNavigation[locale] = annotateVersions(items);
|
|
5528
5599
|
}
|
|
5529
5600
|
const redirects = Array.isArray(config.redirects) ? config.redirects.flatMap((value) => {
|
|
@@ -5547,11 +5618,13 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
5547
5618
|
}];
|
|
5548
5619
|
}) : [];
|
|
5549
5620
|
collectReferenceAccess(navigation, OPEN_NAVIGATION_ACCESS, options.pathPrefix, appearances);
|
|
5621
|
+
const keepsCollectionNamedGroup = [tabs, ...Object.values(localizedNavigation)].some((items) => items.some((item) => item.groups?.some((group) => group.group === (item.displayLabel ?? item.tab))));
|
|
5550
5622
|
return {
|
|
5551
5623
|
docsConfig: {
|
|
5552
5624
|
tabs,
|
|
5553
|
-
...projectionTrace.rootContainerKind === "dropdowns" || versions.length > 1 || shortcuts.length > 0 ? { navigation: {
|
|
5625
|
+
...projectionTrace.rootContainerKind === "dropdowns" || versions.length > 1 || shortcuts.length > 0 || keepsCollectionNamedGroup ? { navigation: {
|
|
5554
5626
|
...projectionTrace.rootContainerKind === "dropdowns" ? { display: "dropdown" } : {},
|
|
5627
|
+
...keepsCollectionNamedGroup ? { groupHeadings: "all" } : {},
|
|
5555
5628
|
...versions.length > 1 ? { versions } : {},
|
|
5556
5629
|
...shortcuts.length > 0 ? { shortcuts } : {}
|
|
5557
5630
|
} } : {},
|
|
@@ -5563,6 +5636,7 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
5563
5636
|
pageReferences: references,
|
|
5564
5637
|
referenceAccess: appearances,
|
|
5565
5638
|
gatedSourceRefs,
|
|
5639
|
+
apiTabSlots,
|
|
5566
5640
|
warnings
|
|
5567
5641
|
};
|
|
5568
5642
|
}
|
|
@@ -7786,7 +7860,10 @@ var VIDEO_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
|
7786
7860
|
"width",
|
|
7787
7861
|
"height",
|
|
7788
7862
|
"preload",
|
|
7789
|
-
"aria-label"
|
|
7863
|
+
"aria-label",
|
|
7864
|
+
// Publisher asset provenance does not change playback and is never emitted.
|
|
7865
|
+
// Keep this explicit: arbitrary data attributes may drive custom controls.
|
|
7866
|
+
"data-path"
|
|
7790
7867
|
]);
|
|
7791
7868
|
var YOUTUBE_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
7792
7869
|
"src",
|
|
@@ -9074,6 +9151,9 @@ function destinationRoute(destination) {
|
|
|
9074
9151
|
function pageRoutes(pages) {
|
|
9075
9152
|
return pages.flatMap((page) => [`/${page.id}`, `/${page.id.replace(/\/index$/, "")}`]);
|
|
9076
9153
|
}
|
|
9154
|
+
function pageEntryRoutes(page) {
|
|
9155
|
+
return [.../* @__PURE__ */ new Set([...pageRoutes([page]), ...page.id === "introduction" ? ["/"] : []])];
|
|
9156
|
+
}
|
|
9077
9157
|
function servedRoutes(pages) {
|
|
9078
9158
|
return new Set(pageRoutes(pages).map((route) => route.toLowerCase()));
|
|
9079
9159
|
}
|
|
@@ -9138,11 +9218,13 @@ function dropConflictingRedirects(config, pages, warnings) {
|
|
|
9138
9218
|
const loopingByCase = [];
|
|
9139
9219
|
const folded = redirectChains();
|
|
9140
9220
|
const asWritten = redirectChains();
|
|
9221
|
+
const rootRedirected = config.redirects.some((redirect) => literalRoute(redirect.source) === "/");
|
|
9141
9222
|
const redirects = config.redirects.filter((redirect) => {
|
|
9142
9223
|
const source = literalRoute(redirect.source);
|
|
9143
9224
|
if (!source) return true;
|
|
9144
9225
|
const writtenSource = exactRoute(redirect.source);
|
|
9145
|
-
|
|
9226
|
+
const retiresRootAlias = source === "/introduction" && !rootRedirected && destinationRoute(redirect.destination) === "/";
|
|
9227
|
+
if (served.has(source) && !retiresRootAlias) {
|
|
9146
9228
|
const hides = servedAsWritten.has(writtenSource) ? hidden : hiddenByCase;
|
|
9147
9229
|
hides.push(redirect.source);
|
|
9148
9230
|
return false;
|
|
@@ -12337,12 +12419,19 @@ function mintlifyTopLevelApiReferences(config) {
|
|
|
12337
12419
|
function specFileCandidates(files) {
|
|
12338
12420
|
return files.filter((file) => /\.(?:json|ya?ml)$/i.test(file.relativePath)).map((file) => ({ sourcePath: file.relativePath, filename: specRefBaseName(file.relativePath) }));
|
|
12339
12421
|
}
|
|
12340
|
-
function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, nameSpec, pages = []) {
|
|
12422
|
+
function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, nameSpec, pages = [], apiTabSlots = []) {
|
|
12341
12423
|
if (!mintlifyConfig) return [];
|
|
12424
|
+
const slotByContainer = new Map(apiTabSlots.map(({ container, slot }) => [container, slot]));
|
|
12425
|
+
const slotByLabel = new Map(apiTabSlots.map(({ slot }) => [slot.tab.tab, slot]));
|
|
12342
12426
|
const references = [
|
|
12343
12427
|
...mintlifyTopLevelApiReferences(mintlifyConfig),
|
|
12344
|
-
...mintlifyNavigationApiReferences(mintlifyConfig)
|
|
12428
|
+
...mintlifyNavigationApiReferences(mintlifyConfig, (container) => slotByContainer.get(container)?.tab.tab)
|
|
12345
12429
|
];
|
|
12430
|
+
const endpointPagesOf = (reference) => {
|
|
12431
|
+
const directory2 = reference.groups ? endpointDirectory(reference.directory) : void 0;
|
|
12432
|
+
const slot = reference.tabLabel ? slotByLabel.get(reference.tabLabel) : void 0;
|
|
12433
|
+
return directory2 === void 0 ? void 0 : { directory: directory2, ...slot ? { slot } : {} };
|
|
12434
|
+
};
|
|
12346
12435
|
const known = new Set(references.map((reference) => canonicalSpecRef(reference.value)));
|
|
12347
12436
|
const specFiles = specFileCandidates(files);
|
|
12348
12437
|
const namedFiles = /* @__PURE__ */ new Map();
|
|
@@ -12383,6 +12472,14 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, n
|
|
|
12383
12472
|
if (reference.groups) {
|
|
12384
12473
|
const merged = mergeApiGroups(shared.target.groups, reference.groups);
|
|
12385
12474
|
if (merged) shared.target.groups = merged;
|
|
12475
|
+
const own2 = endpointPagesOf(reference);
|
|
12476
|
+
if (shared.directory === void 0) {
|
|
12477
|
+
shared.directory = own2?.directory ?? null;
|
|
12478
|
+
if (own2) shared.target.endpointPages = own2;
|
|
12479
|
+
} else if (shared.directory !== (own2?.directory ?? null)) {
|
|
12480
|
+
shared.directory = null;
|
|
12481
|
+
delete shared.target.endpointPages;
|
|
12482
|
+
}
|
|
12386
12483
|
} else if (listsNothing(reference)) {
|
|
12387
12484
|
shared.unlisted = true;
|
|
12388
12485
|
delete shared.target.groups;
|
|
@@ -12401,11 +12498,12 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, n
|
|
|
12401
12498
|
continue;
|
|
12402
12499
|
}
|
|
12403
12500
|
if (/^https:\/\//i.test(reference.value)) {
|
|
12404
|
-
const
|
|
12501
|
+
const pagesTarget = endpointPagesOf(reference);
|
|
12502
|
+
const remote = { url: reference.value, ...reference.tabLabel ? { tabLabel: reference.tabLabel } : {}, ...reference.parentTab ? { parentTab: reference.parentTab } : {}, ...reference.icon ? { icon: reference.icon } : {}, ...reference.hidden ? { hidden: true } : {}, ...groups ? { groups } : {}, ...groups && pagesTarget ? { endpointPages: pagesTarget } : {} };
|
|
12405
12503
|
mountDirectory(remote, reference);
|
|
12406
12504
|
remoteSpecs.push(remote);
|
|
12407
12505
|
remoteByKey.set(dedupeKey, remote);
|
|
12408
|
-
groupTargets.set(dedupeKey, { target: remote, unlisted: listsNothing(reference), withheld: reference.operationsWithheld === true });
|
|
12506
|
+
groupTargets.set(dedupeKey, { target: remote, unlisted: listsNothing(reference), withheld: reference.operationsWithheld === true, ...groups ? { directory: pagesTarget?.directory ?? null } : {} });
|
|
12409
12507
|
warnings.push({
|
|
12410
12508
|
code: "unsupported-config",
|
|
12411
12509
|
message: `The remote OpenAPI spec "${reference.value}"${tabSuffix} requires a network download before this import is complete.`,
|
|
@@ -12426,12 +12524,12 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, n
|
|
|
12426
12524
|
});
|
|
12427
12525
|
continue;
|
|
12428
12526
|
}
|
|
12429
|
-
|
|
12430
|
-
|
|
12431
|
-
|
|
12432
|
-
|
|
12433
|
-
|
|
12434
|
-
|
|
12527
|
+
const directoryWarning = reference.directory ? {
|
|
12528
|
+
code: "unsupported-config",
|
|
12529
|
+
message: `The OpenAPI spec "${reference.value}"${tabSuffix} was limited to pages under "${reference.directory}" in the source, but Thally's API reference always covers a whole tab, so it was migrated as the tab's full API reference. Links in page bodies and Mintlify endpoint URLs under "${reference.directory}/<tag>/<operation>" are redirected to the matching endpoints where one exists (a separate warning counts any endpoint redirects that were skipped); check any other links to "${reference.directory}/..." manually.`
|
|
12530
|
+
} : void 0;
|
|
12531
|
+
const deferWarning = Boolean(groups && endpointPagesOf(reference));
|
|
12532
|
+
if (directoryWarning && !deferWarning) warnings.push(directoryWarning);
|
|
12435
12533
|
const content = readSpecFile(match.absolutePath, match.relativePath, warnings);
|
|
12436
12534
|
if (!content) continue;
|
|
12437
12535
|
const spec = {
|
|
@@ -12444,10 +12542,11 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, n
|
|
|
12444
12542
|
...reference.pageOnly ? { pageOnly: true } : {},
|
|
12445
12543
|
sourcePath: match.relativePath,
|
|
12446
12544
|
directory: reference.directory,
|
|
12447
|
-
...groups ? { groups } : {}
|
|
12545
|
+
...groups ? { groups } : {},
|
|
12546
|
+
...deferWarning ? { endpointPages: endpointPagesOf(reference), directoryWarning } : {}
|
|
12448
12547
|
};
|
|
12449
12548
|
specs.push(spec);
|
|
12450
|
-
groupTargets.set(dedupeKey, { target: spec, unlisted: listsNothing(reference), withheld: reference.operationsWithheld === true });
|
|
12549
|
+
groupTargets.set(dedupeKey, { target: spec, unlisted: listsNothing(reference), withheld: reference.operationsWithheld === true, ...groups ? { directory: endpointPagesOf(reference)?.directory ?? null } : {} });
|
|
12451
12550
|
}
|
|
12452
12551
|
for (const { target: target2, unlisted, withheld } of groupTargets.values()) {
|
|
12453
12552
|
if (withheld && !unlisted && !target2.groups) target2.navigation = false;
|
|
@@ -12503,20 +12602,52 @@ function apiTabSpecIds(tabs) {
|
|
|
12503
12602
|
}
|
|
12504
12603
|
var flagged = (value) => value === true || value === "true";
|
|
12505
12604
|
var isWithheld = (node) => flagged(node["x-hidden"]) || flagged(node["x-excluded"]);
|
|
12605
|
+
var isRecord2 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
12606
|
+
function resolveLocalSpecRef(document, ref) {
|
|
12607
|
+
if (ref !== "#" && !ref.startsWith("#/")) return void 0;
|
|
12608
|
+
let node = document;
|
|
12609
|
+
for (const segment of ref.slice(2).split("/").filter(Boolean)) {
|
|
12610
|
+
if (!isRecord2(node) && !Array.isArray(node)) return void 0;
|
|
12611
|
+
let decoded = segment;
|
|
12612
|
+
try {
|
|
12613
|
+
decoded = decodeURIComponent(segment);
|
|
12614
|
+
} catch {
|
|
12615
|
+
}
|
|
12616
|
+
node = node[decoded.replace(/~1/g, "/").replace(/~0/g, "~")];
|
|
12617
|
+
}
|
|
12618
|
+
return node;
|
|
12619
|
+
}
|
|
12620
|
+
function viewSpecPathItem(document, entry) {
|
|
12621
|
+
const chain = [entry];
|
|
12622
|
+
let current = entry;
|
|
12623
|
+
while (typeof current.$ref === "string") {
|
|
12624
|
+
const target2 = resolveLocalSpecRef(document, current.$ref);
|
|
12625
|
+
if (!isRecord2(target2) || chain.includes(target2)) break;
|
|
12626
|
+
chain.push(target2);
|
|
12627
|
+
current = target2;
|
|
12628
|
+
}
|
|
12629
|
+
const item = Object.assign({}, ...[...chain].reverse());
|
|
12630
|
+
delete item.$ref;
|
|
12631
|
+
return { item, withheld: chain.some(isWithheld) };
|
|
12632
|
+
}
|
|
12506
12633
|
function parseOpenApiOperationsForLinking(content) {
|
|
12507
|
-
|
|
12634
|
+
const document = readSpecDocument(content);
|
|
12635
|
+
return visibleOperations(document, isRecord2(document) ? document.paths : void 0);
|
|
12636
|
+
}
|
|
12637
|
+
function readSpecDocument(content) {
|
|
12508
12638
|
try {
|
|
12509
|
-
|
|
12639
|
+
return parseSpecDocument(content.toString("utf8")).document;
|
|
12510
12640
|
} catch {
|
|
12511
|
-
return
|
|
12641
|
+
return void 0;
|
|
12512
12642
|
}
|
|
12513
|
-
|
|
12514
|
-
|
|
12643
|
+
}
|
|
12644
|
+
function visibleOperations(document, entries) {
|
|
12645
|
+
if (!isRecord2(entries)) return [];
|
|
12515
12646
|
const operations = [];
|
|
12516
|
-
for (const [path, pathItem] of Object.entries(
|
|
12517
|
-
if (!pathItem
|
|
12518
|
-
const item = pathItem;
|
|
12519
|
-
if (
|
|
12647
|
+
for (const [path, pathItem] of Object.entries(entries)) {
|
|
12648
|
+
if (!isRecord2(pathItem)) continue;
|
|
12649
|
+
const { item, withheld } = viewSpecPathItem(document, pathItem);
|
|
12650
|
+
if (withheld) continue;
|
|
12520
12651
|
for (const method of OPENAPI_HTTP_METHODS) {
|
|
12521
12652
|
const operation = item[method];
|
|
12522
12653
|
if (!operation || typeof operation !== "object") continue;
|
|
@@ -12528,7 +12659,8 @@ function parseOpenApiOperationsForLinking(content) {
|
|
|
12528
12659
|
path,
|
|
12529
12660
|
tag: tags[0],
|
|
12530
12661
|
summary: typeof op.summary === "string" ? op.summary : void 0,
|
|
12531
|
-
operationId: typeof op.operationId === "string" ? op.operationId : void 0
|
|
12662
|
+
operationId: typeof op.operationId === "string" ? op.operationId : void 0,
|
|
12663
|
+
description: typeof op.description === "string" ? op.description : void 0
|
|
12532
12664
|
});
|
|
12533
12665
|
}
|
|
12534
12666
|
}
|
|
@@ -12549,13 +12681,26 @@ function servedOperations(source, parsed) {
|
|
|
12549
12681
|
});
|
|
12550
12682
|
}
|
|
12551
12683
|
var mountPrefix = (directory2) => directory2.replace(/^\/+|\/+$/g, "").toLowerCase();
|
|
12684
|
+
function mintlifyEndpointUrl(directory2, operation) {
|
|
12685
|
+
const tag = mintlifyUrlSlug(operation.tag ?? "default");
|
|
12686
|
+
const leaf = mintlifyUrlSlug(operation.summary?.trim() || operation.operationId?.trim() || `${operation.method} ${operation.path}`);
|
|
12687
|
+
return {
|
|
12688
|
+
tag,
|
|
12689
|
+
leaf,
|
|
12690
|
+
url: `${directory2}/${tag}/${leaf}`.replace(/^\/+|\/+$/g, ""),
|
|
12691
|
+
title: operation.summary?.trim() || operation.operationId?.trim() || `${operation.method.toUpperCase()} ${operation.path}`
|
|
12692
|
+
};
|
|
12693
|
+
}
|
|
12552
12694
|
function apiOperationLinkMap(sources, docsConfig, otherMounts = []) {
|
|
12553
12695
|
const map = /* @__PURE__ */ new Map();
|
|
12554
12696
|
const prefixLandings = /* @__PURE__ */ new Map();
|
|
12555
12697
|
const mintlifyPages = /* @__PURE__ */ new Map();
|
|
12556
12698
|
const duplicatePages = [];
|
|
12557
12699
|
const parsedByFile = /* @__PURE__ */ new Map();
|
|
12558
|
-
const bound =
|
|
12700
|
+
const bound = [
|
|
12701
|
+
...apiTabSpecIds(docsConfig.tabs).flatMap(({ tab, specId }) => sources.filter((entry) => !entry.endpointPages && tab.api?.source === specAssetPath(entry.filename) && (!entry.tab || entry.tab === tab.tab)).map((source) => ({ source, specId }))),
|
|
12702
|
+
...sources.filter((entry) => entry.endpointPages).map((source) => ({ source }))
|
|
12703
|
+
];
|
|
12559
12704
|
const mounts = new Set([...bound.map(({ source }) => source.prefix ? mountPrefix(source.prefix) : ""), ...otherMounts.map(mountPrefix)].filter(Boolean));
|
|
12560
12705
|
const underDeeperMount = (route, own2) => {
|
|
12561
12706
|
const lower = route.toLowerCase();
|
|
@@ -12565,9 +12710,12 @@ function apiOperationLinkMap(sources, docsConfig, otherMounts = []) {
|
|
|
12565
12710
|
if (!source.prefix) return;
|
|
12566
12711
|
const base = source.prefix.replace(/^\/+|\/+$/g, "");
|
|
12567
12712
|
const prefix = mountPrefix(source.prefix);
|
|
12568
|
-
if (prefix) prefixLandings.set(prefix, specId === "default" ? "/api" : `/api/${specId}`);
|
|
12713
|
+
if (prefix && specId !== void 0) prefixLandings.set(prefix, specId === "default" ? "/api" : `/api/${specId}`);
|
|
12569
12714
|
for (const operation of servedOperations(source, parsedByFile)) {
|
|
12570
|
-
const
|
|
12715
|
+
const endpoint = mintlifyEndpointUrl(base, operation);
|
|
12716
|
+
if (specId === void 0 && (!endpoint.tag || !endpoint.leaf)) continue;
|
|
12717
|
+
const thallyHref = specId === void 0 ? `/${endpoint.url}` : `/api/${specId}/${thallyOperationSlugSegments(operation.path, operation.method).join("/")}`;
|
|
12718
|
+
if (specId === void 0 && prefix && !prefixLandings.has(prefix)) prefixLandings.set(prefix, thallyHref);
|
|
12571
12719
|
const leafCandidates = /* @__PURE__ */ new Set();
|
|
12572
12720
|
if (operation.operationId) {
|
|
12573
12721
|
const parts = operation.operationId.split(/[_.]/).filter(Boolean);
|
|
@@ -12580,17 +12728,17 @@ function apiOperationLinkMap(sources, docsConfig, otherMounts = []) {
|
|
|
12580
12728
|
if (operation.operationId) leafCandidates.add(mintlifyOperationSlugSegment(operation.operationId));
|
|
12581
12729
|
leafCandidates.add(mintlifyOperationSlugSegment(`${operation.method} ${operation.path}`));
|
|
12582
12730
|
const tagSegment = mintlifyOperationSlugSegment(operation.tag ?? "default");
|
|
12583
|
-
const mintlifyTag
|
|
12584
|
-
const mintlifyLeaf = mintlifyUrlSlug(operation.summary?.trim() || operation.operationId?.trim() || `${operation.method} ${operation.path}`);
|
|
12585
|
-
const canonical2 = `${base}/${mintlifyTag}/${mintlifyLeaf}`.replace(/^\/+|\/+$/g, "");
|
|
12731
|
+
const { tag: mintlifyTag, leaf: mintlifyLeaf, url: canonical2 } = endpoint;
|
|
12586
12732
|
if (mintlifyTag && mintlifyLeaf && !underDeeperMount(canonical2, prefix)) {
|
|
12587
|
-
if (
|
|
12588
|
-
|
|
12733
|
+
if (specId !== void 0) {
|
|
12734
|
+
if (!mintlifyPages.has(canonical2)) mintlifyPages.set(canonical2, thallyHref);
|
|
12735
|
+
else if (mintlifyPages.get(canonical2) !== thallyHref && !duplicatePages.includes(canonical2)) duplicatePages.push(canonical2);
|
|
12736
|
+
}
|
|
12589
12737
|
if (!map.has(canonical2.toLowerCase())) map.set(canonical2.toLowerCase(), thallyHref);
|
|
12590
12738
|
}
|
|
12591
12739
|
const tagRoot = `${base}/${mintlifyTag}`.replace(/^\/+|\/+$/g, "");
|
|
12592
12740
|
if (mintlifyTag && !underDeeperMount(tagRoot, prefix)) {
|
|
12593
|
-
if (!mintlifyPages.has(tagRoot)) mintlifyPages.set(tagRoot, thallyHref);
|
|
12741
|
+
if (specId !== void 0 && !mintlifyPages.has(tagRoot)) mintlifyPages.set(tagRoot, thallyHref);
|
|
12594
12742
|
if (!map.has(tagRoot.toLowerCase())) map.set(tagRoot.toLowerCase(), thallyHref);
|
|
12595
12743
|
}
|
|
12596
12744
|
for (const leaf of leafCandidates) {
|
|
@@ -12631,6 +12779,150 @@ function linkApiMounts(sources, docsConfig, pages, warnings, reservedMounts = []
|
|
|
12631
12779
|
rewriteApiLinksInPages(pages, maps.operationLinks, maps.prefixLandings, warnings, { mounts: reservedMounts, redirects: docsConfig.redirects });
|
|
12632
12780
|
return mintlifyEndpointRedirects(maps, pages, docsConfig.redirects ?? [], warnings);
|
|
12633
12781
|
}
|
|
12782
|
+
var DEFAULT_ENDPOINT_DIRECTORY = "api-reference";
|
|
12783
|
+
function endpointDirectory(directory2) {
|
|
12784
|
+
const value = (directory2 ?? DEFAULT_ENDPOINT_DIRECTORY).replace(/^\/+|\/+$/g, "");
|
|
12785
|
+
const plain = (segment) => /^[\p{L}\p{N}_&-][\p{L}\p{N}_&.-]*$/u.test(segment) && Buffer.byteLength(`${segment}.mdx`) <= 255;
|
|
12786
|
+
return value && value.split("/").every(plain) ? value : void 0;
|
|
12787
|
+
}
|
|
12788
|
+
function createEndpointPageLedger(pages) {
|
|
12789
|
+
return { owners: new Map(pages.map((page) => [page.id.toLowerCase(), { id: page.id, operation: null }])), duplicates: [], unnamed: [] };
|
|
12790
|
+
}
|
|
12791
|
+
function reportEndpointPages(ledger, warnings) {
|
|
12792
|
+
const names = (urls) => `${urls.slice(0, 10).join(", ")}${urls.length > 10 ? ", ..." : ""}`;
|
|
12793
|
+
if (ledger.duplicates.length > 0) {
|
|
12794
|
+
warnings.push({
|
|
12795
|
+
code: "unsupported-config",
|
|
12796
|
+
message: `${ledger.duplicates.length} Mintlify endpoint URL${ledger.duplicates.length === 1 ? " is" : "s are"} shared by more than one operation (same tag and summary), so only the first operation has a page at each: ${names(ledger.duplicates.map((url) => `/${url}`))}.`
|
|
12797
|
+
});
|
|
12798
|
+
}
|
|
12799
|
+
if (ledger.unnamed.length > 0) {
|
|
12800
|
+
warnings.push({
|
|
12801
|
+
code: "unsupported-config",
|
|
12802
|
+
message: `${ledger.unnamed.length} listed operation${ledger.unnamed.length === 1 ? " has" : "s have"} no page because ${ledger.unnamed.length === 1 ? "its" : "their"} tag or title leaves no usable page name: ${names(ledger.unnamed)}.`
|
|
12803
|
+
});
|
|
12804
|
+
}
|
|
12805
|
+
}
|
|
12806
|
+
function endpointDescription(description, title) {
|
|
12807
|
+
const text3 = (description ?? "").split(/\r?\n\s*\r?\n/, 1)[0].replace(/<[^>]*>/g, " ").replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/[`*~]|__/g, "").replace(/^\s*#+\s*/, "").replace(/\s+/g, " ").trim();
|
|
12808
|
+
const sentence = /^(.+?[.!?])(?=\s|$)/.exec(text3)?.[1] ?? text3;
|
|
12809
|
+
const limited = sentence.length > 300 ? `${sentence.slice(0, 297).replace(/\s+\S*$/, "")}...` : sentence;
|
|
12810
|
+
return limited || title;
|
|
12811
|
+
}
|
|
12812
|
+
function insertEndpointTab(tabs, tab, preceding) {
|
|
12813
|
+
if (preceding.length === 0) {
|
|
12814
|
+
tabs.unshift(tab);
|
|
12815
|
+
return;
|
|
12816
|
+
}
|
|
12817
|
+
for (const label of preceding) {
|
|
12818
|
+
const index = tabs.findIndex((candidate) => candidate.tab === label);
|
|
12819
|
+
if (index !== -1) {
|
|
12820
|
+
tabs.splice(index + 1, 0, tab);
|
|
12821
|
+
return;
|
|
12822
|
+
}
|
|
12823
|
+
}
|
|
12824
|
+
tabs.push(tab);
|
|
12825
|
+
}
|
|
12826
|
+
function addEndpointPages(options) {
|
|
12827
|
+
const { tabs, pages, ledger, spec } = options;
|
|
12828
|
+
const operations = parseOpenApiOperationsForLinking(spec.content);
|
|
12829
|
+
if (operations.length === 0) return null;
|
|
12830
|
+
const existing = spec.tabLabel ? tabs.find((tab) => tab.tab === spec.tabLabel) : tabs.find((tab) => !tab.hidden && tab.tab.toLowerCase().includes("api"));
|
|
12831
|
+
if (existing?.api) return null;
|
|
12832
|
+
const byKey = new Map(operations.map((operation) => [`${operation.method} ${operation.path}`, operation]));
|
|
12833
|
+
const listed = [];
|
|
12834
|
+
const pageFor = (reference) => {
|
|
12835
|
+
const [method, ...path] = reference.trim().split(/\s+/);
|
|
12836
|
+
const operation = byKey.get(`${method.toLowerCase()} ${path.join(" ")}`);
|
|
12837
|
+
if (!operation) return void 0;
|
|
12838
|
+
const key = `${operation.method.toUpperCase()} ${operation.path}`;
|
|
12839
|
+
const endpoint = mintlifyEndpointUrl(spec.target.directory, operation);
|
|
12840
|
+
if (!endpoint.tag || !endpoint.leaf || Buffer.byteLength(`${endpoint.tag}.mdx`) > 255 || Buffer.byteLength(`${endpoint.leaf}.mdx`) > 255) {
|
|
12841
|
+
if (!ledger.unnamed.includes(key)) ledger.unnamed.push(key);
|
|
12842
|
+
return void 0;
|
|
12843
|
+
}
|
|
12844
|
+
const identity = `${spec.assetPath} ${key}`;
|
|
12845
|
+
const owner = ledger.owners.get(endpoint.url.toLowerCase());
|
|
12846
|
+
if (owner && owner.operation !== null && owner.operation !== identity) {
|
|
12847
|
+
if (!ledger.duplicates.includes(endpoint.url)) ledger.duplicates.push(endpoint.url);
|
|
12848
|
+
return void 0;
|
|
12849
|
+
}
|
|
12850
|
+
if (!owner) {
|
|
12851
|
+
pages.push({
|
|
12852
|
+
id: endpoint.url,
|
|
12853
|
+
navigationId: endpoint.url,
|
|
12854
|
+
title: endpoint.title,
|
|
12855
|
+
description: endpointDescription(operation.description, endpoint.title),
|
|
12856
|
+
// The summary belongs to metadata; keep full spec prose in the safe
|
|
12857
|
+
// operation Markdown renderer rather than copying it into executable MDX.
|
|
12858
|
+
descriptionPlacement: "operation",
|
|
12859
|
+
keywords: [],
|
|
12860
|
+
body: "",
|
|
12861
|
+
source: "docs.json",
|
|
12862
|
+
openapi: `${spec.assetPath} ${key}`
|
|
12863
|
+
});
|
|
12864
|
+
ledger.owners.set(endpoint.url.toLowerCase(), { id: endpoint.url, operation: identity });
|
|
12865
|
+
}
|
|
12866
|
+
listed.push(key);
|
|
12867
|
+
return owner?.id ?? endpoint.url;
|
|
12868
|
+
};
|
|
12869
|
+
const convert2 = (nodes) => nodes.flatMap((node) => {
|
|
12870
|
+
if (typeof node === "string") {
|
|
12871
|
+
const id = pageFor(node);
|
|
12872
|
+
return id ? [id] : [];
|
|
12873
|
+
}
|
|
12874
|
+
const pagesOf = convert2(node.pages);
|
|
12875
|
+
return pagesOf.length > 0 ? [{ group: node.group, ...node.icon ? { icon: node.icon } : {}, pages: pagesOf }] : [];
|
|
12876
|
+
});
|
|
12877
|
+
const groups = convert2(spec.groups);
|
|
12878
|
+
if (groups.length === 0) return null;
|
|
12879
|
+
if (existing) {
|
|
12880
|
+
if (existing.groups || !existing.pages) existing.groups = [...existing.groups ?? [], ...groups];
|
|
12881
|
+
else existing.pages = [...existing.pages, ...groups];
|
|
12882
|
+
} else {
|
|
12883
|
+
const { slot } = spec.target;
|
|
12884
|
+
const tab = {
|
|
12885
|
+
...slot?.tab ?? { tab: spec.tabLabel ?? "API Reference", ...spec.icon ? { icon: spec.icon } : {}, ...spec.hidden ? { hidden: true } : {} },
|
|
12886
|
+
groups
|
|
12887
|
+
};
|
|
12888
|
+
if (slot) insertEndpointTab(tabs, tab, slot.preceding);
|
|
12889
|
+
else insertApiTab(tabs, tab, spec.parentTab);
|
|
12890
|
+
}
|
|
12891
|
+
if (!tabs.some((tab) => tab.api?.source === spec.assetPath)) {
|
|
12892
|
+
insertApiTab(tabs, { tab: `OpenAPI: ${spec.source}`, hidden: true, api: { source: spec.assetPath } });
|
|
12893
|
+
}
|
|
12894
|
+
return { operations: listed };
|
|
12895
|
+
}
|
|
12896
|
+
function specLookupOrder(tabs, versions = []) {
|
|
12897
|
+
const collected = (tab) => !tab.hidden || Boolean(tab.version && versions.some((version) => version.label === tab.version));
|
|
12898
|
+
const sources = [...tabs.filter(collected), ...tabs.filter((tab) => !collected(tab))].flatMap((tab) => tab.api ? [tab.api.source] : []);
|
|
12899
|
+
return [...new Set(sources)];
|
|
12900
|
+
}
|
|
12901
|
+
function publishedOperationKeys(content) {
|
|
12902
|
+
const document = readSpecDocument(content);
|
|
12903
|
+
const table = (field) => visibleOperations(document, isRecord2(document) ? document[field] : void 0);
|
|
12904
|
+
return /* @__PURE__ */ new Set([
|
|
12905
|
+
...table("paths").map((operation) => `${operation.method} ${operation.path}`),
|
|
12906
|
+
...table("webhooks").map((operation) => `webhook ${operation.path}`)
|
|
12907
|
+
]);
|
|
12908
|
+
}
|
|
12909
|
+
function qualifyDisplacedBareRefs(options) {
|
|
12910
|
+
const { pages, before, after, content, qualifier } = options;
|
|
12911
|
+
if (before.join("\n") === after.join("\n")) return;
|
|
12912
|
+
const published = /* @__PURE__ */ new Map();
|
|
12913
|
+
const firstPublishing = (order, key) => order.find((source) => {
|
|
12914
|
+
if (!published.has(source)) published.set(source, publishedOperationKeys(content(source) ?? Buffer.alloc(0)));
|
|
12915
|
+
return published.get(source).has(key);
|
|
12916
|
+
});
|
|
12917
|
+
for (const page of pages) {
|
|
12918
|
+
const ref = page.openapi ? splitOpenApiRef(page.openapi) : null;
|
|
12919
|
+
if (!ref || ref.specRef) continue;
|
|
12920
|
+
const [method, ...rest] = ref.operation.trim().split(/\s+/);
|
|
12921
|
+
const key = `${method.toLowerCase()} ${rest.join(" ")}`;
|
|
12922
|
+
const reached = firstPublishing(before, key);
|
|
12923
|
+
if (reached !== void 0 && reached !== firstPublishing(after, key)) page.openapi = withSpecRef(ref, qualifier(reached));
|
|
12924
|
+
}
|
|
12925
|
+
}
|
|
12634
12926
|
function rewriteApiLinksInPages(pages, operationLinks, prefixLandings, warnings, answered = {}) {
|
|
12635
12927
|
if (operationLinks.size === 0 && prefixLandings.size === 0) return;
|
|
12636
12928
|
const unmatched = /* @__PURE__ */ new Set();
|
|
@@ -13878,6 +14170,7 @@ function migrateRepository(options) {
|
|
|
13878
14170
|
const referenceOrder = /* @__PURE__ */ new Map();
|
|
13879
14171
|
let docusaurusSidebars = null;
|
|
13880
14172
|
let mintlifyConfig = null;
|
|
14173
|
+
let mintlifyApiTabSlots = [];
|
|
13881
14174
|
const mintlifyNavigationAccess = /* @__PURE__ */ new Map();
|
|
13882
14175
|
let fernRawConfig = null;
|
|
13883
14176
|
let fernBasePath = "";
|
|
@@ -13922,6 +14215,7 @@ function migrateRepository(options) {
|
|
|
13922
14215
|
}
|
|
13923
14216
|
});
|
|
13924
14217
|
docsConfig = projected.docsConfig;
|
|
14218
|
+
mintlifyApiTabSlots = projected.apiTabSlots;
|
|
13925
14219
|
warnings.push(...projected.warnings);
|
|
13926
14220
|
for (const repo of projected.gatedSourceRefs) gatedSourceRepos.add(repo.toLowerCase());
|
|
13927
14221
|
for (const appearance of projected.referenceAccess) {
|
|
@@ -15029,7 +15323,8 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
15029
15323
|
warnings.push({ code: "gated-page", message: sharedSpecMessage(path, excluded), source: path });
|
|
15030
15324
|
};
|
|
15031
15325
|
const nameSpec = createSpecAssetNamer();
|
|
15032
|
-
const
|
|
15326
|
+
const generatedEndpointPages = /* @__PURE__ */ new Set();
|
|
15327
|
+
const allSpecs = resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteApiSpecs, nameSpec, pages.filter((page) => !restrictedPages.has(page)), mintlifyApiTabSlots);
|
|
15033
15328
|
const navigation = navigationSpecContext(mintlifyConfig, (path) => resolvePageIdentity(path)?.id ?? null);
|
|
15034
15329
|
const defaultSources = /* @__PURE__ */ new Set([
|
|
15035
15330
|
...allSpecs.filter((spec) => !spec.pageOnly && spec.tabLabel === void 0).map((spec) => spec.sourcePath),
|
|
@@ -15072,12 +15367,61 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
15072
15367
|
spec.pageReferenced = namedByPages.has(spec);
|
|
15073
15368
|
spec.generatedNavigation = Boolean(spec.directory) && !publishedSpecRefs.some((ref) => specRefMatches(ref, spec.sourcePath, true));
|
|
15074
15369
|
}
|
|
15075
|
-
|
|
15370
|
+
const listingSpecs = resolvedSpecs.filter((spec) => spec.groups && spec.endpointPages);
|
|
15371
|
+
const unbound = docsConfig;
|
|
15372
|
+
docsConfig = injectOpenApiSpecs(docsConfig, resolvedSpecs.filter((spec) => !listingSpecs.includes(spec)), warnings);
|
|
15373
|
+
const ledger = createEndpointPageLedger(pages);
|
|
15374
|
+
const tabs = docsConfig.tabs.map((tab) => ({ ...tab }));
|
|
15375
|
+
const pagesBefore = pages.length;
|
|
15376
|
+
const endpointSpecs = /* @__PURE__ */ new Set();
|
|
15377
|
+
for (const spec of listingSpecs) {
|
|
15378
|
+
if (!spec.groups || !spec.endpointPages) continue;
|
|
15379
|
+
const added = addEndpointPages({
|
|
15380
|
+
tabs,
|
|
15381
|
+
pages,
|
|
15382
|
+
ledger,
|
|
15383
|
+
spec: {
|
|
15384
|
+
assetPath: specAssetPath(spec.filename),
|
|
15385
|
+
source: spec.sourcePath,
|
|
15386
|
+
content: spec.content,
|
|
15387
|
+
groups: spec.groups,
|
|
15388
|
+
target: spec.endpointPages,
|
|
15389
|
+
tabLabel: spec.tabLabel,
|
|
15390
|
+
parentTab: spec.parentTab,
|
|
15391
|
+
icon: spec.icon,
|
|
15392
|
+
hidden: spec.hidden
|
|
15393
|
+
}
|
|
15394
|
+
});
|
|
15395
|
+
if (!added) continue;
|
|
15396
|
+
spec.endpointOperations = added.operations;
|
|
15397
|
+
endpointSpecs.add(spec);
|
|
15398
|
+
}
|
|
15399
|
+
reportEndpointPages(ledger, warnings);
|
|
15400
|
+
for (const spec of resolvedSpecs) if (spec.directoryWarning && !endpointSpecs.has(spec)) warnings.push(spec.directoryWarning);
|
|
15401
|
+
for (const page of pages.slice(pagesBefore)) generatedEndpointPages.add(page);
|
|
15402
|
+
docsConfig = injectOpenApiSpecs({ ...docsConfig, tabs }, listingSpecs.filter((spec) => !endpointSpecs.has(spec)), warnings);
|
|
15403
|
+
if (remoteApiSpecs.length === 0 && endpointSpecs.size > 0) {
|
|
15404
|
+
const bySource = new Map(resolvedSpecs.map((spec) => [specAssetPath(spec.filename), spec]));
|
|
15405
|
+
qualifyDisplacedBareRefs({
|
|
15406
|
+
pages,
|
|
15407
|
+
before: specLookupOrder(injectOpenApiSpecs(unbound, resolvedSpecs).tabs, docsConfig.navigation?.versions),
|
|
15408
|
+
after: specLookupOrder(docsConfig.tabs, docsConfig.navigation?.versions),
|
|
15409
|
+
content: (source) => bySource.get(source)?.content,
|
|
15410
|
+
qualifier: (source) => bySource.get(source)?.sourcePath ?? source
|
|
15411
|
+
});
|
|
15412
|
+
}
|
|
15413
|
+
const mountOf = (spec) => endpointSpecs.has(spec) ? { prefix: spec.endpointPages?.directory, operations: spec.endpointOperations } : { prefix: spec.directory };
|
|
15076
15414
|
if (remoteApiSpecs.length > 0) {
|
|
15077
|
-
localApiMounts.push(...resolvedSpecs.flatMap((spec) =>
|
|
15415
|
+
localApiMounts.push(...resolvedSpecs.flatMap((spec) => {
|
|
15416
|
+
const { prefix, operations } = mountOf(spec);
|
|
15417
|
+
return prefix ? [{ filename: spec.filename, directory: prefix, ...spec.tabLabel ? { tab: spec.tabLabel } : {}, ...operations ? { endpointOperations: operations } : {} }] : [];
|
|
15418
|
+
}));
|
|
15078
15419
|
} else {
|
|
15079
15420
|
const endpointRedirects = linkApiMounts(
|
|
15080
|
-
resolvedSpecs.map((spec) =>
|
|
15421
|
+
resolvedSpecs.map((spec) => {
|
|
15422
|
+
const { prefix, operations } = mountOf(spec);
|
|
15423
|
+
return { filename: spec.filename, content: spec.content, prefix, ...operations ? { endpointPages: true, operations } : {}, ...spec.tabLabel ? { tab: spec.tabLabel } : {} };
|
|
15424
|
+
}),
|
|
15081
15425
|
docsConfig,
|
|
15082
15426
|
pages,
|
|
15083
15427
|
warnings
|
|
@@ -15134,7 +15478,7 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
15134
15478
|
}
|
|
15135
15479
|
return sameName ? "the file could not be read as an OpenAPI document" : `no file exists at "${key}"`;
|
|
15136
15480
|
};
|
|
15137
|
-
rewriteMintlifyPageSpecRefs(pages, pageSpecs, new Set(remoteApiSpecs.map((spec) => spec.url)), warnings, explainMissingSpec);
|
|
15481
|
+
rewriteMintlifyPageSpecRefs(pages.filter((page) => !generatedEndpointPages.has(page)), pageSpecs, new Set(remoteApiSpecs.map((spec) => spec.url)), warnings, explainMissingSpec);
|
|
15138
15482
|
if (docsConfig.tabs.some((tab) => tab.api)) docsConfig = { ...docsConfig, api: { ...docsConfig.api, specLink: false } };
|
|
15139
15483
|
}
|
|
15140
15484
|
if (platform === "mintlify") {
|
|
@@ -15356,6 +15700,24 @@ ${body}`;
|
|
|
15356
15700
|
if (docsConfig.redirects) {
|
|
15357
15701
|
docsConfig = dropConflictingRedirects(dropUnroutableRedirects(docsConfig, warnings), [...pages, ...sourceRefPages], warnings);
|
|
15358
15702
|
}
|
|
15703
|
+
const redirectSources = new Map((docsConfig.redirects ?? []).map((redirect) => [(redirect.source.replace(/\/+$/, "") || "/").toLowerCase(), redirect.destination]));
|
|
15704
|
+
const linkRedirects = [];
|
|
15705
|
+
for (const page of [...pages, ...sourceRefPages]) {
|
|
15706
|
+
if (!page.externalUrl) continue;
|
|
15707
|
+
for (const source of pageEntryRoutes(page)) {
|
|
15708
|
+
const existing = redirectSources.get(source.toLowerCase());
|
|
15709
|
+
if (existing !== void 0) {
|
|
15710
|
+
warnings.push({
|
|
15711
|
+
code: "unsupported-config",
|
|
15712
|
+
message: `Page "${page.id}" links to ${stripControlCharacters(page.externalUrl)}, but "${source}" already redirects to ${stripControlCharacters(existing)}; that redirect was kept, so "${source}" does not open the link.`
|
|
15713
|
+
});
|
|
15714
|
+
continue;
|
|
15715
|
+
}
|
|
15716
|
+
redirectSources.set(source.toLowerCase(), page.externalUrl);
|
|
15717
|
+
linkRedirects.push({ source, destination: page.externalUrl, permanent: false });
|
|
15718
|
+
}
|
|
15719
|
+
}
|
|
15720
|
+
if (linkRedirects.length > 0) docsConfig = { ...docsConfig, redirects: [...docsConfig.redirects ?? [], ...linkRedirects] };
|
|
15359
15721
|
if (pages.length === 0) {
|
|
15360
15722
|
const reasons = warnings.map((warning) => warning.message);
|
|
15361
15723
|
throw new Error(reasons.length ? `No importable Markdown or MDX pages were found in the repository. Warnings encountered during migration:
|
|
@@ -15439,7 +15801,7 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}` : "No importable Markdown
|
|
|
15439
15801
|
});
|
|
15440
15802
|
}
|
|
15441
15803
|
if (!docsConfig.navigation?.display && docsConfig.tabs.filter((tab) => !tab.hidden).length > 6) {
|
|
15442
|
-
docsConfig = { ...docsConfig, navigation: { display: "dropdown" } };
|
|
15804
|
+
docsConfig = { ...docsConfig, navigation: { display: "dropdown", ...docsConfig.navigation?.groupHeadings ? { groupHeadings: docsConfig.navigation.groupHeadings } : {} } };
|
|
15443
15805
|
}
|
|
15444
15806
|
const themeColors = mintlifyConfig ? mintlifyThemeColors(mintlifyConfig.colors) : fernRawConfig ? fernThemeColors(fernRawConfig.colors) ?? (fernRawConfig["global-theme"] === "nvidia" ? { primary: "#76B900" } : void 0) : isTopLevelDocusaurus ? presentation?.colors ?? readDocusaurusThemeColor(docusaurusProjectRoot) : void 0;
|
|
15445
15807
|
const assetPaths = new Set(assets.map((asset) => asset.path));
|
|
@@ -15635,7 +15997,7 @@ function renderPage(bundle, page) {
|
|
|
15635
15997
|
page.icon ? `icon: ${yamlString(page.icon)}` : null,
|
|
15636
15998
|
page.iconType ? `iconType: ${yamlString(page.iconType)}` : null,
|
|
15637
15999
|
`description: ${yamlString(page.description)}`,
|
|
15638
|
-
page.descriptionPlacement === "body" ?
|
|
16000
|
+
page.descriptionPlacement === "body" || page.descriptionPlacement === "operation" ? `descriptionPlacement: ${page.descriptionPlacement}` : null,
|
|
15639
16001
|
page.badge ? `badge: ${yamlString(page.badge)}` : null,
|
|
15640
16002
|
page.keywords.length > 0 ? `keywords: [${page.keywords.map(yamlString).join(", ")}]` : null,
|
|
15641
16003
|
page.mode ? `mode: ${yamlString(page.mode)}` : null,
|
|
@@ -15760,6 +16122,7 @@ function renderMigrationFiles(bundle, options = {}) {
|
|
|
15760
16122
|
// src/url-run.ts
|
|
15761
16123
|
import { createHash as createHash6 } from "crypto";
|
|
15762
16124
|
import { load as load8 } from "cheerio";
|
|
16125
|
+
import { parse as parse2, postprocess, preprocess } from "micromark";
|
|
15763
16126
|
import remarkParse5 from "remark-parse";
|
|
15764
16127
|
import remarkMdx5 from "remark-mdx";
|
|
15765
16128
|
import { unified as unified5 } from "unified";
|
|
@@ -16838,9 +17201,9 @@ function apiOperationCodeControls(body, specification, operation) {
|
|
|
16838
17201
|
}
|
|
16839
17202
|
|
|
16840
17203
|
// src/url-run.ts
|
|
16841
|
-
var CONVERTER_VERSION = "url-evidence-
|
|
17204
|
+
var CONVERTER_VERSION = "url-evidence-v7";
|
|
16842
17205
|
var parser3 = unified5().use(remarkParse5).use(remarkMdx5);
|
|
16843
|
-
var ACCEPT = "text/
|
|
17206
|
+
var ACCEPT = "text/html,application/xhtml+xml";
|
|
16844
17207
|
var MAX_RESPONSE_BYTES = 8e6;
|
|
16845
17208
|
var MAX_ASSET_BYTES2 = 1e7;
|
|
16846
17209
|
var MAX_RECORDS = 1e5;
|
|
@@ -16870,6 +17233,11 @@ function canonical(value, base) {
|
|
|
16870
17233
|
return null;
|
|
16871
17234
|
}
|
|
16872
17235
|
}
|
|
17236
|
+
function sameRouteMarkdownRepresentation(alternate, primary) {
|
|
17237
|
+
const target2 = new URL(alternate), source = new URL(primary);
|
|
17238
|
+
const directory2 = (path) => path.replace(/\.mdx?$/i, "").replace(/\/index\/?$/i, "").replace(/\/$/, "");
|
|
17239
|
+
return target2.origin === source.origin && target2.search === source.search && directory2(target2.pathname) === directory2(source.pathname) && /\.mdx?$/i.test(target2.pathname);
|
|
17240
|
+
}
|
|
16873
17241
|
function classifyMigrationResponse(document) {
|
|
16874
17242
|
if (document.status && document.status >= 400) return "unsupported";
|
|
16875
17243
|
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";
|
|
@@ -17120,7 +17488,7 @@ function resolveMigrationRecord(records, record) {
|
|
|
17120
17488
|
}
|
|
17121
17489
|
return record;
|
|
17122
17490
|
}
|
|
17123
|
-
function navigationConfig(checkpoint, records) {
|
|
17491
|
+
function navigationConfig(checkpoint, records, occurrencePages = /* @__PURE__ */ new Map()) {
|
|
17124
17492
|
const navigation = checkpoint.navigation;
|
|
17125
17493
|
const shortcuts = [];
|
|
17126
17494
|
const collectShortcuts = (nodes) => {
|
|
@@ -17145,7 +17513,7 @@ function navigationConfig(checkpoint, records) {
|
|
|
17145
17513
|
const project2 = (nodes) => nodes.flatMap((node) => {
|
|
17146
17514
|
const record = node.url ? records.get(canonical(node.url, node.url) ?? "") : void 0;
|
|
17147
17515
|
const target2 = resolveMigrationRecord(records, record);
|
|
17148
|
-
const page = target2?.page;
|
|
17516
|
+
const page = occurrencePages.get(node) ?? target2?.page;
|
|
17149
17517
|
const children = project2(node.children ?? []);
|
|
17150
17518
|
if (children.length) {
|
|
17151
17519
|
const contains = (entries) => entries.some((entry) => typeof entry === "string" ? entry === (page && projection.navigationId(page)) : contains(entry.pages));
|
|
@@ -17445,8 +17813,19 @@ async function runUrlMigration(options) {
|
|
|
17445
17813
|
if (!record.evidence) continue;
|
|
17446
17814
|
const final = canonical(record.evidence.finalUrl, sourceUrl);
|
|
17447
17815
|
if (!final) continue;
|
|
17448
|
-
if (record.outcome === "imported")
|
|
17449
|
-
|
|
17816
|
+
if (record.outcome === "imported") {
|
|
17817
|
+
enqueueArticleLinks(record.evidence.links, final, record.url);
|
|
17818
|
+
for (const reference of record.evidence.markdownRepresentations ?? []) {
|
|
17819
|
+
const alternate = canonical(reference, final);
|
|
17820
|
+
if (!alternate || !sameRouteMarkdownRepresentation(alternate, final)) continue;
|
|
17821
|
+
enqueue(alternate, final, "declared-markdown-representation");
|
|
17822
|
+
const sibling = records.get(alternate);
|
|
17823
|
+
if (sibling && sibling.representationOf !== record.url) {
|
|
17824
|
+
sibling.representationOf = record.url;
|
|
17825
|
+
changed.push(sibling);
|
|
17826
|
+
}
|
|
17827
|
+
}
|
|
17828
|
+
} else if (record.outcome === "excluded") {
|
|
17450
17829
|
if (classifyMigrationResponse({ finalUrl: new URL(final), contentType: record.evidence.contentType, body: "" }) === "index") {
|
|
17451
17830
|
for (const link of record.evidence.links) enqueue(link, final, record.url);
|
|
17452
17831
|
}
|
|
@@ -17529,6 +17908,7 @@ async function runUrlMigration(options) {
|
|
|
17529
17908
|
let claimedId;
|
|
17530
17909
|
let claimedFinal;
|
|
17531
17910
|
let markdownRepresentation;
|
|
17911
|
+
const markdownRepresentations = [];
|
|
17532
17912
|
let exactKey;
|
|
17533
17913
|
try {
|
|
17534
17914
|
delete record.reason;
|
|
@@ -17621,13 +18001,13 @@ async function runUrlMigration(options) {
|
|
|
17621
18001
|
$('link[rel="alternate"][type="text/markdown"][href]').each((_index, node) => {
|
|
17622
18002
|
const alternate = canonical($(node).attr("href"), final);
|
|
17623
18003
|
if (!alternate) return;
|
|
17624
|
-
|
|
17625
|
-
const directory2 = (path) => path.replace(/\.mdx?$/i, "").replace(/\/index\/?$/i, "").replace(/\/$/, "");
|
|
17626
|
-
if (target2.origin !== primary.origin || target2.search !== primary.search || directory2(target2.pathname) !== directory2(primary.pathname) || !/\.mdx?$/i.test(target2.pathname)) return;
|
|
18004
|
+
if (!sameRouteMarkdownRepresentation(alternate, final)) return;
|
|
17627
18005
|
enqueue(alternate, final, "declared-markdown-representation");
|
|
17628
18006
|
const sibling = records.get(alternate);
|
|
18007
|
+
if (!sibling) return;
|
|
17629
18008
|
sibling.representationOf = record.url;
|
|
17630
18009
|
markdownRepresentation ??= alternate;
|
|
18010
|
+
markdownRepresentations.push(alternate);
|
|
17631
18011
|
changed.push(sibling);
|
|
17632
18012
|
});
|
|
17633
18013
|
}
|
|
@@ -17640,7 +18020,8 @@ async function runUrlMigration(options) {
|
|
|
17640
18020
|
}
|
|
17641
18021
|
enqueueNavigation(observedNavigation, final);
|
|
17642
18022
|
}
|
|
17643
|
-
|
|
18023
|
+
const replacesRepresentation = imported >= maxPages && markdownRepresentations.some((url) => records.get(url)?.page);
|
|
18024
|
+
if (imported >= maxPages && !replacesRepresentation) {
|
|
17644
18025
|
record.outcome = "excluded";
|
|
17645
18026
|
record.reason = "A discovery endpoint resolved to an article after the selected page limit.";
|
|
17646
18027
|
return;
|
|
@@ -17659,14 +18040,17 @@ async function runUrlMigration(options) {
|
|
|
17659
18040
|
const locale = language.locale;
|
|
17660
18041
|
const navigationId = locale ? id.split("/").filter((segment) => segment.toLowerCase() !== locale.toLowerCase()).join("/") || "introduction" : id;
|
|
17661
18042
|
const identityId = locale ? `${locale}/${navigationId}` : id;
|
|
17662
|
-
|
|
18043
|
+
const owner = records.get(usedIds.get(identityId) ?? "");
|
|
18044
|
+
const sharesDeclaredRepresentation = owner && (owner.representationOf === record.url || record.representationOf === owner.url);
|
|
18045
|
+
if (owner && owner !== record && !sharesDeclaredRepresentation) {
|
|
17663
18046
|
record.outcome = "failed";
|
|
17664
18047
|
record.reason = `Destination collision for ${identityId}.`;
|
|
17665
18048
|
return;
|
|
17666
18049
|
}
|
|
17667
|
-
usedIds.set(identityId, record.url);
|
|
18050
|
+
if (!owner || owner === record || owner.representationOf === record.url) usedIds.set(identityId, record.url);
|
|
17668
18051
|
claimedId = identityId;
|
|
17669
18052
|
const evidence = evidenceOf(document);
|
|
18053
|
+
if (markdownRepresentations.length) evidence.markdownRepresentations = markdownRepresentations;
|
|
17670
18054
|
const page = convert(document, id);
|
|
17671
18055
|
if (!page) {
|
|
17672
18056
|
record.outcome = "failed";
|
|
@@ -17877,6 +18261,7 @@ ${difference}`;
|
|
|
17877
18261
|
if (!primary || primary === record) continue;
|
|
17878
18262
|
const winner = primary.outcome === "imported" ? primary : record.outcome === "imported" && primary.outcome === "failed" ? record : void 0;
|
|
17879
18263
|
if (!winner) continue;
|
|
18264
|
+
if (winner.page) usedIds.set(winner.page.id, winner.url);
|
|
17880
18265
|
const alternate = winner === primary ? record : primary;
|
|
17881
18266
|
if (alternate.outcome === "alias" && alternate.aliasOf === winner.url) continue;
|
|
17882
18267
|
if (alternate.outcome === "imported") {
|
|
@@ -17898,7 +18283,17 @@ ${difference}`;
|
|
|
17898
18283
|
settleArticleIdentities();
|
|
17899
18284
|
while (cursor < pending.length && !options.signal?.aborted && !budgetExhausted && cursor < (options.maxCaptures ?? Infinity)) {
|
|
17900
18285
|
if (imported >= maxPages) {
|
|
17901
|
-
const index = pending.findIndex((record, position) =>
|
|
18286
|
+
const index = pending.findIndex((record, position) => {
|
|
18287
|
+
if (position < cursor || record.outcome !== "pending") return false;
|
|
18288
|
+
const url = new URL(record.url);
|
|
18289
|
+
if (isDiscoveryIndex(url, source)) return true;
|
|
18290
|
+
if (/\.mdx?$/i.test(url.pathname)) return false;
|
|
18291
|
+
return [".md", ".mdx", "/index.md", "/index.mdx"].some((extension) => {
|
|
18292
|
+
const alternate = new URL(url);
|
|
18293
|
+
alternate.pathname = alternate.pathname.replace(/\/index$/i, "") + extension;
|
|
18294
|
+
return records.get(alternate.href)?.outcome === "imported";
|
|
18295
|
+
});
|
|
18296
|
+
});
|
|
17902
18297
|
if (index < 0) break;
|
|
17903
18298
|
pending.splice(cursor, 0, pending.splice(index, 1)[0]);
|
|
17904
18299
|
}
|
|
@@ -17922,19 +18317,60 @@ ${difference}`;
|
|
|
17922
18317
|
}
|
|
17923
18318
|
const navigationLabels = /* @__PURE__ */ new Map();
|
|
17924
18319
|
const navigationIssues = [];
|
|
18320
|
+
const navigationOccurrences = /* @__PURE__ */ new Map();
|
|
17925
18321
|
const labelPages = (nodes) => {
|
|
17926
18322
|
for (const node of nodes) {
|
|
17927
18323
|
const entry = node.url ? records.get(canonical(node.url, sourceUrl) ?? "") : void 0;
|
|
17928
18324
|
const target2 = resolveMigrationRecord(records, entry);
|
|
17929
|
-
if (target2?.page && node.label && !node.children?.length && !entry
|
|
17930
|
-
const
|
|
17931
|
-
|
|
17932
|
-
|
|
18325
|
+
if (entry && target2?.page && node.label && !node.children?.length && !entry.aliasAnchor) {
|
|
18326
|
+
const occurrences = navigationOccurrences.get(target2) ?? [];
|
|
18327
|
+
occurrences.push({ node, entry });
|
|
18328
|
+
navigationOccurrences.set(target2, occurrences);
|
|
17933
18329
|
}
|
|
17934
18330
|
labelPages(node.children ?? []);
|
|
17935
18331
|
}
|
|
17936
18332
|
};
|
|
17937
18333
|
labelPages(checkpoint.navigation);
|
|
18334
|
+
const occurrencePages = /* @__PURE__ */ new Map();
|
|
18335
|
+
const navigationAliases = /* @__PURE__ */ new Map();
|
|
18336
|
+
const occupiedPageIds = new Set(checkpoint.records.flatMap((record) => record.page ? [projection.pageId(record.page)] : []));
|
|
18337
|
+
const navigationRedirects = [];
|
|
18338
|
+
for (const [target2, occurrences] of navigationOccurrences) {
|
|
18339
|
+
const final = target2.evidence && canonical(target2.evidence.finalUrl, sourceUrl);
|
|
18340
|
+
const primary = occurrences.find(({ entry }) => entry.url === final) ?? occurrences.find(({ entry }) => entry === target2) ?? occurrences[0];
|
|
18341
|
+
navigationLabels.set(target2.url, primary.node.label);
|
|
18342
|
+
for (const { node, entry } of occurrences) {
|
|
18343
|
+
if (node.label === primary.node.label) continue;
|
|
18344
|
+
const existing = navigationAliases.get(entry.url);
|
|
18345
|
+
if (existing?.page.navTitle === node.label && existing.target === target2) {
|
|
18346
|
+
occurrencePages.set(node, existing.page);
|
|
18347
|
+
continue;
|
|
18348
|
+
}
|
|
18349
|
+
const sourceRoute = new URL(entry.url);
|
|
18350
|
+
const id = inScope(sourceRoute, source, scopePath) ? idForUrl(sourceRoute, scopePath) : null;
|
|
18351
|
+
const locale = projection.canonicalLocale(target2.page);
|
|
18352
|
+
let navigationId = id && (locale ? id.split("/").filter((segment) => segment.toLowerCase() !== locale.toLowerCase()).join("/") || "introduction" : id);
|
|
18353
|
+
const legacyPrefix = locale && `${locale.toLowerCase()}-`;
|
|
18354
|
+
if (navigationId && legacyPrefix && projection.navigationId(target2.page) !== target2.page.navigationId && navigationId.toLowerCase().startsWith(legacyPrefix)) navigationId = navigationId.slice(legacyPrefix.length);
|
|
18355
|
+
const page = navigationId ? {
|
|
18356
|
+
...target2.page,
|
|
18357
|
+
id: locale ? `${locale}/${navigationId}` : navigationId,
|
|
18358
|
+
navigationId,
|
|
18359
|
+
...locale ? { locale } : {},
|
|
18360
|
+
navTitle: node.label,
|
|
18361
|
+
source: entry.url,
|
|
18362
|
+
noindex: true
|
|
18363
|
+
} : void 0;
|
|
18364
|
+
if (!page || existing || occupiedPageIds.has(projection.pageId(page))) {
|
|
18365
|
+
navigationIssues.push({ code: "unsupported-component", source: target2.url, message: `This page has multiple source navigation labels (${primary.node.label}, ${node.label}); their source routes cannot retain distinct sidebar titles safely.` });
|
|
18366
|
+
continue;
|
|
18367
|
+
}
|
|
18368
|
+
occupiedPageIds.add(projection.pageId(page));
|
|
18369
|
+
navigationAliases.set(entry.url, { page, target: target2 });
|
|
18370
|
+
occurrencePages.set(node, page);
|
|
18371
|
+
navigationRedirects.push({ source: projection.route(page), destination: projection.route(target2.page), permanent: true });
|
|
18372
|
+
}
|
|
18373
|
+
}
|
|
17938
18374
|
const pages = checkpoint.records.flatMap((record) => record.page ? [{ ...record.page, id: projection.pageId(record.page), navigationId: projection.navigationId(record.page), ...projection.canonicalLocale(record.page) ? { locale: projection.canonicalLocale(record.page) } : {}, ...navigationLabels.has(record.url) ? { navTitle: navigationLabels.get(record.url) } : {}, body: rewriteMarkdownDestinations(record.page.body, (value) => {
|
|
17939
18375
|
let url;
|
|
17940
18376
|
try {
|
|
@@ -17955,6 +18391,10 @@ ${difference}`;
|
|
|
17955
18391
|
const hasBrokenSourceAnchor = Boolean(url.hash && destination?.outcome === "imported" && destination.evidence && !destination.evidence.anchors.includes(anchor));
|
|
17956
18392
|
return `${route}${hasBrokenSourceAnchor ? "" : effectiveHash}`;
|
|
17957
18393
|
}) }] : []);
|
|
18394
|
+
const projectedPages = new Map(pages.map((page) => [page.id, page]));
|
|
18395
|
+
for (const { page, target: target2 } of navigationAliases.values()) {
|
|
18396
|
+
pages.push({ ...page, id: projection.pageId(page), body: projectedPages.get(projection.pageId(target2.page)).body });
|
|
18397
|
+
}
|
|
17958
18398
|
const validation = validateUrlMigration(checkpoint, Boolean(options.signal?.aborted));
|
|
17959
18399
|
validation.issues.push(...navigationIssues);
|
|
17960
18400
|
if (navigationIssues.length && validation.status === "passed") validation.status = "partial";
|
|
@@ -17975,12 +18415,12 @@ ${difference}`;
|
|
|
17975
18415
|
platform: options.platform ?? "generic",
|
|
17976
18416
|
pages,
|
|
17977
18417
|
assets: [...assets.values()],
|
|
17978
|
-
docsConfig: navigationConfig(checkpoint, records) ?? buildNavigationFromPages(pages),
|
|
18418
|
+
docsConfig: navigationConfig(checkpoint, records, occurrencePages) ?? buildNavigationFromPages(pages),
|
|
17979
18419
|
warnings: [...validation.issues, ...validation.warnings ?? []].map((issue) => ({ code: issue.code === "missing-page" ? "missing-page" : "unsupported-config", message: issue.message, source: issue.source })),
|
|
17980
18420
|
urlMigrationValidation: validation,
|
|
17981
18421
|
stats: { discovered: records.size, imported: pages.length, skipped: records.size - pages.length }
|
|
17982
18422
|
};
|
|
17983
|
-
if (projection.redirects.length) bundle.docsConfig.redirects = projection.redirects;
|
|
18423
|
+
if (projection.redirects.length || navigationRedirects.length) bundle.docsConfig.redirects = [...projection.redirects, ...navigationRedirects];
|
|
17984
18424
|
if (projection.locales.length) {
|
|
17985
18425
|
const locales = [.../* @__PURE__ */ new Set([projection.defaultLocale, ...projection.locales])];
|
|
17986
18426
|
bundle.docsConfig.i18n = { ...bundle.docsConfig.i18n, defaultLocale: projection.defaultLocale, locales: locales.map((code) => ({ code, label: code === "en" ? "English" : code })) };
|
|
@@ -17998,9 +18438,11 @@ function rewriteMarkdownDestinations(body, rewrite) {
|
|
|
17998
18438
|
const original = body.slice(start, end);
|
|
17999
18439
|
const replacement = rewrite(node.url);
|
|
18000
18440
|
if (replacement === node.url) return null;
|
|
18001
|
-
const
|
|
18002
|
-
|
|
18003
|
-
|
|
18441
|
+
const destinations = postprocess(parse2().document().write(preprocess()(original, void 0, true))).filter(([event, token]) => event === "enter" && ["resourceDestinationString", "definitionDestinationString", "autolinkProtocol", "autolinkEmail"].includes(token.type));
|
|
18442
|
+
const destination = destinations.at(-1)?.[1];
|
|
18443
|
+
if (!destination) return null;
|
|
18444
|
+
const escaped = replacement.replace(/[\\&()<>]/g, "\\$&").replace(/[\t\n\r ]/g, (character) => encodeURIComponent(character));
|
|
18445
|
+
return { start: start + destination.start.offset, end: start + destination.end.offset, replacement: escaped };
|
|
18004
18446
|
}).filter((edit) => edit !== null).sort((a, b) => b.start - a.start);
|
|
18005
18447
|
for (const node of markdownNodes(body)) for (const attribute of node.attributes ?? []) {
|
|
18006
18448
|
if (!attribute.name || !["src", "poster", "href", "srcSet", "srcset", "img", "primaryHref", "secondaryHref"].includes(attribute.name) || !attribute.position) continue;
|
|
@@ -18164,6 +18606,12 @@ function slug(value) {
|
|
|
18164
18606
|
function operationTarget(specId, operation) {
|
|
18165
18607
|
return `/api/${specId}/${thallyOperationSlugSegments(operation.path, operation.method).join("/")}`;
|
|
18166
18608
|
}
|
|
18609
|
+
function bindApiTab(tabs, reference, api) {
|
|
18610
|
+
const tab = reference.tabLabel ? tabs.find((candidate) => candidate.tab === reference.tabLabel) : tabs.find((candidate) => candidate.tab.toLowerCase().includes("api"));
|
|
18611
|
+
if (tab) tab.api = api;
|
|
18612
|
+
else insertApiTab(tabs, { tab: reference.tabLabel ?? "API Reference", ...reference.icon ? { icon: reference.icon } : {}, ...reference.hidden ? { hidden: true } : {}, api }, reference.parentTab);
|
|
18613
|
+
return tab?.tab ?? reference.tabLabel ?? "API Reference";
|
|
18614
|
+
}
|
|
18167
18615
|
async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
18168
18616
|
if (!bundle.remoteApiSpecs?.length) return bundle;
|
|
18169
18617
|
const assets = [...bundle.assets];
|
|
@@ -18172,7 +18620,8 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
18172
18620
|
const warnings = [...bundle.warnings];
|
|
18173
18621
|
const pages = bundle.pages.map((page) => ({ ...page }));
|
|
18174
18622
|
const authoredLinks = /* @__PURE__ */ new Set();
|
|
18175
|
-
const
|
|
18623
|
+
const ledger = createEndpointPageLedger(pages);
|
|
18624
|
+
const pagesBefore = pages.length;
|
|
18176
18625
|
const endpointUrls = /* @__PURE__ */ new Map();
|
|
18177
18626
|
for (const page of bundle.pages) {
|
|
18178
18627
|
for (const match of page.body.matchAll(/\/[a-z0-9_/-]+/gi)) {
|
|
@@ -18183,6 +18632,10 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
18183
18632
|
}
|
|
18184
18633
|
}
|
|
18185
18634
|
const bound = [];
|
|
18635
|
+
const apiTabs = bundle.docsConfig.tabs.map((tab) => ({ ...tab }));
|
|
18636
|
+
for (const mount of bundle.localApiMounts ?? []) {
|
|
18637
|
+
if (mount.endpointOperations) bindApiTab(apiTabs, { tabLabel: mount.tab }, { source: `openapi/${mount.filename}` });
|
|
18638
|
+
}
|
|
18186
18639
|
for (const reference of bundle.remoteApiSpecs) {
|
|
18187
18640
|
for (let index = warnings.length - 1; index >= 0; index--) {
|
|
18188
18641
|
if (warnings[index].source === reference.url && warnings[index].message.includes("requires a network download")) warnings.splice(index, 1);
|
|
@@ -18202,11 +18655,29 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
18202
18655
|
const ref = page.openapi ? splitOpenApiRef(page.openapi) : null;
|
|
18203
18656
|
if (ref?.specRef === reference.url) page.openapi = withSpecRef(ref, `openapi/${filename}`);
|
|
18204
18657
|
}
|
|
18205
|
-
|
|
18658
|
+
bindApiTab(apiTabs, reference, { source: `openapi/${filename}` });
|
|
18659
|
+
const endpoint = reference.groups && reference.endpointPages ? addEndpointPages({
|
|
18660
|
+
tabs,
|
|
18661
|
+
pages,
|
|
18662
|
+
ledger,
|
|
18663
|
+
spec: {
|
|
18664
|
+
assetPath: `openapi/${filename}`,
|
|
18665
|
+
source: reference.url,
|
|
18666
|
+
content: body,
|
|
18667
|
+
groups: reference.groups,
|
|
18668
|
+
target: reference.endpointPages,
|
|
18669
|
+
tabLabel: reference.tabLabel,
|
|
18670
|
+
parentTab: reference.parentTab,
|
|
18671
|
+
icon: reference.icon,
|
|
18672
|
+
hidden: reference.hidden
|
|
18673
|
+
}
|
|
18674
|
+
}) : null;
|
|
18675
|
+
if (endpoint) {
|
|
18676
|
+
bound.push({ reference, filename, content: body, operations, tabName: reference.tabLabel ?? "API Reference", endpointOperations: endpoint.operations });
|
|
18677
|
+
continue;
|
|
18678
|
+
}
|
|
18206
18679
|
const api = { source: `openapi/${filename}`, ...reference.navigation === false ? { navigation: false } : {}, ...reference.groups ? { groups: reference.groups } : {} };
|
|
18207
|
-
|
|
18208
|
-
else insertApiTab(tabs, { tab: reference.tabLabel ?? "API Reference", ...reference.icon ? { icon: reference.icon } : {}, ...reference.hidden ? { hidden: true } : {}, api }, reference.parentTab);
|
|
18209
|
-
bound.push({ reference, filename, content: body, operations, tabName: tab?.tab ?? reference.tabLabel ?? "API Reference" });
|
|
18680
|
+
bound.push({ reference, filename, content: body, operations, tabName: bindApiTab(tabs, reference, api) });
|
|
18210
18681
|
} catch (error) {
|
|
18211
18682
|
warnings.push({
|
|
18212
18683
|
code: "fetch-failed",
|
|
@@ -18215,19 +18686,22 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
18215
18686
|
});
|
|
18216
18687
|
}
|
|
18217
18688
|
}
|
|
18689
|
+
const pageMounts = bound.flatMap(({ reference, endpointOperations }) => endpointOperations && reference.endpointPages ? [reference.endpointPages.directory] : []);
|
|
18218
18690
|
const directories = [
|
|
18219
18691
|
...(bundle.localApiMounts ?? []).map(({ directory: directory2 }) => directory2),
|
|
18220
|
-
...bundle.remoteApiSpecs.flatMap((reference) => (reference.directories ?? []).map(({ directory: directory2 }) => directory2))
|
|
18692
|
+
...bundle.remoteApiSpecs.flatMap((reference) => (reference.directories ?? []).map(({ directory: directory2 }) => directory2)),
|
|
18693
|
+
...pageMounts
|
|
18221
18694
|
];
|
|
18222
18695
|
const endpointRedirects = linkApiMounts(
|
|
18223
18696
|
[
|
|
18224
|
-
...(bundle.localApiMounts ?? []).map(({ filename, directory: directory2, tab }) => ({
|
|
18697
|
+
...(bundle.localApiMounts ?? []).map(({ filename, directory: directory2, tab, endpointOperations }) => ({
|
|
18225
18698
|
filename,
|
|
18226
18699
|
content: Buffer.from(assets.find((asset) => asset.path === `openapi/${filename}`)?.content ?? []),
|
|
18227
18700
|
prefix: directory2,
|
|
18701
|
+
...endpointOperations ? { endpointPages: true, operations: endpointOperations } : {},
|
|
18228
18702
|
...tab ? { tab } : {}
|
|
18229
18703
|
})),
|
|
18230
|
-
...bound.flatMap(({ reference, filename, content, tabName }) => (reference.directories ?? []).map(({ directory: directory2, operations: listed }) => ({ filename, content, prefix: directory2, tab: tabName, ...listed ? { operations: listed } : {} })))
|
|
18704
|
+
...bound.flatMap(({ reference, filename, content, tabName, endpointOperations }) => endpointOperations && reference.endpointPages ? [{ filename, content, prefix: reference.endpointPages.directory, tab: tabName, endpointPages: true, operations: endpointOperations }] : (reference.directories ?? []).map(({ directory: directory2, operations: listed }) => ({ filename, content, prefix: directory2, tab: tabName, ...listed ? { operations: listed } : {} })))
|
|
18231
18705
|
],
|
|
18232
18706
|
{ ...bundle.docsConfig, tabs, redirects },
|
|
18233
18707
|
pages,
|
|
@@ -18238,6 +18712,18 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
18238
18712
|
redirects.push(redirect);
|
|
18239
18713
|
endpointUrls.set(literalRoute(redirect.source) ?? redirect.source, redirect.destination);
|
|
18240
18714
|
}
|
|
18715
|
+
reportEndpointPages(ledger, warnings);
|
|
18716
|
+
qualifyDisplacedBareRefs({
|
|
18717
|
+
pages,
|
|
18718
|
+
before: specLookupOrder(apiTabs, bundle.docsConfig.navigation?.versions),
|
|
18719
|
+
after: specLookupOrder(tabs, bundle.docsConfig.navigation?.versions),
|
|
18720
|
+
content: (source) => {
|
|
18721
|
+
const asset = assets.find((entry) => entry.path === source);
|
|
18722
|
+
return asset ? Buffer.from(asset.content) : void 0;
|
|
18723
|
+
},
|
|
18724
|
+
qualifier: (source) => source
|
|
18725
|
+
});
|
|
18726
|
+
const served = servedRoutes(pages);
|
|
18241
18727
|
const existingSources = new Set(redirects.map((redirect) => literalRoute(redirect.source) ?? redirect.source.toLowerCase()));
|
|
18242
18728
|
const mounts = directories.map(mountPrefix).filter(Boolean);
|
|
18243
18729
|
const underMount = (source) => mounts.some((prefix) => source.toLowerCase() === `/${prefix}` || source.toLowerCase().startsWith(`/${prefix}/`));
|
|
@@ -18262,12 +18748,19 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
18262
18748
|
const endpoint = endpointUrls.get(literalRoute(redirect.destination) ?? "");
|
|
18263
18749
|
return endpoint ? { ...redirect, destination: endpoint } : redirect;
|
|
18264
18750
|
});
|
|
18751
|
+
const boundConfig = { ...bundle.docsConfig, tabs, ...direct.length > 0 ? { redirects: direct } : {} };
|
|
18752
|
+
const newPages = pages.slice(pagesBefore);
|
|
18753
|
+
const withDirectories = bundle.platform === "mintlify" && newPages.length > 0 ? addMintlifyDirectoryRedirects(boundConfig, newPages) : boundConfig;
|
|
18754
|
+
const linkRedirects = new Set(pages.flatMap((page) => page.externalUrl ? pageEntryRoutes(page).map((source) => `${source} ${page.externalUrl}`) : []));
|
|
18755
|
+
const isLinkRedirect = (redirect) => linkRedirects.has(`${redirect.source} ${redirect.destination}`);
|
|
18756
|
+
const links = (withDirectories.redirects ?? []).filter(isLinkRedirect);
|
|
18757
|
+
const unchecked = links.length > 0 ? { ...withDirectories, redirects: withDirectories.redirects.filter((redirect) => !isLinkRedirect(redirect)) } : withDirectories;
|
|
18758
|
+
const checked = dropConflictingRedirects(dropUnroutableRedirects(unchecked, warnings), pages, warnings);
|
|
18265
18759
|
return {
|
|
18266
18760
|
...bundle,
|
|
18267
18761
|
pages,
|
|
18268
18762
|
assets,
|
|
18269
|
-
|
|
18270
|
-
docsConfig: dropConflictingRedirects(dropUnroutableRedirects({ ...bundle.docsConfig, tabs, ...direct.length > 0 ? { redirects: direct } : {} }, warnings), pages, warnings),
|
|
18763
|
+
docsConfig: links.length > 0 ? { ...checked, redirects: [...checked.redirects ?? [], ...links] } : checked,
|
|
18271
18764
|
warnings
|
|
18272
18765
|
};
|
|
18273
18766
|
}
|