@thallylabs/migrate 0.2.2 → 0.2.4
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 +7 -6
- package/dist/index.d.ts +8 -0
- package/dist/index.js +138 -72
- package/dist/index.js.map +1 -1
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -5,12 +5,13 @@ Cloud. It imports documentation repositories and public documentation URLs
|
|
|
5
5
|
into one canonical bundle before any caller writes files.
|
|
6
6
|
|
|
7
7
|
Repository migration includes dedicated Mintlify and Docusaurus adapters.
|
|
8
|
-
Mintlify repositories are located inside monorepos automatically
|
|
9
|
-
`docs.json`/`mint.json`
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
Mintlify repositories are located inside monorepos automatically. Their
|
|
9
|
+
`docs.json`/`mint.json` page and group trees are projected without flattening
|
|
10
|
+
authored nesting or order. The adapter supports tabs, dropdowns, products,
|
|
11
|
+
versions, languages, and reusable `$ref` navigation files; it also preserves
|
|
12
|
+
dropdown presentation, collection descriptions and icons, explicit default
|
|
13
|
+
versions, page route casing, redirects, local snippets, static assets,
|
|
14
|
+
compatible page frontmatter, site identity, and OpenAPI configuration. For public Mintlify
|
|
14
15
|
sites, the URL adapter reads the structured configuration embedded in the
|
|
15
16
|
rendered application before falling back to DOM link inference.
|
|
16
17
|
|
package/dist/index.d.ts
CHANGED
|
@@ -12,8 +12,12 @@ interface MigrationNavigationGroup {
|
|
|
12
12
|
}
|
|
13
13
|
interface MigrationNavigationTab {
|
|
14
14
|
tab: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
icon?: string;
|
|
15
17
|
href?: string;
|
|
16
18
|
hidden?: boolean;
|
|
19
|
+
/** Root page/group nodes used when the source has no synthetic section heading. */
|
|
20
|
+
pages?: Array<string | MigrationNavigationGroup>;
|
|
17
21
|
groups?: Array<MigrationNavigationGroup>;
|
|
18
22
|
api?: {
|
|
19
23
|
source: string;
|
|
@@ -54,6 +58,10 @@ interface MigrationFooterConfig {
|
|
|
54
58
|
}
|
|
55
59
|
interface MigrationDocsConfig {
|
|
56
60
|
tabs: Array<MigrationNavigationTab>;
|
|
61
|
+
navigation?: {
|
|
62
|
+
/** How sibling documentation collections are presented to readers. */
|
|
63
|
+
display?: 'tabs' | 'dropdown';
|
|
64
|
+
};
|
|
57
65
|
theme?: 'default' | 'maple' | 'sharp' | 'minimal';
|
|
58
66
|
banner?: MigrationBannerConfig;
|
|
59
67
|
navbar?: MigrationNavbarConfig;
|
package/dist/index.js
CHANGED
|
@@ -534,15 +534,26 @@ function projectDocusaurusNavigation(input) {
|
|
|
534
534
|
}
|
|
535
535
|
|
|
536
536
|
// src/frontmatter.ts
|
|
537
|
-
import
|
|
538
|
-
var FRONTMATTER_OPTIONS = {
|
|
539
|
-
engines: {
|
|
540
|
-
javascript: () => ({}),
|
|
541
|
-
js: () => ({})
|
|
542
|
-
}
|
|
543
|
-
};
|
|
537
|
+
import { parse as parseYaml2 } from "yaml";
|
|
544
538
|
function parseFrontmatter(raw) {
|
|
545
|
-
|
|
539
|
+
const source = raw.charCodeAt(0) === 65279 ? raw.slice(1) : raw;
|
|
540
|
+
const opening = /^---([^\r\n]*)\r?\n/.exec(source);
|
|
541
|
+
if (!opening || opening[1].startsWith("-")) return { content: source, data: {} };
|
|
542
|
+
const language = opening[1].trim().toLowerCase();
|
|
543
|
+
const remainder = source.slice(opening[0].length);
|
|
544
|
+
const closing = /^---[ \t]*\r?$/m.exec(remainder);
|
|
545
|
+
const matter = closing ? remainder.slice(0, closing.index) : remainder;
|
|
546
|
+
let content = closing ? remainder.slice(closing.index + closing[0].length) : "";
|
|
547
|
+
if (content.startsWith("\r\n")) content = content.slice(2);
|
|
548
|
+
else if (content.startsWith("\n")) content = content.slice(1);
|
|
549
|
+
if (matter.trim() === "" || !["", "yaml", "yml"].includes(language)) {
|
|
550
|
+
return { content, data: {} };
|
|
551
|
+
}
|
|
552
|
+
const parsed = parseYaml2(matter);
|
|
553
|
+
return {
|
|
554
|
+
content,
|
|
555
|
+
data: parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {}
|
|
556
|
+
};
|
|
546
557
|
}
|
|
547
558
|
|
|
548
559
|
// src/mdx.ts
|
|
@@ -776,6 +787,12 @@ function iconName(value) {
|
|
|
776
787
|
const icon = objectValue2(value);
|
|
777
788
|
return typeof icon?.name === "string" && icon.name ? icon.name : void 0;
|
|
778
789
|
}
|
|
790
|
+
function containerPresentation(value) {
|
|
791
|
+
return {
|
|
792
|
+
...typeof value.description === "string" && value.description.trim() ? { description: value.description.trim() } : {},
|
|
793
|
+
...iconName(value.icon) ? { icon: iconName(value.icon) } : {}
|
|
794
|
+
};
|
|
795
|
+
}
|
|
779
796
|
function registerReference(value, context) {
|
|
780
797
|
const localePrefix = context.locale ? `${context.locale}/` : "";
|
|
781
798
|
const localizedValue = localePrefix && value.replace(/^\/+/, "").startsWith(localePrefix) ? value.replace(/^\/+/, "").slice(localePrefix.length) : value;
|
|
@@ -825,56 +842,76 @@ function convertPage(value, context) {
|
|
|
825
842
|
}
|
|
826
843
|
return null;
|
|
827
844
|
}
|
|
828
|
-
function
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
if (!converted) continue;
|
|
834
|
-
if (typeof converted === "string") loosePages.push(converted);
|
|
835
|
-
else groups.push(converted);
|
|
836
|
-
}
|
|
837
|
-
if (loosePages.length > 0) groups.unshift({ group: fallbackGroup, pages: loosePages });
|
|
838
|
-
return groups;
|
|
845
|
+
function convertNavigationValues(values, context) {
|
|
846
|
+
return values.flatMap((value) => {
|
|
847
|
+
const page = convertPage(value, context);
|
|
848
|
+
return page ? [page] : [];
|
|
849
|
+
});
|
|
839
850
|
}
|
|
840
|
-
function convertContainerToTabs(containerValue, context, fallbackTab) {
|
|
851
|
+
function convertContainerToTabs(containerValue, context, fallbackTab, trace, depth = 0) {
|
|
841
852
|
const container = objectValue2(containerValue);
|
|
842
853
|
if (!container) return [];
|
|
843
|
-
|
|
854
|
+
const containerKeys = ["tabs", "anchors", "products", "dropdowns", "versions", "menus"];
|
|
855
|
+
for (const key of containerKeys) {
|
|
844
856
|
if (!Array.isArray(container[key])) continue;
|
|
845
|
-
const
|
|
857
|
+
const entries = [...container[key]];
|
|
858
|
+
if (key === "versions") {
|
|
859
|
+
entries.sort((left, right) => Number(objectValue2(right)?.default === true) - Number(objectValue2(left)?.default === true));
|
|
860
|
+
}
|
|
861
|
+
const tabs = entries.flatMap((value, index) => {
|
|
846
862
|
const object = objectValue2(value);
|
|
847
863
|
if (!object) return [];
|
|
848
864
|
const tab = labelFor(object, `${fallbackTab} ${index + 1}`);
|
|
849
865
|
const href = projectedHref(object.href);
|
|
850
|
-
|
|
851
|
-
|
|
866
|
+
const hasNestedContainers = containerKeys.some((containerKey) => Array.isArray(object[containerKey]));
|
|
867
|
+
if (href && !object.pages && !object.groups && !hasNestedContainers) {
|
|
868
|
+
return [{
|
|
869
|
+
tab,
|
|
870
|
+
href,
|
|
871
|
+
...containerPresentation(object),
|
|
872
|
+
...object.hidden === true ? { hidden: true } : {}
|
|
873
|
+
}];
|
|
852
874
|
}
|
|
853
|
-
const nested = convertContainerToTabs(object, context, tab);
|
|
875
|
+
const nested = convertContainerToTabs(object, context, tab, trace, depth + 1);
|
|
854
876
|
if (nested.length > 0) {
|
|
855
877
|
if (nested.length === 1) {
|
|
856
878
|
return [{
|
|
857
879
|
...nested[0],
|
|
858
880
|
tab,
|
|
881
|
+
...containerPresentation(object),
|
|
859
882
|
...href ? { href } : {},
|
|
860
883
|
...object.hidden === true ? { hidden: true } : {}
|
|
861
884
|
}];
|
|
862
885
|
}
|
|
863
|
-
|
|
886
|
+
const presentation = containerPresentation(object);
|
|
887
|
+
return nested.map((item, childIndex) => ({
|
|
888
|
+
...presentation,
|
|
889
|
+
...item,
|
|
890
|
+
tab: `${tab}: ${item.tab}`,
|
|
891
|
+
...childIndex === 0 && href && !item.href ? { href } : {},
|
|
892
|
+
...object.hidden === true ? { hidden: true } : {}
|
|
893
|
+
}));
|
|
864
894
|
}
|
|
865
895
|
return [];
|
|
866
896
|
});
|
|
867
|
-
if (tabs.length > 0)
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
897
|
+
if (tabs.length > 0) {
|
|
898
|
+
if (depth === 0 && trace) trace.rootContainerKind = key;
|
|
899
|
+
return tabs;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
const rawGroups = Array.isArray(container.groups) ? container.groups : [];
|
|
903
|
+
const rawPages = Array.isArray(container.pages) ? container.pages : [];
|
|
904
|
+
const hasRootNodes = typeof container.root === "string" || rawPages.length > 0;
|
|
905
|
+
const values = [
|
|
906
|
+
...typeof container.root === "string" ? [container.root] : [],
|
|
907
|
+
...rawGroups,
|
|
908
|
+
...rawPages
|
|
872
909
|
];
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
return groups.length > 0 ? [{
|
|
910
|
+
const children = convertNavigationValues(values, context);
|
|
911
|
+
return children.length > 0 ? [{
|
|
876
912
|
tab: fallbackTab,
|
|
877
|
-
groups,
|
|
913
|
+
...hasRootNodes ? { pages: children } : { groups: children },
|
|
914
|
+
...containerPresentation(container),
|
|
878
915
|
...projectedHref(container.href) ? { href: projectedHref(container.href) } : {},
|
|
879
916
|
...container.hidden === true ? { hidden: true } : {}
|
|
880
917
|
}] : [];
|
|
@@ -1003,9 +1040,10 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
1003
1040
|
const languages = Array.isArray(navigation.languages) ? navigation.languages.map(objectValue2).filter((value) => Boolean(value)) : [];
|
|
1004
1041
|
let tabs = [];
|
|
1005
1042
|
let i18n;
|
|
1043
|
+
const projectionTrace = {};
|
|
1006
1044
|
if (languages.length > 0) {
|
|
1007
1045
|
const defaultLanguage = languages.find((entry) => entry.default === true) ?? languages[0];
|
|
1008
|
-
const defaultLocale = String(defaultLanguage.language ?? "en");
|
|
1046
|
+
const defaultLocale = String(defaultLanguage.language ?? defaultLanguage.locale ?? "en");
|
|
1009
1047
|
const locales = languages.map((entry) => {
|
|
1010
1048
|
const code = String(entry.language ?? entry.locale ?? "en");
|
|
1011
1049
|
let label = LANGUAGE_LABELS[code];
|
|
@@ -1026,15 +1064,26 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
1026
1064
|
warnings,
|
|
1027
1065
|
warningKeys
|
|
1028
1066
|
};
|
|
1029
|
-
const languageTabs = convertContainerToTabs(
|
|
1067
|
+
const languageTabs = convertContainerToTabs(
|
|
1068
|
+
language,
|
|
1069
|
+
context,
|
|
1070
|
+
"Documentation",
|
|
1071
|
+
language === defaultLanguage ? projectionTrace : void 0
|
|
1072
|
+
);
|
|
1030
1073
|
if (language === defaultLanguage) tabs = languageTabs;
|
|
1031
1074
|
}
|
|
1032
1075
|
} else {
|
|
1033
1076
|
const context = { references, seenReferences, warnings, warningKeys, pathPrefix: options.pathPrefix };
|
|
1034
|
-
tabs = convertContainerToTabs(navigation, context, "Documentation");
|
|
1077
|
+
tabs = convertContainerToTabs(navigation, context, "Documentation", projectionTrace);
|
|
1035
1078
|
if (tabs.length === 0 && Array.isArray(config.navigation)) {
|
|
1036
|
-
const
|
|
1037
|
-
if (
|
|
1079
|
+
const children = convertNavigationValues(config.navigation, context);
|
|
1080
|
+
if (children.length > 0) {
|
|
1081
|
+
const hasRootPages = children.some((page) => typeof page === "string");
|
|
1082
|
+
tabs = [{
|
|
1083
|
+
tab: "Documentation",
|
|
1084
|
+
...hasRootPages ? { pages: children } : { groups: children }
|
|
1085
|
+
}];
|
|
1086
|
+
}
|
|
1038
1087
|
}
|
|
1039
1088
|
}
|
|
1040
1089
|
if (tabs.length === 0) {
|
|
@@ -1058,6 +1107,7 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
1058
1107
|
return {
|
|
1059
1108
|
docsConfig: {
|
|
1060
1109
|
tabs,
|
|
1110
|
+
...projectionTrace.rootContainerKind === "dropdowns" ? { navigation: { display: "dropdown" } } : {},
|
|
1061
1111
|
...projectedCompatibleConfig(config),
|
|
1062
1112
|
...i18n ? { i18n } : {},
|
|
1063
1113
|
...redirects.length > 0 ? { redirects } : {}
|
|
@@ -1927,41 +1977,56 @@ function mergeMigrationConfig(existing, incoming) {
|
|
|
1927
1977
|
const tabs = existing.tabs.filter((tab) => tab.tab.toLowerCase() !== "changelog");
|
|
1928
1978
|
const names = new Set(tabs.map((tab) => tab.tab.toLowerCase()));
|
|
1929
1979
|
const seenPages = /* @__PURE__ */ new Set();
|
|
1930
|
-
function recordPages(
|
|
1931
|
-
for (const
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
else recordPages([page]);
|
|
1935
|
-
}
|
|
1980
|
+
function recordPages(pages = []) {
|
|
1981
|
+
for (const page of pages) {
|
|
1982
|
+
if (typeof page === "string") seenPages.add(page);
|
|
1983
|
+
else recordPages(page.pages);
|
|
1936
1984
|
}
|
|
1937
1985
|
}
|
|
1938
|
-
for (const tab of tabs)
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
return
|
|
1986
|
+
for (const tab of tabs) {
|
|
1987
|
+
recordPages(tab.pages);
|
|
1988
|
+
recordPages(tab.groups);
|
|
1989
|
+
}
|
|
1990
|
+
function uniquePages(pages = []) {
|
|
1991
|
+
return pages.flatMap((page) => {
|
|
1992
|
+
if (typeof page === "string") {
|
|
1993
|
+
if (seenPages.has(page)) return [];
|
|
1994
|
+
seenPages.add(page);
|
|
1995
|
+
return [page];
|
|
1996
|
+
}
|
|
1997
|
+
const children = uniquePages(page.pages);
|
|
1998
|
+
return children.length > 0 ? [{ ...page, pages: children }] : [];
|
|
1951
1999
|
});
|
|
1952
2000
|
}
|
|
2001
|
+
function uniqueGroups(groups) {
|
|
2002
|
+
return uniquePages(groups ?? []);
|
|
2003
|
+
}
|
|
1953
2004
|
for (const tab of incoming.tabs) {
|
|
1954
2005
|
if (tab.tab.toLowerCase() === "changelog") continue;
|
|
1955
|
-
const uniqueTab = {
|
|
1956
|
-
|
|
2006
|
+
const uniqueTab = {
|
|
2007
|
+
...tab,
|
|
2008
|
+
...tab.pages ? { pages: uniquePages(tab.pages) } : {},
|
|
2009
|
+
...tab.groups ? { groups: uniqueGroups(tab.groups) } : {}
|
|
2010
|
+
};
|
|
2011
|
+
if ((tab.pages || tab.groups) && !uniqueTab.pages?.length && !uniqueTab.groups?.length && !tab.href && !tab.api) continue;
|
|
1957
2012
|
if (!names.has(tab.tab.toLowerCase())) {
|
|
1958
2013
|
tabs.push(uniqueTab);
|
|
1959
2014
|
names.add(tab.tab.toLowerCase());
|
|
1960
2015
|
continue;
|
|
1961
2016
|
}
|
|
1962
2017
|
const target = tabs.find((item) => item.tab.toLowerCase() === tab.tab.toLowerCase());
|
|
1963
|
-
if (!target
|
|
1964
|
-
|
|
2018
|
+
if (!target) continue;
|
|
2019
|
+
const incomingRootNodes = [
|
|
2020
|
+
...uniqueTab.pages ?? [],
|
|
2021
|
+
...uniqueTab.groups ?? []
|
|
2022
|
+
];
|
|
2023
|
+
if (uniqueTab.pages?.length) {
|
|
2024
|
+
target.pages = [...target.pages ?? target.groups ?? [], ...incomingRootNodes];
|
|
2025
|
+
delete target.groups;
|
|
2026
|
+
} else if (uniqueTab.groups?.length) {
|
|
2027
|
+
if (target.pages) target.pages = [...target.pages, ...uniqueTab.groups];
|
|
2028
|
+
else target.groups = [...target.groups ?? [], ...uniqueTab.groups];
|
|
2029
|
+
}
|
|
1965
2030
|
}
|
|
1966
2031
|
const changelog = existing.tabs.find((tab) => tab.tab.toLowerCase() === "changelog") ?? incoming.tabs.find((tab) => tab.tab.toLowerCase() === "changelog");
|
|
1967
2032
|
if (changelog) tabs.push(changelog);
|
|
@@ -1975,6 +2040,9 @@ function mergeMigrationConfig(existing, incoming) {
|
|
|
1975
2040
|
...incoming,
|
|
1976
2041
|
...existing,
|
|
1977
2042
|
tabs,
|
|
2043
|
+
// Collection presentation belongs to the imported information
|
|
2044
|
+
// architecture; starter defaults must not coerce source dropdowns to tabs.
|
|
2045
|
+
navigation: incoming.navigation ?? existing.navigation,
|
|
1978
2046
|
...i18n ? { i18n } : {}
|
|
1979
2047
|
};
|
|
1980
2048
|
}
|
|
@@ -1994,7 +2062,7 @@ function renderMigrationFiles(bundle, options = {}) {
|
|
|
1994
2062
|
// src/url.ts
|
|
1995
2063
|
import { load } from "cheerio";
|
|
1996
2064
|
import TurndownService from "turndown";
|
|
1997
|
-
import { parse as
|
|
2065
|
+
import { parse as parseYaml3, stringify as stringifyYaml } from "yaml";
|
|
1998
2066
|
var DEFAULT_MAX_PAGES = 1e3;
|
|
1999
2067
|
var DEFAULT_MAX_TOTAL_BYTES = 1e8;
|
|
2000
2068
|
var MAX_DISCOVERED_URLS = 5e3;
|
|
@@ -2556,7 +2624,7 @@ function extractEmbeddedOpenApi(content) {
|
|
|
2556
2624
|
const match = fencePattern.exec(content);
|
|
2557
2625
|
if (!match) return { content };
|
|
2558
2626
|
try {
|
|
2559
|
-
const parsed =
|
|
2627
|
+
const parsed = parseYaml3(match[5], { maxAliasCount: 50 });
|
|
2560
2628
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return { content };
|
|
2561
2629
|
const document = parsed;
|
|
2562
2630
|
if (typeof document.openapi !== "string" && typeof document.swagger !== "string") return { content };
|
|
@@ -3025,15 +3093,17 @@ function htmlTopLevelNavigation(document, source, scopePath) {
|
|
|
3025
3093
|
}
|
|
3026
3094
|
function remapNavigationHome(config, sourceHomePageId) {
|
|
3027
3095
|
if (!sourceHomePageId || sourceHomePageId === "introduction") return config;
|
|
3096
|
+
const remapPages = (pages) => pages.map((page) => typeof page === "string" ? page === sourceHomePageId ? "introduction" : page : { ...page, pages: remapPages(page.pages) });
|
|
3028
3097
|
const remapGroups = (groups) => groups.map((group) => ({
|
|
3029
3098
|
...group,
|
|
3030
|
-
pages: group.pages
|
|
3099
|
+
pages: remapPages(group.pages)
|
|
3031
3100
|
}));
|
|
3032
3101
|
return {
|
|
3033
3102
|
...config,
|
|
3034
3103
|
tabs: config.tabs.map((tab) => ({
|
|
3035
3104
|
...tab,
|
|
3036
3105
|
...tab.href === `/${sourceHomePageId}` ? { href: "/" } : {},
|
|
3106
|
+
...tab.pages ? { pages: remapPages(tab.pages) } : {},
|
|
3037
3107
|
...tab.groups ? { groups: remapGroups(tab.groups) } : {}
|
|
3038
3108
|
}))
|
|
3039
3109
|
};
|
|
@@ -3352,12 +3422,8 @@ async function migrateUrl(options) {
|
|
|
3352
3422
|
const openApiAsset = mergeEmbeddedOpenApi(openApiFragments);
|
|
3353
3423
|
if (openApiAsset) {
|
|
3354
3424
|
const operationPageIds = new Set(pages.filter((page) => page.openapi).map((page) => page.navigationId));
|
|
3355
|
-
const
|
|
3356
|
-
|
|
3357
|
-
return typeof page === "string" ? operationPageIds.has(page) : containsOperation(page.pages);
|
|
3358
|
-
});
|
|
3359
|
-
return containsOperation(group.pages);
|
|
3360
|
-
})) ?? docsConfig.tabs[0];
|
|
3425
|
+
const containsOperation = (navigationPages = []) => navigationPages.some((page) => typeof page === "string" ? operationPageIds.has(page) : containsOperation(page.pages));
|
|
3426
|
+
const apiTab = docsConfig.tabs.find((tab) => containsOperation(tab.pages) || containsOperation(tab.groups)) ?? docsConfig.tabs[0];
|
|
3361
3427
|
if (apiTab) {
|
|
3362
3428
|
apiTab.api = { source: "/openapi.yaml", navigation: false };
|
|
3363
3429
|
}
|