@thallylabs/migrate 0.2.1 → 0.2.3
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 +14 -4
- package/dist/index.d.ts +79 -3
- package/dist/index.js +734 -140
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { spawn } from "child_process";
|
|
3
3
|
import {
|
|
4
4
|
existsSync as existsSync3,
|
|
5
|
-
lstatSync as
|
|
5
|
+
lstatSync as lstatSync3,
|
|
6
6
|
readFileSync as readFileSync3,
|
|
7
7
|
readdirSync
|
|
8
8
|
} from "fs";
|
|
@@ -16,16 +16,29 @@ import { parse as parseYaml } from "yaml";
|
|
|
16
16
|
|
|
17
17
|
// src/path.ts
|
|
18
18
|
import { isAbsolute, relative, resolve, sep } from "path";
|
|
19
|
-
var SAFE_SEGMENT = /[^a-z0-9._-]+/
|
|
20
|
-
function
|
|
19
|
+
var SAFE_SEGMENT = /[^a-z0-9._-]+/gi;
|
|
20
|
+
function trimTrailingSlashes(value) {
|
|
21
|
+
let end = value.length;
|
|
22
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) end--;
|
|
23
|
+
return value.slice(0, end);
|
|
24
|
+
}
|
|
25
|
+
function trimEdgeSlashes(value) {
|
|
26
|
+
let start = 0;
|
|
27
|
+
let end = value.length;
|
|
28
|
+
while (start < end && value.charCodeAt(start) === 47) start++;
|
|
29
|
+
while (end > start && value.charCodeAt(end - 1) === 47) end--;
|
|
30
|
+
return value.slice(start, end);
|
|
31
|
+
}
|
|
32
|
+
function slugifySegment(value, preserveCase = false) {
|
|
21
33
|
let decoded = value;
|
|
22
34
|
try {
|
|
23
35
|
decoded = decodeURIComponent(value);
|
|
24
36
|
} catch {
|
|
25
37
|
}
|
|
26
|
-
|
|
38
|
+
const normalized = preserveCase ? decoded : decoded.toLowerCase();
|
|
39
|
+
return normalized.replace(/\.(?:html?|mdx?)$/i, "").replace(SAFE_SEGMENT, "-").replace(/(^-|-$)/g, "");
|
|
27
40
|
}
|
|
28
|
-
function pageIdFromReference(value) {
|
|
41
|
+
function pageIdFromReference(value, preserveCase = false) {
|
|
29
42
|
const withoutQuery = value.split(/[?#]/, 1)[0].replace(/\\/g, "/").replace(/^\/+/, "");
|
|
30
43
|
if (!withoutQuery || withoutQuery.includes("\0")) return null;
|
|
31
44
|
const rawSegments = withoutQuery.split("/").filter(Boolean);
|
|
@@ -35,7 +48,7 @@ function pageIdFromReference(value) {
|
|
|
35
48
|
if (!/^(?:index|readme)$/i.test(last)) {
|
|
36
49
|
baseSegments[baseSegments.length - 1] = last;
|
|
37
50
|
}
|
|
38
|
-
const segments = baseSegments.map(slugifySegment).filter(Boolean);
|
|
51
|
+
const segments = baseSegments.map((segment) => slugifySegment(segment, preserveCase)).filter(Boolean);
|
|
39
52
|
return segments.join("/") || "introduction";
|
|
40
53
|
}
|
|
41
54
|
function resolveWithin(root, candidate) {
|
|
@@ -585,7 +598,7 @@ function normalizeMdx(body) {
|
|
|
585
598
|
return normalizeDocusaurusAdmonitions(body).replace(/^import\s+(?:Tabs|TabItem|Link|DocCardList|TOCInline)\s+from\s+['"]@(?:theme|docusaurus)\/[^'"]+['"]\s*;?\s*$/gm, "").replace(/<TabItem\b([^>]*)>/g, (_match, attributes) => {
|
|
586
599
|
const title = attributes.match(/\blabel=(?:"([^"]*)"|'([^']*)')/)?.slice(1).find(Boolean) ?? attributes.match(/\bvalue=(?:"([^"]*)"|'([^']*)')/)?.slice(1).find(Boolean) ?? "Tab";
|
|
587
600
|
return `<Tab title="${title.replace(/"/g, """)}">`;
|
|
588
|
-
}).replace(/<\/TabItem>/g, "</Tab>").replace(/<Link\b([^>]*)\bto=(?:"([^"]*)"|'([^']*)')([^>]*)>/g, (_match, before, doubleQuoted, singleQuoted, after) => `<a${before}href="${doubleQuoted ?? singleQuoted}"${after}>`).replace(/<\/Link>/g, "</a>").replace(/<(?:DocCardList|TOCInline)\b[^>]*\/>/g, "").replace(/<!--([\s\S]*?)-->/g, (_match, content) => `{/*${content}*/}`).replace(/<Danger(\s[^>]*)?>/g, "<Error$1>").replace(/<\/Danger>/g, "</Error>").replace(/<Check(\s[^>]*)?>/g, "<Note$1>").replace(/<\/Check>/g, "</Note>").replace(/<Tree\.Folder/g, "<Folder").replace(/<\/Tree\.Folder>/g, "</Folder>").replace(/<Tree\.File/g, "<File").replace(/<\/Tree\.File>/g, "</File>");
|
|
601
|
+
}).replace(/<\/TabItem>/g, "</Tab>").replace(/<Link\b([^>]*)\bto=(?:"([^"]*)"|'([^']*)')([^>]*)>/g, (_match, before, doubleQuoted, singleQuoted, after) => `<a${before}href="${doubleQuoted ?? singleQuoted}"${after}>`).replace(/<\/Link>/g, "</a>").replace(/<(?:DocCardList|TOCInline)\b[^>]*\/>/g, "").replace(/<!--([\s\S]*?)-->/g, (_match, content) => `{/*${content}*/}`).replace(/<Danger(\s[^>]*)?>/g, "<Error$1>").replace(/<\/Danger>/g, "</Error>").replace(/<Warn(\s[^>]*)?>/g, "<Warning$1>").replace(/<\/Warn>/g, "</Warning>").replace(/<Check(\s[^>]*)?>/g, "<Note$1>").replace(/<\/Check>/g, "</Note>").replace(/<Tree\.Folder/g, "<Folder").replace(/<\/Tree\.Folder>/g, "</Folder>").replace(/<Tree\.File/g, "<File").replace(/<\/Tree\.File>/g, "</File>");
|
|
589
602
|
}
|
|
590
603
|
function parseMarkdownPage(input) {
|
|
591
604
|
const parsed = parseFrontmatter(input.raw);
|
|
@@ -598,14 +611,23 @@ function parseMarkdownPage(input) {
|
|
|
598
611
|
const body = normalizeMdx(parsed.content).trim();
|
|
599
612
|
const keywords = Array.isArray(parsed.data.keywords) ? parsed.data.keywords.filter((value) => typeof value === "string") : [];
|
|
600
613
|
const title = typeof parsed.data.title === "string" && parsed.data.title.trim() ? parsed.data.title.trim() : titleFromId(identity.navigationId);
|
|
614
|
+
const navTitle = typeof parsed.data.sidebarTitle === "string" && parsed.data.sidebarTitle.trim() ? parsed.data.sidebarTitle.trim() : typeof parsed.data.navTitle === "string" && parsed.data.navTitle.trim() ? parsed.data.navTitle.trim() : void 0;
|
|
615
|
+
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;
|
|
616
|
+
const sourceMode = typeof parsed.data.mode === "string" ? parsed.data.mode : void 0;
|
|
617
|
+
const mode = sourceMode === "frame" ? "wide" : ["default", "wide", "custom", "center", "home"].includes(sourceMode ?? "") ? sourceMode : void 0;
|
|
601
618
|
const description = typeof parsed.data.description === "string" && parsed.data.description.trim() ? parsed.data.description.trim() : firstParagraph(body);
|
|
602
619
|
return {
|
|
603
620
|
id: identity.id,
|
|
604
621
|
navigationId: identity.navigationId,
|
|
605
622
|
locale: identity.locale,
|
|
606
623
|
title,
|
|
624
|
+
navTitle,
|
|
607
625
|
description,
|
|
626
|
+
badge,
|
|
608
627
|
keywords,
|
|
628
|
+
mode,
|
|
629
|
+
hidden: parsed.data.hidden === true ? true : void 0,
|
|
630
|
+
noindex: parsed.data.noindex === true || parsed.data.noindex === "true" ? true : void 0,
|
|
609
631
|
openapi: typeof parsed.data.openapi === "string" ? parsed.data.openapi.trim() : void 0,
|
|
610
632
|
body,
|
|
611
633
|
source: input.source
|
|
@@ -613,8 +635,24 @@ function parseMarkdownPage(input) {
|
|
|
613
635
|
}
|
|
614
636
|
|
|
615
637
|
// src/navigation.ts
|
|
616
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
638
|
+
import { existsSync as existsSync2, lstatSync as lstatSync2, readFileSync as readFileSync2, realpathSync } from "fs";
|
|
617
639
|
import { dirname, extname as extname2, relative as relative2 } from "path";
|
|
640
|
+
var MAX_MINTLIFY_CONFIG_BYTES = 2e6;
|
|
641
|
+
function addMintlifyDirectoryRedirects(config, pages) {
|
|
642
|
+
const pageIds = new Set(pages.filter((page) => !page.locale).map((page) => page.navigationId));
|
|
643
|
+
const redirects = [...config.redirects ?? []];
|
|
644
|
+
const redirectSources = new Set(redirects.map((redirect) => redirect.source.replace(/\/$/, "") || "/"));
|
|
645
|
+
for (const page of pages) {
|
|
646
|
+
if (page.locale || !/(?:^|\/)(?:overview|introduction)$/.test(page.navigationId)) continue;
|
|
647
|
+
const parent = page.navigationId.replace(/\/(?:overview|introduction)$/, "");
|
|
648
|
+
if (!parent || pageIds.has(parent)) continue;
|
|
649
|
+
const source = `/${parent}`;
|
|
650
|
+
if (redirectSources.has(source)) continue;
|
|
651
|
+
redirects.push({ source, destination: `/${page.navigationId}`, permanent: false });
|
|
652
|
+
redirectSources.add(source);
|
|
653
|
+
}
|
|
654
|
+
return redirects.length > 0 ? { ...config, redirects } : config;
|
|
655
|
+
}
|
|
618
656
|
var LANGUAGE_LABELS = {
|
|
619
657
|
ar: "Arabic",
|
|
620
658
|
de: "German",
|
|
@@ -636,6 +674,15 @@ var LANGUAGE_LABELS = {
|
|
|
636
674
|
function objectValue2(value) {
|
|
637
675
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
638
676
|
}
|
|
677
|
+
function projectedHref(value) {
|
|
678
|
+
if (typeof value !== "string") return void 0;
|
|
679
|
+
const href = value.trim();
|
|
680
|
+
if (!href || /[\u0000-\u001f\u007f]/.test(href)) return void 0;
|
|
681
|
+
if (/^(?:javascript|data|vbscript|file):/i.test(href)) return void 0;
|
|
682
|
+
const scheme = href.match(/^([a-z][a-z0-9+.-]*):/i)?.[1].toLowerCase();
|
|
683
|
+
if (scheme && !["http", "https", "mailto", "tel"].includes(scheme)) return void 0;
|
|
684
|
+
return href;
|
|
685
|
+
}
|
|
639
686
|
function labelFor(value, fallback) {
|
|
640
687
|
for (const key of ["tab", "group", "anchor", "product", "dropdown", "version", "menu", "label", "name", "title"]) {
|
|
641
688
|
if (typeof value[key] === "string" && value[key]) return String(value[key]);
|
|
@@ -649,11 +696,27 @@ function jsonPointer(root, pointer) {
|
|
|
649
696
|
if (!pointer || pointer === "#") return root;
|
|
650
697
|
const tokens = pointer.replace(/^#\/?/, "").split("/").filter(Boolean);
|
|
651
698
|
return tokens.reduce((current, token) => {
|
|
699
|
+
if (Array.isArray(current)) {
|
|
700
|
+
const index = Number(token);
|
|
701
|
+
return Number.isSafeInteger(index) && index >= 0 ? current[index] : void 0;
|
|
702
|
+
}
|
|
652
703
|
const object = objectValue2(current);
|
|
653
704
|
if (!object) return void 0;
|
|
654
705
|
return object[token.replace(/~1/g, "/").replace(/~0/g, "~")];
|
|
655
706
|
}, root);
|
|
656
707
|
}
|
|
708
|
+
function readMintlifyJson(path, repositoryRoot) {
|
|
709
|
+
if (!existsSync2(path) || !lstatSync2(path).isFile()) {
|
|
710
|
+
throw new Error(`Mintlify config reference is not a regular file: ${relative2(repositoryRoot, path)}`);
|
|
711
|
+
}
|
|
712
|
+
const realPath = realpathSync(path);
|
|
713
|
+
const realRoot = realpathSync(repositoryRoot);
|
|
714
|
+
resolveWithin(realRoot, relative2(realRoot, realPath));
|
|
715
|
+
if (lstatSync2(realPath).size > MAX_MINTLIFY_CONFIG_BYTES) {
|
|
716
|
+
throw new Error(`Mintlify config reference exceeded ${MAX_MINTLIFY_CONFIG_BYTES / 1e6} MB: ${relative2(repositoryRoot, path)}`);
|
|
717
|
+
}
|
|
718
|
+
return JSON.parse(readFileSync2(realPath, "utf8"));
|
|
719
|
+
}
|
|
657
720
|
function resolveJsonReferences(value, currentFile, repositoryRoot, stack) {
|
|
658
721
|
if (Array.isArray(value)) {
|
|
659
722
|
return value.map((entry) => resolveJsonReferences(entry, currentFile, repositoryRoot, stack));
|
|
@@ -668,11 +731,17 @@ function resolveJsonReferences(value, currentFile, repositoryRoot, stack) {
|
|
|
668
731
|
const stackKey = `${referencedFile}#${pointer}`;
|
|
669
732
|
if (stack.has(stackKey)) throw new Error(`Circular Mintlify $ref: ${object.$ref}`);
|
|
670
733
|
stack.add(stackKey);
|
|
671
|
-
const referencedRoot =
|
|
734
|
+
const referencedRoot = readMintlifyJson(referencedFile, repositoryRoot);
|
|
672
735
|
const referenced = jsonPointer(referencedRoot, pointer ? `#${pointer}` : "");
|
|
673
736
|
const resolved = resolveJsonReferences(referenced, referencedFile, repositoryRoot, stack);
|
|
674
737
|
stack.delete(stackKey);
|
|
675
|
-
|
|
738
|
+
const siblings = Object.fromEntries(
|
|
739
|
+
Object.entries(object).filter(([key]) => key !== "$ref").map(([key, entry]) => [
|
|
740
|
+
key,
|
|
741
|
+
resolveJsonReferences(entry, currentFile, repositoryRoot, stack)
|
|
742
|
+
])
|
|
743
|
+
);
|
|
744
|
+
return objectValue2(resolved) ? { ...resolved, ...siblings } : resolved;
|
|
676
745
|
}
|
|
677
746
|
return Object.fromEntries(
|
|
678
747
|
Object.entries(object).map(([key, entry]) => [
|
|
@@ -684,18 +753,39 @@ function resolveJsonReferences(value, currentFile, repositoryRoot, stack) {
|
|
|
684
753
|
function readMintlifyConfig(repositoryRoot) {
|
|
685
754
|
const configPath = ["docs.json", "mint.json"].map((filename) => resolveWithin(repositoryRoot, filename)).find(existsSync2);
|
|
686
755
|
if (!configPath) return null;
|
|
687
|
-
const raw =
|
|
756
|
+
const raw = readMintlifyJson(configPath, repositoryRoot);
|
|
688
757
|
return resolveJsonReferences(raw, configPath, repositoryRoot, /* @__PURE__ */ new Set());
|
|
689
758
|
}
|
|
690
|
-
function normalizePageRef(value) {
|
|
759
|
+
function normalizePageRef(value, pathPrefix = "") {
|
|
691
760
|
if (/^(?:https?:)?\/\//i.test(value) || value.startsWith("#")) return null;
|
|
692
|
-
|
|
693
|
-
|
|
761
|
+
let ref = localReference(value).split("?", 1)[0].replace(/^\/+/, "");
|
|
762
|
+
const prefix = trimEdgeSlashes(pathPrefix);
|
|
763
|
+
if (prefix && (ref === prefix || ref.startsWith(`${prefix}/`))) {
|
|
764
|
+
ref = ref === prefix ? "introduction" : ref.slice(prefix.length + 1);
|
|
765
|
+
}
|
|
766
|
+
ref = ref.replace(/\.(?:mdx?|rst|txt)$/i, "");
|
|
767
|
+
return pageIdFromReference(ref, true);
|
|
768
|
+
}
|
|
769
|
+
function warnOnce(context, key, message) {
|
|
770
|
+
if (context.warningKeys.has(key)) return;
|
|
771
|
+
context.warningKeys.add(key);
|
|
772
|
+
context.warnings.push({ code: "unsupported-config", message });
|
|
773
|
+
}
|
|
774
|
+
function iconName(value) {
|
|
775
|
+
if (typeof value === "string" && value) return value;
|
|
776
|
+
const icon = objectValue2(value);
|
|
777
|
+
return typeof icon?.name === "string" && icon.name ? icon.name : void 0;
|
|
778
|
+
}
|
|
779
|
+
function containerPresentation(value) {
|
|
780
|
+
return {
|
|
781
|
+
...typeof value.description === "string" && value.description.trim() ? { description: value.description.trim() } : {},
|
|
782
|
+
...iconName(value.icon) ? { icon: iconName(value.icon) } : {}
|
|
783
|
+
};
|
|
694
784
|
}
|
|
695
785
|
function registerReference(value, context) {
|
|
696
786
|
const localePrefix = context.locale ? `${context.locale}/` : "";
|
|
697
787
|
const localizedValue = localePrefix && value.replace(/^\/+/, "").startsWith(localePrefix) ? value.replace(/^\/+/, "").slice(localePrefix.length) : value;
|
|
698
|
-
const navigationId = normalizePageRef(localizedValue);
|
|
788
|
+
const navigationId = normalizePageRef(localizedValue, context.pathPrefix);
|
|
699
789
|
if (!navigationId) return null;
|
|
700
790
|
const key = `${context.locale ?? ""}:${value}`;
|
|
701
791
|
if (!context.seenReferences.has(key)) {
|
|
@@ -709,6 +799,17 @@ function convertPage(value, context) {
|
|
|
709
799
|
const object = objectValue2(value);
|
|
710
800
|
if (!object) return null;
|
|
711
801
|
if (typeof object.page === "string") return registerReference(object.page, context);
|
|
802
|
+
const href = projectedHref(object.href);
|
|
803
|
+
if (href && !object.pages && !object.groups) {
|
|
804
|
+
const page = registerReference(href, context);
|
|
805
|
+
if (page) return page;
|
|
806
|
+
warnOnce(
|
|
807
|
+
context,
|
|
808
|
+
"external-page-link",
|
|
809
|
+
"External links nested inside a Mintlify sidebar cannot be represented as Thally pages and were omitted."
|
|
810
|
+
);
|
|
811
|
+
return null;
|
|
812
|
+
}
|
|
712
813
|
const pages = Array.isArray(object.pages) ? object.pages : [];
|
|
713
814
|
if ("group" in object || pages.length > 0) {
|
|
714
815
|
const children = [];
|
|
@@ -723,84 +824,255 @@ function convertPage(value, context) {
|
|
|
723
824
|
if (children.length === 0) return null;
|
|
724
825
|
return {
|
|
725
826
|
group: labelFor(object, "Documentation"),
|
|
726
|
-
...
|
|
827
|
+
...iconName(object.icon) ? { icon: iconName(object.icon) } : {},
|
|
828
|
+
...object.hidden === true ? { hidden: true } : {},
|
|
727
829
|
pages: children
|
|
728
830
|
};
|
|
729
831
|
}
|
|
730
832
|
return null;
|
|
731
833
|
}
|
|
732
|
-
function
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
if (!converted) continue;
|
|
738
|
-
if (typeof converted === "string") loosePages.push(converted);
|
|
739
|
-
else groups.push(converted);
|
|
740
|
-
}
|
|
741
|
-
if (loosePages.length > 0) groups.unshift({ group: fallbackGroup, pages: loosePages });
|
|
742
|
-
return groups;
|
|
834
|
+
function convertNavigationValues(values, context) {
|
|
835
|
+
return values.flatMap((value) => {
|
|
836
|
+
const page = convertPage(value, context);
|
|
837
|
+
return page ? [page] : [];
|
|
838
|
+
});
|
|
743
839
|
}
|
|
744
|
-
function convertContainerToTabs(containerValue, context, fallbackTab) {
|
|
840
|
+
function convertContainerToTabs(containerValue, context, fallbackTab, trace, depth = 0) {
|
|
745
841
|
const container = objectValue2(containerValue);
|
|
746
842
|
if (!container) return [];
|
|
747
|
-
|
|
843
|
+
const containerKeys = ["tabs", "anchors", "products", "dropdowns", "versions", "menus"];
|
|
844
|
+
for (const key of containerKeys) {
|
|
748
845
|
if (!Array.isArray(container[key])) continue;
|
|
749
|
-
const
|
|
846
|
+
const entries = [...container[key]];
|
|
847
|
+
if (key === "versions") {
|
|
848
|
+
entries.sort((left, right) => Number(objectValue2(right)?.default === true) - Number(objectValue2(left)?.default === true));
|
|
849
|
+
}
|
|
850
|
+
const tabs = entries.flatMap((value, index) => {
|
|
750
851
|
const object = objectValue2(value);
|
|
751
852
|
if (!object) return [];
|
|
752
853
|
const tab = labelFor(object, `${fallbackTab} ${index + 1}`);
|
|
753
|
-
|
|
754
|
-
|
|
854
|
+
const href = projectedHref(object.href);
|
|
855
|
+
const hasNestedContainers = containerKeys.some((containerKey) => Array.isArray(object[containerKey]));
|
|
856
|
+
if (href && !object.pages && !object.groups && !hasNestedContainers) {
|
|
857
|
+
return [{
|
|
858
|
+
tab,
|
|
859
|
+
href,
|
|
860
|
+
...containerPresentation(object),
|
|
861
|
+
...object.hidden === true ? { hidden: true } : {}
|
|
862
|
+
}];
|
|
755
863
|
}
|
|
756
|
-
const nested = convertContainerToTabs(object, context, tab);
|
|
864
|
+
const nested = convertContainerToTabs(object, context, tab, trace, depth + 1);
|
|
757
865
|
if (nested.length > 0) {
|
|
758
|
-
if (nested.length === 1)
|
|
759
|
-
|
|
866
|
+
if (nested.length === 1) {
|
|
867
|
+
return [{
|
|
868
|
+
...nested[0],
|
|
869
|
+
tab,
|
|
870
|
+
...containerPresentation(object),
|
|
871
|
+
...href ? { href } : {},
|
|
872
|
+
...object.hidden === true ? { hidden: true } : {}
|
|
873
|
+
}];
|
|
874
|
+
}
|
|
875
|
+
const presentation = containerPresentation(object);
|
|
876
|
+
return nested.map((item, childIndex) => ({
|
|
877
|
+
...presentation,
|
|
878
|
+
...item,
|
|
879
|
+
tab: `${tab}: ${item.tab}`,
|
|
880
|
+
...childIndex === 0 && href && !item.href ? { href } : {},
|
|
881
|
+
...object.hidden === true ? { hidden: true } : {}
|
|
882
|
+
}));
|
|
760
883
|
}
|
|
761
884
|
return [];
|
|
762
885
|
});
|
|
763
|
-
if (tabs.length > 0)
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
886
|
+
if (tabs.length > 0) {
|
|
887
|
+
if (depth === 0 && trace) trace.rootContainerKind = key;
|
|
888
|
+
return tabs;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
const rawGroups = Array.isArray(container.groups) ? container.groups : [];
|
|
892
|
+
const rawPages = Array.isArray(container.pages) ? container.pages : [];
|
|
893
|
+
const hasRootNodes = typeof container.root === "string" || rawPages.length > 0;
|
|
894
|
+
const values = [
|
|
895
|
+
...typeof container.root === "string" ? [container.root] : [],
|
|
896
|
+
...rawGroups,
|
|
897
|
+
...rawPages
|
|
768
898
|
];
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
899
|
+
const children = convertNavigationValues(values, context);
|
|
900
|
+
return children.length > 0 ? [{
|
|
901
|
+
tab: fallbackTab,
|
|
902
|
+
...hasRootNodes ? { pages: children } : { groups: children },
|
|
903
|
+
...containerPresentation(container),
|
|
904
|
+
...projectedHref(container.href) ? { href: projectedHref(container.href) } : {},
|
|
905
|
+
...container.hidden === true ? { hidden: true } : {}
|
|
906
|
+
}] : [];
|
|
907
|
+
}
|
|
908
|
+
function projectedTheme(value) {
|
|
909
|
+
if (value === "maple") return "maple";
|
|
910
|
+
if (["aspen", "luma", "sequoia"].includes(String(value))) return "sharp";
|
|
911
|
+
if (["almond", "palm"].includes(String(value))) return "minimal";
|
|
912
|
+
return typeof value === "string" ? "default" : void 0;
|
|
913
|
+
}
|
|
914
|
+
function projectedNavbar(value) {
|
|
915
|
+
const navbar = objectValue2(value);
|
|
916
|
+
if (!navbar) return void 0;
|
|
917
|
+
const links = Array.isArray(navbar.links) ? navbar.links.flatMap((entry) => {
|
|
918
|
+
const link = objectValue2(entry);
|
|
919
|
+
const href = projectedHref(link?.href);
|
|
920
|
+
if (!link || !href) return [];
|
|
921
|
+
const label = typeof link.label === "string" ? link.label : typeof link.name === "string" ? link.name : "";
|
|
922
|
+
if (!label) return [];
|
|
923
|
+
return [{ label, href, ...link.type === "github" ? { type: "github" } : {} }];
|
|
924
|
+
}) : [];
|
|
925
|
+
const primaryValue = objectValue2(navbar.primary);
|
|
926
|
+
const primaryHref = projectedHref(primaryValue?.href);
|
|
927
|
+
const primary = primaryValue && primaryHref ? {
|
|
928
|
+
label: typeof primaryValue.label === "string" ? primaryValue.label : primaryValue.type === "github" ? "GitHub" : "Get started",
|
|
929
|
+
href: primaryHref
|
|
930
|
+
} : void 0;
|
|
931
|
+
return links.length > 0 || primary ? { ...links.length > 0 ? { links } : {}, ...primary ? { primary } : {} } : void 0;
|
|
932
|
+
}
|
|
933
|
+
function projectedGlobalNavigationLinks(value) {
|
|
934
|
+
const global = objectValue2(value);
|
|
935
|
+
if (!global) return [];
|
|
936
|
+
const links = [];
|
|
937
|
+
const visit = (entry) => {
|
|
938
|
+
if (Array.isArray(entry)) {
|
|
939
|
+
entry.forEach(visit);
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
const item = objectValue2(entry);
|
|
943
|
+
if (!item) return;
|
|
944
|
+
const href = projectedHref(item.href);
|
|
945
|
+
if (href) {
|
|
946
|
+
const label = labelFor(item, "");
|
|
947
|
+
if (label) links.push({ label, href });
|
|
948
|
+
}
|
|
949
|
+
for (const key of ["tabs", "anchors", "dropdowns", "products", "versions", "languages", "menus"]) {
|
|
950
|
+
if (Array.isArray(item[key])) visit(item[key]);
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
visit(global);
|
|
954
|
+
return links;
|
|
955
|
+
}
|
|
956
|
+
function projectedFooter(value) {
|
|
957
|
+
const footer = objectValue2(value);
|
|
958
|
+
if (!footer) return void 0;
|
|
959
|
+
const socials = objectValue2(footer.socials);
|
|
960
|
+
const socialLinks = socials ? Object.fromEntries(Object.entries(socials).flatMap(([key, value2]) => {
|
|
961
|
+
const href = projectedHref(value2);
|
|
962
|
+
return href ? [[key, href]] : [];
|
|
963
|
+
})) : void 0;
|
|
964
|
+
const links = Array.isArray(footer.links) ? footer.links.flatMap((entry) => {
|
|
965
|
+
const column = objectValue2(entry);
|
|
966
|
+
if (!column || !Array.isArray(column.items)) return [];
|
|
967
|
+
const heading = typeof column.heading === "string" ? column.heading : typeof column.header === "string" ? column.header : "";
|
|
968
|
+
const items = column.items.flatMap((item) => {
|
|
969
|
+
const link = objectValue2(item);
|
|
970
|
+
const href = projectedHref(link?.href);
|
|
971
|
+
return link && typeof link.label === "string" && href ? [{ label: link.label, href }] : [];
|
|
972
|
+
});
|
|
973
|
+
return heading && items.length > 0 ? [{ heading, items }] : [];
|
|
974
|
+
}) : [];
|
|
975
|
+
return socialLinks && Object.keys(socialLinks).length > 0 || links.length > 0 ? { ...socialLinks && Object.keys(socialLinks).length > 0 ? { socials: socialLinks } : {}, ...links.length > 0 ? { links } : {} } : void 0;
|
|
976
|
+
}
|
|
977
|
+
function projectedFont(value) {
|
|
978
|
+
if (typeof value === "string" && value) return { family: value };
|
|
979
|
+
const font = objectValue2(value);
|
|
980
|
+
if (!font) return void 0;
|
|
981
|
+
const family = typeof font.family === "string" ? font.family : typeof font.name === "string" ? font.name : void 0;
|
|
982
|
+
if (!family) return void 0;
|
|
983
|
+
const weight = Array.isArray(font.weight) ? font.weight.map(String) : Array.isArray(font.weights) ? font.weights.map(String) : void 0;
|
|
984
|
+
return { family, ...weight && weight.length > 0 ? { weight } : {} };
|
|
985
|
+
}
|
|
986
|
+
function projectedCompatibleConfig(config) {
|
|
987
|
+
const banner = objectValue2(config.banner);
|
|
988
|
+
const bannerContent = banner && (typeof banner.content === "string" || objectValue2(banner.content)) ? banner.content : void 0;
|
|
989
|
+
const bannerType = banner && ["info", "warning", "critical"].includes(String(banner.type ?? banner.variant)) ? String(banner.type ?? banner.variant) : void 0;
|
|
990
|
+
const bannerColor = objectValue2(banner?.color);
|
|
991
|
+
const bodyFont = projectedFont(objectValue2(config.fonts)?.body ?? config.fonts);
|
|
992
|
+
const headingFont = projectedFont(objectValue2(config.fonts)?.heading);
|
|
993
|
+
const feedback = objectValue2(config.feedback);
|
|
994
|
+
const seo = objectValue2(config.seo);
|
|
995
|
+
const navbar = projectedNavbar(config.navbar);
|
|
996
|
+
const globalLinks = projectedGlobalNavigationLinks(objectValue2(config.navigation)?.global);
|
|
997
|
+
const navbarLinks = [...new Map(
|
|
998
|
+
[...navbar?.links ?? [], ...globalLinks].map((link) => [`${link.label}:${link.href}`, link])
|
|
999
|
+
).values()];
|
|
1000
|
+
const projectedNavigation = navbarLinks.length > 0 || navbar?.primary ? { ...navbarLinks.length > 0 ? { links: navbarLinks } : {}, ...navbar?.primary ? { primary: navbar.primary } : {} } : void 0;
|
|
1001
|
+
return {
|
|
1002
|
+
...projectedTheme(config.theme) ? { theme: projectedTheme(config.theme) } : {},
|
|
1003
|
+
...bannerContent ? {
|
|
1004
|
+
banner: {
|
|
1005
|
+
content: bannerContent,
|
|
1006
|
+
...banner?.dismissible === false ? { dismissible: false } : {},
|
|
1007
|
+
...typeof banner?.id === "string" ? { id: banner.id } : {},
|
|
1008
|
+
...typeof banner?.revision === "string" ? { revision: banner.revision } : {},
|
|
1009
|
+
...bannerType ? { type: bannerType } : {},
|
|
1010
|
+
...bannerColor ? { color: {
|
|
1011
|
+
...typeof bannerColor.light === "string" ? { light: bannerColor.light } : {},
|
|
1012
|
+
...typeof bannerColor.dark === "string" ? { dark: bannerColor.dark } : {}
|
|
1013
|
+
} } : {}
|
|
1014
|
+
}
|
|
1015
|
+
} : {},
|
|
1016
|
+
...projectedNavigation ? { navbar: projectedNavigation } : {},
|
|
1017
|
+
...projectedFooter(config.footer) ? { footer: projectedFooter(config.footer) } : {},
|
|
1018
|
+
...bodyFont || headingFont ? { fonts: { ...bodyFont ? { body: bodyFont } : {}, ...headingFont ? { heading: headingFont } : {} } } : {},
|
|
1019
|
+
...seo?.indexing === "all" ? { seo: { indexing: "all" } } : {},
|
|
1020
|
+
...typeof feedback?.thumbsRating === "boolean" ? { feedback: { thumbsRating: feedback.thumbsRating } } : {}
|
|
1021
|
+
};
|
|
772
1022
|
}
|
|
773
|
-
function projectMintlifyNavigation(config) {
|
|
1023
|
+
function projectMintlifyNavigation(config, options = {}) {
|
|
774
1024
|
const warnings = [];
|
|
775
1025
|
const references = [];
|
|
776
1026
|
const seenReferences = /* @__PURE__ */ new Set();
|
|
1027
|
+
const warningKeys = /* @__PURE__ */ new Set();
|
|
777
1028
|
const navigation = objectValue2(config.navigation) ?? config;
|
|
778
1029
|
const languages = Array.isArray(navigation.languages) ? navigation.languages.map(objectValue2).filter((value) => Boolean(value)) : [];
|
|
779
1030
|
let tabs = [];
|
|
780
1031
|
let i18n;
|
|
1032
|
+
const projectionTrace = {};
|
|
781
1033
|
if (languages.length > 0) {
|
|
782
|
-
const defaultLanguage = languages.find((entry) => entry.
|
|
783
|
-
const defaultLocale = String(defaultLanguage.language ?? "en");
|
|
1034
|
+
const defaultLanguage = languages.find((entry) => entry.default === true) ?? languages[0];
|
|
1035
|
+
const defaultLocale = String(defaultLanguage.language ?? defaultLanguage.locale ?? "en");
|
|
784
1036
|
const locales = languages.map((entry) => {
|
|
785
1037
|
const code = String(entry.language ?? entry.locale ?? "en");
|
|
786
|
-
|
|
1038
|
+
let label = LANGUAGE_LABELS[code];
|
|
1039
|
+
try {
|
|
1040
|
+
label ??= new Intl.DisplayNames(["en"], { type: "language" }).of(code) ?? void 0;
|
|
1041
|
+
} catch {
|
|
1042
|
+
}
|
|
1043
|
+
return { code, label: label ?? code.toUpperCase() };
|
|
787
1044
|
});
|
|
788
1045
|
i18n = { defaultLocale, locales };
|
|
789
1046
|
for (const language of languages) {
|
|
790
1047
|
const locale = String(language.language ?? language.locale ?? defaultLocale);
|
|
791
1048
|
const context = {
|
|
792
1049
|
locale,
|
|
1050
|
+
pathPrefix: options.pathPrefix,
|
|
793
1051
|
references,
|
|
794
|
-
seenReferences
|
|
1052
|
+
seenReferences,
|
|
1053
|
+
warnings,
|
|
1054
|
+
warningKeys
|
|
795
1055
|
};
|
|
796
|
-
const languageTabs = convertContainerToTabs(
|
|
1056
|
+
const languageTabs = convertContainerToTabs(
|
|
1057
|
+
language,
|
|
1058
|
+
context,
|
|
1059
|
+
"Documentation",
|
|
1060
|
+
language === defaultLanguage ? projectionTrace : void 0
|
|
1061
|
+
);
|
|
797
1062
|
if (language === defaultLanguage) tabs = languageTabs;
|
|
798
1063
|
}
|
|
799
1064
|
} else {
|
|
800
|
-
|
|
1065
|
+
const context = { references, seenReferences, warnings, warningKeys, pathPrefix: options.pathPrefix };
|
|
1066
|
+
tabs = convertContainerToTabs(navigation, context, "Documentation", projectionTrace);
|
|
801
1067
|
if (tabs.length === 0 && Array.isArray(config.navigation)) {
|
|
802
|
-
const
|
|
803
|
-
if (
|
|
1068
|
+
const children = convertNavigationValues(config.navigation, context);
|
|
1069
|
+
if (children.length > 0) {
|
|
1070
|
+
const hasRootPages = children.some((page) => typeof page === "string");
|
|
1071
|
+
tabs = [{
|
|
1072
|
+
tab: "Documentation",
|
|
1073
|
+
...hasRootPages ? { pages: children } : { groups: children }
|
|
1074
|
+
}];
|
|
1075
|
+
}
|
|
804
1076
|
}
|
|
805
1077
|
}
|
|
806
1078
|
if (tabs.length === 0) {
|
|
@@ -809,20 +1081,26 @@ function projectMintlifyNavigation(config) {
|
|
|
809
1081
|
message: "Mintlify navigation could not be projected; generated navigation will be used."
|
|
810
1082
|
});
|
|
811
1083
|
}
|
|
812
|
-
if (!tabs.some((tab) => tab.tab.toLowerCase() === "changelog")) {
|
|
813
|
-
tabs.push({ tab: "Changelog", href: "/changelog" });
|
|
814
|
-
}
|
|
815
1084
|
const redirects = Array.isArray(config.redirects) ? config.redirects.flatMap((value) => {
|
|
816
1085
|
const redirect = objectValue2(value);
|
|
817
1086
|
if (!redirect || typeof redirect.source !== "string" || typeof redirect.destination !== "string") return [];
|
|
1087
|
+
const source = redirect.source.trim();
|
|
1088
|
+
const destination = redirect.destination.trim();
|
|
1089
|
+
if (!source.startsWith("/") || !destination.startsWith("/") || source.startsWith("//") || destination.startsWith("//")) return [];
|
|
818
1090
|
return [{
|
|
819
|
-
source
|
|
820
|
-
destination
|
|
1091
|
+
source,
|
|
1092
|
+
destination,
|
|
821
1093
|
...typeof redirect.permanent === "boolean" ? { permanent: redirect.permanent } : {}
|
|
822
1094
|
}];
|
|
823
1095
|
}) : [];
|
|
824
1096
|
return {
|
|
825
|
-
docsConfig: {
|
|
1097
|
+
docsConfig: {
|
|
1098
|
+
tabs,
|
|
1099
|
+
...projectionTrace.rootContainerKind === "dropdowns" ? { navigation: { display: "dropdown" } } : {},
|
|
1100
|
+
...projectedCompatibleConfig(config),
|
|
1101
|
+
...i18n ? { i18n } : {},
|
|
1102
|
+
...redirects.length > 0 ? { redirects } : {}
|
|
1103
|
+
},
|
|
826
1104
|
pageReferences: references,
|
|
827
1105
|
warnings
|
|
828
1106
|
};
|
|
@@ -991,12 +1269,50 @@ var DOCUSAURUS_CONFIG_FILENAMES = [
|
|
|
991
1269
|
function hasDocusaurusConfig(directory) {
|
|
992
1270
|
return DOCUSAURUS_CONFIG_FILENAMES.some((filename) => {
|
|
993
1271
|
const path = resolveWithin(directory, filename);
|
|
994
|
-
return existsSync3(path) &&
|
|
1272
|
+
return existsSync3(path) && lstatSync3(path).isFile();
|
|
995
1273
|
});
|
|
996
1274
|
}
|
|
1275
|
+
function hasMintlifyConfig(directory) {
|
|
1276
|
+
return ["docs.json", "mint.json"].some((filename) => {
|
|
1277
|
+
const path = resolveWithin(directory, filename);
|
|
1278
|
+
if (!existsSync3(path) || !lstatSync3(path).isFile()) return false;
|
|
1279
|
+
if (filename === "mint.json") return true;
|
|
1280
|
+
try {
|
|
1281
|
+
const config = JSON.parse(readFileSync3(path, "utf8"));
|
|
1282
|
+
return String(config.$schema ?? "").includes("mintlify") || "navigation" in config;
|
|
1283
|
+
} catch {
|
|
1284
|
+
return false;
|
|
1285
|
+
}
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
function findMintlifyProjectRoot(repositoryDir, docsDir) {
|
|
1289
|
+
if (docsDir !== void 0) {
|
|
1290
|
+
let candidate = trimTrailingSlashes(docsDir);
|
|
1291
|
+
while (true) {
|
|
1292
|
+
const path = resolveWithin(repositoryDir, candidate || ".");
|
|
1293
|
+
if (hasMintlifyConfig(path)) return path;
|
|
1294
|
+
if (!candidate) break;
|
|
1295
|
+
const parent = dirname2(candidate);
|
|
1296
|
+
candidate = parent === "." ? "" : parent;
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
const queue = [{ directory: repositoryDir, depth: 0 }];
|
|
1300
|
+
let visited = 0;
|
|
1301
|
+
while (queue.length > 0 && visited < 500) {
|
|
1302
|
+
const current = queue.shift();
|
|
1303
|
+
visited++;
|
|
1304
|
+
if (hasMintlifyConfig(current.directory)) return current.directory;
|
|
1305
|
+
if (current.depth >= 4) continue;
|
|
1306
|
+
for (const entry of readdirSync(current.directory, { withFileTypes: true })) {
|
|
1307
|
+
if (!entry.isDirectory() || entry.isSymbolicLink() || IGNORED_DIRECTORIES.has(entry.name)) continue;
|
|
1308
|
+
queue.push({ directory: resolveWithin(current.directory, entry.name), depth: current.depth + 1 });
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
return null;
|
|
1312
|
+
}
|
|
997
1313
|
function findDocusaurusProjectRoot(repositoryDir, docsDir) {
|
|
998
1314
|
if (docsDir !== void 0) {
|
|
999
|
-
let candidate = docsDir
|
|
1315
|
+
let candidate = trimTrailingSlashes(docsDir);
|
|
1000
1316
|
while (true) {
|
|
1001
1317
|
const path = resolveWithin(repositoryDir, candidate || ".");
|
|
1002
1318
|
if (hasDocusaurusConfig(path)) return path;
|
|
@@ -1023,14 +1339,14 @@ function findDocusaurusProjectRoot(repositoryDir, docsDir) {
|
|
|
1023
1339
|
return null;
|
|
1024
1340
|
}
|
|
1025
1341
|
function readDocusaurusConfigSource(projectRoot) {
|
|
1026
|
-
const path = DOCUSAURUS_CONFIG_FILENAMES.map((filename) => resolveWithin(projectRoot, filename)).find((candidate) => existsSync3(candidate) &&
|
|
1027
|
-
if (!path ||
|
|
1342
|
+
const path = DOCUSAURUS_CONFIG_FILENAMES.map((filename) => resolveWithin(projectRoot, filename)).find((candidate) => existsSync3(candidate) && lstatSync3(candidate).isFile());
|
|
1343
|
+
if (!path || lstatSync3(path).size > 1e6) return "";
|
|
1028
1344
|
return readFileSync3(path, "utf8");
|
|
1029
1345
|
}
|
|
1030
1346
|
function primaryDocusaurusDocsDirectory(projectRoot) {
|
|
1031
1347
|
const source = readDocusaurusConfigSource(projectRoot);
|
|
1032
1348
|
const configured = source.match(/\bdocs\s*:\s*\{[\s\S]{0,4000}?\bpath\s*:\s*(['"])([^'"]+)\1/)?.[2];
|
|
1033
|
-
return configured?.replace(/^\.\//, "")
|
|
1349
|
+
return trimTrailingSlashes(configured?.replace(/^\.\//, "") ?? "") || "docs";
|
|
1034
1350
|
}
|
|
1035
1351
|
function additionalDocusaurusPluginRoots(repositoryDir, projectRoot) {
|
|
1036
1352
|
const source = readDocusaurusConfigSource(projectRoot);
|
|
@@ -1038,12 +1354,12 @@ function additionalDocusaurusPluginRoots(repositoryDir, projectRoot) {
|
|
|
1038
1354
|
const plugins = [];
|
|
1039
1355
|
const matcher = /['"]@docusaurus\/plugin-content-docs['"][\s\S]{0,3000}?\bpath\s*:\s*(['"])([^'"]+)\1[\s\S]{0,1000}?\brouteBasePath\s*:\s*(['"])([^'"]+)\3/g;
|
|
1040
1356
|
for (const match of source.matchAll(matcher)) {
|
|
1041
|
-
const localPath = match[2].replace(/^\.\//, "")
|
|
1042
|
-
const routePrefix = match[4]
|
|
1357
|
+
const localPath = trimTrailingSlashes(match[2].replace(/^\.\//, ""));
|
|
1358
|
+
const routePrefix = trimEdgeSlashes(match[4]);
|
|
1043
1359
|
if (!localPath || !routePrefix) continue;
|
|
1044
1360
|
const docsDir = [projectRelative, localPath].filter(Boolean).join("/");
|
|
1045
1361
|
const absolute = resolveWithin(repositoryDir, docsDir);
|
|
1046
|
-
if (!existsSync3(absolute) || !
|
|
1362
|
+
if (!existsSync3(absolute) || !lstatSync3(absolute).isDirectory()) continue;
|
|
1047
1363
|
plugins.push({ docsDir, routePrefix });
|
|
1048
1364
|
}
|
|
1049
1365
|
return plugins;
|
|
@@ -1100,13 +1416,13 @@ async function cloneGitHubRepository(source, targetDir) {
|
|
|
1100
1416
|
});
|
|
1101
1417
|
});
|
|
1102
1418
|
}
|
|
1103
|
-
function detectRepositoryPlatform(repositoryDir) {
|
|
1104
|
-
if (
|
|
1105
|
-
const
|
|
1419
|
+
function detectRepositoryPlatform(repositoryDir, docsDir) {
|
|
1420
|
+
if (findMintlifyProjectRoot(repositoryDir, docsDir)) return "mintlify";
|
|
1421
|
+
const selectedRoot = docsDir === void 0 ? repositoryDir : resolveWithin(repositoryDir, docsDir || ".");
|
|
1422
|
+
const docsJson = resolveWithin(selectedRoot, "docs.json");
|
|
1106
1423
|
if (existsSync3(docsJson)) {
|
|
1107
1424
|
try {
|
|
1108
1425
|
const config = JSON.parse(readFileSync3(docsJson, "utf8"));
|
|
1109
|
-
if (String(config.$schema ?? "").includes("mintlify") || "navigation" in config) return "mintlify";
|
|
1110
1426
|
if (Array.isArray(config.tabs)) return "thally";
|
|
1111
1427
|
} catch {
|
|
1112
1428
|
}
|
|
@@ -1132,7 +1448,7 @@ function containsMarkdown(directory, depth = 0) {
|
|
|
1132
1448
|
function detectRepositoryDocsDir(repositoryDir) {
|
|
1133
1449
|
for (const candidate of ["docs", "documentation", "content", "pages", "src/content", "src/pages", "guide", "guides", ""]) {
|
|
1134
1450
|
const path = resolveWithin(repositoryDir, candidate);
|
|
1135
|
-
if (existsSync3(path) &&
|
|
1451
|
+
if (existsSync3(path) && lstatSync3(path).isDirectory() && containsMarkdown(path)) return candidate;
|
|
1136
1452
|
}
|
|
1137
1453
|
return "";
|
|
1138
1454
|
}
|
|
@@ -1154,30 +1470,135 @@ function scanFiles(root) {
|
|
|
1154
1470
|
function normalizedReferenceKey(value) {
|
|
1155
1471
|
return value.split(/[?#]/, 1)[0].replace(/^\/+/, "").replace(/\\/g, "/").replace(/\.(?:mdx?|rst|txt)$/i, "").replace(/\/(?:index|readme)$/i, "").replace(/^(?:index|readme)$/i, "") || "introduction";
|
|
1156
1472
|
}
|
|
1473
|
+
function exactReferenceKey(value) {
|
|
1474
|
+
return value.split(/[?#]/, 1)[0].replace(/^\/+/, "").replace(/\\/g, "/").replace(/\.(?:mdx?|rst|txt)$/i, "");
|
|
1475
|
+
}
|
|
1157
1476
|
function findOpenApi(files) {
|
|
1158
1477
|
return files.find((file) => OPENAPI_FILENAMES.has(basename(file.relativePath).toLowerCase())) ?? null;
|
|
1159
1478
|
}
|
|
1479
|
+
function findConfiguredMintlifyOpenApi(config, files) {
|
|
1480
|
+
const api = config?.api && typeof config.api === "object" && !Array.isArray(config.api) ? config.api : null;
|
|
1481
|
+
const configured = typeof api?.openapi === "string" ? [api.openapi] : Array.isArray(api?.openapi) ? api.openapi.filter((value) => typeof value === "string") : [];
|
|
1482
|
+
for (const reference of configured) {
|
|
1483
|
+
if (/^(?:https?:)?\/\//i.test(reference)) continue;
|
|
1484
|
+
const key = reference.split(/[?#]/, 1)[0].replace(/^\/+/, "").replace(/\\/g, "/");
|
|
1485
|
+
const match = files.find((file) => file.relativePath === key);
|
|
1486
|
+
if (match) return match;
|
|
1487
|
+
}
|
|
1488
|
+
return null;
|
|
1489
|
+
}
|
|
1160
1490
|
function withoutFrontmatter(value) {
|
|
1161
1491
|
return value.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "").trim();
|
|
1162
1492
|
}
|
|
1163
|
-
function
|
|
1493
|
+
function staticSnippetProperties(attributes) {
|
|
1494
|
+
const properties = /* @__PURE__ */ new Map();
|
|
1495
|
+
const matcher = /\b([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?:"([^"]*)"|'([^']*)'|\{\s*"([^"]*)"\s*\}|\{\s*'([^']*)'\s*\})/g;
|
|
1496
|
+
for (const match of attributes.matchAll(matcher)) {
|
|
1497
|
+
properties.set(match[1], match[2] ?? match[3] ?? match[4] ?? match[5] ?? "");
|
|
1498
|
+
}
|
|
1499
|
+
return properties;
|
|
1500
|
+
}
|
|
1501
|
+
function interpolateSnippet(snippet, attributes) {
|
|
1502
|
+
const properties = staticSnippetProperties(attributes);
|
|
1503
|
+
if (properties.size === 0) return snippet;
|
|
1504
|
+
let fence = "";
|
|
1505
|
+
return snippet.split("\n").map((line) => {
|
|
1506
|
+
const marker = line.match(/^\s*(`{3,}|~{3,})/)?.[1];
|
|
1507
|
+
if (marker) {
|
|
1508
|
+
if (!fence) fence = marker[0];
|
|
1509
|
+
else if (marker[0] === fence) fence = "";
|
|
1510
|
+
return line;
|
|
1511
|
+
}
|
|
1512
|
+
if (fence) return line;
|
|
1513
|
+
return line.replace(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (original, name) => {
|
|
1514
|
+
return properties.get(name) ?? original;
|
|
1515
|
+
});
|
|
1516
|
+
}).join("\n");
|
|
1517
|
+
}
|
|
1518
|
+
function resolveSnippetPath(sourcePath, currentFile, repositoryRoot, siteRoot) {
|
|
1519
|
+
const repositoryRelative = sourcePath.startsWith("@site/") ? relative3(repositoryRoot, resolveWithin(siteRoot, sourcePath.slice("@site/".length))).replace(/\\/g, "/") : sourcePath.startsWith("/") ? relative3(repositoryRoot, resolveWithin(siteRoot, sourcePath.replace(/^\/+/, ""))).replace(/\\/g, "/") : relative3(repositoryRoot, resolvePath(dirname2(currentFile), sourcePath)).replace(/\\/g, "/");
|
|
1520
|
+
const candidate = resolveWithin(repositoryRoot, repositoryRelative);
|
|
1521
|
+
resolveWithin(repositoryRoot, relative3(repositoryRoot, candidate));
|
|
1522
|
+
return candidate;
|
|
1523
|
+
}
|
|
1524
|
+
function globalSnippetAliases(files, repositoryRoot, siteRoot) {
|
|
1525
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
1526
|
+
const matcher = /^import\s+(?:\{\s*default\s+as\s+)?([A-Z][A-Za-z0-9_]*)\s*\}?\s+from\s+['"]([^'"]+\.mdx?)['"]\s*;?(?:\s*\/\/.*)?$/gm;
|
|
1527
|
+
for (const file of files) {
|
|
1528
|
+
const segments = file.relativePath.split("/");
|
|
1529
|
+
if (!segments.some((segment) => SNIPPET_DIRECTORIES.has(segment.toLowerCase()))) continue;
|
|
1530
|
+
const basenameWithoutExtension = basename(file.relativePath).replace(/\.mdx?$/i, "");
|
|
1531
|
+
const conventionalAlias = basenameWithoutExtension.split(/[^A-Za-z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
1532
|
+
if (conventionalAlias) aliases.set(conventionalAlias, file.absolutePath);
|
|
1533
|
+
}
|
|
1534
|
+
for (const file of files) {
|
|
1535
|
+
if (![".md", ".mdx"].includes(extname3(file.relativePath).toLowerCase())) continue;
|
|
1536
|
+
const raw = readFileSync3(file.absolutePath, "utf8");
|
|
1537
|
+
for (const match of raw.matchAll(matcher)) {
|
|
1538
|
+
try {
|
|
1539
|
+
const candidate = resolveSnippetPath(match[2], file.absolutePath, repositoryRoot, siteRoot);
|
|
1540
|
+
if (existsSync3(candidate) && lstatSync3(candidate).isFile()) {
|
|
1541
|
+
aliases.set(match[1], candidate);
|
|
1542
|
+
}
|
|
1543
|
+
} catch {
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
return aliases;
|
|
1548
|
+
}
|
|
1549
|
+
function repositoryAssetHref(value, currentFile, siteRoot) {
|
|
1550
|
+
const isBracketed = value.startsWith("<") && value.endsWith(">");
|
|
1551
|
+
const raw = isBracketed ? value.slice(1, -1) : value;
|
|
1552
|
+
if (!raw || raw.startsWith("#") || /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(raw)) return null;
|
|
1553
|
+
const suffixIndex = raw.search(/[?#]/);
|
|
1554
|
+
const pathname = suffixIndex >= 0 ? raw.slice(0, suffixIndex) : raw;
|
|
1555
|
+
const suffix = suffixIndex >= 0 ? raw.slice(suffixIndex) : "";
|
|
1556
|
+
let decodedPath;
|
|
1557
|
+
try {
|
|
1558
|
+
decodedPath = decodeURIComponent(pathname);
|
|
1559
|
+
} catch {
|
|
1560
|
+
return null;
|
|
1561
|
+
}
|
|
1562
|
+
if (!ASSET_EXTENSIONS.has(extname3(decodedPath).toLowerCase())) return null;
|
|
1563
|
+
try {
|
|
1564
|
+
const candidate = decodedPath.startsWith("/") ? resolveWithin(siteRoot, decodedPath.replace(/^\/+/, "")) : resolveWithin(dirname2(currentFile), decodedPath);
|
|
1565
|
+
const siteRelative = relative3(siteRoot, candidate).replace(/\\/g, "/");
|
|
1566
|
+
resolveWithin(siteRoot, siteRelative);
|
|
1567
|
+
if (!existsSync3(candidate) || !lstatSync3(candidate).isFile()) return null;
|
|
1568
|
+
const normalized = normalizeAssetPath(siteRelative);
|
|
1569
|
+
if (!normalized) return null;
|
|
1570
|
+
const rewritten = `/${normalized}${suffix}`;
|
|
1571
|
+
return isBracketed ? `<${rewritten}>` : rewritten;
|
|
1572
|
+
} catch {
|
|
1573
|
+
return null;
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
function rewriteRepositoryAssetLinks(body, currentFile, siteRoot) {
|
|
1577
|
+
return body.replace(/(!?\[[^\]]*\]\()(<[^>]+>|[^)\s]+)([^)]*\))/g, (original, opening, destination, closing) => {
|
|
1578
|
+
const rewritten = repositoryAssetHref(destination, currentFile, siteRoot);
|
|
1579
|
+
return rewritten ? `${opening}${rewritten}${closing}` : original;
|
|
1580
|
+
}).replace(/\b(src|img|image|href)=(['"])([^'"]+)\2/g, (original, property, quote, destination) => {
|
|
1581
|
+
const rewritten = repositoryAssetHref(destination, currentFile, siteRoot);
|
|
1582
|
+
return rewritten ? `${property}=${quote}${rewritten}${quote}` : original;
|
|
1583
|
+
});
|
|
1584
|
+
}
|
|
1585
|
+
function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0, siteRoot = repositoryRoot, globalAliases = /* @__PURE__ */ new Map()) {
|
|
1164
1586
|
if (depth >= 8) return raw;
|
|
1165
1587
|
const snippets = /* @__PURE__ */ new Map();
|
|
1166
1588
|
const withoutImports = raw.replace(
|
|
1167
1589
|
/^import\s+(?:\{\s*default\s+as\s+)?([A-Z][A-Za-z0-9_]*)\s*\}?\s+from\s+['"]([^'"]+\.mdx?)['"]\s*;?(?:\s*\/\/.*)?$/gm,
|
|
1168
1590
|
(_statement, componentName, sourcePath) => {
|
|
1169
1591
|
try {
|
|
1170
|
-
const
|
|
1171
|
-
|
|
1172
|
-
resolveWithin(repositoryRoot, relative3(repositoryRoot, candidate));
|
|
1173
|
-
if (!existsSync3(candidate) || !lstatSync2(candidate).isFile()) throw new Error("file not found");
|
|
1592
|
+
const candidate = resolveSnippetPath(sourcePath, currentFile, repositoryRoot, siteRoot);
|
|
1593
|
+
if (!existsSync3(candidate) || !lstatSync3(candidate).isFile()) throw new Error("file not found");
|
|
1174
1594
|
const nested = inlineMdxSnippets(
|
|
1175
1595
|
withoutFrontmatter(readFileSync3(candidate, "utf8")),
|
|
1176
1596
|
candidate,
|
|
1177
1597
|
repositoryRoot,
|
|
1178
1598
|
warnings,
|
|
1179
1599
|
depth + 1,
|
|
1180
|
-
siteRoot
|
|
1600
|
+
siteRoot,
|
|
1601
|
+
globalAliases
|
|
1181
1602
|
);
|
|
1182
1603
|
snippets.set(componentName, nested);
|
|
1183
1604
|
return "";
|
|
@@ -1192,26 +1613,40 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
1192
1613
|
}
|
|
1193
1614
|
}
|
|
1194
1615
|
);
|
|
1616
|
+
for (const [componentName, candidate] of globalAliases) {
|
|
1617
|
+
if (snippets.has(componentName) || !new RegExp(`<${componentName}(?:\\s|/?>)`).test(withoutImports)) continue;
|
|
1618
|
+
const nested = inlineMdxSnippets(
|
|
1619
|
+
withoutFrontmatter(readFileSync3(candidate, "utf8")),
|
|
1620
|
+
candidate,
|
|
1621
|
+
repositoryRoot,
|
|
1622
|
+
warnings,
|
|
1623
|
+
depth + 1,
|
|
1624
|
+
siteRoot,
|
|
1625
|
+
globalAliases
|
|
1626
|
+
);
|
|
1627
|
+
snippets.set(componentName, nested);
|
|
1628
|
+
}
|
|
1195
1629
|
let result = withoutImports;
|
|
1196
1630
|
for (const [componentName, snippet] of snippets) {
|
|
1197
|
-
result = result.replace(new RegExp(`<${componentName}(?:\\s[^>]*)
|
|
1631
|
+
result = result.replace(new RegExp(`<${componentName}((?:\\s[^>]*)?)\\s*/>`, "g"), (_tag, attributes) => {
|
|
1632
|
+
return interpolateSnippet(snippet, attributes);
|
|
1633
|
+
}).replace(new RegExp(`<${componentName}((?:\\s[^>]*)?)>(?:[\\s\\S]*?)<\\/${componentName}>`, "g"), (_tag, attributes) => {
|
|
1634
|
+
return interpolateSnippet(snippet, attributes);
|
|
1635
|
+
});
|
|
1198
1636
|
}
|
|
1199
1637
|
return result;
|
|
1200
1638
|
}
|
|
1201
1639
|
function injectOpenApi(config, filename) {
|
|
1202
|
-
const tabs = config.tabs.
|
|
1203
|
-
const apiTab =
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
};
|
|
1207
|
-
const changelog = tabs.findIndex((tab) => tab.tab.toLowerCase() === "changelog");
|
|
1208
|
-
if (changelog >= 0) tabs.splice(changelog, 0, apiTab);
|
|
1209
|
-
else tabs.push(apiTab);
|
|
1640
|
+
const tabs = config.tabs.map((tab) => ({ ...tab }));
|
|
1641
|
+
const apiTab = tabs.find((tab) => tab.tab.toLowerCase().includes("api"));
|
|
1642
|
+
if (apiTab) apiTab.api = { source: `/${filename}`, navigation: false };
|
|
1643
|
+
else tabs.push({ tab: "API Reference", api: { source: `/${filename}` } });
|
|
1210
1644
|
return { ...config, tabs };
|
|
1211
1645
|
}
|
|
1212
1646
|
function migrateRepository(options) {
|
|
1213
1647
|
const repositoryDir = options.repositoryDir;
|
|
1214
|
-
const platform = options.platform ?? detectRepositoryPlatform(repositoryDir);
|
|
1648
|
+
const platform = options.platform ?? detectRepositoryPlatform(repositoryDir, options.docsDir);
|
|
1649
|
+
const mintlifyProjectRoot = platform === "mintlify" ? findMintlifyProjectRoot(repositoryDir, options.docsDir) : null;
|
|
1215
1650
|
const docusaurusProjectRoot = platform === "docusaurus" ? findDocusaurusProjectRoot(repositoryDir, options.docsDir) : null;
|
|
1216
1651
|
const configuredDocsDir = (() => {
|
|
1217
1652
|
if (options.docsDir !== void 0) {
|
|
@@ -1226,23 +1661,30 @@ function migrateRepository(options) {
|
|
|
1226
1661
|
const projectRelative = relative3(repositoryDir, docusaurusProjectRoot).replace(/\\/g, "/");
|
|
1227
1662
|
return [projectRelative, primaryDocusaurusDocsDirectory(docusaurusProjectRoot)].filter(Boolean).join("/");
|
|
1228
1663
|
}
|
|
1664
|
+
if (platform === "mintlify" && mintlifyProjectRoot) {
|
|
1665
|
+
return relative3(repositoryDir, mintlifyProjectRoot).replace(/\\/g, "/");
|
|
1666
|
+
}
|
|
1229
1667
|
return platform === "mintlify" ? "" : detectRepositoryDocsDir(repositoryDir);
|
|
1230
1668
|
})();
|
|
1231
1669
|
const warnings = [];
|
|
1232
1670
|
let docsConfig = { tabs: [] };
|
|
1233
1671
|
const referenceMap = /* @__PURE__ */ new Map();
|
|
1672
|
+
const exactReferenceMap = /* @__PURE__ */ new Map();
|
|
1234
1673
|
const referenceOrder = /* @__PURE__ */ new Map();
|
|
1235
1674
|
let docusaurusSidebars = null;
|
|
1675
|
+
let mintlifyConfig = null;
|
|
1236
1676
|
if (platform === "mintlify") {
|
|
1237
1677
|
try {
|
|
1238
|
-
const config = readMintlifyConfig(repositoryDir);
|
|
1678
|
+
const config = readMintlifyConfig(mintlifyProjectRoot ?? repositoryDir);
|
|
1239
1679
|
if (config) {
|
|
1680
|
+
mintlifyConfig = config;
|
|
1240
1681
|
const projected = projectMintlifyNavigation(config);
|
|
1241
1682
|
docsConfig = projected.docsConfig;
|
|
1242
1683
|
warnings.push(...projected.warnings);
|
|
1243
1684
|
for (const [index, reference] of projected.pageReferences.entries()) {
|
|
1244
1685
|
const key = normalizedReferenceKey(reference.ref);
|
|
1245
1686
|
referenceMap.set(key, reference);
|
|
1687
|
+
exactReferenceMap.set(exactReferenceKey(reference.ref), reference);
|
|
1246
1688
|
referenceOrder.set(key, index);
|
|
1247
1689
|
}
|
|
1248
1690
|
}
|
|
@@ -1264,7 +1706,7 @@ function migrateRepository(options) {
|
|
|
1264
1706
|
}
|
|
1265
1707
|
}
|
|
1266
1708
|
const contentRoot = resolveWithin(repositoryDir, configuredDocsDir);
|
|
1267
|
-
if (!existsSync3(contentRoot) || !
|
|
1709
|
+
if (!existsSync3(contentRoot) || !lstatSync3(contentRoot).isDirectory()) {
|
|
1268
1710
|
throw new Error(`Documentation directory does not exist: ${configuredDocsDir || "."}`);
|
|
1269
1711
|
}
|
|
1270
1712
|
const files = scanFiles(contentRoot);
|
|
@@ -1280,6 +1722,7 @@ function migrateRepository(options) {
|
|
|
1280
1722
|
const rightOrder = referenceOrder.get(normalizedReferenceKey(right.relativePath)) ?? Number.MAX_SAFE_INTEGER;
|
|
1281
1723
|
return leftOrder - rightOrder || left.relativePath.localeCompare(right.relativePath);
|
|
1282
1724
|
});
|
|
1725
|
+
const snippetAliases = platform === "mintlify" && mintlifyProjectRoot ? globalSnippetAliases(files, repositoryDir, mintlifyProjectRoot) : /* @__PURE__ */ new Map();
|
|
1283
1726
|
for (const file of pageFiles) {
|
|
1284
1727
|
if (!isDocumentationExtension(file.relativePath)) continue;
|
|
1285
1728
|
const sourceSegments = file.relativePath.split("/");
|
|
@@ -1288,7 +1731,7 @@ function migrateRepository(options) {
|
|
|
1288
1731
|
continue;
|
|
1289
1732
|
}
|
|
1290
1733
|
const rootFilename = !file.relativePath.includes("/") ? basename(file.relativePath).toLowerCase() : "";
|
|
1291
|
-
if (
|
|
1734
|
+
if (REPOSITORY_ONLY_DOCUMENTS.has(rootFilename) && !exactReferenceMap.has(exactReferenceKey(file.relativePath))) {
|
|
1292
1735
|
skipped++;
|
|
1293
1736
|
continue;
|
|
1294
1737
|
}
|
|
@@ -1297,21 +1740,21 @@ function migrateRepository(options) {
|
|
|
1297
1740
|
warnings.push({ code: "skipped-file", message: "Only Markdown and MDX are imported without an explicit converter.", source: file.relativePath });
|
|
1298
1741
|
continue;
|
|
1299
1742
|
}
|
|
1300
|
-
const size =
|
|
1743
|
+
const size = lstatSync3(file.absolutePath).size;
|
|
1301
1744
|
if (size > MAX_PAGE_BYTES) {
|
|
1302
1745
|
skipped++;
|
|
1303
1746
|
warnings.push({ code: "skipped-file", message: "Page exceeded the 2 MB repository import limit.", source: file.relativePath });
|
|
1304
1747
|
continue;
|
|
1305
1748
|
}
|
|
1306
1749
|
const key = normalizedReferenceKey(file.relativePath);
|
|
1307
|
-
const referenced = referenceMap.get(key);
|
|
1750
|
+
const referenced = exactReferenceMap.get(exactReferenceKey(file.relativePath)) ?? referenceMap.get(key);
|
|
1308
1751
|
let locale = referenced?.locale;
|
|
1309
|
-
let navigationId = referenced?.navigationId ?? pageIdFromReference(file.relativePath);
|
|
1752
|
+
let navigationId = referenced?.navigationId ?? pageIdFromReference(file.relativePath, platform === "mintlify");
|
|
1310
1753
|
if (!referenced && localeConfig) {
|
|
1311
1754
|
const prefix = file.relativePath.split("/", 1)[0];
|
|
1312
1755
|
if (localeConfig.locales.some((entry) => entry.code === prefix)) {
|
|
1313
1756
|
locale = prefix;
|
|
1314
|
-
navigationId = pageIdFromReference(file.relativePath.slice(prefix.length + 1));
|
|
1757
|
+
navigationId = pageIdFromReference(file.relativePath.slice(prefix.length + 1), platform === "mintlify");
|
|
1315
1758
|
}
|
|
1316
1759
|
}
|
|
1317
1760
|
if (!navigationId) {
|
|
@@ -1327,7 +1770,8 @@ function migrateRepository(options) {
|
|
|
1327
1770
|
repositoryDir,
|
|
1328
1771
|
warnings,
|
|
1329
1772
|
0,
|
|
1330
|
-
docusaurusProjectRoot ?? repositoryDir
|
|
1773
|
+
mintlifyProjectRoot ?? docusaurusProjectRoot ?? repositoryDir,
|
|
1774
|
+
snippetAliases
|
|
1331
1775
|
);
|
|
1332
1776
|
let docusaurusDescriptor;
|
|
1333
1777
|
const page = parseMarkdownPage({
|
|
@@ -1335,11 +1779,11 @@ function migrateRepository(options) {
|
|
|
1335
1779
|
navigationId,
|
|
1336
1780
|
...locale ? { locale } : {},
|
|
1337
1781
|
raw,
|
|
1338
|
-
source: `${options.sourceUrl}#${file.
|
|
1782
|
+
source: `${options.sourceUrl}#${relative3(repositoryDir, file.absolutePath).replace(/\\/g, "/")}`,
|
|
1339
1783
|
...platform === "docusaurus" ? {
|
|
1340
1784
|
resolveIdentity: (frontmatter, fallback) => {
|
|
1341
1785
|
const resolved = resolveDocusaurusPageIdentity(file.relativePath, frontmatter, fallback);
|
|
1342
|
-
const routePrefix = options.docusaurusRoutePrefix
|
|
1786
|
+
const routePrefix = options.docusaurusRoutePrefix === void 0 ? void 0 : trimEdgeSlashes(options.docusaurusRoutePrefix);
|
|
1343
1787
|
if (!routePrefix) {
|
|
1344
1788
|
docusaurusDescriptor = resolved.descriptor;
|
|
1345
1789
|
return resolved.identity;
|
|
@@ -1362,6 +1806,9 @@ function migrateRepository(options) {
|
|
|
1362
1806
|
skipped++;
|
|
1363
1807
|
continue;
|
|
1364
1808
|
}
|
|
1809
|
+
if (platform === "mintlify" && mintlifyProjectRoot) {
|
|
1810
|
+
page.body = rewriteRepositoryAssetLinks(page.body, file.absolutePath, mintlifyProjectRoot);
|
|
1811
|
+
}
|
|
1365
1812
|
if (seenPageIds.has(page.id)) {
|
|
1366
1813
|
skipped++;
|
|
1367
1814
|
warnings.push({ code: "collision", message: `Multiple source files map to ${page.id}; the first file was kept.`, source: file.relativePath });
|
|
@@ -1382,7 +1829,7 @@ function migrateRepository(options) {
|
|
|
1382
1829
|
const docusaurusAssetRoot = docusaurusProjectRoot ?? repositoryDir;
|
|
1383
1830
|
const repositoryAssets = platform === "docusaurus" && configuredDocsDir && !options.docusaurusSkipAssets ? ["static", "public"].flatMap((directory) => {
|
|
1384
1831
|
const root = resolveWithin(docusaurusAssetRoot, directory);
|
|
1385
|
-
if (!existsSync3(root) || !
|
|
1832
|
+
if (!existsSync3(root) || !lstatSync3(root).isDirectory()) return [];
|
|
1386
1833
|
return scanFiles(root).map((file) => ({
|
|
1387
1834
|
...file,
|
|
1388
1835
|
relativePath: `${directory}/${file.relativePath}`
|
|
@@ -1391,8 +1838,9 @@ function migrateRepository(options) {
|
|
|
1391
1838
|
let totalAssetBytes = 0;
|
|
1392
1839
|
for (const file of [...files, ...repositoryAssets]) {
|
|
1393
1840
|
const firstSegment = file.relativePath.split("/", 1)[0].toLowerCase();
|
|
1394
|
-
if (!
|
|
1395
|
-
|
|
1841
|
+
if (!ASSET_EXTENSIONS.has(extname3(file.relativePath).toLowerCase())) continue;
|
|
1842
|
+
if (platform !== "mintlify" && !ASSET_DIRECTORIES.has(firstSegment)) continue;
|
|
1843
|
+
const size = lstatSync3(file.absolutePath).size;
|
|
1396
1844
|
if (size > MAX_ASSET_BYTES || totalAssetBytes + size > MAX_TOTAL_ASSET_BYTES) {
|
|
1397
1845
|
warnings.push({ code: "limit-reached", message: "An asset was skipped because the migration asset budget was exhausted.", source: file.relativePath });
|
|
1398
1846
|
continue;
|
|
@@ -1430,7 +1878,7 @@ function migrateRepository(options) {
|
|
|
1430
1878
|
}
|
|
1431
1879
|
}
|
|
1432
1880
|
if (docsConfig.tabs.length === 0) docsConfig = buildNavigationFromPages(pages);
|
|
1433
|
-
const openApi = findOpenApi(files);
|
|
1881
|
+
const openApi = findConfiguredMintlifyOpenApi(mintlifyConfig, files) ?? findOpenApi(files);
|
|
1434
1882
|
if (openApi) {
|
|
1435
1883
|
const filename = basename(openApi.relativePath);
|
|
1436
1884
|
if (!assets.some((asset) => asset.path === filename)) {
|
|
@@ -1438,6 +1886,7 @@ function migrateRepository(options) {
|
|
|
1438
1886
|
}
|
|
1439
1887
|
docsConfig = injectOpenApi(docsConfig, filename);
|
|
1440
1888
|
}
|
|
1889
|
+
if (platform === "mintlify") docsConfig = addMintlifyDirectoryRedirects(docsConfig, pages);
|
|
1441
1890
|
if (platform === "docusaurus" && docusaurusProjectRoot && !options.docusaurusSkipPlugins) {
|
|
1442
1891
|
for (const plugin of additionalDocusaurusPluginRoots(repositoryDir, docusaurusProjectRoot)) {
|
|
1443
1892
|
if (plugin.docsDir === configuredDocsDir) continue;
|
|
@@ -1479,6 +1928,12 @@ function migrateRepository(options) {
|
|
|
1479
1928
|
pages,
|
|
1480
1929
|
assets,
|
|
1481
1930
|
docsConfig,
|
|
1931
|
+
...mintlifyConfig ? {
|
|
1932
|
+
site: {
|
|
1933
|
+
...typeof mintlifyConfig.name === "string" ? { name: mintlifyConfig.name } : {},
|
|
1934
|
+
...typeof mintlifyConfig.description === "string" ? { description: mintlifyConfig.description } : {}
|
|
1935
|
+
}
|
|
1936
|
+
} : {},
|
|
1482
1937
|
warnings,
|
|
1483
1938
|
stats: { discovered, imported: pages.length, skipped }
|
|
1484
1939
|
};
|
|
@@ -1492,8 +1947,13 @@ function renderPage(bundle, page) {
|
|
|
1492
1947
|
return [
|
|
1493
1948
|
"---",
|
|
1494
1949
|
`title: ${yamlString(page.title)}`,
|
|
1950
|
+
page.navTitle ? `navTitle: ${yamlString(page.navTitle)}` : null,
|
|
1495
1951
|
`description: ${yamlString(page.description)}`,
|
|
1952
|
+
page.badge ? `badge: ${yamlString(page.badge)}` : null,
|
|
1496
1953
|
page.keywords.length > 0 ? `keywords: [${page.keywords.map(yamlString).join(", ")}]` : null,
|
|
1954
|
+
page.mode ? `mode: ${yamlString(page.mode)}` : null,
|
|
1955
|
+
page.hidden ? "hidden: true" : null,
|
|
1956
|
+
page.noindex ? "noindex: true" : null,
|
|
1497
1957
|
page.openapi ? `openapi: ${yamlString(page.openapi)}` : null,
|
|
1498
1958
|
bundle.sourceKind === "url" ? `source: ${yamlString(page.source)}` : null,
|
|
1499
1959
|
"---",
|
|
@@ -1506,41 +1966,56 @@ function mergeMigrationConfig(existing, incoming) {
|
|
|
1506
1966
|
const tabs = existing.tabs.filter((tab) => tab.tab.toLowerCase() !== "changelog");
|
|
1507
1967
|
const names = new Set(tabs.map((tab) => tab.tab.toLowerCase()));
|
|
1508
1968
|
const seenPages = /* @__PURE__ */ new Set();
|
|
1509
|
-
function recordPages(
|
|
1510
|
-
for (const
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
else recordPages([page]);
|
|
1514
|
-
}
|
|
1969
|
+
function recordPages(pages = []) {
|
|
1970
|
+
for (const page of pages) {
|
|
1971
|
+
if (typeof page === "string") seenPages.add(page);
|
|
1972
|
+
else recordPages(page.pages);
|
|
1515
1973
|
}
|
|
1516
1974
|
}
|
|
1517
|
-
for (const tab of tabs)
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
return
|
|
1975
|
+
for (const tab of tabs) {
|
|
1976
|
+
recordPages(tab.pages);
|
|
1977
|
+
recordPages(tab.groups);
|
|
1978
|
+
}
|
|
1979
|
+
function uniquePages(pages = []) {
|
|
1980
|
+
return pages.flatMap((page) => {
|
|
1981
|
+
if (typeof page === "string") {
|
|
1982
|
+
if (seenPages.has(page)) return [];
|
|
1983
|
+
seenPages.add(page);
|
|
1984
|
+
return [page];
|
|
1985
|
+
}
|
|
1986
|
+
const children = uniquePages(page.pages);
|
|
1987
|
+
return children.length > 0 ? [{ ...page, pages: children }] : [];
|
|
1530
1988
|
});
|
|
1531
1989
|
}
|
|
1990
|
+
function uniqueGroups(groups) {
|
|
1991
|
+
return uniquePages(groups ?? []);
|
|
1992
|
+
}
|
|
1532
1993
|
for (const tab of incoming.tabs) {
|
|
1533
1994
|
if (tab.tab.toLowerCase() === "changelog") continue;
|
|
1534
|
-
const uniqueTab = {
|
|
1535
|
-
|
|
1995
|
+
const uniqueTab = {
|
|
1996
|
+
...tab,
|
|
1997
|
+
...tab.pages ? { pages: uniquePages(tab.pages) } : {},
|
|
1998
|
+
...tab.groups ? { groups: uniqueGroups(tab.groups) } : {}
|
|
1999
|
+
};
|
|
2000
|
+
if ((tab.pages || tab.groups) && !uniqueTab.pages?.length && !uniqueTab.groups?.length && !tab.href && !tab.api) continue;
|
|
1536
2001
|
if (!names.has(tab.tab.toLowerCase())) {
|
|
1537
2002
|
tabs.push(uniqueTab);
|
|
1538
2003
|
names.add(tab.tab.toLowerCase());
|
|
1539
2004
|
continue;
|
|
1540
2005
|
}
|
|
1541
2006
|
const target = tabs.find((item) => item.tab.toLowerCase() === tab.tab.toLowerCase());
|
|
1542
|
-
if (!target
|
|
1543
|
-
|
|
2007
|
+
if (!target) continue;
|
|
2008
|
+
const incomingRootNodes = [
|
|
2009
|
+
...uniqueTab.pages ?? [],
|
|
2010
|
+
...uniqueTab.groups ?? []
|
|
2011
|
+
];
|
|
2012
|
+
if (uniqueTab.pages?.length) {
|
|
2013
|
+
target.pages = [...target.pages ?? target.groups ?? [], ...incomingRootNodes];
|
|
2014
|
+
delete target.groups;
|
|
2015
|
+
} else if (uniqueTab.groups?.length) {
|
|
2016
|
+
if (target.pages) target.pages = [...target.pages, ...uniqueTab.groups];
|
|
2017
|
+
else target.groups = [...target.groups ?? [], ...uniqueTab.groups];
|
|
2018
|
+
}
|
|
1544
2019
|
}
|
|
1545
2020
|
const changelog = existing.tabs.find((tab) => tab.tab.toLowerCase() === "changelog") ?? incoming.tabs.find((tab) => tab.tab.toLowerCase() === "changelog");
|
|
1546
2021
|
if (changelog) tabs.push(changelog);
|
|
@@ -1554,6 +2029,9 @@ function mergeMigrationConfig(existing, incoming) {
|
|
|
1554
2029
|
...incoming,
|
|
1555
2030
|
...existing,
|
|
1556
2031
|
tabs,
|
|
2032
|
+
// Collection presentation belongs to the imported information
|
|
2033
|
+
// architecture; starter defaults must not coerce source dropdowns to tabs.
|
|
2034
|
+
navigation: incoming.navigation ?? existing.navigation,
|
|
1557
2035
|
...i18n ? { i18n } : {}
|
|
1558
2036
|
};
|
|
1559
2037
|
}
|
|
@@ -1591,10 +2069,13 @@ var PORTABLE_MDX_COMPONENTS = /* @__PURE__ */ new Set([
|
|
|
1591
2069
|
"Color",
|
|
1592
2070
|
"Column",
|
|
1593
2071
|
"Columns",
|
|
2072
|
+
"ContentPanel",
|
|
1594
2073
|
"Danger",
|
|
1595
2074
|
"Error",
|
|
1596
2075
|
"Expandable",
|
|
1597
2076
|
"Agent",
|
|
2077
|
+
"AgentPrompt",
|
|
2078
|
+
"BannerPreview",
|
|
1598
2079
|
"Embed",
|
|
1599
2080
|
"File",
|
|
1600
2081
|
"Folder",
|
|
@@ -1785,7 +2266,7 @@ function pageIdForUrl(url, scopePath) {
|
|
|
1785
2266
|
else if (path === scopePath) path = "";
|
|
1786
2267
|
else if (path.startsWith(`${scopePath}/`)) path = path.slice(scopePath.length + 1);
|
|
1787
2268
|
}
|
|
1788
|
-
return pageIdFromReference(path.replace(/^\/+/, "") || "introduction");
|
|
2269
|
+
return pageIdFromReference(path.replace(/^\/+/, "") || "introduction", true);
|
|
1789
2270
|
}
|
|
1790
2271
|
function canonicalLocalizedPageId(id) {
|
|
1791
2272
|
const [segment, ...rest] = id.split("/");
|
|
@@ -1807,6 +2288,72 @@ function detectUrlPlatform(document) {
|
|
|
1807
2288
|
if (value.includes("starlight")) return "starlight";
|
|
1808
2289
|
return "generic";
|
|
1809
2290
|
}
|
|
2291
|
+
function jsonObjectAfterKey(value, key) {
|
|
2292
|
+
let cursor = 0;
|
|
2293
|
+
const marker = `"${key}":`;
|
|
2294
|
+
while (cursor < value.length) {
|
|
2295
|
+
const markerIndex = value.indexOf(marker, cursor);
|
|
2296
|
+
if (markerIndex < 0) return null;
|
|
2297
|
+
let start = markerIndex + marker.length;
|
|
2298
|
+
while (/\s/.test(value[start] ?? "")) start += 1;
|
|
2299
|
+
if (value[start] !== "{") {
|
|
2300
|
+
cursor = start + 1;
|
|
2301
|
+
continue;
|
|
2302
|
+
}
|
|
2303
|
+
let depth = 0;
|
|
2304
|
+
let isQuoted = false;
|
|
2305
|
+
let isEscaped = false;
|
|
2306
|
+
for (let index = start; index < value.length; index += 1) {
|
|
2307
|
+
const character = value[index];
|
|
2308
|
+
if (isQuoted) {
|
|
2309
|
+
if (isEscaped) isEscaped = false;
|
|
2310
|
+
else if (character === "\\") isEscaped = true;
|
|
2311
|
+
else if (character === '"') isQuoted = false;
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2314
|
+
if (character === '"') {
|
|
2315
|
+
isQuoted = true;
|
|
2316
|
+
continue;
|
|
2317
|
+
}
|
|
2318
|
+
if (character === "{") depth += 1;
|
|
2319
|
+
if (character === "}") {
|
|
2320
|
+
depth -= 1;
|
|
2321
|
+
if (depth !== 0) continue;
|
|
2322
|
+
try {
|
|
2323
|
+
const parsed = JSON.parse(value.slice(start, index + 1));
|
|
2324
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
2325
|
+
} catch {
|
|
2326
|
+
break;
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
cursor = start + 1;
|
|
2331
|
+
}
|
|
2332
|
+
return null;
|
|
2333
|
+
}
|
|
2334
|
+
function embeddedMintlifyConfig(body) {
|
|
2335
|
+
const $ = load(body);
|
|
2336
|
+
const flightPayloads = [];
|
|
2337
|
+
$("script").each((_index, element) => {
|
|
2338
|
+
const script = $(element).text();
|
|
2339
|
+
for (const match of script.matchAll(/self\.__next_f\.push\(\[1,("(?:\\.|[^"\\])*")\]\)/g)) {
|
|
2340
|
+
try {
|
|
2341
|
+
const payload2 = JSON.parse(match[1]);
|
|
2342
|
+
if (typeof payload2 === "string") flightPayloads.push(payload2);
|
|
2343
|
+
} catch {
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
});
|
|
2347
|
+
if (flightPayloads.length === 0) return null;
|
|
2348
|
+
const payload = flightPayloads.join("\n");
|
|
2349
|
+
const docsConfig = jsonObjectAfterKey(payload, "docsConfig");
|
|
2350
|
+
const scopedNavigation = jsonObjectAfterKey(payload, "scopedNav");
|
|
2351
|
+
if (!docsConfig && !scopedNavigation) return null;
|
|
2352
|
+
return {
|
|
2353
|
+
...docsConfig ?? {},
|
|
2354
|
+
...scopedNavigation ? { navigation: scopedNavigation } : {}
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
1810
2357
|
function plainDescription(value) {
|
|
1811
2358
|
return value.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/[`*_>#-]/g, "").replace(/\s+/g, " ").trim().slice(0, 240);
|
|
1812
2359
|
}
|
|
@@ -2045,7 +2592,12 @@ function remoteMarkdownMetadata(body) {
|
|
|
2045
2592
|
return {
|
|
2046
2593
|
content: body.slice(contentStart),
|
|
2047
2594
|
title: scalar("title"),
|
|
2048
|
-
description: scalar("description")
|
|
2595
|
+
description: scalar("description"),
|
|
2596
|
+
sidebarTitle: scalar("sidebarTitle"),
|
|
2597
|
+
tag: scalar("tag"),
|
|
2598
|
+
mode: scalar("mode"),
|
|
2599
|
+
hidden: scalar("hidden") === "true" ? true : void 0,
|
|
2600
|
+
noindex: scalar("noindex") === "true" ? true : void 0
|
|
2049
2601
|
};
|
|
2050
2602
|
}
|
|
2051
2603
|
function stripMintlifyDocumentationIndex(body) {
|
|
@@ -2105,6 +2657,11 @@ function markdownPage(document, id) {
|
|
|
2105
2657
|
"---",
|
|
2106
2658
|
`title: ${JSON.stringify(title)}`,
|
|
2107
2659
|
...description ? [`description: ${JSON.stringify(description)}`] : [],
|
|
2660
|
+
...parsed.sidebarTitle ? [`sidebarTitle: ${JSON.stringify(parsed.sidebarTitle)}`] : [],
|
|
2661
|
+
...parsed.tag ? [`tag: ${JSON.stringify(parsed.tag)}`] : [],
|
|
2662
|
+
...parsed.mode ? [`mode: ${JSON.stringify(parsed.mode)}`] : [],
|
|
2663
|
+
...parsed.hidden ? ["hidden: true"] : [],
|
|
2664
|
+
...parsed.noindex ? ["noindex: true"] : [],
|
|
2108
2665
|
...embeddedOpenApi.openapi ? [`openapi: ${JSON.stringify(embeddedOpenApi.openapi)}`] : [],
|
|
2109
2666
|
"---",
|
|
2110
2667
|
"",
|
|
@@ -2487,7 +3044,7 @@ function htmlTopLevelNavigation(document, source, scopePath) {
|
|
|
2487
3044
|
const collectCandidates = (selector) => {
|
|
2488
3045
|
const candidates2 = [];
|
|
2489
3046
|
$(selector).each((_containerIndex, container) => {
|
|
2490
|
-
const
|
|
3047
|
+
const entries2 = [];
|
|
2491
3048
|
const seenSections = /* @__PURE__ */ new Set();
|
|
2492
3049
|
let anchorCount = 0;
|
|
2493
3050
|
$(container).find("a[href]").each((_index, element) => {
|
|
@@ -2503,22 +3060,42 @@ function htmlTopLevelNavigation(document, source, scopePath) {
|
|
|
2503
3060
|
const section = targetId.split("/", 1)[0] || "introduction";
|
|
2504
3061
|
if (!pageId || seenSections.has(section)) return;
|
|
2505
3062
|
seenSections.add(section);
|
|
2506
|
-
|
|
3063
|
+
entries2.push({ section, label, pageId });
|
|
2507
3064
|
} catch {
|
|
2508
3065
|
}
|
|
2509
3066
|
});
|
|
2510
|
-
if (
|
|
2511
|
-
candidates2.push({ entries, anchorCount });
|
|
3067
|
+
if (entries2.length > 1) {
|
|
3068
|
+
candidates2.push({ entries: entries2, anchorCount });
|
|
2512
3069
|
}
|
|
2513
3070
|
});
|
|
2514
3071
|
return candidates2;
|
|
2515
3072
|
};
|
|
2516
3073
|
const tabCandidates = collectCandidates(".nav-tabs");
|
|
2517
3074
|
const candidates = tabCandidates.length > 0 ? tabCandidates : collectCandidates('nav, [role="navigation"]');
|
|
2518
|
-
|
|
3075
|
+
const entries = candidates.sort((left, right) => {
|
|
2519
3076
|
const densityDifference = right.entries.length / right.anchorCount - left.entries.length / left.anchorCount;
|
|
2520
3077
|
return densityDifference || right.entries.length - left.entries.length;
|
|
2521
3078
|
})[0]?.entries ?? [];
|
|
3079
|
+
const normalizedLabels = entries.map((entry) => entry.label.trim().toLowerCase());
|
|
3080
|
+
if (entries.length > 12 || new Set(normalizedLabels).size !== normalizedLabels.length) return [];
|
|
3081
|
+
return entries;
|
|
3082
|
+
}
|
|
3083
|
+
function remapNavigationHome(config, sourceHomePageId) {
|
|
3084
|
+
if (!sourceHomePageId || sourceHomePageId === "introduction") return config;
|
|
3085
|
+
const remapPages = (pages) => pages.map((page) => typeof page === "string" ? page === sourceHomePageId ? "introduction" : page : { ...page, pages: remapPages(page.pages) });
|
|
3086
|
+
const remapGroups = (groups) => groups.map((group) => ({
|
|
3087
|
+
...group,
|
|
3088
|
+
pages: remapPages(group.pages)
|
|
3089
|
+
}));
|
|
3090
|
+
return {
|
|
3091
|
+
...config,
|
|
3092
|
+
tabs: config.tabs.map((tab) => ({
|
|
3093
|
+
...tab,
|
|
3094
|
+
...tab.href === `/${sourceHomePageId}` ? { href: "/" } : {},
|
|
3095
|
+
...tab.pages ? { pages: remapPages(tab.pages) } : {},
|
|
3096
|
+
...tab.groups ? { groups: remapGroups(tab.groups) } : {}
|
|
3097
|
+
}))
|
|
3098
|
+
};
|
|
2522
3099
|
}
|
|
2523
3100
|
function markdownLinks(body) {
|
|
2524
3101
|
return [...body.matchAll(/\[[^\]]+\]\(([^)\s]+)(?:\s+['"][^'"]*['"])?\)/g)].map((match) => match[1]);
|
|
@@ -2583,8 +3160,13 @@ async function migrateUrl(options) {
|
|
|
2583
3160
|
}
|
|
2584
3161
|
const docusaurusDiscovery = platform === "docusaurus" && docusaurusHtmlProbe ? deriveDocusaurusScope(source, docusaurusHtmlProbe, submittedScopePath) : null;
|
|
2585
3162
|
const scopePath = platform === "mintlify" ? machineIndexScopePath(source, [initial, scopedHtmlProbe]) ?? submittedScopePath : docusaurusDiscovery?.scopePath ?? submittedScopePath;
|
|
2586
|
-
const
|
|
2587
|
-
const
|
|
3163
|
+
const sourceMintlifyConfig = platform === "mintlify" && scopedHtmlProbe && /html/i.test(scopedHtmlProbe.contentType) ? embeddedMintlifyConfig(scopedHtmlProbe.body) : null;
|
|
3164
|
+
const sourceMintlifyProjection = sourceMintlifyConfig ? projectMintlifyNavigation(sourceMintlifyConfig, { pathPrefix: scopePath }) : null;
|
|
3165
|
+
const hasStructuredMintlifyNavigation = Boolean(
|
|
3166
|
+
sourceMintlifyProjection?.docsConfig.tabs.length && sourceMintlifyProjection.pageReferences.length
|
|
3167
|
+
);
|
|
3168
|
+
const sourceTopLevelNavigation = platform === "mintlify" && !hasStructuredMintlifyNavigation && scopedHtmlProbe && /html/i.test(scopedHtmlProbe.contentType) ? htmlTopLevelNavigation(scopedHtmlProbe, source, scopePath) : void 0;
|
|
3169
|
+
const sourceHomePageId = sourceMintlifyProjection?.pageReferences[0]?.navigationId ?? sourceTopLevelNavigation?.[0]?.pageId ?? (platform === "mintlify" && scopePath === "/" ? canonicalLocalizedPageId(pageIdForUrl(source, scopePath) ?? "") || void 0 : void 0);
|
|
2588
3170
|
const cache = /* @__PURE__ */ new Map([[source.toString(), initial]]);
|
|
2589
3171
|
if (docusaurusHtmlProbe) cache.set(docusaurusHtmlProbe.finalUrl.toString(), docusaurusHtmlProbe);
|
|
2590
3172
|
const queue = [source];
|
|
@@ -2605,6 +3187,13 @@ async function migrateUrl(options) {
|
|
|
2605
3187
|
queued.add(candidateIdentity(url));
|
|
2606
3188
|
queue.push(url);
|
|
2607
3189
|
}
|
|
3190
|
+
for (const reference of sourceMintlifyProjection?.pageReferences ?? []) {
|
|
3191
|
+
let href = reference.ref;
|
|
3192
|
+
if (scopePath !== "/" && href.startsWith("/") && href !== scopePath && !href.startsWith(`${scopePath}/`)) {
|
|
3193
|
+
href = `${scopePath}${href}`;
|
|
3194
|
+
}
|
|
3195
|
+
enqueue(href, source);
|
|
3196
|
+
}
|
|
2608
3197
|
const navigationProbe = docusaurusHtmlProbe ?? scopedHtmlProbe;
|
|
2609
3198
|
if (navigationProbe && /html/i.test(navigationProbe.contentType)) {
|
|
2610
3199
|
for (const link of htmlNavigationLinks(navigationProbe)) enqueue(link, navigationProbe.finalUrl);
|
|
@@ -2808,10 +3397,11 @@ async function migrateUrl(options) {
|
|
|
2808
3397
|
...entry,
|
|
2809
3398
|
pageId: entry.pageId === sourceHomePageId ? "introduction" : entry.pageId
|
|
2810
3399
|
}));
|
|
2811
|
-
|
|
3400
|
+
let docsConfig = platform === "docusaurus" ? docusaurusNavigationFromSnapshots(docusaurusSidebars, pages, scopePath) : hasStructuredMintlifyNavigation && sourceMintlifyProjection ? remapNavigationHome(sourceMintlifyProjection.docsConfig, sourceHomePageId) : buildNavigationFromPages(pages, {
|
|
2812
3401
|
topLevelTabs: platform === "mintlify",
|
|
2813
3402
|
topLevelNavigation
|
|
2814
3403
|
});
|
|
3404
|
+
if (sourceMintlifyProjection) warnings.push(...sourceMintlifyProjection.warnings);
|
|
2815
3405
|
if (docusaurusRedirects.length > 0) {
|
|
2816
3406
|
docsConfig.redirects = [...new Map(docusaurusRedirects.map((redirect) => [
|
|
2817
3407
|
`${redirect.source}:${redirect.destination}`,
|
|
@@ -2821,12 +3411,8 @@ async function migrateUrl(options) {
|
|
|
2821
3411
|
const openApiAsset = mergeEmbeddedOpenApi(openApiFragments);
|
|
2822
3412
|
if (openApiAsset) {
|
|
2823
3413
|
const operationPageIds = new Set(pages.filter((page) => page.openapi).map((page) => page.navigationId));
|
|
2824
|
-
const
|
|
2825
|
-
|
|
2826
|
-
return typeof page === "string" ? operationPageIds.has(page) : containsOperation(page.pages);
|
|
2827
|
-
});
|
|
2828
|
-
return containsOperation(group.pages);
|
|
2829
|
-
})) ?? docsConfig.tabs[0];
|
|
3414
|
+
const containsOperation = (navigationPages = []) => navigationPages.some((page) => typeof page === "string" ? operationPageIds.has(page) : containsOperation(page.pages));
|
|
3415
|
+
const apiTab = docsConfig.tabs.find((tab) => containsOperation(tab.pages) || containsOperation(tab.groups)) ?? docsConfig.tabs[0];
|
|
2830
3416
|
if (apiTab) {
|
|
2831
3417
|
apiTab.api = { source: "/openapi.yaml", navigation: false };
|
|
2832
3418
|
}
|
|
@@ -2841,6 +3427,7 @@ async function migrateUrl(options) {
|
|
|
2841
3427
|
]
|
|
2842
3428
|
};
|
|
2843
3429
|
}
|
|
3430
|
+
if (platform === "mintlify") docsConfig = addMintlifyDirectoryRedirects(docsConfig, pages);
|
|
2844
3431
|
return {
|
|
2845
3432
|
sourceUrl: source.toString(),
|
|
2846
3433
|
sourceKind: "url",
|
|
@@ -2848,6 +3435,12 @@ async function migrateUrl(options) {
|
|
|
2848
3435
|
pages,
|
|
2849
3436
|
assets: openApiAsset ? [{ path: "openapi.yaml", content: openApiAsset }] : [],
|
|
2850
3437
|
docsConfig,
|
|
3438
|
+
...sourceMintlifyConfig ? {
|
|
3439
|
+
site: {
|
|
3440
|
+
...typeof sourceMintlifyConfig.name === "string" ? { name: sourceMintlifyConfig.name } : {},
|
|
3441
|
+
...typeof sourceMintlifyConfig.description === "string" ? { description: sourceMintlifyConfig.description } : {}
|
|
3442
|
+
}
|
|
3443
|
+
} : {},
|
|
2851
3444
|
warnings,
|
|
2852
3445
|
stats: {
|
|
2853
3446
|
discovered: visited.size,
|
|
@@ -2857,6 +3450,7 @@ async function migrateUrl(options) {
|
|
|
2857
3450
|
};
|
|
2858
3451
|
}
|
|
2859
3452
|
export {
|
|
3453
|
+
addMintlifyDirectoryRedirects,
|
|
2860
3454
|
buildNavigationFromPages,
|
|
2861
3455
|
cloneGitHubRepository,
|
|
2862
3456
|
defaultMigrationFetcher,
|