@thallylabs/migrate 0.2.46 → 0.2.48
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 +99 -7
- package/dist/index.d.ts +4 -2
- package/dist/index.js +654 -136
- package/dist/index.js.map +1 -1
- package/dist/url-migration.d.ts +2 -2
- package/dist/url-migration.js +137 -19
- package/dist/url-migration.js.map +1 -1
- package/dist/{url-run-D-E4dr2h.d.ts → url-run-0BYlnvvB.d.ts} +6 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -419,7 +419,7 @@ function analyzeUnit(index, source, reactGlobals) {
|
|
|
419
419
|
const statement = sf.statements[0];
|
|
420
420
|
const blockers = [];
|
|
421
421
|
if (!statement || sf.statements.length !== 1) {
|
|
422
|
-
return { index, source, names: [], refs: [], assigned: [], hooks: false, clientOnly: false, componentLike: false, blockers: ["is not a single declaration"] };
|
|
422
|
+
return { index, source, names: [], refs: [], assigned: [], hooks: false, clientOnly: false, handlers: false, componentLike: false, blockers: ["is not a single declaration"] };
|
|
423
423
|
}
|
|
424
424
|
const { names, componentLike, defaultExport } = declaredNames(statement);
|
|
425
425
|
if (defaultExport) blockers.push("is a default export");
|
|
@@ -447,6 +447,7 @@ function analyzeUnit(index, source, reactGlobals) {
|
|
|
447
447
|
assigned,
|
|
448
448
|
hooks: refs.some(({ name }) => reactGlobals.has(name)) || /\bReact\.(?:use[A-Z]\w*|createContext|forwardRef|memo)\b/.test(source),
|
|
449
449
|
clientOnly: handlers || refs.some(({ name }) => BROWSER_IDENTIFIERS.has(name)),
|
|
450
|
+
handlers,
|
|
450
451
|
componentLike,
|
|
451
452
|
blockers: [...new Set(blockers)]
|
|
452
453
|
};
|
|
@@ -462,9 +463,9 @@ function importLocals(statementText) {
|
|
|
462
463
|
if (!ts.isImportDeclaration(statement) || !statement.importClause) continue;
|
|
463
464
|
const clause = statement.importClause;
|
|
464
465
|
if (clause.name) locals.push(clause.name.text);
|
|
465
|
-
const
|
|
466
|
-
if (
|
|
467
|
-
if (
|
|
466
|
+
const named2 = clause.namedBindings;
|
|
467
|
+
if (named2 && ts.isNamespaceImport(named2)) locals.push(named2.name.text);
|
|
468
|
+
if (named2 && ts.isNamedImports(named2)) for (const element of named2.elements) locals.push(element.name.text);
|
|
468
469
|
}
|
|
469
470
|
return locals;
|
|
470
471
|
}
|
|
@@ -497,6 +498,38 @@ function bodyReferences(tree) {
|
|
|
497
498
|
visit(tree);
|
|
498
499
|
return { mdastTags, refs };
|
|
499
500
|
}
|
|
501
|
+
function gateOnMount(source, helper) {
|
|
502
|
+
const sf = parse(source);
|
|
503
|
+
const [statement] = sf.statements;
|
|
504
|
+
if (sf.statements.length !== 1) return void 0;
|
|
505
|
+
if (ts.isVariableStatement(statement)) {
|
|
506
|
+
const [declaration, ...others] = statement.declarationList.declarations;
|
|
507
|
+
const value = declaration.initializer && unwrap(declaration.initializer);
|
|
508
|
+
if (others.length > 0 || !ts.isIdentifier(declaration.name) || !declaration.initializer || !value || !(ts.isArrowFunction(value) || ts.isFunctionExpression(value))) return void 0;
|
|
509
|
+
const start = declaration.initializer.getStart(sf);
|
|
510
|
+
return `${source.slice(0, start)}${helper}(${source.slice(start, declaration.initializer.end)})${source.slice(declaration.initializer.end)}`;
|
|
511
|
+
}
|
|
512
|
+
if (ts.isFunctionDeclaration(statement) && statement.name && statement.body && !statement.asteriskToken) {
|
|
513
|
+
const start = statement.getStart(sf);
|
|
514
|
+
const header = /^(export\s+)?function\b/.exec(source.slice(start));
|
|
515
|
+
if (!header) return void 0;
|
|
516
|
+
const keyword = start + (header[1]?.length ?? 0);
|
|
517
|
+
return `${source.slice(0, keyword)}const ${statement.name.text} = ${helper}(${source.slice(keyword, statement.end)});${source.slice(statement.end)}`;
|
|
518
|
+
}
|
|
519
|
+
return void 0;
|
|
520
|
+
}
|
|
521
|
+
function mountGateHelper(name) {
|
|
522
|
+
return [
|
|
523
|
+
"// Renders nothing on the server or on the first client render, so a component that reads a browser global never disagrees with the server HTML.",
|
|
524
|
+
`function ${name}(Component) {`,
|
|
525
|
+
" return function AfterMount(props) {",
|
|
526
|
+
" const [mounted, setMounted] = useState(false)",
|
|
527
|
+
" useEffect(() => { setMounted(true) }, [])",
|
|
528
|
+
" return mounted ? <Component {...props} /> : null",
|
|
529
|
+
" }",
|
|
530
|
+
"}"
|
|
531
|
+
].join("\n");
|
|
532
|
+
}
|
|
500
533
|
function planInlineExtraction(input) {
|
|
501
534
|
const units = input.declarations.map((declaration, index) => analyzeUnit(index, declaration.source, input.reactGlobals));
|
|
502
535
|
const owner = /* @__PURE__ */ new Map();
|
|
@@ -550,12 +583,17 @@ function planInlineExtraction(input) {
|
|
|
550
583
|
}
|
|
551
584
|
return void 0;
|
|
552
585
|
};
|
|
553
|
-
const
|
|
586
|
+
const readsBrowserGlobal = (unit) => unit.componentLike && !unit.hooks && !unit.handlers && unit.refs.some(({ name, kind }) => BROWSER_IDENTIFIERS.has(name) && kind !== "tag" && kind !== "member" && !owner.has(name) && !importByLocal.has(name) && !helperByName.has(name)) && gateOnMount(unit.source, "gate") !== void 0;
|
|
587
|
+
const roots = units.filter((unit) => (unit.hooks || readsBrowserGlobal(unit)) && unit.names.some((name) => /^[A-Z]/.test(name))).map((unit) => unit.index);
|
|
554
588
|
const blocked = [];
|
|
555
589
|
const active = new Set(roots);
|
|
556
590
|
const block = (rootIndex, reason) => {
|
|
557
591
|
active.delete(rootIndex);
|
|
558
|
-
blocked.push({
|
|
592
|
+
blocked.push({
|
|
593
|
+
name: units[rootIndex].names.find((name) => /^[A-Z]/.test(name)) ?? units[rootIndex].names[0],
|
|
594
|
+
reason,
|
|
595
|
+
browser: readsBrowserGlobal(units[rootIndex])
|
|
596
|
+
});
|
|
559
597
|
};
|
|
560
598
|
for (const rootIndex of roots) {
|
|
561
599
|
for (const member of closureOf(rootIndex)) {
|
|
@@ -644,6 +682,7 @@ function planInlineExtraction(input) {
|
|
|
644
682
|
continue;
|
|
645
683
|
}
|
|
646
684
|
const movedNames = [...moved].flatMap((index) => units[index].names);
|
|
685
|
+
const gated = [...moved].filter((index) => readsBrowserGlobal(units[index])).sort((a, b) => a - b);
|
|
647
686
|
const registryNames = movedNames.filter((name) => body.mdastTags.has(name));
|
|
648
687
|
const importNames = movedNames.filter((name) => pageRefs.some((ref) => ref.name === name));
|
|
649
688
|
const moduleMembers = [...inModule].sort((a, b) => a - b);
|
|
@@ -666,6 +705,7 @@ function planInlineExtraction(input) {
|
|
|
666
705
|
blocked,
|
|
667
706
|
moved: [...moved].sort((a, b) => a - b),
|
|
668
707
|
copied: [...kept].sort((a, b) => a - b),
|
|
708
|
+
gated,
|
|
669
709
|
movedNames,
|
|
670
710
|
moduleImports: usedImports,
|
|
671
711
|
moduleHelpers: usedHelpers,
|
|
@@ -675,7 +715,7 @@ function planInlineExtraction(input) {
|
|
|
675
715
|
pageReferences
|
|
676
716
|
};
|
|
677
717
|
}
|
|
678
|
-
return { blocked, moved: [], copied: [], movedNames: [], moduleImports: [], moduleHelpers: [], registryNames: [], pageImportNames: [], moduleNames: /* @__PURE__ */ new Set(), pageReferences: /* @__PURE__ */ new Set() };
|
|
718
|
+
return { blocked, moved: [], copied: [], gated: [], movedNames: [], moduleImports: [], moduleHelpers: [], registryNames: [], pageImportNames: [], moduleNames: /* @__PURE__ */ new Set(), pageReferences: /* @__PURE__ */ new Set() };
|
|
679
719
|
}
|
|
680
720
|
function unboundTags(moduleSource, boundNames) {
|
|
681
721
|
const sf = parse(moduleSource);
|
|
@@ -801,6 +841,7 @@ import { existsSync, lstatSync, readFileSync } from "fs";
|
|
|
801
841
|
import { basename, dirname, extname as extname2, posix as posix2, relative as relative2, resolve as resolve2 } from "path";
|
|
802
842
|
import postcss2 from "postcss";
|
|
803
843
|
import selectorParser2 from "postcss-selector-parser";
|
|
844
|
+
import remarkGfm2 from "remark-gfm";
|
|
804
845
|
import remarkMdx2 from "remark-mdx";
|
|
805
846
|
import remarkParse3 from "remark-parse";
|
|
806
847
|
import ts3 from "typescript";
|
|
@@ -822,6 +863,50 @@ function salvageFrontmatterLines(matter) {
|
|
|
822
863
|
}
|
|
823
864
|
return data;
|
|
824
865
|
}
|
|
866
|
+
var KEY_LINE = /^[A-Za-z_][\w-]*:(?:\s|$)/;
|
|
867
|
+
var QUOTED_KEY_LINE = /^[A-Za-z_][\w-]*:[ \t]*(["'])/;
|
|
868
|
+
function closingQuote(line, from, quote) {
|
|
869
|
+
for (let index = from; index < line.length; index++) {
|
|
870
|
+
if (quote === '"' && line[index] === "\\") index++;
|
|
871
|
+
else if (line[index] === quote) {
|
|
872
|
+
if (quote === "'" && line[index + 1] === "'") index++;
|
|
873
|
+
else return index;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
return -1;
|
|
877
|
+
}
|
|
878
|
+
function foldQuotedLineBreaks(matter) {
|
|
879
|
+
const lines = matter.split(/\r?\n/);
|
|
880
|
+
const folded = [];
|
|
881
|
+
let changed = false;
|
|
882
|
+
for (let start = 0; start < lines.length; start++) {
|
|
883
|
+
const opening = QUOTED_KEY_LINE.exec(lines[start]);
|
|
884
|
+
if (!opening || closingQuote(lines[start], opening[0].length, opening[1]) !== -1) {
|
|
885
|
+
folded.push(lines[start]);
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
const quote = opening[1];
|
|
889
|
+
let value = lines[start].slice(opening[0].length).trimEnd();
|
|
890
|
+
let end = start + 1;
|
|
891
|
+
for (; end < lines.length; end++) {
|
|
892
|
+
const line = lines[end];
|
|
893
|
+
if (line.trim() === "" || KEY_LINE.test(line)) return void 0;
|
|
894
|
+
const close = closingQuote(line, 0, quote);
|
|
895
|
+
if (close === -1) {
|
|
896
|
+
value += ` ${line.trim()}`;
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
if (!/^\s*(?:#.*)?$/.test(line.slice(close + 1))) return void 0;
|
|
900
|
+
value += ` ${line.slice(0, close).trimStart()}`;
|
|
901
|
+
break;
|
|
902
|
+
}
|
|
903
|
+
if (end === lines.length) return void 0;
|
|
904
|
+
folded.push(`${lines[start].slice(0, opening[0].length - 1)}${quote}${value}${quote}`);
|
|
905
|
+
changed = true;
|
|
906
|
+
start = end;
|
|
907
|
+
}
|
|
908
|
+
return changed ? folded.join("\n") : void 0;
|
|
909
|
+
}
|
|
825
910
|
function parseFrontmatter(raw) {
|
|
826
911
|
const source = raw.charCodeAt(0) === 65279 ? raw.slice(1) : raw;
|
|
827
912
|
const opening = /^---([^\r\n]*)\r?\n/.exec(source);
|
|
@@ -843,6 +928,14 @@ function parseFrontmatter(raw) {
|
|
|
843
928
|
data: parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {}
|
|
844
929
|
};
|
|
845
930
|
} catch (err) {
|
|
931
|
+
const foldedMatter = foldQuotedLineBreaks(matter);
|
|
932
|
+
if (foldedMatter !== void 0) {
|
|
933
|
+
try {
|
|
934
|
+
const parsed = parseYaml(foldedMatter);
|
|
935
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return { content, data: parsed };
|
|
936
|
+
} catch {
|
|
937
|
+
}
|
|
938
|
+
}
|
|
846
939
|
return {
|
|
847
940
|
content,
|
|
848
941
|
data: salvageFrontmatterLines(matter),
|
|
@@ -1402,13 +1495,13 @@ function projectAuthoredStyles(css, contents, modules, namespace) {
|
|
|
1402
1495
|
});
|
|
1403
1496
|
const definitionsNamed = /* @__PURE__ */ new Map();
|
|
1404
1497
|
for (const rule of definitions) pushTo(definitionsNamed, rule.params.trim().toLowerCase(), rule);
|
|
1405
|
-
const
|
|
1498
|
+
const named2 = /* @__PURE__ */ new Set();
|
|
1406
1499
|
const unread = [];
|
|
1407
1500
|
const nameWords = (decl) => {
|
|
1408
1501
|
for (const [word] of decl.value.matchAll(/[^\s,()"']+/g)) {
|
|
1409
1502
|
const name = word.toLowerCase();
|
|
1410
|
-
if (!
|
|
1411
|
-
|
|
1503
|
+
if (!named2.has(name)) {
|
|
1504
|
+
named2.add(name);
|
|
1412
1505
|
unread.push(name);
|
|
1413
1506
|
}
|
|
1414
1507
|
}
|
|
@@ -1424,7 +1517,7 @@ function projectAuthoredStyles(css, contents, modules, namespace) {
|
|
|
1424
1517
|
const name = rule.name.toLowerCase();
|
|
1425
1518
|
if (name === "font-face") return;
|
|
1426
1519
|
if (definitions.has(rule)) {
|
|
1427
|
-
if (
|
|
1520
|
+
if (named2.has(rule.params.trim().toLowerCase())) return;
|
|
1428
1521
|
omittedAtRules.push(describe(rule));
|
|
1429
1522
|
rule.remove();
|
|
1430
1523
|
return;
|
|
@@ -1549,6 +1642,7 @@ function normalizeMintlifyCodeFences(body, warn) {
|
|
|
1549
1642
|
}
|
|
1550
1643
|
|
|
1551
1644
|
// src/mdx.ts
|
|
1645
|
+
var MDX_COMPILE_OPTIONS = { outputFormat: "program", remarkPlugins: [remarkGfm] };
|
|
1552
1646
|
function titleFromId(id) {
|
|
1553
1647
|
const value = id.split("/").at(-1) ?? id;
|
|
1554
1648
|
if (value === "introduction") return "Introduction";
|
|
@@ -1830,6 +1924,7 @@ function mintlifyHeadingSlug(text4) {
|
|
|
1830
1924
|
let id = "";
|
|
1831
1925
|
let afterDash = false;
|
|
1832
1926
|
let endsWithDash = false;
|
|
1927
|
+
let softDash = false;
|
|
1833
1928
|
chars.forEach((char, index) => {
|
|
1834
1929
|
const before = chars[index - 1];
|
|
1835
1930
|
const after = chars[index + 1];
|
|
@@ -1837,7 +1932,9 @@ function mintlifyHeadingSlug(text4) {
|
|
|
1837
1932
|
if (isWord(char)) {
|
|
1838
1933
|
id += char;
|
|
1839
1934
|
afterDash = false;
|
|
1935
|
+
softDash = false;
|
|
1840
1936
|
} else if (/[\s-]/.test(char) || char === "." && (isWord(after) || after === ",") || char === "(" && isWord(before) && (isWord(after) || after === "{") || char === ")" && after !== void 0 && !/\s/.test(after)) {
|
|
1937
|
+
softDash = /[\s-]/.test(char) ? false : id !== "" && !afterDash || softDash;
|
|
1841
1938
|
if (id && !afterDash) id += "-";
|
|
1842
1939
|
afterDash = true;
|
|
1843
1940
|
endsWithDash = true;
|
|
@@ -1845,24 +1942,28 @@ function mintlifyHeadingSlug(text4) {
|
|
|
1845
1942
|
afterDash = false;
|
|
1846
1943
|
}
|
|
1847
1944
|
});
|
|
1848
|
-
return endsWithDash ? id.replace(/-$/, "") : id;
|
|
1945
|
+
return endsWithDash || softDash ? id.replace(/-$/, "") : id;
|
|
1849
1946
|
}
|
|
1850
1947
|
function thallyHeadingSlug(text4) {
|
|
1851
1948
|
return text4.normalize("NFC").toLowerCase().replace(/[^\p{L}\p{M}\p{N}]+/gu, "-").replace(/(^-|-$)/g, "");
|
|
1852
1949
|
}
|
|
1950
|
+
var LINK_DESTINATION = String.raw`\]\((?:[^()]|\([^()]*\))*\)`;
|
|
1951
|
+
var TYPESET_PROTECTED = new RegExp(`(\`[^\`]*\`|<[^>]*>|${LINK_DESTINATION})`);
|
|
1853
1952
|
function typesetQuotes(text4) {
|
|
1854
1953
|
const opensClosed = text4.startsWith('"') && !text4.trimEnd().endsWith('"');
|
|
1855
|
-
return text4.split(
|
|
1954
|
+
return text4.split(TYPESET_PROTECTED).map((part, index) => {
|
|
1856
1955
|
if (index % 2) return part;
|
|
1857
1956
|
return part.replace(/(^|[\s([{\u2014\u2013])"/g, (match, before) => opensClosed && index === 0 && before === "" ? match : `${before}\u201C`).replace(/"/g, "\u201D").replace(/(^|[\s([{\u2014\u2013\u201c])'(?=\S)(?!<|<)/g, "$1\u2018").replace(/'/g, "\u2019");
|
|
1858
1957
|
}).join("");
|
|
1859
1958
|
}
|
|
1860
1959
|
function typesetEllipses(text4) {
|
|
1861
|
-
return text4.split(
|
|
1960
|
+
return text4.split(TYPESET_PROTECTED).map((part, index) => index % 2 ? part : part.replace(/\.{3}/g, "\u2026")).join("");
|
|
1862
1961
|
}
|
|
1962
|
+
var LINK_HOLDING_CODE = new RegExp(`(\`[^\`]*\`)|!?\\[((?:\`[^\`]*\`|[^\\]\`])*)${LINK_DESTINATION}`, "g");
|
|
1963
|
+
var PLAIN_LINK = new RegExp(`!?\\[([^\\]]*)${LINK_DESTINATION}`, "g");
|
|
1863
1964
|
function plainHeadingText(source) {
|
|
1864
|
-
const unlinked = !source.includes("`") ? source : source.replace(
|
|
1865
|
-
return unlinked.split(/(`[^`]*`)/).map((part, index) => index % 2 ? part.slice(1, -1) : part.replace(/\{\/\*[\s\S]*?\*\/\}/g, " ").replace(
|
|
1965
|
+
const unlinked = !source.includes("`") ? source : source.replace(LINK_HOLDING_CODE, (_match, code, text4 = "") => code ?? text4);
|
|
1966
|
+
return unlinked.split(/(`[^`]*`)/).map((part, index) => index % 2 ? part.slice(1, -1) : part.replace(/\{\/\*[\s\S]*?\*\/\}/g, " ").replace(PLAIN_LINK, "$1").replace(/<\/?[A-Za-z][^>]*>/g, "").replace(/(?<!\\)(\*\*|__|~~|\*)/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/\\([\\`*_{}[\]()#+.!&<>|~-])/g, "$1")).join("");
|
|
1866
1967
|
}
|
|
1867
1968
|
function staticAttributeString(value) {
|
|
1868
1969
|
if (typeof value === "string") return value;
|
|
@@ -1992,8 +2093,8 @@ function foldStatic(node, literals) {
|
|
|
1992
2093
|
}
|
|
1993
2094
|
case "Identifier":
|
|
1994
2095
|
case "MemberExpression": {
|
|
1995
|
-
const
|
|
1996
|
-
return
|
|
2096
|
+
const span = `${node.start}:${node.end}`;
|
|
2097
|
+
return literals.has(span) ? { value: literals.get(span) } : void 0;
|
|
1997
2098
|
}
|
|
1998
2099
|
case "JSXElement":
|
|
1999
2100
|
case "JSXFragment":
|
|
@@ -2032,8 +2133,8 @@ function foldStatic(node, literals) {
|
|
|
2032
2133
|
}
|
|
2033
2134
|
}
|
|
2034
2135
|
var PLAIN_TEXT = new RegExp("^\\p{L}(?:[\\p{L}\\p{N} ,.;'?%$=+-]*[\\p{L}\\p{N}.])?$", "u");
|
|
2035
|
-
function bindSnippetProps(body, properties) {
|
|
2036
|
-
if (properties.size === 0 || !body.includes("props") && ![...properties.keys()].some((name) => body.includes(name))) return body;
|
|
2136
|
+
function bindSnippetProps(body, properties, unset = /* @__PURE__ */ new Set()) {
|
|
2137
|
+
if (properties.size === 0 && unset.size === 0 || !body.includes("props") && ![...properties.keys(), ...unset].some((name) => body.includes(name))) return body;
|
|
2037
2138
|
const isJsx = /<[A-Za-z][A-Za-z0-9]*/.test(body);
|
|
2038
2139
|
let tree;
|
|
2039
2140
|
try {
|
|
@@ -2075,6 +2176,14 @@ function bindSnippetProps(body, properties) {
|
|
|
2075
2176
|
}
|
|
2076
2177
|
}
|
|
2077
2178
|
const bound = properties.get(name);
|
|
2179
|
+
if (variables && bound === void 0 && unset.has(name)) {
|
|
2180
|
+
if (parent?.type === "Property" && parent.shorthand) edits.push({ start: parent.start, end: parent.end, value: `${name}: undefined` });
|
|
2181
|
+
else {
|
|
2182
|
+
edits.push({ start, end, value: "undefined" });
|
|
2183
|
+
literals.set(`${start}:${end}`, void 0);
|
|
2184
|
+
}
|
|
2185
|
+
continue;
|
|
2186
|
+
}
|
|
2078
2187
|
if (!variables || bound === void 0) continue;
|
|
2079
2188
|
if (name !== "children") {
|
|
2080
2189
|
if (parent?.type === "Property" && parent.shorthand) edits.push({ start: parent.start, end: parent.end, value: `${name}: ${JSON.stringify(bound)}` });
|
|
@@ -2123,8 +2232,8 @@ function bindSnippetProps(body, properties) {
|
|
|
2123
2232
|
const { value } = folded;
|
|
2124
2233
|
const place = (text4) => flow ? asBlock(text4, start, end) : { start, end, value: text4 };
|
|
2125
2234
|
if (typeof value === "object" && value !== null) return inAttribute ? void 0 : place(keepJsx(value.jsx, bound, literals));
|
|
2126
|
-
if (inAttribute) return { start, end, value: `{${JSON.stringify(value)}}` };
|
|
2127
|
-
if (typeof value === "boolean" || value === null || value === "") return place("");
|
|
2235
|
+
if (inAttribute) return { start, end, value: `{${value === void 0 ? "undefined" : JSON.stringify(value)}}` };
|
|
2236
|
+
if (typeof value === "boolean" || value === null || value === void 0 || value === "") return place("");
|
|
2128
2237
|
return place(typeof value === "string" && PLAIN_TEXT.test(value) ? value : `{${JSON.stringify(value)}}`);
|
|
2129
2238
|
};
|
|
2130
2239
|
const foldBound = (program, bound, literals, span, inAttribute, flow) => {
|
|
@@ -2143,9 +2252,10 @@ function bindSnippetProps(body, properties) {
|
|
|
2143
2252
|
const lone = node.type !== "mdxjsEsm" && program.body.length === 1 && statement.type === "ExpressionStatement" && statement.expression.type === "Identifier" ? statement.expression : void 0;
|
|
2144
2253
|
if (lone) {
|
|
2145
2254
|
const bound = moduleNames.has(lone.name) ? void 0 : properties.get(lone.name);
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
else if (
|
|
2255
|
+
const missing = bound === void 0 && !moduleNames.has(lone.name) && unset.has(lone.name);
|
|
2256
|
+
if (bound === void 0 && !missing) {
|
|
2257
|
+
} else if (span || isJsx && lone.name !== "children") edits.push({ start: lone.start, end: lone.end, value: missing ? "undefined" : JSON.stringify(bound) });
|
|
2258
|
+
else if (start !== void 0 && end !== void 0) edits.push(node.type === "mdxFlowExpression" ? asBlock(bound ?? "", start, end) : { start, end, value: bound ?? "" });
|
|
2149
2259
|
} else {
|
|
2150
2260
|
const first = edits.length;
|
|
2151
2261
|
const literals = /* @__PURE__ */ new Map();
|
|
@@ -2371,11 +2481,11 @@ function protectMathBlocks(raw) {
|
|
|
2371
2481
|
const protectedBody = front + output.join("\n");
|
|
2372
2482
|
if (!converted) return { body: protectedBody, converted };
|
|
2373
2483
|
try {
|
|
2374
|
-
compileSync(protectedBody,
|
|
2484
|
+
compileSync(protectedBody, MDX_COMPILE_OPTIONS);
|
|
2375
2485
|
return { body: protectedBody, converted };
|
|
2376
2486
|
} catch {
|
|
2377
2487
|
try {
|
|
2378
|
-
compileSync(raw,
|
|
2488
|
+
compileSync(raw, MDX_COMPILE_OPTIONS);
|
|
2379
2489
|
return { body: raw, converted: false, guardTriggered: true };
|
|
2380
2490
|
} catch {
|
|
2381
2491
|
return { body: protectedBody, converted };
|
|
@@ -2533,7 +2643,7 @@ function maskCode(body) {
|
|
|
2533
2643
|
}
|
|
2534
2644
|
continue;
|
|
2535
2645
|
}
|
|
2536
|
-
if (fenceMatch) {
|
|
2646
|
+
if (fenceMatch && !(fenceMatch[1][0] === "`" && line.slice(fenceMatch[0].length).includes("`"))) {
|
|
2537
2647
|
codeFence = fenceMatch[1];
|
|
2538
2648
|
fenceBuffer = [line];
|
|
2539
2649
|
continue;
|
|
@@ -2582,6 +2692,10 @@ function indentSnippetLines(snippet, indent) {
|
|
|
2582
2692
|
return indent + line;
|
|
2583
2693
|
}).join("\n");
|
|
2584
2694
|
}
|
|
2695
|
+
function maskedOutsideCode(body) {
|
|
2696
|
+
const { masked, openFence } = maskCode(body);
|
|
2697
|
+
return { text: masked, openFence: openFence !== null };
|
|
2698
|
+
}
|
|
2585
2699
|
function replaceOutsideCode(body, transform) {
|
|
2586
2700
|
const { masked, unmask } = maskCode(body);
|
|
2587
2701
|
return unmask(transform(masked));
|
|
@@ -2640,6 +2754,63 @@ function rewriteFernRelativePageLinks(body, currentSourcePath, routesBySourcePat
|
|
|
2640
2754
|
(_match, opening, quote, target2) => `${opening}${quote}${rewrite(target2)}${quote}`
|
|
2641
2755
|
));
|
|
2642
2756
|
}
|
|
2757
|
+
function rewriteRelativeJsxHrefs(body, pagePath) {
|
|
2758
|
+
const rewrite = (target2) => {
|
|
2759
|
+
if (!/^\.\.?\//.test(target2) || target2.includes("\\") || /[\u0000-\u001f\u007f]/.test(target2)) return target2;
|
|
2760
|
+
const suffixAt = target2.search(/[?#]/);
|
|
2761
|
+
const pathname = suffixAt < 0 ? target2 : target2.slice(0, suffixAt);
|
|
2762
|
+
if (/%2e|%2f|%5c/i.test(pathname)) return target2;
|
|
2763
|
+
const segments = pagePath.split("/").slice(0, -1);
|
|
2764
|
+
for (const part of pathname.split("/")) {
|
|
2765
|
+
if (part === "..") {
|
|
2766
|
+
segments.pop();
|
|
2767
|
+
} else if (part !== "." && part !== "") {
|
|
2768
|
+
segments.push(part);
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
return `/${segments.join("/")}${pathname.endsWith("/") && segments.length > 0 ? "/" : ""}${suffixAt < 0 ? "" : target2.slice(suffixAt)}`;
|
|
2772
|
+
};
|
|
2773
|
+
return replaceOutsideCodeAndComments(body, (text4) => text4.replace(
|
|
2774
|
+
/((?<![\w-])href\s*=\s*)(["'])([^"'\n]+)\2/g,
|
|
2775
|
+
(_match, opening, quote, target2) => `${opening}${quote}${rewrite(target2)}${quote}`
|
|
2776
|
+
).replace(
|
|
2777
|
+
/((?<![\w-])href\s*=\s*\{\s*)(["'])([^"'\n]+)\2(?=\s*\})/g,
|
|
2778
|
+
(_match, opening, quote, target2) => `${opening}${quote}${rewrite(target2)}${quote}`
|
|
2779
|
+
));
|
|
2780
|
+
}
|
|
2781
|
+
function templateLiteralRanges(body) {
|
|
2782
|
+
let tree;
|
|
2783
|
+
try {
|
|
2784
|
+
tree = descriptionParser.parse(body);
|
|
2785
|
+
} catch {
|
|
2786
|
+
return null;
|
|
2787
|
+
}
|
|
2788
|
+
const ranges = [];
|
|
2789
|
+
const scan = (value) => {
|
|
2790
|
+
if (!value || typeof value !== "object") return;
|
|
2791
|
+
const node = value;
|
|
2792
|
+
if (node.type === "TemplateLiteral" && typeof node.start === "number" && typeof node.end === "number") ranges.push([node.start, node.end]);
|
|
2793
|
+
for (const child of Object.values(node)) scan(child);
|
|
2794
|
+
};
|
|
2795
|
+
scan(tree);
|
|
2796
|
+
return ranges.sort((left, right) => left[0] - right[0]);
|
|
2797
|
+
}
|
|
2798
|
+
function esmTemplateLiteralRanges(body) {
|
|
2799
|
+
const text4 = body.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, (frontmatter) => frontmatter.replace(/[^\r\n]/g, " "));
|
|
2800
|
+
const direct = templateLiteralRanges(text4);
|
|
2801
|
+
if (direct) return direct;
|
|
2802
|
+
const blanked = text4.replace(/<!--[\s\S]*?-->/g, (comment) => comment.replace(/[^\r\n]/g, " "));
|
|
2803
|
+
const repaired = escapeUnparseableExpressions(escapeUnmatchedClosingTags(blanked).body);
|
|
2804
|
+
const ranges = templateLiteralRanges(repaired.body);
|
|
2805
|
+
if (!ranges) return [];
|
|
2806
|
+
const inserted = [];
|
|
2807
|
+
for (let at = 0, source = 0; at < repaired.body.length; at++) {
|
|
2808
|
+
if (repaired.body[at] === blanked[source]) source++;
|
|
2809
|
+
else inserted.push(at);
|
|
2810
|
+
}
|
|
2811
|
+
const original = (offset) => offset - inserted.filter((at) => at < offset).length;
|
|
2812
|
+
return ranges.map(([start, end]) => [original(start), original(end)]);
|
|
2813
|
+
}
|
|
2643
2814
|
function normalizeFernFileTrees(body) {
|
|
2644
2815
|
return replaceOutsideCode(body, (whole) => whole.replace(
|
|
2645
2816
|
/<FileTree\s*>\s*\n([\s\S]*?)\n\s*<\/FileTree>/g,
|
|
@@ -2934,6 +3105,28 @@ function normalizeDocusaurusTabs(body) {
|
|
|
2934
3105
|
}
|
|
2935
3106
|
return result.replace(/<ThallyTabs\b/g, "<Tabs").replace(/<\/ThallyTabs>/g, "</Tabs>");
|
|
2936
3107
|
}
|
|
3108
|
+
function normalizeStrayTabItems(body) {
|
|
3109
|
+
const tags = [...body.matchAll(/<TabItem\b([^<>]*)>|<\/TabItem>/g)].filter((tag) => !/\/$/.test(tag[1] ?? ""));
|
|
3110
|
+
const openers = [];
|
|
3111
|
+
const paired = /* @__PURE__ */ new Set();
|
|
3112
|
+
tags.forEach((tag, index) => {
|
|
3113
|
+
if (tag[0] !== "</TabItem>") openers.push(index);
|
|
3114
|
+
else if (openers.length > 0) {
|
|
3115
|
+
paired.add(openers.pop());
|
|
3116
|
+
paired.add(index);
|
|
3117
|
+
}
|
|
3118
|
+
});
|
|
3119
|
+
let result = "";
|
|
3120
|
+
let cursor = 0;
|
|
3121
|
+
tags.forEach((tag, index) => {
|
|
3122
|
+
if (!paired.has(index)) return;
|
|
3123
|
+
const attributes = tag[1] ?? "";
|
|
3124
|
+
const title = attributes.match(/\blabel=(?:"([^"]*)"|'([^']*)')/)?.slice(1).find(Boolean) ?? attributes.match(/\bvalue=(?:"([^"]*)"|'([^']*)')/)?.slice(1).find(Boolean) ?? "Tab";
|
|
3125
|
+
result += `${body.slice(cursor, tag.index)}${tag[0] === "</TabItem>" ? "</Tab>" : `<Tab title="${title.replace(/"/g, """)}">`}`;
|
|
3126
|
+
cursor = tag.index + tag[0].length;
|
|
3127
|
+
});
|
|
3128
|
+
return result + body.slice(cursor);
|
|
3129
|
+
}
|
|
2937
3130
|
var TAB_FENCE_OPEN = /^(`{3,}|~{3,})(\S*)\s+tab\b(.*)$/;
|
|
2938
3131
|
function normalizeDocusaurusTabBlocks(body) {
|
|
2939
3132
|
const lines = body.split("\n");
|
|
@@ -3157,6 +3350,37 @@ function pinStepsTitleSize(body) {
|
|
|
3157
3350
|
}
|
|
3158
3351
|
return result + body.slice(cursor);
|
|
3159
3352
|
}
|
|
3353
|
+
function addMintlifyVideoAttributes(body) {
|
|
3354
|
+
if (!body.includes("<video")) return body;
|
|
3355
|
+
let result = "";
|
|
3356
|
+
let cursor = 0;
|
|
3357
|
+
for (const match of body.matchAll(/<video(?=[\s/>])/g)) {
|
|
3358
|
+
if (match.index < cursor) continue;
|
|
3359
|
+
const tag = readTagEnd(body, match.index + match[0].length);
|
|
3360
|
+
if (tag === UNTERMINATED) break;
|
|
3361
|
+
if (!tag) continue;
|
|
3362
|
+
let attributes;
|
|
3363
|
+
try {
|
|
3364
|
+
attributes = descriptionParser.parse(`<video${tag.attributes}/>`).children?.[0]?.attributes ?? [];
|
|
3365
|
+
} catch {
|
|
3366
|
+
continue;
|
|
3367
|
+
}
|
|
3368
|
+
const named2 = (name) => attributes.find((attribute2) => attribute2.type === "mdxJsxAttribute" && attribute2.name?.toLowerCase() === name.toLowerCase());
|
|
3369
|
+
const autoPlay = named2("autoPlay");
|
|
3370
|
+
const start = autoPlay?.position?.start.offset;
|
|
3371
|
+
const end = autoPlay?.position?.end.offset;
|
|
3372
|
+
const off = typeof autoPlay?.value === "object" && autoPlay.value?.value?.trim() === "false";
|
|
3373
|
+
const missing = ["muted", "loop", "playsInline"].filter((name) => !named2(name));
|
|
3374
|
+
if (!autoPlay || off || missing.length === 0 || start === void 0 || end === void 0) continue;
|
|
3375
|
+
const at = match.index + end;
|
|
3376
|
+
const indent = body.slice(body.lastIndexOf("\n", match.index + start - 1) + 1, match.index + start);
|
|
3377
|
+
const eol = /^[ \t]*(\r?\n)/.exec(body.slice(at))?.[1];
|
|
3378
|
+
const insert = eol && /^[ \t]*$/.test(indent) ? missing.map((name) => `${eol}${indent}${name}`).join("") : missing.map((name) => ` ${name}`).join("");
|
|
3379
|
+
result += body.slice(cursor, at) + insert;
|
|
3380
|
+
cursor = at;
|
|
3381
|
+
}
|
|
3382
|
+
return result + body.slice(cursor);
|
|
3383
|
+
}
|
|
3160
3384
|
function escapeUnmatchedClosingTags(body) {
|
|
3161
3385
|
const masked = maskCodeRegions(body);
|
|
3162
3386
|
const tagPattern = /(\\?)<(\/?)([A-Za-z][\w.:-]*)/g;
|
|
@@ -3174,21 +3398,69 @@ function escapeUnmatchedClosingTags(body) {
|
|
|
3174
3398
|
} else if (open.get(name)) {
|
|
3175
3399
|
open.set(name, open.get(name) - 1);
|
|
3176
3400
|
} else {
|
|
3177
|
-
edits.push(match.index);
|
|
3401
|
+
edits.push({ start: match.index, end: tag.end });
|
|
3178
3402
|
}
|
|
3179
3403
|
}
|
|
3180
|
-
if (edits.length === 0) return { body,
|
|
3404
|
+
if (edits.length === 0) return { body, escaped: [] };
|
|
3181
3405
|
let result = "";
|
|
3182
3406
|
let cursor = 0;
|
|
3183
|
-
const
|
|
3184
|
-
let line = 1;
|
|
3185
|
-
for (const start of edits) {
|
|
3407
|
+
for (const { start } of edits) {
|
|
3186
3408
|
result += `${body.slice(cursor, start)}\\`;
|
|
3187
|
-
for (let i = cursor; i < start; i++) if (body.charCodeAt(i) === 10) line++;
|
|
3188
|
-
lines.push(line);
|
|
3189
3409
|
cursor = start;
|
|
3190
3410
|
}
|
|
3191
|
-
return { body: result + body.slice(cursor),
|
|
3411
|
+
return { body: result + body.slice(cursor), escaped: edits.map(({ start, end }) => body.slice(start, end)) };
|
|
3412
|
+
}
|
|
3413
|
+
function isBackslashEscaped(text4, index) {
|
|
3414
|
+
let slashes = 0;
|
|
3415
|
+
while (index - 1 - slashes >= 0 && text4[index - 1 - slashes] === "\\") slashes++;
|
|
3416
|
+
return slashes % 2 === 1;
|
|
3417
|
+
}
|
|
3418
|
+
var MAX_EXPRESSION_REPAIRS = 50;
|
|
3419
|
+
function escapeUnparseableExpressions(body) {
|
|
3420
|
+
let current = body;
|
|
3421
|
+
const escaped = [];
|
|
3422
|
+
for (let repairs = 0; ; repairs++) {
|
|
3423
|
+
let failure;
|
|
3424
|
+
try {
|
|
3425
|
+
compileSync(current, MDX_COMPILE_OPTIONS);
|
|
3426
|
+
return { body: current, escaped };
|
|
3427
|
+
} catch (error) {
|
|
3428
|
+
failure = error;
|
|
3429
|
+
}
|
|
3430
|
+
const offset = failure?.place?.offset;
|
|
3431
|
+
if (repairs === MAX_EXPRESSION_REPAIRS || failure?.source !== "micromark-extension-mdx-expression" || failure.ruleId !== "acorn" || typeof offset !== "number") return { body, escaped: [] };
|
|
3432
|
+
const masked = maskCodeRegions(current);
|
|
3433
|
+
let opener = -1;
|
|
3434
|
+
for (let i = offset - 1, depth = 0; i >= 0 && opener < 0; i--) {
|
|
3435
|
+
if (isBackslashEscaped(masked, i)) continue;
|
|
3436
|
+
if (masked[i] === "}") depth++;
|
|
3437
|
+
else if (masked[i] === "{") {
|
|
3438
|
+
if (depth === 0) opener = i;
|
|
3439
|
+
else depth--;
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3442
|
+
if (opener < 0) return { body, escaped: [] };
|
|
3443
|
+
let braces = [];
|
|
3444
|
+
let close = -1;
|
|
3445
|
+
for (let i = opener, depth = 0; i < masked.length && close < 0; i++) {
|
|
3446
|
+
if (isBackslashEscaped(masked, i)) continue;
|
|
3447
|
+
if (masked[i] === "{") {
|
|
3448
|
+
depth++;
|
|
3449
|
+
braces.push(i);
|
|
3450
|
+
} else if (masked[i] === "}" && --depth === 0) {
|
|
3451
|
+
close = i;
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
if (close < 0) braces = [opener];
|
|
3455
|
+
escaped.push(current.slice(opener, close < 0 ? opener + 1 : close + 1));
|
|
3456
|
+
let cursor = 0;
|
|
3457
|
+
let result = "";
|
|
3458
|
+
for (const brace of braces) {
|
|
3459
|
+
result += `${current.slice(cursor, brace)}\\`;
|
|
3460
|
+
cursor = brace;
|
|
3461
|
+
}
|
|
3462
|
+
current = result + current.slice(cursor);
|
|
3463
|
+
}
|
|
3192
3464
|
}
|
|
3193
3465
|
function isKnownComponentName(name, body) {
|
|
3194
3466
|
if (isThallyBuiltinComponent(name)) return true;
|
|
@@ -3219,7 +3491,7 @@ function escapeOrphanCapitalizedTags(body) {
|
|
|
3219
3491
|
}
|
|
3220
3492
|
if (edits.length === 0) return body;
|
|
3221
3493
|
try {
|
|
3222
|
-
compileSync(body,
|
|
3494
|
+
compileSync(body, MDX_COMPILE_OPTIONS);
|
|
3223
3495
|
return body;
|
|
3224
3496
|
} catch {
|
|
3225
3497
|
}
|
|
@@ -3345,20 +3617,18 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
|
3345
3617
|
));
|
|
3346
3618
|
rewritten = rewritten.replace(/^\n{2,}/, "\n");
|
|
3347
3619
|
}
|
|
3620
|
+
if (runMintlify && rewritten.includes("<TabItem")) rewritten = replaceOutsideCode(rewritten, normalizeDocusaurusTabs);
|
|
3348
3621
|
if (runMintlify) rewritten = normalizeMintlifyParameterAnchors(rewritten);
|
|
3349
3622
|
rewritten = unwrapHtmlCommentInMdxComment(rewritten);
|
|
3350
3623
|
rewritten = replaceOutsideCode(rewritten, (segment) => {
|
|
3351
3624
|
let result = convertHtmlStyleAttributes(segment).replace(/<!--([\s\S]*?)-->/g, (_match, content) => mdxComment(content)).replace(/<Danger(\s[^>]*)?>/g, "<Error$1>").replace(/<\/Danger>/g, "</Error>").replace(/<Warn(\s[^>]*)?>/g, "<Warning$1>").replace(/<\/Warn>/g, "</Warning>").replace(/<Tree\.Folder/g, "<Folder").replace(/<\/Tree\.Folder>/g, "</Folder>").replace(/<Tree\.File/g, "<File").replace(/<\/Tree\.File>/g, "</File>");
|
|
3352
3625
|
if (runDocusaurus) {
|
|
3353
|
-
result = result.replace(/<
|
|
3354
|
-
const title = attributes.match(/\blabel=(?:"([^"]*)"|'([^']*)')/)?.slice(1).find(Boolean) ?? attributes.match(/\bvalue=(?:"([^"]*)"|'([^']*)')/)?.slice(1).find(Boolean) ?? "Tab";
|
|
3355
|
-
return `<Tab title="${title.replace(/"/g, """)}">`;
|
|
3356
|
-
}).replace(/<\/TabItem>/g, "</Tab>");
|
|
3357
|
-
result = normalizeDocusaurusLinkTags(result).replace(/<(?:DocCardList|TOCInline)\b[^<>]*\/>/g, "");
|
|
3626
|
+
result = normalizeDocusaurusLinkTags(normalizeStrayTabItems(result)).replace(/<(?:DocCardList|TOCInline)\b[^<>]*\/>/g, "");
|
|
3358
3627
|
}
|
|
3359
3628
|
if (runMintlify) {
|
|
3360
|
-
result = normalizeMintlifyUpdateLabels(result).replace(/<FileTree(\s[^>]*)?>/g, "<Tree$1>").replace(/<\/FileTree>/g, "</Tree>").replace(/<GitHub\.Repo/g, "<GitHub").replace(/<\/GitHub\.Repo>/g, "</GitHub>").replace(/<Callout(\s[^<>]*)?>/g, (tag) => tag.replace(/(\s)type=(?:"[^"]*"|'[^']*'|\{[^{}]*\})/, '$1type="info"')).replace(/<Column(\s[^>]*)?>/g, "<div$1>").replace(/<\/Column>/g, "</div>");
|
|
3629
|
+
result = normalizeMintlifyUpdateLabels(normalizeStrayTabItems(result)).replace(/<FileTree(\s[^>]*)?>/g, "<Tree$1>").replace(/<\/FileTree>/g, "</Tree>").replace(/<GitHub\.Repo/g, "<GitHub").replace(/<\/GitHub\.Repo>/g, "</GitHub>").replace(/<Callout(\s[^<>]*)?>/g, (tag) => tag.replace(/(\s)type=(?:"[^"]*"|'[^']*'|\{[^{}]*\})/, '$1type="info"')).replace(/<Column(\s[^>]*)?>/g, "<div$1>").replace(/<\/Column>/g, "</div>");
|
|
3361
3630
|
result = pinStepsTitleSize(result);
|
|
3631
|
+
result = addMintlifyVideoAttributes(result);
|
|
3362
3632
|
}
|
|
3363
3633
|
if (runFern) {
|
|
3364
3634
|
result = result.replace(/<CodeBlocks(\s[^>]*)?>/g, "<CodeGroup$1>").replace(/<\/CodeBlocks>/g, "</CodeGroup>").replace(/<ParameterField\b/g, "<ParamField").replace(/<\/ParameterField>/g, "</ParamField>").replace(/<Cards(\s[^>]*)?>/g, "<CardGroup$1>").replace(/<\/Cards>/g, "</CardGroup>").replace(/<Success(\s[^>]*)?>/g, "<Tip$1>").replace(/<\/Success>/g, "</Tip>").replace(/<Launch(\s[^>]*)?>/g, "<Note$1>").replace(/<\/Launch>/g, "</Note>").replace(/<Files(\s[^>]*)?>\n?/g, "").replace(/<\/Files>/g, "");
|
|
@@ -3369,7 +3639,7 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
|
3369
3639
|
const normalized = escapeOrphanCapitalizedTags(provideScopedGlobalReferences(rewritten));
|
|
3370
3640
|
if (runDocusaurus && sourceBody !== body) {
|
|
3371
3641
|
try {
|
|
3372
|
-
compileSync(normalized,
|
|
3642
|
+
compileSync(normalized, MDX_COMPILE_OPTIONS);
|
|
3373
3643
|
} catch {
|
|
3374
3644
|
return normalizeMdx(body, platform, false);
|
|
3375
3645
|
}
|
|
@@ -3431,14 +3701,20 @@ function parseMarkdownPage(input) {
|
|
|
3431
3701
|
const normalized = normalizeMdx(parsed.content, input.platform);
|
|
3432
3702
|
const body = removeUndefinedExpressions(injectReactHookImports(input.platform === "mintlify" ? normalizeMintlifyCodeFences(normalized, input.warn) : normalized), input.warn).trim();
|
|
3433
3703
|
const keywords = Array.isArray(parsed.data.keywords) ? parsed.data.keywords.filter((value) => typeof value === "string") : [];
|
|
3434
|
-
const
|
|
3704
|
+
const namesOperation = typeof parsed.data.openapi === "string" && Boolean(parsed.data.openapi.trim());
|
|
3705
|
+
const heading = input.platform === "mintlify" && !namesOperation ? void 0 : leadingPageHeading(body);
|
|
3435
3706
|
const authoredTitle = typeof parsed.data.title === "string" && parsed.data.title.trim() ? parsed.data.title.trim() : heading?.title;
|
|
3436
3707
|
const title = authoredTitle ?? titleFromId(identity.navigationId);
|
|
3437
|
-
const namesOperation = typeof parsed.data.openapi === "string" && Boolean(parsed.data.openapi.trim());
|
|
3438
3708
|
const sidebarTitle = input.platform === "docusaurus" ? parsed.data.sidebar_label : parsed.data.sidebarTitle;
|
|
3439
3709
|
const navTitle = typeof sidebarTitle === "string" && sidebarTitle.trim() ? sidebarTitle.trim() : typeof parsed.data.navTitle === "string" && parsed.data.navTitle.trim() ? parsed.data.navTitle.trim() : void 0;
|
|
3440
|
-
const
|
|
3441
|
-
const
|
|
3710
|
+
const iconObject = parsed.data.icon && typeof parsed.data.icon === "object" && !Array.isArray(parsed.data.icon) ? parsed.data.icon : void 0;
|
|
3711
|
+
const iconSource = iconObject ? iconObject.name : parsed.data.icon;
|
|
3712
|
+
const icon = typeof iconSource === "string" && iconSource.trim() ? iconSource.trim() : void 0;
|
|
3713
|
+
const iconStyle = (value) => typeof value === "string" && ["regular", "solid", "outline", "brands"].includes(value) ? value : void 0;
|
|
3714
|
+
const iconType = icon ? iconStyle(iconObject?.style) ?? iconStyle(parsed.data.iconType) : void 0;
|
|
3715
|
+
if (icon && typeof iconObject?.library === "string" && input.siteIconLibrary !== void 0 && iconObject.library !== input.siteIconLibrary) {
|
|
3716
|
+
input.warn?.(`Page "${identity.id}": its icon names the "${iconObject.library}" icon library, but this site uses "${input.siteIconLibrary}", so the icon "${icon}" is looked up there and may show a different icon or none. Use an icon name from "${input.siteIconLibrary}", or set icons.library in docs.json to "${iconObject.library}".`);
|
|
3717
|
+
}
|
|
3442
3718
|
const meta = {};
|
|
3443
3719
|
for (const [source, field] of PAGE_META_FIELDS) {
|
|
3444
3720
|
const value = parsed.data[source];
|
|
@@ -3667,7 +3943,12 @@ function youtubeEmbedVideoId(node, specifier) {
|
|
|
3667
3943
|
}
|
|
3668
3944
|
return void 0;
|
|
3669
3945
|
}
|
|
3670
|
-
var
|
|
3946
|
+
var COMPONENT_ANALYSIS_FAILED = "Custom component analysis could not parse this MDX";
|
|
3947
|
+
function pageHasComponentWork(body) {
|
|
3948
|
+
const { text: text4, openFence } = maskedOutsideCode(splitFrontmatterBlock(body).body);
|
|
3949
|
+
return openFence || /^[ \t]*(?:import|export)\b|\bon[A-Z]\w*\s*=|\brequire\s*\(/m.test(text4);
|
|
3950
|
+
}
|
|
3951
|
+
var parser = unified3().use(remarkParse3).use(remarkGfm2).use(remarkMdx2);
|
|
3671
3952
|
var CODE_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".jsx", ".ts", ".tsx", ".mjs"]);
|
|
3672
3953
|
var DATA_EXTENSIONS = /* @__PURE__ */ new Set([".json", ".css", ".svg", ".png", ".jpg", ".jpeg", ".webp", ".gif", ".avif", ".woff", ".woff2"]);
|
|
3673
3954
|
var RESCUABLE_ASSET_EXTENSIONS = /* @__PURE__ */ new Set([".svg", ".png", ".jpg", ".jpeg", ".webp", ".gif", ".avif", ".ico", ".docx", ".pdf"]);
|
|
@@ -4437,7 +4718,7 @@ ${client ? "'use client';\n" : ""}
|
|
|
4437
4718
|
try {
|
|
4438
4719
|
tree = parser.parse(content);
|
|
4439
4720
|
} catch {
|
|
4440
|
-
warn(
|
|
4721
|
+
warn(`${COMPONENT_ANALYSIS_FAILED}; its source was preserved for manual migration.`, currentFile);
|
|
4441
4722
|
return frontmatter + neutralizeUnresolvableImportsWithoutAst(content, currentFile, warn);
|
|
4442
4723
|
}
|
|
4443
4724
|
const aliases = /* @__PURE__ */ new Map();
|
|
@@ -4541,7 +4822,7 @@ ${client ? "'use client';\n" : ""}
|
|
|
4541
4822
|
}
|
|
4542
4823
|
if (!specifier.startsWith(".") && !specifier.startsWith("/")) {
|
|
4543
4824
|
if (SHARED_IMPORTS.has(specifier)) {
|
|
4544
|
-
const isUnusedReactHookImport = specifier === "react" && bindings.length > 0 &&
|
|
4825
|
+
const isUnusedReactHookImport = specifier === "react" && bindings.length > 0 && !hasExpressionReference(new Set(bindings.map((binding) => binding.local)), { includeDirectTags: true });
|
|
4545
4826
|
if (!isUnusedReactHookImport) moduleImports.push(statement.getText(ast));
|
|
4546
4827
|
if (isUnusedReactHookImport) edits.push({ start: node.position.start.offset + statement.getStart(ast), end: node.position.start.offset + statement.end, value: "" });
|
|
4547
4828
|
else sharedImportEdits.push({ start: node.position.start.offset + statement.getStart(ast), end: node.position.start.offset + statement.end, value: "" });
|
|
@@ -4688,14 +4969,22 @@ ${client ? "'use client';\n" : ""}
|
|
|
4688
4969
|
unavailableImports: unsupportedImports,
|
|
4689
4970
|
reactGlobals: REACT_GLOBALS
|
|
4690
4971
|
});
|
|
4691
|
-
for (const { name, reason } of plan.blocked) {
|
|
4972
|
+
for (const { name, reason, browser } of plan.blocked) {
|
|
4692
4973
|
refusedInlineComponents.add(name);
|
|
4693
|
-
warn(`Inline component "${name}" calls a React hook but was left in the page: ${reason}. Move it and everything it uses into a client component manually.`, currentFile);
|
|
4974
|
+
warn(`Inline component "${name}" ${browser ? "uses `window` or `document`, which only exist in the browser," : "calls a React hook"} but was left in the page: ${reason}. Move it and everything it uses into a client component manually.`, currentFile);
|
|
4975
|
+
}
|
|
4976
|
+
const moduleIndexes = [...plan.moved, ...plan.copied].sort((a, b) => a - b);
|
|
4977
|
+
const gated = new Set(plan.gated);
|
|
4978
|
+
let gate = "renderAfterMount";
|
|
4979
|
+
if (gated.size > 0) {
|
|
4980
|
+
const spelled = identifierNames(sourceFile([...plan.moduleImports, ...plan.moduleHelpers, ...moduleIndexes.map((index) => declarations2[index].source)].join("\n"), "inline.jsx"));
|
|
4981
|
+
for (let suffix = 2; spelled.has(gate); suffix += 1) gate = `renderAfterMount${suffix}`;
|
|
4694
4982
|
}
|
|
4695
4983
|
const moduleSource = plan.moved.length === 0 ? "" : [
|
|
4696
4984
|
...plan.moduleImports,
|
|
4697
4985
|
...plan.moduleHelpers,
|
|
4698
|
-
...
|
|
4986
|
+
...moduleIndexes.map((index) => (gated.has(index) ? gateOnMount(declarations2[index].source, gate) : void 0) ?? declarations2[index].source),
|
|
4987
|
+
...gated.size > 0 ? [mountGateHelper(gate)] : []
|
|
4699
4988
|
].join("\n\n");
|
|
4700
4989
|
if (plan.moved.length > 0 && (copied.size >= MAX_COMPONENT_FILES || Buffer.byteLength(moduleSource) > MAX_FILE_BYTES || copiedBytes + Buffer.byteLength(moduleSource) > MAX_COMPONENT_BYTES)) {
|
|
4701
4990
|
warn(`Inline component "${plan.movedNames[0]}" exceeded the component migration budget; source was preserved.`, currentFile);
|
|
@@ -5221,6 +5510,18 @@ function pageRoutes(pages) {
|
|
|
5221
5510
|
function pageEntryRoutes(page) {
|
|
5222
5511
|
return [.../* @__PURE__ */ new Set([...pageRoutes([page]), ...page.id === "introduction" ? ["/"] : []])];
|
|
5223
5512
|
}
|
|
5513
|
+
function pagesRedirectedFrom(redirects, pages) {
|
|
5514
|
+
const sources = new Set(redirects.flatMap(({ source }) => exactRoute(source) ?? []));
|
|
5515
|
+
return pages.filter((page) => page.id !== "introduction" && !(page.locale && page.id === `${page.locale}/introduction`) && pageRoutes([page]).some((route) => sources.has(route)));
|
|
5516
|
+
}
|
|
5517
|
+
function redirectsOverPagesWarning(routes) {
|
|
5518
|
+
if (routes.length === 0) return null;
|
|
5519
|
+
const one = routes.length === 1;
|
|
5520
|
+
return {
|
|
5521
|
+
code: "unsupported-config",
|
|
5522
|
+
message: `Kept ${routes.length} redirect${one ? "" : "s"} from ${list([...routes])}: ${one ? "that URL is" : "those URLs are"} also ${one ? "a page" : "pages"} in this site. Mintlify follows a redirect and never shows the page, so the ${one ? "page was" : "pages were"} marked noindex and ${one ? "its file stays" : "their files stay"}. Delete ${one ? "the page" : "a page"} and its navigation entry if you do not need it.`
|
|
5523
|
+
};
|
|
5524
|
+
}
|
|
5224
5525
|
function servedRoutes(pages) {
|
|
5225
5526
|
return new Set(pageRoutes(pages).map((route) => route.toLowerCase()));
|
|
5226
5527
|
}
|
|
@@ -5427,15 +5728,6 @@ function addMintlifyDirectoryRedirects(config, pages) {
|
|
|
5427
5728
|
return match ? route === match[1] || route.startsWith(`${match[1]}/`) : false;
|
|
5428
5729
|
});
|
|
5429
5730
|
}
|
|
5430
|
-
for (const page of pages) {
|
|
5431
|
-
if (!/\/(?:overview|introduction)$/.test(page.navigationId)) continue;
|
|
5432
|
-
const parent = page.id.replace(/\/(?:overview|introduction)$/, "");
|
|
5433
|
-
if (!parent || pageIds.has(parent.toLowerCase())) continue;
|
|
5434
|
-
const source = `/${parent}`;
|
|
5435
|
-
if (hasAuthoredRedirect(source)) continue;
|
|
5436
|
-
redirects.push({ source, destination: `/${page.id}`, permanent: false });
|
|
5437
|
-
redirectSources.add(source.toLowerCase());
|
|
5438
|
-
}
|
|
5439
5731
|
const navigationOrder = [];
|
|
5440
5732
|
function collectPages(nodes) {
|
|
5441
5733
|
for (const node of nodes) {
|
|
@@ -5463,6 +5755,15 @@ function addMintlifyDirectoryRedirects(config, pages) {
|
|
|
5463
5755
|
}
|
|
5464
5756
|
}
|
|
5465
5757
|
}
|
|
5758
|
+
for (const page of pages) {
|
|
5759
|
+
if (!/\/(?:overview|introduction)$/.test(page.navigationId)) continue;
|
|
5760
|
+
const parent = page.id.replace(/\/(?:overview|introduction)$/, "");
|
|
5761
|
+
if (!parent || pageIds.has(parent.toLowerCase()) || !firstDescendantByDirectory.has(parent)) continue;
|
|
5762
|
+
const source = `/${parent}`;
|
|
5763
|
+
if (hasAuthoredRedirect(source)) continue;
|
|
5764
|
+
redirects.push({ source, destination: `/${page.id}`, permanent: false });
|
|
5765
|
+
redirectSources.add(source.toLowerCase());
|
|
5766
|
+
}
|
|
5466
5767
|
for (const [directory2, landing] of firstDescendantByDirectory) {
|
|
5467
5768
|
if (pageIds.has(directory2.toLowerCase())) continue;
|
|
5468
5769
|
const source = `/${directory2}`;
|
|
@@ -5472,6 +5773,9 @@ function addMintlifyDirectoryRedirects(config, pages) {
|
|
|
5472
5773
|
}
|
|
5473
5774
|
return redirects.length > 0 ? { ...config, redirects } : config;
|
|
5474
5775
|
}
|
|
5776
|
+
function isMintlifyRootIndex(page, defaultLocale) {
|
|
5777
|
+
return page.id === "introduction" && (!page.locale || page.locale === defaultLocale) && /(?:^|[/#])index\.mdx?$/i.test(page.source);
|
|
5778
|
+
}
|
|
5475
5779
|
function addMintlifyHomepageRedirects(config, pages) {
|
|
5476
5780
|
const defaultPages = new Set(pages.filter((page) => !page.locale || page.locale === config.i18n?.defaultLocale).map((page) => page.navigationId));
|
|
5477
5781
|
function firstPage(nodes) {
|
|
@@ -5491,8 +5795,9 @@ function addMintlifyHomepageRedirects(config, pages) {
|
|
|
5491
5795
|
const sources = new Set(redirects.map((redirect) => routeKey(redirect.source)));
|
|
5492
5796
|
const roots = ["", ...(config.i18n?.locales ?? []).filter((locale) => locale.code !== config.i18n?.defaultLocale).filter((locale) => homepage !== "introduction" || pages.some((page) => page.locale === locale.code && page.navigationId === homepage)).map((locale) => locale.code)];
|
|
5493
5797
|
const homeLinksElsewhere = pages.some((page) => page.id === "introduction" && page.externalUrl);
|
|
5798
|
+
const rootIsIndexPage = pages.some((page) => isMintlifyRootIndex(page, config.i18n?.defaultLocale));
|
|
5494
5799
|
for (const locale of roots) {
|
|
5495
|
-
if (!locale && homeLinksElsewhere) continue;
|
|
5800
|
+
if (!locale && (homeLinksElsewhere || rootIsIndexPage)) continue;
|
|
5496
5801
|
const source = locale ? `/${locale}` : "/";
|
|
5497
5802
|
if (sources.has(source.toLowerCase())) continue;
|
|
5498
5803
|
const destination = `${locale ? `/${locale}` : ""}/${homepage}`;
|
|
@@ -6257,12 +6562,43 @@ function convertContainerToTabs(containerValue, context, fallbackTab, trace, dep
|
|
|
6257
6562
|
...container.hidden === true ? { hidden: true } : {}
|
|
6258
6563
|
}] : [];
|
|
6259
6564
|
}
|
|
6565
|
+
function named(text4) {
|
|
6566
|
+
return text4.replace(/[\x00-\x1f\x7f]/g, "").slice(0, 60);
|
|
6567
|
+
}
|
|
6260
6568
|
function projectedTheme(value) {
|
|
6261
6569
|
if (value === "maple" || value === "aspen") return "maple";
|
|
6262
6570
|
if (["luma", "sequoia"].includes(String(value))) return "sharp";
|
|
6263
6571
|
if (["almond", "palm"].includes(String(value))) return "minimal";
|
|
6264
6572
|
return typeof value === "string" ? "default" : void 0;
|
|
6265
6573
|
}
|
|
6574
|
+
function projectedThemeWithWarning(value, warnings) {
|
|
6575
|
+
const theme = projectedTheme(value);
|
|
6576
|
+
if (theme && value !== theme && value !== "mint") {
|
|
6577
|
+
warnings.push({ code: "unsupported-config", message: `theme ${JSON.stringify(named(String(value)))} has no exact Thally equivalent, so ${JSON.stringify(theme)} was used, which is the closest. Compare the look of the migrated site with the live one.`, source: "docs.json" });
|
|
6578
|
+
}
|
|
6579
|
+
return theme;
|
|
6580
|
+
}
|
|
6581
|
+
function projectedErrors(value, warnings) {
|
|
6582
|
+
const errors = objectValue2(value);
|
|
6583
|
+
if (!errors) return void 0;
|
|
6584
|
+
const notCarried = [];
|
|
6585
|
+
let redirect;
|
|
6586
|
+
for (const [status, entry] of Object.entries(errors)) {
|
|
6587
|
+
const settings = status === "404" ? objectValue2(entry) : null;
|
|
6588
|
+
if (!settings) {
|
|
6589
|
+
notCarried.push(named(`errors.${status}`));
|
|
6590
|
+
continue;
|
|
6591
|
+
}
|
|
6592
|
+
for (const [key, setting] of Object.entries(settings)) {
|
|
6593
|
+
if (key === "redirect" && typeof setting === "boolean") redirect = setting;
|
|
6594
|
+
else notCarried.push(named(`errors.404.${key}`));
|
|
6595
|
+
}
|
|
6596
|
+
}
|
|
6597
|
+
if (notCarried.length > 0) {
|
|
6598
|
+
warnings.push({ code: "unsupported-config", message: `docs.json ${notCarried.slice(0, 10).join(", ")}${notCarried.length > 10 ? ", ..." : ""} ${notCarried.length === 1 ? "was" : "were"} not carried over: Thally carries only errors.404.redirect (true or false).`, source: "docs.json" });
|
|
6599
|
+
}
|
|
6600
|
+
return redirect === void 0 ? void 0 : { "404": { redirect } };
|
|
6601
|
+
}
|
|
6266
6602
|
function projectedColors(value, warnings) {
|
|
6267
6603
|
const colors = objectValue2(value);
|
|
6268
6604
|
if (!colors) {
|
|
@@ -6395,7 +6731,7 @@ function projectedCompatibleConfig(config, warnings, shortcutSources) {
|
|
|
6395
6731
|
const feedback = objectValue2(config.feedback);
|
|
6396
6732
|
const seo = objectValue2(config.seo);
|
|
6397
6733
|
const contextualOptions = Array.isArray(objectValue2(config.contextual)?.options) ? objectValue2(config.contextual).options : [];
|
|
6398
|
-
const projectedContextual = contextualOptions.filter((option) => typeof option === "string" && ["copy", "view", "chatgpt", "claude", "perplexity"].includes(option));
|
|
6734
|
+
const projectedContextual = contextualOptions.filter((option) => typeof option === "string" && ["copy", "view", "chatgpt", "claude", "perplexity", "llms-full", "mcp", "cursor", "vscode"].includes(option));
|
|
6399
6735
|
const droppedContextual = contextualOptions.filter((option) => !projectedContextual.includes(option));
|
|
6400
6736
|
if (droppedContextual.length > 0) {
|
|
6401
6737
|
warnings.push({ code: "unsupported-config", message: `contextual.options entries not supported by the page menu were dropped: ${droppedContextual.map((option) => typeof option === "string" ? option : "custom entry").join(", ")}.`, source: "docs.json" });
|
|
@@ -6410,6 +6746,8 @@ function projectedCompatibleConfig(config, warnings, shortcutSources) {
|
|
|
6410
6746
|
}
|
|
6411
6747
|
const projectedMetatags = metatagEntries.length > 0 ? Object.fromEntries(metatagEntries) : void 0;
|
|
6412
6748
|
const projectedColorsValue = projectedColors(config.colors, warnings);
|
|
6749
|
+
const theme = projectedThemeWithWarning(config.theme, warnings);
|
|
6750
|
+
const errors = projectedErrors(config.errors, warnings);
|
|
6413
6751
|
const iconLibrary = objectValue2(config.icons)?.library;
|
|
6414
6752
|
const projectedIconLibrary = iconLibrary === void 0 ? "fontawesome" : ["lucide", "fontawesome", "tabler"].includes(String(iconLibrary)) ? String(iconLibrary) : void 0;
|
|
6415
6753
|
const docsNavbar = projectedNavbar(config.navbar);
|
|
@@ -6444,7 +6782,8 @@ function projectedCompatibleConfig(config, warnings, shortcutSources) {
|
|
|
6444
6782
|
smartQuotes: true,
|
|
6445
6783
|
// `styling.eyebrows: "breadcrumbs"` shows the whole group path; "section" (the default) shows the nearest group.
|
|
6446
6784
|
...objectValue2(config.styling)?.eyebrows === "breadcrumbs" ? { eyebrow: "path" } : {},
|
|
6447
|
-
...
|
|
6785
|
+
...theme ? { theme } : {},
|
|
6786
|
+
...errors ? { errors } : {},
|
|
6448
6787
|
...projectedContextual.length > 0 ? { contextual: { options: projectedContextual } } : {},
|
|
6449
6788
|
...projectedColorsValue ? { colors: projectedColorsValue } : {},
|
|
6450
6789
|
...projectedIconLibrary ? { icons: { library: projectedIconLibrary } } : {},
|
|
@@ -8257,10 +8596,10 @@ function namedExportStringText(source, name) {
|
|
|
8257
8596
|
`\\bexport\\s+(?:const|let|var)\\s+${name}\\b(?:\\s*:\\s*[^=;]+)?\\s*=\\s*`
|
|
8258
8597
|
).exec(source);
|
|
8259
8598
|
if (!match) return void 0;
|
|
8260
|
-
const
|
|
8261
|
-
if (!
|
|
8599
|
+
const quoted2 = source.slice(match.index + match[0].length).match(/^("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*')/);
|
|
8600
|
+
if (!quoted2) return void 0;
|
|
8262
8601
|
try {
|
|
8263
|
-
const parsed = JSON5.parse(
|
|
8602
|
+
const parsed = JSON5.parse(quoted2[1]);
|
|
8264
8603
|
return typeof parsed === "string" ? parsed : void 0;
|
|
8265
8604
|
} catch {
|
|
8266
8605
|
return void 0;
|
|
@@ -8411,13 +8750,13 @@ function staticObjectEntries(array) {
|
|
|
8411
8750
|
function staticStringField(source, name, bindings) {
|
|
8412
8751
|
const start = propertyStart(source, name);
|
|
8413
8752
|
if (start < 0) return void 0;
|
|
8414
|
-
const
|
|
8415
|
-
if (!
|
|
8753
|
+
const quoted2 = source.slice(start).match(/^("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*')/);
|
|
8754
|
+
if (!quoted2) {
|
|
8416
8755
|
const reference = source.slice(start).match(/^([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/)?.[1];
|
|
8417
8756
|
return reference ? bindings?.get(reference) : void 0;
|
|
8418
8757
|
}
|
|
8419
8758
|
try {
|
|
8420
|
-
const parsed = JSON5.parse(
|
|
8759
|
+
const parsed = JSON5.parse(quoted2[1]);
|
|
8421
8760
|
return typeof parsed === "string" ? parsed : void 0;
|
|
8422
8761
|
} catch {
|
|
8423
8762
|
return void 0;
|
|
@@ -9291,6 +9630,18 @@ var SAFE_PATH = /^\/[A-Za-z0-9._~\-/]*$/;
|
|
|
9291
9630
|
var MAX_PLAUSIBLE_DOMAINS = 10;
|
|
9292
9631
|
var SUPPORTED = ["ga4", "gtm", "posthog", "plausible"];
|
|
9293
9632
|
var LEGACY_GA4_ALIAS = "googleAnalytics";
|
|
9633
|
+
var KNOWN_TRACKERS = [
|
|
9634
|
+
["PostHog", /posthog/i],
|
|
9635
|
+
["Intercom", /intercom/i],
|
|
9636
|
+
["Segment", /segment\.(?:com|io)/i],
|
|
9637
|
+
["Hotjar", /hotjar|_hjSettings/i],
|
|
9638
|
+
["Google Tag Manager/Analytics", /googletagmanager|google-analytics\.com|\bgtag\s*\(|\bdataLayer\b/i],
|
|
9639
|
+
["Mixpanel", /mixpanel/i],
|
|
9640
|
+
["Amplitude", /amplitude/i]
|
|
9641
|
+
];
|
|
9642
|
+
function trackersIn(source) {
|
|
9643
|
+
return KNOWN_TRACKERS.filter(([, pattern]) => pattern.test(source)).map(([name]) => name);
|
|
9644
|
+
}
|
|
9294
9645
|
function own(record, key) {
|
|
9295
9646
|
return Object.prototype.hasOwnProperty.call(record, key) ? record[key] : void 0;
|
|
9296
9647
|
}
|
|
@@ -10015,9 +10366,9 @@ function projectCapturedTabs($, root) {
|
|
|
10015
10366
|
import { createHash as createHash4 } from "crypto";
|
|
10016
10367
|
import remarkMdx3 from "remark-mdx";
|
|
10017
10368
|
import remarkParse4 from "remark-parse";
|
|
10018
|
-
import
|
|
10369
|
+
import remarkGfm3 from "remark-gfm";
|
|
10019
10370
|
import { unified as unified4 } from "unified";
|
|
10020
|
-
var parser2 = unified4().use(remarkParse4).use(
|
|
10371
|
+
var parser2 = unified4().use(remarkParse4).use(remarkGfm3).use(remarkMdx3);
|
|
10021
10372
|
var MAX_SOURCE_BYTES = 8e6;
|
|
10022
10373
|
var sourceTrees = /* @__PURE__ */ new Map();
|
|
10023
10374
|
var cachedSourceBytes = 0;
|
|
@@ -10053,20 +10404,20 @@ function readMigrationFlightDocument($) {
|
|
|
10053
10404
|
}
|
|
10054
10405
|
function literalJson(value) {
|
|
10055
10406
|
if (Buffer.byteLength(value) > MAX_SOURCE_BYTES) return void 0;
|
|
10056
|
-
let depth = 0,
|
|
10407
|
+
let depth = 0, quoted2 = false, escaped = false;
|
|
10057
10408
|
for (const character of value) {
|
|
10058
|
-
if (
|
|
10409
|
+
if (quoted2) {
|
|
10059
10410
|
if (escaped) escaped = false;
|
|
10060
10411
|
else if (character === "\\") escaped = true;
|
|
10061
|
-
else if (character === '"')
|
|
10062
|
-
} else if (character === '"')
|
|
10412
|
+
else if (character === '"') quoted2 = false;
|
|
10413
|
+
} else if (character === '"') quoted2 = true;
|
|
10063
10414
|
else if (character === "[" || character === "{") {
|
|
10064
10415
|
if (++depth > 96) return void 0;
|
|
10065
10416
|
} else if (character === "]" || character === "}") {
|
|
10066
10417
|
if (--depth < 0) return void 0;
|
|
10067
10418
|
}
|
|
10068
10419
|
}
|
|
10069
|
-
if (depth !== 0 ||
|
|
10420
|
+
if (depth !== 0 || quoted2) return void 0;
|
|
10070
10421
|
try {
|
|
10071
10422
|
return JSON.parse(value);
|
|
10072
10423
|
} catch {
|
|
@@ -13925,14 +14276,49 @@ function readMintignoreMatcher(mintlifyRoot) {
|
|
|
13925
14276
|
if (!existsSync5(path) || !lstatSync6(path).isFile()) return null;
|
|
13926
14277
|
return createIgnoreMatcher().add(readFileSync6(path, "utf8"));
|
|
13927
14278
|
}
|
|
14279
|
+
var RUNTIME_DEFAULT_ICON_LIBRARY = "lucide";
|
|
14280
|
+
function quoted(items) {
|
|
14281
|
+
const unique = [...new Set(items.map((item) => item.replace(/\s+/g, " ").trim()))];
|
|
14282
|
+
const shown = unique.slice(0, 3).map((item) => `\`${item.length > 60 ? `${item.slice(0, 59)}\u2026` : item}\``);
|
|
14283
|
+
return `${shown.join(", ")}${unique.length > 3 ? `, and ${unique.length - 3} more` : ""}`;
|
|
14284
|
+
}
|
|
13928
14285
|
function invalidMdxReason(body) {
|
|
13929
14286
|
try {
|
|
13930
|
-
compileSync2(body,
|
|
14287
|
+
compileSync2(body, MDX_COMPILE_OPTIONS);
|
|
13931
14288
|
return null;
|
|
13932
14289
|
} catch (error) {
|
|
13933
14290
|
return error instanceof Error ? error.message : String(error);
|
|
13934
14291
|
}
|
|
13935
14292
|
}
|
|
14293
|
+
function unresolvedComponentWarning(name, source) {
|
|
14294
|
+
return {
|
|
14295
|
+
code: "unsupported-config",
|
|
14296
|
+
message: `Unresolved MDX component <${name}> was replaced with a plain <div> (or removed, if self-closing) so the page still builds. It may be a site-authored or third-party implementation; review its source before adding a Thally equivalent.`,
|
|
14297
|
+
source
|
|
14298
|
+
};
|
|
14299
|
+
}
|
|
14300
|
+
function repairUncompilableMdx(body) {
|
|
14301
|
+
const closingTags = escapeUnmatchedClosingTags(body);
|
|
14302
|
+
if (closingTags.escaped.length > 0 && invalidMdxReason(closingTags.body) === null) {
|
|
14303
|
+
return { body: closingTags.body, closingTags: closingTags.escaped, braces: [] };
|
|
14304
|
+
}
|
|
14305
|
+
const braces = escapeUnparseableExpressions(closingTags.body);
|
|
14306
|
+
return braces.escaped.length > 0 ? { body: braces.body, closingTags: closingTags.escaped, braces: braces.escaped } : null;
|
|
14307
|
+
}
|
|
14308
|
+
function repairWarnings(repair, source) {
|
|
14309
|
+
return [
|
|
14310
|
+
...repair.closingTags.length > 0 ? [{
|
|
14311
|
+
code: "unsupported-config",
|
|
14312
|
+
message: `Escaped unmatched closing tag(s) ${quoted(repair.closingTags)} so the page compiles; they render as literal text.`,
|
|
14313
|
+
source
|
|
14314
|
+
}] : [],
|
|
14315
|
+
...repair.braces.length > 0 ? [{
|
|
14316
|
+
code: "unsupported-config",
|
|
14317
|
+
message: `Escaped the braces of ${quoted(repair.braces)} so the page compiles; they render as literal text.`,
|
|
14318
|
+
source
|
|
14319
|
+
}] : []
|
|
14320
|
+
];
|
|
14321
|
+
}
|
|
13936
14322
|
var HEX_COLOR = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
13937
14323
|
function mintlifyThemeColors(value) {
|
|
13938
14324
|
if (!value || typeof value !== "object") return void 0;
|
|
@@ -14177,9 +14563,9 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, n
|
|
|
14177
14563
|
for (const page of pages) {
|
|
14178
14564
|
const specRef = page.openapi ? splitOpenApiRef(page.openapi)?.specRef : void 0;
|
|
14179
14565
|
if (!specRef || /^[a-z][a-z0-9+.-]*:/i.test(specRef)) continue;
|
|
14180
|
-
const
|
|
14181
|
-
namedFiles.set(specRef,
|
|
14182
|
-
const key =
|
|
14566
|
+
const named2 = namedFiles.get(specRef) ?? resolveSpecRef(specRef, specFiles, false);
|
|
14567
|
+
namedFiles.set(specRef, named2);
|
|
14568
|
+
const key = named2.kind === "match" ? named2.spec.sourcePath : "";
|
|
14183
14569
|
if (!key || known.has(key)) continue;
|
|
14184
14570
|
known.add(key);
|
|
14185
14571
|
references.push({ value: key, kind: "openapi", tabLabel: `OpenAPI: ${key}`, hidden: true, pageOnly: true });
|
|
@@ -14462,23 +14848,23 @@ function mintlifyEndpointUrls(directory2, operations) {
|
|
|
14462
14848
|
const title = mintlifyOperationTitle(operation);
|
|
14463
14849
|
const tag = operation.tag === void 0 ? "" : mintlifyUrlSlug(operation.tag);
|
|
14464
14850
|
const slug2 = mintlifyUrlSlug(title);
|
|
14465
|
-
const
|
|
14851
|
+
const named2 = slug2 !== "" && (operation.tag === void 0 || tag !== "");
|
|
14466
14852
|
const folder = [directory2, tag].filter(Boolean).join("/");
|
|
14467
|
-
slugs.set(operation, { tag, slug: slug2, folder, title, named });
|
|
14468
|
-
if (
|
|
14853
|
+
slugs.set(operation, { tag, slug: slug2, folder, title, named: named2 });
|
|
14854
|
+
if (named2) spelled.add(`${folder}/${slug2}`);
|
|
14469
14855
|
}
|
|
14470
14856
|
const endpoints = /* @__PURE__ */ new Map();
|
|
14471
14857
|
const taken = /* @__PURE__ */ new Set();
|
|
14472
14858
|
const next = /* @__PURE__ */ new Map();
|
|
14473
|
-
for (const [operation, { tag, slug: slug2, folder, title, named }] of slugs) {
|
|
14859
|
+
for (const [operation, { tag, slug: slug2, folder, title, named: named2 }] of slugs) {
|
|
14474
14860
|
let leaf = slug2;
|
|
14475
|
-
if (
|
|
14861
|
+
if (named2) {
|
|
14476
14862
|
let number = next.get(`${folder}/${slug2}`) ?? 1;
|
|
14477
14863
|
while (taken.has(`${folder}/${leaf}`) || leaf !== slug2 && spelled.has(`${folder}/${leaf}`)) leaf = `${slug2}-${number++}`;
|
|
14478
14864
|
next.set(`${folder}/${slug2}`, number);
|
|
14479
14865
|
taken.add(`${folder}/${leaf}`);
|
|
14480
14866
|
}
|
|
14481
|
-
endpoints.set(operation, { tag, leaf, url: [folder, leaf].filter(Boolean).join("/"), title, named });
|
|
14867
|
+
endpoints.set(operation, { tag, leaf, url: [folder, leaf].filter(Boolean).join("/"), title, named: named2 });
|
|
14482
14868
|
}
|
|
14483
14869
|
return endpoints;
|
|
14484
14870
|
}
|
|
@@ -15041,10 +15427,29 @@ function staticSnippetProperties(attributes) {
|
|
|
15041
15427
|
}
|
|
15042
15428
|
return properties;
|
|
15043
15429
|
}
|
|
15044
|
-
function
|
|
15430
|
+
function passedAttributeNames(attributes) {
|
|
15431
|
+
const tree = ts5.createSourceFile("snippet.tsx", `const snippet = <Snippet ${attributes.replace(/\/\s*$/, "")} />`, ts5.ScriptTarget.Latest, true, ts5.ScriptKind.TSX);
|
|
15432
|
+
const statement = tree.statements[0];
|
|
15433
|
+
const element = statement && ts5.isVariableStatement(statement) ? statement.declarationList.declarations[0]?.initializer : void 0;
|
|
15434
|
+
if (!element || !ts5.isJsxSelfClosingElement(element)) return void 0;
|
|
15435
|
+
const names = /* @__PURE__ */ new Set();
|
|
15436
|
+
for (const attribute2 of element.attributes.properties) {
|
|
15437
|
+
if (!ts5.isJsxAttribute(attribute2)) return void 0;
|
|
15438
|
+
names.add(attribute2.name.getText(tree));
|
|
15439
|
+
}
|
|
15440
|
+
return names;
|
|
15441
|
+
}
|
|
15442
|
+
function interpolateSnippet(snippet, attributes, children, parameters = []) {
|
|
15045
15443
|
const properties = staticSnippetProperties(attributes);
|
|
15046
15444
|
if (children !== void 0) properties.set("children", children.trim());
|
|
15047
|
-
|
|
15445
|
+
const unset = /* @__PURE__ */ new Set();
|
|
15446
|
+
const passed = parameters.length > 0 ? passedAttributeNames(attributes) : void 0;
|
|
15447
|
+
for (const { name, fallback } of passed ? parameters : []) {
|
|
15448
|
+
if (name === "children" || passed.has(name)) continue;
|
|
15449
|
+
if (fallback === void 0) unset.add(name);
|
|
15450
|
+
else properties.set(name, fallback);
|
|
15451
|
+
}
|
|
15452
|
+
return bindSnippetProps(snippet, properties, unset);
|
|
15048
15453
|
}
|
|
15049
15454
|
function isolateFences(snippet, source, start, end) {
|
|
15050
15455
|
const fence = /^\s*(?:`{3,}|~{3,})/;
|
|
@@ -15058,6 +15463,23 @@ function alignToTag(snippet, source, start) {
|
|
|
15058
15463
|
const indent = /^[ \t]*(?:(?:[-*+]|\d{1,9}[.)])[ \t]+)?$/.test(before) ? before.replace(/\S/g, " ") : before.match(/^[ \t]*/)[0];
|
|
15059
15464
|
return indentSnippetLines(snippet, indent);
|
|
15060
15465
|
}
|
|
15466
|
+
function snippetParameters(source, componentName) {
|
|
15467
|
+
const parsed = ts5.createSourceFile("snippet.tsx", source, ts5.ScriptTarget.Latest, true, ts5.ScriptKind.TSX);
|
|
15468
|
+
for (const statement of parsed.statements) {
|
|
15469
|
+
if (!ts5.isVariableStatement(statement)) continue;
|
|
15470
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
15471
|
+
if (!ts5.isIdentifier(declaration.name) || declaration.name.text !== componentName) continue;
|
|
15472
|
+
const pattern = declaration.initializer && ts5.isArrowFunction(declaration.initializer) ? declaration.initializer.parameters[0]?.name : void 0;
|
|
15473
|
+
if (!pattern || !ts5.isObjectBindingPattern(pattern)) return [];
|
|
15474
|
+
return pattern.elements.flatMap((element) => {
|
|
15475
|
+
if (element.dotDotDotToken || element.propertyName || !ts5.isIdentifier(element.name)) return [];
|
|
15476
|
+
if (!element.initializer) return [{ name: element.name.text }];
|
|
15477
|
+
return ts5.isStringLiteralLike(element.initializer) ? [{ name: element.name.text, fallback: element.initializer.text }] : [];
|
|
15478
|
+
});
|
|
15479
|
+
}
|
|
15480
|
+
}
|
|
15481
|
+
return [];
|
|
15482
|
+
}
|
|
15061
15483
|
function snippetComponentBody(source, componentName) {
|
|
15062
15484
|
const parsed = ts5.createSourceFile("snippet.tsx", source, ts5.ScriptTarget.Latest, true, ts5.ScriptKind.TSX);
|
|
15063
15485
|
for (const statement of parsed.statements) {
|
|
@@ -15144,20 +15566,37 @@ function staticNamedSnippetValues(source) {
|
|
|
15144
15566
|
return values;
|
|
15145
15567
|
}
|
|
15146
15568
|
function hoistMdxImports(source) {
|
|
15147
|
-
const
|
|
15148
|
-
|
|
15149
|
-
|
|
15150
|
-
|
|
15151
|
-
|
|
15152
|
-
|
|
15153
|
-
|
|
15154
|
-
|
|
15569
|
+
const hoist = (text4) => {
|
|
15570
|
+
const imports3 = /* @__PURE__ */ new Set();
|
|
15571
|
+
const rest2 = replaceOutsideCode(text4, (body) => body.replace(
|
|
15572
|
+
/^[ \t]*import\s+(?:\{[^}\n]+\}|[A-Za-z_$][\w$]*)\s+from\s+(['"])[^'"\n]+\1[ \t]*;?/gm,
|
|
15573
|
+
(statement) => {
|
|
15574
|
+
imports3.add(statement.trim().replace(/;?$/, ";"));
|
|
15575
|
+
return "";
|
|
15576
|
+
}
|
|
15577
|
+
));
|
|
15578
|
+
return { imports: imports3, rest: rest2 };
|
|
15579
|
+
};
|
|
15580
|
+
let { imports: imports2, rest } = hoist(source);
|
|
15155
15581
|
if (imports2.size === 0) return source;
|
|
15156
|
-
const
|
|
15582
|
+
const literals = [];
|
|
15583
|
+
let protectedSource = "";
|
|
15584
|
+
let cursor = 0;
|
|
15585
|
+
for (const [start, end] of source.includes("`") ? esmTemplateLiteralRanges(source) : []) {
|
|
15586
|
+
if (start < cursor) continue;
|
|
15587
|
+
literals.push(source.slice(start, end));
|
|
15588
|
+
protectedSource += `${source.slice(cursor, start)}${literals.length - 1}`;
|
|
15589
|
+
cursor = end;
|
|
15590
|
+
}
|
|
15591
|
+
if (literals.length > 0) {
|
|
15592
|
+
({ imports: imports2, rest } = hoist(protectedSource + source.slice(cursor)));
|
|
15593
|
+
if (imports2.size === 0) return source;
|
|
15594
|
+
}
|
|
15595
|
+
const frontmatter = rest.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/);
|
|
15157
15596
|
const prefix = frontmatter?.[0] ?? "";
|
|
15158
15597
|
return `${prefix}${[...imports2].join("\n")}
|
|
15159
15598
|
|
|
15160
|
-
${
|
|
15599
|
+
${rest.slice(prefix.length).replace(/^(?:\r?\n)*/, "")}`.replace(/\u0002(\d+)\u0002/g, (marker, index) => literals[Number(index)] ?? marker);
|
|
15161
15600
|
}
|
|
15162
15601
|
function fernSourceBasePath(config) {
|
|
15163
15602
|
const instance = Array.isArray(config.instances) ? config.instances[0] : null;
|
|
@@ -15213,14 +15652,26 @@ function stripFernBasePathFromLinks(body, basePath) {
|
|
|
15213
15652
|
const escaped = basePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
15214
15653
|
return replaceOutsideCode(body, (text4) => text4.replace(new RegExp(`(\\]\\()${escaped}(?=\\/|[)#?])`, "g"), (match, prefix, offset, source) => prefix + (source[offset + match.length] === "/" ? "" : "/")).replace(new RegExp(`(\\b(?:href|to)=["'])${escaped}(?=\\/|["'#?])`, "g"), (match, prefix, offset, source) => prefix + (source[offset + match.length] === "/" ? "" : "/")));
|
|
15215
15654
|
}
|
|
15216
|
-
function
|
|
15217
|
-
const
|
|
15655
|
+
function mintlifySourceSite(config) {
|
|
15656
|
+
const canonical2 = config?.seo?.metatags?.canonical;
|
|
15657
|
+
if (typeof canonical2 === "string") {
|
|
15658
|
+
try {
|
|
15659
|
+
const url = new URL(canonical2.trim());
|
|
15660
|
+
if (url.protocol === "http:" || url.protocol === "https:") return { host: url.hostname, path: url.pathname.replace(/\/+$/, "") };
|
|
15661
|
+
} catch {
|
|
15662
|
+
}
|
|
15663
|
+
}
|
|
15664
|
+
const domain = config?.integrations?.plausible?.domain;
|
|
15665
|
+
return typeof domain === "string" && /^(?:docs|developers?)(?:\.[a-z0-9-]+)+$/i.test(domain.trim()) ? { host: domain.trim().toLowerCase(), path: "" } : void 0;
|
|
15666
|
+
}
|
|
15667
|
+
function rewriteMintlifyMountedLinks(body, pageIds, sourceSite) {
|
|
15668
|
+
const resolve5 = (target2) => {
|
|
15218
15669
|
const suffixAt = target2.search(/[?#]/);
|
|
15219
15670
|
const pathname = suffixAt < 0 ? target2 : target2.slice(0, suffixAt);
|
|
15220
15671
|
const suffix = suffixAt < 0 ? "" : target2.slice(suffixAt);
|
|
15221
|
-
if (!pathname.startsWith("/") || pathname.startsWith("//") || pathname.includes("\\")) return
|
|
15672
|
+
if (!pathname.startsWith("/") || pathname.startsWith("//") || pathname.includes("\\")) return void 0;
|
|
15222
15673
|
const segments = pathname.slice(1).split("/");
|
|
15223
|
-
if (segments.some((segment) => !segment || segment === "." || segment === "..")) return
|
|
15674
|
+
if (segments.some((segment) => !segment || segment === "." || segment === "..")) return void 0;
|
|
15224
15675
|
const markdown = pathname.endsWith(".md");
|
|
15225
15676
|
const sourceMdx = pathname.endsWith(".mdx");
|
|
15226
15677
|
const routeSegments = markdown || sourceMdx ? [...segments.slice(0, -1), segments.at(-1).replace(/\.mdx?$/, "")] : segments;
|
|
@@ -15229,9 +15680,21 @@ function rewriteMintlifyMountedLinks(body, pageIds) {
|
|
|
15229
15680
|
const candidate = routeSegments.slice(count).join("/");
|
|
15230
15681
|
if (pageIds.has(candidate)) return `/${candidate}${markdown ? ".md" : ""}${suffix}`;
|
|
15231
15682
|
}
|
|
15232
|
-
return
|
|
15683
|
+
return void 0;
|
|
15684
|
+
};
|
|
15685
|
+
const rewrite = (target2) => {
|
|
15686
|
+
if (target2.startsWith("/")) return resolve5(target2) ?? target2;
|
|
15687
|
+
if (!sourceSite) return target2;
|
|
15688
|
+
try {
|
|
15689
|
+
const url = new URL(target2);
|
|
15690
|
+
if (url.hostname !== sourceSite.host || url.port || url.username || url.password) return target2;
|
|
15691
|
+
if (sourceSite.path && url.pathname !== sourceSite.path && !url.pathname.startsWith(`${sourceSite.path}/`)) return target2;
|
|
15692
|
+
return resolve5(`${url.pathname}${url.search}${url.hash}`) ?? target2;
|
|
15693
|
+
} catch {
|
|
15694
|
+
return target2;
|
|
15695
|
+
}
|
|
15233
15696
|
};
|
|
15234
|
-
return replaceOutsideCode(body, (text4) => text4.replace(/(\]\()(\/[^\s)]
|
|
15697
|
+
return replaceOutsideCode(body, (text4) => text4.replace(/(\]\()(\/[^\s)]{1,2048}|https?:\/\/[^\s)]{1,2048})(\))/g, (_match, before, target2, after) => `${before}${rewrite(target2)}${after}`).replace(/(\b(?:href|to)=(['"]))(\/[^'"\n]{1,2048}|https?:\/\/[^'"\n]{1,2048})\2/g, (_match, before, quote, target2) => `${before}${rewrite(target2)}${quote}`));
|
|
15235
15698
|
}
|
|
15236
15699
|
function preserveLinkedAnchors(pages) {
|
|
15237
15700
|
const pageById = new Map(pages.map((page) => [page.id, page]));
|
|
@@ -15521,8 +15984,8 @@ function importUndeclaredSnippetComponents(raw, currentFile, repositoryRoot, sit
|
|
|
15521
15984
|
try {
|
|
15522
15985
|
const candidate = resolveSnippetPath(specifier, currentFile, repositoryRoot, siteRoot);
|
|
15523
15986
|
if (candidate !== match || !lstatSync6(candidate).isFile() || gate?.(candidate)) continue;
|
|
15524
|
-
const
|
|
15525
|
-
statements.push(
|
|
15987
|
+
const named2 = snippetExportedNames(readFileSync6(candidate, "utf8")).has(name);
|
|
15988
|
+
statements.push(named2 ? `import { ${name} } from '${specifier}'` : `import ${name} from '${specifier}'`);
|
|
15526
15989
|
warnings.push({
|
|
15527
15990
|
code: "unsupported-config",
|
|
15528
15991
|
message: `<${name}> is used without an import; it was resolved to ${specifier.slice(1)} (the only snippet exporting that name). Mintlify renders unimported components as empty, so this page now shows content the live site does not.`,
|
|
@@ -15641,6 +16104,7 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
15641
16104
|
if (depth >= 8) return raw;
|
|
15642
16105
|
raw = normalizeIndentedFences(raw);
|
|
15643
16106
|
const snippets = /* @__PURE__ */ new Map();
|
|
16107
|
+
const snippetProps = /* @__PURE__ */ new Map();
|
|
15644
16108
|
const preservedDeclarations = /* @__PURE__ */ new Map();
|
|
15645
16109
|
const source = relative6(repositoryRoot, currentFile).replace(/\\/g, "/");
|
|
15646
16110
|
const blockInline = (candidate, shownPath, label = shownPath) => {
|
|
@@ -15749,7 +16213,10 @@ ${indent}`), segment, match.index, end);
|
|
|
15749
16213
|
);
|
|
15750
16214
|
const declaration = statefulSnippetDeclaration(nested, componentName);
|
|
15751
16215
|
if (declaration) preservedDeclarations.set(componentName, declaration);
|
|
15752
|
-
else
|
|
16216
|
+
else {
|
|
16217
|
+
snippets.set(componentName, snippetComponentBody(nested, componentName));
|
|
16218
|
+
snippetProps.set(componentName, snippetParameters(nested, componentName));
|
|
16219
|
+
}
|
|
15753
16220
|
return "";
|
|
15754
16221
|
} catch (error) {
|
|
15755
16222
|
if (error instanceof Error && error.message.includes("escapes its root")) {
|
|
@@ -15834,6 +16301,7 @@ ${indent}`), segment, match.index, end);
|
|
|
15834
16301
|
continue;
|
|
15835
16302
|
}
|
|
15836
16303
|
components.push([binding.local, body]);
|
|
16304
|
+
if (/^[A-Z]/.test(binding.exported)) snippetProps.set(binding.local, snippetParameters(snippetSource, binding.exported));
|
|
15837
16305
|
}
|
|
15838
16306
|
for (const [name, body] of components) snippets.set(name, body);
|
|
15839
16307
|
return exportBlock(declarations2, statement, sourcePath);
|
|
@@ -15875,14 +16343,17 @@ ${indent}`), segment, match.index, end);
|
|
|
15875
16343
|
);
|
|
15876
16344
|
const declaration = statefulSnippetDeclaration(nested, componentName);
|
|
15877
16345
|
if (declaration) preservedDeclarations.set(componentName, declaration);
|
|
15878
|
-
else
|
|
16346
|
+
else {
|
|
16347
|
+
snippets.set(componentName, snippetComponentBody(nested, componentName));
|
|
16348
|
+
snippetProps.set(componentName, snippetParameters(nested, componentName));
|
|
16349
|
+
}
|
|
15879
16350
|
}
|
|
15880
16351
|
let result = replaceOutsideCodeAndComments(withoutImports, (segment) => {
|
|
15881
16352
|
for (const [componentName, snippet] of snippets) {
|
|
15882
16353
|
segment = segment.replace(new RegExp(`<${componentName}((?:\\s[^>]*)?)\\s*/>`, "g"), (tag, attributes, offset, source2) => {
|
|
15883
|
-
return isolateFences(alignToTag(closeOpenCodeFence(interpolateSnippet(snippet, attributes)), source2, offset), source2, offset, offset + tag.length);
|
|
16354
|
+
return isolateFences(alignToTag(closeOpenCodeFence(interpolateSnippet(snippet, attributes, void 0, snippetProps.get(componentName))), source2, offset), source2, offset, offset + tag.length);
|
|
15884
16355
|
}).replace(new RegExp(`<${componentName}((?:\\s[^>]*)?)>([\\s\\S]*?)<\\/${componentName}>`, "g"), (tag, attributes, children, offset, source2) => {
|
|
15885
|
-
return isolateFences(alignToTag(closeOpenCodeFence(interpolateSnippet(snippet, attributes, children)), source2, offset), source2, offset, offset + tag.length);
|
|
16356
|
+
return isolateFences(alignToTag(closeOpenCodeFence(interpolateSnippet(snippet, attributes, children, snippetProps.get(componentName))), source2, offset), source2, offset, offset + tag.length);
|
|
15886
16357
|
});
|
|
15887
16358
|
}
|
|
15888
16359
|
const tagLabel = (filePath) => platform === "fern" ? `Included file ${filePath}` : `Snippet file="${filePath}"`;
|
|
@@ -16064,6 +16535,7 @@ function migrateRepository(options) {
|
|
|
16064
16535
|
let mintlifyConfig = null;
|
|
16065
16536
|
let mintlifyApiTabSlots = [];
|
|
16066
16537
|
let mintlifyDirectories = [];
|
|
16538
|
+
let mintlifyAuthoredRedirects = [];
|
|
16067
16539
|
const mintlifyNavigationAccess = /* @__PURE__ */ new Map();
|
|
16068
16540
|
let fernRawConfig = null;
|
|
16069
16541
|
let fernBasePath = "";
|
|
@@ -16110,6 +16582,7 @@ function migrateRepository(options) {
|
|
|
16110
16582
|
docsConfig = projected.docsConfig;
|
|
16111
16583
|
mintlifyApiTabSlots = projected.apiTabSlots;
|
|
16112
16584
|
mintlifyDirectories = projected.directories;
|
|
16585
|
+
mintlifyAuthoredRedirects = projected.docsConfig.redirects ?? [];
|
|
16113
16586
|
warnings.push(...projected.warnings);
|
|
16114
16587
|
for (const repo of projected.gatedSourceRefs) gatedSourceRepos.add(repo.toLowerCase());
|
|
16115
16588
|
for (const appearance of projected.referenceAccess) {
|
|
@@ -16419,6 +16892,7 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
16419
16892
|
return { locale, navigationId, id: isDefaultLocale ? navigationId : `${locale}/${navigationId}` };
|
|
16420
16893
|
};
|
|
16421
16894
|
const routeAliases = [];
|
|
16895
|
+
const siteIconLibrary = docsConfig.icons?.library ?? RUNTIME_DEFAULT_ICON_LIBRARY;
|
|
16422
16896
|
const pageFiles = [...files].sort((left, right) => {
|
|
16423
16897
|
const leftOrder = referenceOrder.get(normalizedReferenceKey(left.relativePath)) ?? Number.MAX_SAFE_INTEGER;
|
|
16424
16898
|
const rightOrder = referenceOrder.get(normalizedReferenceKey(right.relativePath)) ?? Number.MAX_SAFE_INTEGER;
|
|
@@ -16595,9 +17069,27 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
16595
17069
|
);
|
|
16596
17070
|
}
|
|
16597
17071
|
const pageWarningSource = relative6(componentRoot, file.absolutePath).replace(/\\/g, "/");
|
|
17072
|
+
let componentAnalysisLeftWork = false;
|
|
16598
17073
|
if (componentMigrator) {
|
|
16599
17074
|
const warningsBeforeTransform = warnings.length;
|
|
17075
|
+
const analysisFailed = () => warnings.slice(warningsBeforeTransform).some((warning) => warning.message.startsWith(COMPONENT_ANALYSIS_FAILED) && warning.source !== void 0 && resolvePath(componentRoot, warning.source) === file.absolutePath);
|
|
17076
|
+
const beforeTransform = raw;
|
|
16600
17077
|
raw = componentMigrator.transform(raw, file.absolutePath);
|
|
17078
|
+
if (analysisFailed()) {
|
|
17079
|
+
const { front, body } = splitFrontmatterBlock(protectMathBlocks(beforeTransform).body);
|
|
17080
|
+
const repair = repairUncompilableMdx(normalizeHtmlComments(body));
|
|
17081
|
+
if (repair) {
|
|
17082
|
+
const failed = warnings.splice(warningsBeforeTransform);
|
|
17083
|
+
const retried = componentMigrator.transform(front + repair.body, file.absolutePath);
|
|
17084
|
+
if (analysisFailed()) {
|
|
17085
|
+
warnings.splice(warningsBeforeTransform, warnings.length, ...failed);
|
|
17086
|
+
} else {
|
|
17087
|
+
raw = retried;
|
|
17088
|
+
warnings.push(...repairWarnings(repair, file.relativePath));
|
|
17089
|
+
}
|
|
17090
|
+
}
|
|
17091
|
+
}
|
|
17092
|
+
componentAnalysisLeftWork = analysisFailed() && pageHasComponentWork(beforeTransform);
|
|
16601
17093
|
if (warnings.slice(warningsBeforeTransform).some((warning) => warning.code === "skipped-file" && warning.source !== void 0 && resolvePath(componentRoot, warning.source) === file.absolutePath)) {
|
|
16602
17094
|
skipped++;
|
|
16603
17095
|
continue;
|
|
@@ -16624,6 +17116,7 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
16624
17116
|
navigationId,
|
|
16625
17117
|
warn: (message) => warnings.push({ code: "unsupported-config", message, source: pageWarningSource }),
|
|
16626
17118
|
...locale ? { locale } : {},
|
|
17119
|
+
siteIconLibrary,
|
|
16627
17120
|
raw,
|
|
16628
17121
|
platform,
|
|
16629
17122
|
source: `${options.sourceUrl}#${relative6(repositoryDir, file.absolutePath).replace(/\\/g, "/")}`,
|
|
@@ -16698,25 +17191,28 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
16698
17191
|
if (platform === "mintlify" || platform === "docusaurus" || platform === "fern") {
|
|
16699
17192
|
page.body = replaceLinkWithAnchor(page.body);
|
|
16700
17193
|
page.body = replaceUnknownComponents(page.body, (name) => {
|
|
16701
|
-
warnings.push(
|
|
16702
|
-
code: "unsupported-config",
|
|
16703
|
-
message: `Unresolved MDX component <${name}> was replaced with a plain <div> (or removed, if self-closing) so the page still builds. It may be a site-authored or third-party implementation; review its source before adding a Thally equivalent.`,
|
|
16704
|
-
source: file.relativePath
|
|
16705
|
-
});
|
|
17194
|
+
warnings.push(unresolvedComponentWarning(name, file.relativePath));
|
|
16706
17195
|
});
|
|
16707
17196
|
}
|
|
16708
17197
|
if (platform === "docusaurus") resolvePageDisplayHeading(page, platform);
|
|
16709
17198
|
let mdxError = invalidMdxReason(page.body);
|
|
16710
17199
|
if (mdxError) {
|
|
16711
|
-
const
|
|
16712
|
-
if (
|
|
16713
|
-
|
|
16714
|
-
|
|
16715
|
-
|
|
16716
|
-
|
|
16717
|
-
|
|
16718
|
-
source: file.relativePath
|
|
17200
|
+
const repair = repairUncompilableMdx(page.body);
|
|
17201
|
+
if (repair && (repair.braces.length === 0 || !componentAnalysisLeftWork)) {
|
|
17202
|
+
const settledWarnings = [];
|
|
17203
|
+
let settled = escapeFernLiteralBraces(repair.body);
|
|
17204
|
+
settled = normalizeFlowParagraphContainers(settled);
|
|
17205
|
+
settled = removeUndefinedExpressions(settled, (message) => {
|
|
17206
|
+
settledWarnings.push({ code: "unsupported-config", message, source: pageWarningSource });
|
|
16719
17207
|
});
|
|
17208
|
+
settled = replaceUnknownComponents(replaceLinkWithAnchor(settled), (name) => {
|
|
17209
|
+
settledWarnings.push(unresolvedComponentWarning(name, file.relativePath));
|
|
17210
|
+
});
|
|
17211
|
+
if (invalidMdxReason(settled) === null) {
|
|
17212
|
+
page.body = settled;
|
|
17213
|
+
mdxError = null;
|
|
17214
|
+
warnings.push(...repairWarnings(repair, file.relativePath), ...settledWarnings);
|
|
17215
|
+
}
|
|
16720
17216
|
}
|
|
16721
17217
|
}
|
|
16722
17218
|
if (mdxError) {
|
|
@@ -16758,7 +17254,7 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
16758
17254
|
if (declarationsReferenceBrowserGlobal(page.body)) {
|
|
16759
17255
|
warnings.push({
|
|
16760
17256
|
code: "unsupported-config",
|
|
16761
|
-
message: "This page defines
|
|
17257
|
+
message: "This page still defines code that uses `document`/`window`, which isn't available when pages are rendered on the server. Move that code into a client component or edit the page manually.",
|
|
16762
17258
|
source: file.relativePath
|
|
16763
17259
|
});
|
|
16764
17260
|
}
|
|
@@ -16987,6 +17483,17 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
16987
17483
|
code: "unsupported-config",
|
|
16988
17484
|
message: `${scripts.length} script(s) from the content directory (${scripts.map((entry) => entry.path).join(", ")}) now load on every page via docs.json customScripts, as they did on Mintlify. They may target Mintlify's page structure; review them.`
|
|
16989
17485
|
});
|
|
17486
|
+
for (const entry of scripts) {
|
|
17487
|
+
const content = assets.find((asset) => asset.path === entry.path)?.content;
|
|
17488
|
+
const trackers = content === void 0 ? [] : trackersIn(Buffer.from(content).toString("utf8"));
|
|
17489
|
+
if (trackers.length > 0) {
|
|
17490
|
+
warnings.push({
|
|
17491
|
+
code: "unsupported-config",
|
|
17492
|
+
message: `Script ${stripControlCharacters(entry.path)} loads or names ${trackers.join(", ")}, which tracks visitors. It was carried over and now runs on every page of the migrated site. Delete the file and its docs.json customScripts entry if you do not want that.`,
|
|
17493
|
+
source: entry.path
|
|
17494
|
+
});
|
|
17495
|
+
}
|
|
17496
|
+
}
|
|
16990
17497
|
}
|
|
16991
17498
|
for (const entry of copiedSite.filter((item) => item.kind === "style")) {
|
|
16992
17499
|
warnings.push({
|
|
@@ -17450,7 +17957,8 @@ ${warnings.map((warning) => `- ${warning.message}`).join("\n")}`);
|
|
|
17450
17957
|
...pages.map((page) => page.id),
|
|
17451
17958
|
...(docsConfig.redirects ?? []).map((redirect) => redirect.source.replace(/^\//, ""))
|
|
17452
17959
|
]);
|
|
17453
|
-
|
|
17960
|
+
const sourceSite = mintlifySourceSite(mintlifyConfig);
|
|
17961
|
+
for (const page of pages) page.body = rewriteMintlifyMountedLinks(page.body, reachablePaths, sourceSite);
|
|
17454
17962
|
}
|
|
17455
17963
|
if (platform === "docusaurus" && docusaurusProjectRoot && !options.docusaurusSkipPlugins) {
|
|
17456
17964
|
const additionalRoots = [
|
|
@@ -17648,6 +18156,9 @@ ${body}`;
|
|
|
17648
18156
|
if (source) page.body = rewriteFernRelativePageLinks(page.body, source, routes);
|
|
17649
18157
|
}
|
|
17650
18158
|
}
|
|
18159
|
+
if (platform === "mintlify") {
|
|
18160
|
+
for (const page of pages) page.body = rewriteRelativeJsxHrefs(page.body, page.id);
|
|
18161
|
+
}
|
|
17651
18162
|
appendMintlifyDirectories(pages, mintlifyDirectories, warnings);
|
|
17652
18163
|
preserveLinkedAnchors(pages);
|
|
17653
18164
|
if (platform === "fern" && fernRawConfig) {
|
|
@@ -17663,7 +18174,13 @@ ${body}`;
|
|
|
17663
18174
|
}
|
|
17664
18175
|
}
|
|
17665
18176
|
if (docsConfig.redirects) {
|
|
17666
|
-
|
|
18177
|
+
const allPages = [...pages, ...sourceRefPages];
|
|
18178
|
+
const takenOver = platform === "mintlify" ? pagesRedirectedFrom(mintlifyAuthoredRedirects, allPages) : [];
|
|
18179
|
+
docsConfig = dropConflictingRedirects(dropUnroutableRedirects(docsConfig, warnings), takenOver.length > 0 ? allPages.filter((page) => !takenOver.includes(page)) : allPages, warnings);
|
|
18180
|
+
const standIns = pagesRedirectedFrom(docsConfig.redirects ?? [], takenOver);
|
|
18181
|
+
for (const page of standIns) page.noindex = true;
|
|
18182
|
+
const standInWarning = redirectsOverPagesWarning(standIns.map((page) => `/${page.id}`));
|
|
18183
|
+
if (standInWarning) warnings.push(standInWarning);
|
|
17667
18184
|
}
|
|
17668
18185
|
const redirectSources = new Map((docsConfig.redirects ?? []).map((redirect) => [(redirect.source.replace(/\/+$/, "") || "/").toLowerCase(), redirect.destination]));
|
|
17669
18186
|
const linkRedirects = [];
|
|
@@ -17781,13 +18298,13 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}` : "No importable Markdown
|
|
|
17781
18298
|
});
|
|
17782
18299
|
}
|
|
17783
18300
|
if (!docsConfig.navigation?.display && docsConfig.tabs.filter((tab) => !tab.hidden).length > 6) {
|
|
17784
|
-
docsConfig = { ...docsConfig, navigation: {
|
|
18301
|
+
docsConfig = { ...docsConfig, navigation: { ...docsConfig.navigation, display: "dropdown" } };
|
|
17785
18302
|
}
|
|
17786
18303
|
const themeColors = mintlifyConfig ? mintlifyThemeColors(mintlifyConfig.colors) : fernRawConfig ? fernThemeColors(fernRawConfig.colors) ?? (fernRawConfig["global-theme"] === "nvidia" ? { primary: "#76B900" } : void 0) : isTopLevelDocusaurus ? presentation?.colors ?? readDocusaurusThemeColor(docusaurusProjectRoot) : void 0;
|
|
17787
18304
|
const assetPaths = new Set(assets.map((asset) => asset.path));
|
|
17788
18305
|
const publicBrandPath = (value) => {
|
|
17789
18306
|
if (typeof value !== "string" || /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(value)) return void 0;
|
|
17790
|
-
const normalized = fernBrandAssetPaths.get(value) ?? normalizeAssetPath(value);
|
|
18307
|
+
const normalized = fernBrandAssetPaths.get(value) ?? normalizeAssetPath(value.replace(/^(?:\.[/\\]+)+/, ""));
|
|
17791
18308
|
return normalized && assetPaths.has(normalized) ? `/${normalized}` : void 0;
|
|
17792
18309
|
};
|
|
17793
18310
|
const brandVariants = (value) => {
|
|
@@ -18279,14 +18796,14 @@ function target(value, base) {
|
|
|
18279
18796
|
function readJson(value) {
|
|
18280
18797
|
if (Buffer.byteLength(value) > MAX_JSON_BYTES) return void 0;
|
|
18281
18798
|
let depth = 0;
|
|
18282
|
-
let
|
|
18799
|
+
let quoted2 = false;
|
|
18283
18800
|
let escaped = false;
|
|
18284
18801
|
for (const char of value) {
|
|
18285
|
-
if (
|
|
18802
|
+
if (quoted2) {
|
|
18286
18803
|
if (escaped) escaped = false;
|
|
18287
18804
|
else if (char === "\\") escaped = true;
|
|
18288
|
-
else if (char === '"')
|
|
18289
|
-
} else if (char === '"')
|
|
18805
|
+
else if (char === '"') quoted2 = false;
|
|
18806
|
+
} else if (char === '"') quoted2 = true;
|
|
18290
18807
|
else if (char === "[" || char === "{") {
|
|
18291
18808
|
if (++depth > 96) return void 0;
|
|
18292
18809
|
} else if (char === "]" || char === "}") depth--;
|
|
@@ -20674,7 +21191,8 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
20674
21191
|
const withDirectories = bundle.platform === "mintlify" && newPages.length > 0 ? addMintlifyDirectoryRedirects(boundConfig, newPages) : boundConfig;
|
|
20675
21192
|
const links = (withDirectories.redirects ?? []).filter(isLinkRedirect);
|
|
20676
21193
|
const unchecked = links.length > 0 ? { ...withDirectories, redirects: withDirectories.redirects.filter((redirect) => !isLinkRedirect(redirect)) } : withDirectories;
|
|
20677
|
-
const
|
|
21194
|
+
const standIns = bundle.platform === "mintlify" ? pagesRedirectedFrom(unchecked.redirects ?? [], pages.filter((page) => page.noindex)) : [];
|
|
21195
|
+
const checked = dropConflictingRedirects(dropUnroutableRedirects(unchecked, warnings), standIns.length > 0 ? pages.filter((page) => !standIns.includes(page)) : pages, warnings);
|
|
20678
21196
|
const checkedWithLinks = links.length > 0 ? dropConflictingRedirects({ ...checked, redirects: [...checked.redirects ?? [], ...links] }, [], warnings) : checked;
|
|
20679
21197
|
return {
|
|
20680
21198
|
...bundle,
|