@thallylabs/migrate 0.2.19 → 0.2.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +16 -0
- package/dist/index.js +425 -128
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/repository.ts
|
|
2
2
|
import { compileSync as compileSync2 } from "@mdx-js/mdx";
|
|
3
|
+
import { createHash as createHash2 } from "crypto";
|
|
3
4
|
import { spawn } from "child_process";
|
|
4
5
|
import {
|
|
5
6
|
closeSync,
|
|
@@ -16,7 +17,7 @@ import {
|
|
|
16
17
|
import { createRequire } from "module";
|
|
17
18
|
import { basename as basename3, dirname as dirname4, extname as extname6, isAbsolute as isAbsolute2, posix as posix3, relative as relative5, resolve as resolvePath, sep as sep2 } from "path";
|
|
18
19
|
import { parse as parseYaml4 } from "yaml";
|
|
19
|
-
import * as
|
|
20
|
+
import * as ts4 from "typescript";
|
|
20
21
|
|
|
21
22
|
// src/components.ts
|
|
22
23
|
import { createHash } from "crypto";
|
|
@@ -263,7 +264,8 @@ function unwrapDocusaurusMdxCodeBlocks(body) {
|
|
|
263
264
|
}
|
|
264
265
|
return isMdxCodeBlock ? body : output.join("\n");
|
|
265
266
|
}
|
|
266
|
-
|
|
267
|
+
var HTML_ID = /^[^\s"'<>`{}&]+$/u;
|
|
268
|
+
function normalizeExplicitHeadingIds(raw, warn) {
|
|
267
269
|
const { front, body } = splitFrontmatterBlock(raw);
|
|
268
270
|
return front + replaceOutsideCode(body, (segment) => segment.split("\n").map((line) => {
|
|
269
271
|
if (!/^[ \t]{0,3}#{1,6}[ \t]+/.test(line)) return line;
|
|
@@ -272,10 +274,12 @@ function normalizeExplicitHeadingIds(raw) {
|
|
|
272
274
|
const marker = trimmed.lastIndexOf(" {#");
|
|
273
275
|
if (marker >= 0) {
|
|
274
276
|
const id = trimmed.slice(marker + 3, -1);
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
277
|
+
const heading = trimmed.slice(0, marker).trimEnd();
|
|
278
|
+
if (/[{}]/.test(id)) return line;
|
|
279
|
+
if (HTML_ID.test(id)) return `<a id="${id}"></a>
|
|
280
|
+
${heading}`;
|
|
281
|
+
warn?.(`Heading anchor {#${id}} is not a valid HTML id and was removed from "${heading.replace(/^\s*#+\s*/, "")}".`);
|
|
282
|
+
return heading;
|
|
279
283
|
}
|
|
280
284
|
}
|
|
281
285
|
if (trimmed.endsWith("*/}")) {
|
|
@@ -283,7 +287,7 @@ ${trimmed.slice(0, marker).trimEnd()}`;
|
|
|
283
287
|
if (marker >= 0) {
|
|
284
288
|
const comment = trimmed.slice(marker + 4, -3).trim();
|
|
285
289
|
const id = comment.startsWith("#") ? comment.slice(1) : "";
|
|
286
|
-
if (
|
|
290
|
+
if (HTML_ID.test(id)) {
|
|
287
291
|
return `<a id="${id}"></a>
|
|
288
292
|
${trimmed.slice(0, marker).trimEnd()}`;
|
|
289
293
|
}
|
|
@@ -425,6 +429,9 @@ function bracketDelta(line) {
|
|
|
425
429
|
return delta;
|
|
426
430
|
}
|
|
427
431
|
var ESM_OPEN = /^(?:import|export)\b/;
|
|
432
|
+
function latexElement(source, block = false) {
|
|
433
|
+
return `<Latex${block ? " block" : ""}>{${JSON.stringify(source)}}</Latex>`;
|
|
434
|
+
}
|
|
428
435
|
function protectMathBlocks(raw) {
|
|
429
436
|
const { front, body } = splitFrontmatterBlock(raw);
|
|
430
437
|
const lines = body.split(/\r\n|\r|\n/);
|
|
@@ -439,7 +446,7 @@ function protectMathBlocks(raw) {
|
|
|
439
446
|
const trimmed = line.trim();
|
|
440
447
|
if (mathBlockDelimiter) {
|
|
441
448
|
if (trimmed === mathBlockDelimiter) {
|
|
442
|
-
output.push("
|
|
449
|
+
output.push(latexElement(mathLines.join("\n"), true));
|
|
443
450
|
mathBlockDelimiter = null;
|
|
444
451
|
mathLines = [];
|
|
445
452
|
converted = true;
|
|
@@ -481,11 +488,11 @@ function protectMathBlocks(raw) {
|
|
|
481
488
|
(whole, block, inline) => {
|
|
482
489
|
if (block !== void 0) {
|
|
483
490
|
converted = true;
|
|
484
|
-
return
|
|
491
|
+
return latexElement(unmask(block));
|
|
485
492
|
}
|
|
486
493
|
if (inline !== void 0 && hasTexSignal(unmask(inline))) {
|
|
487
494
|
converted = true;
|
|
488
|
-
return
|
|
495
|
+
return latexElement(unmask(inline));
|
|
489
496
|
}
|
|
490
497
|
return whole;
|
|
491
498
|
}
|
|
@@ -671,13 +678,25 @@ function maskCode(body) {
|
|
|
671
678
|
if (fenceBuffer.length) lines.push(stash(fenceBuffer.join("\n")));
|
|
672
679
|
return {
|
|
673
680
|
masked: lines.join("\n"),
|
|
674
|
-
unmask: (text2) => text2.replace(/\u0000(\d+)\u0000/g, (_match, index) => blocks[Number(index)])
|
|
681
|
+
unmask: (text2) => text2.replace(/\u0000(\d+)\u0000/g, (_match, index) => blocks[Number(index)]),
|
|
682
|
+
openFence: codeFence
|
|
675
683
|
};
|
|
676
684
|
}
|
|
685
|
+
function closeOpenFence(body) {
|
|
686
|
+
const { openFence } = maskCode(body);
|
|
687
|
+
return openFence ? `${body}${body.endsWith("\n") ? "" : "\n"}${openFence}
|
|
688
|
+
` : body;
|
|
689
|
+
}
|
|
677
690
|
function replaceOutsideCode(body, transform) {
|
|
678
691
|
const { masked, unmask } = maskCode(body);
|
|
679
692
|
return unmask(transform(masked));
|
|
680
693
|
}
|
|
694
|
+
function mdxComment(text2) {
|
|
695
|
+
return `{/*${text2.replace(/\*\//g, "* /")}*/}`;
|
|
696
|
+
}
|
|
697
|
+
function replaceOutsideCodeAndComments(body, transform) {
|
|
698
|
+
return replaceOutsideCode(body, (masked) => masked.split(/(\{\s*\/\*[\s\S]*?\*\/\s*\})/).map((part, index) => index % 2 ? part : transform(part)).join(""));
|
|
699
|
+
}
|
|
681
700
|
function rewriteFernRelativePageLinks(body, currentSourcePath, routesBySourcePath) {
|
|
682
701
|
const rewrite = (target) => {
|
|
683
702
|
if (!target || target.startsWith("/") || target.startsWith("#") || target.startsWith("?") || target.includes("\\") || /[\u0000-\u001f\u007f]/.test(target) || /^[A-Za-z][A-Za-z\d+.-]*:/.test(target)) return target;
|
|
@@ -739,7 +758,7 @@ function normalizeFernFileTrees(body) {
|
|
|
739
758
|
));
|
|
740
759
|
}
|
|
741
760
|
function normalizeHtmlComments(body) {
|
|
742
|
-
return replaceOutsideCode(body, (whole) => whole.replace(/<!--([\s\S]*?)-->/g, (_match, comment) =>
|
|
761
|
+
return replaceOutsideCode(body, (whole) => whole.replace(/<!--([\s\S]*?)-->/g, (_match, comment) => mdxComment(comment)));
|
|
743
762
|
}
|
|
744
763
|
function normalizeFernCallouts(body) {
|
|
745
764
|
return replaceOutsideCode(body, (whole) => {
|
|
@@ -1207,6 +1226,32 @@ function injectReactHookImports(body) {
|
|
|
1207
1226
|
|
|
1208
1227
|
${body}` : body;
|
|
1209
1228
|
}
|
|
1229
|
+
function normalizeFlowParagraphContainers(body) {
|
|
1230
|
+
if (!body.includes("<p")) return body;
|
|
1231
|
+
let tree;
|
|
1232
|
+
try {
|
|
1233
|
+
tree = descriptionParser.parse(body);
|
|
1234
|
+
} catch {
|
|
1235
|
+
return body;
|
|
1236
|
+
}
|
|
1237
|
+
const edits = [];
|
|
1238
|
+
function visit(node) {
|
|
1239
|
+
if (node.type === "mdxJsxFlowElement" && node.name === "p" && node.children?.some((child) => child.type === "paragraph" || child.type === "list" || child.type === "mdxJsxFlowElement")) {
|
|
1240
|
+
const start = node.position?.start.offset;
|
|
1241
|
+
const end = node.position?.end.offset;
|
|
1242
|
+
if (start !== void 0 && end !== void 0 && body.slice(start, start + 2) === "<p") {
|
|
1243
|
+
const closing = body.slice(start, end).match(/<\/p\s*>\s*$/i);
|
|
1244
|
+
if (closing?.index !== void 0) {
|
|
1245
|
+
edits.push({ offset: start + 1, value: "div" });
|
|
1246
|
+
edits.push({ offset: start + closing.index + 2, value: "div" });
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
for (const child of node.children ?? []) visit(child);
|
|
1251
|
+
}
|
|
1252
|
+
visit(tree);
|
|
1253
|
+
return edits.sort((a, b) => b.offset - a.offset).reduce((text2, edit) => text2.slice(0, edit.offset) + edit.value + text2.slice(edit.offset + 1), body);
|
|
1254
|
+
}
|
|
1210
1255
|
function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
1211
1256
|
const runFern = platform === "fern";
|
|
1212
1257
|
const runMintlify = platform === "mintlify";
|
|
@@ -1218,6 +1263,13 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
|
1218
1263
|
/:([+\w-]+):/g,
|
|
1219
1264
|
(shortcode, name) => nameToEmoji[name] ?? shortcode
|
|
1220
1265
|
));
|
|
1266
|
+
rewritten = replaceOutsideCode(rewritten, (segment) => segment.replace(
|
|
1267
|
+
/\b(href|src)=\{\s*require\(\s*(['"])@docusaurus\/useBaseUrl\2\s*\)\.default\(\s*(['"])([^'"]+)\3\s*\)\s*\}/g,
|
|
1268
|
+
(original, attribute, _moduleQuote, _pathQuote, path) => {
|
|
1269
|
+
if (!/^[\w./~%-]+$/.test(path) || path.split("/").includes("..")) return original;
|
|
1270
|
+
return `${attribute}="/${path.replace(/^\.\//, "").replace(/^\/+/, "")}"`;
|
|
1271
|
+
}
|
|
1272
|
+
));
|
|
1221
1273
|
rewritten = normalizeDocusaurusTabBlocks(normalizeDocusaurusTabs(removeGlobalDocusaurusImports(rewritten)));
|
|
1222
1274
|
rewritten = replaceOutsideCode(rewritten, (segment) => segment.replace(
|
|
1223
1275
|
/\bimport\s+([A-Za-z_$][\w$]*)\s+from\s+(['"])(@site\/[^'"]+)\2\s*;?/g,
|
|
@@ -1230,7 +1282,7 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
|
1230
1282
|
}
|
|
1231
1283
|
if (runMintlify) rewritten = normalizeMintlifyParameterAnchors(rewritten);
|
|
1232
1284
|
rewritten = replaceOutsideCode(rewritten, (segment) => {
|
|
1233
|
-
let result = convertHtmlStyleAttributes(segment).replace(/<!--([\s\S]*?)-->/g, (_match, content) =>
|
|
1285
|
+
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(/<Check(\s[^>]*)?>/g, "<Note$1>").replace(/<\/Check>/g, "</Note>").replace(/<Tree\.Folder/g, "<Folder").replace(/<\/Tree\.Folder>/g, "</Folder>").replace(/<Tree\.File/g, "<File").replace(/<\/Tree\.File>/g, "</File>");
|
|
1234
1286
|
if (runDocusaurus) {
|
|
1235
1287
|
result = result.replace(/<TabItem\b([^>]*)>/g, (_match, attributes) => {
|
|
1236
1288
|
const title = attributes.match(/\blabel=(?:"([^"]*)"|'([^']*)')/)?.slice(1).find(Boolean) ?? attributes.match(/\bvalue=(?:"([^"]*)"|'([^']*)')/)?.slice(1).find(Boolean) ?? "Tab";
|
|
@@ -1254,7 +1306,7 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
|
1254
1306
|
return normalizeMdx(body, platform, false);
|
|
1255
1307
|
}
|
|
1256
1308
|
}
|
|
1257
|
-
return normalized;
|
|
1309
|
+
return normalizeFlowParagraphContainers(normalized);
|
|
1258
1310
|
}
|
|
1259
1311
|
function parseMarkdownPage(input) {
|
|
1260
1312
|
const parsed = parseFrontmatter(input.raw);
|
|
@@ -2190,26 +2242,33 @@ function hash(value) {
|
|
|
2190
2242
|
function portableSpecifier(path) {
|
|
2191
2243
|
return path.replace(/\.tsx?$/, "");
|
|
2192
2244
|
}
|
|
2193
|
-
function
|
|
2245
|
+
function sanitizeCssModuleSelectors(css) {
|
|
2194
2246
|
const root = postcss.parse(css);
|
|
2247
|
+
let omitted = 0;
|
|
2195
2248
|
root.walkRules((rule) => {
|
|
2196
|
-
rule.
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
if (
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2249
|
+
if (rule.parent?.type === "atrule" && /keyframes$/i.test(rule.parent.name)) return;
|
|
2250
|
+
if (/^:export$|^:import\(/.test(rule.selector.trim())) return;
|
|
2251
|
+
const selectors = selectorParser().astSync(rule.selector);
|
|
2252
|
+
selectors.each((selector) => {
|
|
2253
|
+
let hasLocalClassOrId = false;
|
|
2254
|
+
selector.walk((node) => {
|
|
2255
|
+
if (node.type !== "class" && node.type !== "id") return;
|
|
2256
|
+
let parent = node.parent;
|
|
2257
|
+
while (parent) {
|
|
2258
|
+
if (parent.type === "pseudo" && parent.value === ":global") return;
|
|
2259
|
+
parent = parent.parent;
|
|
2260
|
+
}
|
|
2261
|
+
hasLocalClassOrId = true;
|
|
2209
2262
|
});
|
|
2210
|
-
|
|
2263
|
+
if (!hasLocalClassOrId) {
|
|
2264
|
+
selector.remove();
|
|
2265
|
+
omitted++;
|
|
2266
|
+
}
|
|
2267
|
+
});
|
|
2268
|
+
if (selectors.nodes.length === 0) rule.remove();
|
|
2269
|
+
else rule.selector = selectors.toString();
|
|
2211
2270
|
});
|
|
2212
|
-
return root.toString();
|
|
2271
|
+
return { css: root.toString(), omitted };
|
|
2213
2272
|
}
|
|
2214
2273
|
function sourceFile(source, filename) {
|
|
2215
2274
|
return ts2.createSourceFile(
|
|
@@ -2380,7 +2439,8 @@ function neutralizeUnresolvableImportsWithoutAst(content, currentFile, warn) {
|
|
|
2380
2439
|
});
|
|
2381
2440
|
for (const { name, specifier } of dropped) {
|
|
2382
2441
|
warn(`Component import ${JSON.stringify(specifier)} could not be resolved because this page has invalid MDX (see the previous warning), so the import and its usage were removed to keep the site building.`, currentFile);
|
|
2383
|
-
|
|
2442
|
+
const removed = mdxComment(` Removed <${name}>: unresolved during fallback migration `);
|
|
2443
|
+
result = replaceOutsideCodeAndComments(result, (segment) => segment.replace(new RegExp(`<${name}(?:\\s[^>]*)?/>`, "g"), removed).replace(new RegExp(`<${name}(?:\\s[^>]*)?>[\\s\\S]*?<\\/${name}>`, "g"), removed));
|
|
2384
2444
|
}
|
|
2385
2445
|
return result;
|
|
2386
2446
|
}
|
|
@@ -2439,6 +2499,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2439
2499
|
}
|
|
2440
2500
|
function copyGraph(entry) {
|
|
2441
2501
|
const staged = /* @__PURE__ */ new Map();
|
|
2502
|
+
const stagedWarnings = [];
|
|
2442
2503
|
let stagedBytes = 0;
|
|
2443
2504
|
function stageShim(filename, content) {
|
|
2444
2505
|
const shimDestination = `${destinationRoot}/shims/${filename}`;
|
|
@@ -2459,13 +2520,14 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2459
2520
|
if (!CODE_EXTENSIONS.has(extension)) {
|
|
2460
2521
|
if (extension === ".css" && /@import\b|url\s*\(/i.test(content.toString("utf8"))) throw new Error("CSS resource dependencies require manual migration");
|
|
2461
2522
|
if (extension === ".css" && path.toLowerCase().endsWith(".module.css")) {
|
|
2462
|
-
let
|
|
2523
|
+
let sanitized;
|
|
2463
2524
|
try {
|
|
2464
|
-
|
|
2525
|
+
sanitized = sanitizeCssModuleSelectors(content.toString("utf8"));
|
|
2465
2526
|
} catch {
|
|
2466
2527
|
throw new Error("CSS module could not be parsed to check for Turbopack-safe selectors");
|
|
2467
2528
|
}
|
|
2468
|
-
|
|
2529
|
+
if (sanitized.omitted > 0) stagedWarnings.push({ path, omitted: sanitized.omitted });
|
|
2530
|
+
staged.set(destination, { path: destination, content: sanitized.css });
|
|
2469
2531
|
}
|
|
2470
2532
|
return;
|
|
2471
2533
|
}
|
|
@@ -2534,6 +2596,9 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2534
2596
|
}
|
|
2535
2597
|
visit(entry);
|
|
2536
2598
|
for (const [path, file] of staged) copied.set(path, file);
|
|
2599
|
+
for (const { path, omitted } of stagedWarnings) {
|
|
2600
|
+
warn(`Site-authored CSS module ${relative2(root, path).replace(/\\/g, "/")} has ${omitted} global-only selector branch(es) that cannot be copied into Thally CSS Modules; those styles were omitted.`, path);
|
|
2601
|
+
}
|
|
2537
2602
|
copiedBytes += stagedBytes;
|
|
2538
2603
|
return outputPath(entry);
|
|
2539
2604
|
}
|
|
@@ -2787,7 +2852,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2787
2852
|
warn(`Asset import ${JSON.stringify(rawSpecifier)} could not be copied as a component; it was copied to ${rescuedAssetHref} and bound to that URL instead.`, currentFile);
|
|
2788
2853
|
} else {
|
|
2789
2854
|
edits.push({ start: importStart, end: importEnd, value: "" });
|
|
2790
|
-
warn(`
|
|
2855
|
+
warn(`Site-authored component import ${JSON.stringify(rawSpecifier)} could not be copied and was removed: ${error instanceof Error ? error.message : "unsupported dependency"}. Its usage on this page was neutralized; review this custom implementation manually.`, currentFile);
|
|
2791
2856
|
}
|
|
2792
2857
|
}
|
|
2793
2858
|
}
|
|
@@ -3043,7 +3108,7 @@ ${inlineSource}` });
|
|
|
3043
3108
|
const start = node.position.start.offset;
|
|
3044
3109
|
const end = node.position.end.offset;
|
|
3045
3110
|
const videoId = youtubeEmbedVideoId(node, specifier);
|
|
3046
|
-
const value = videoId ? `<iframe width="560" height="315" src="https://www.youtube.com/embed/${videoId}" title="Embedded video" allowFullScreen />` : `
|
|
3111
|
+
const value = videoId ? `<iframe width="560" height="315" src="https://www.youtube.com/embed/${videoId}" title="Embedded video" allowFullScreen />` : mdxComment(` Removed <${node.name}>: unsupported import '${specifier}' `);
|
|
3047
3112
|
edits.push({ start, end, value });
|
|
3048
3113
|
});
|
|
3049
3114
|
const rendered = applyReplacements(content, edits);
|
|
@@ -3117,6 +3182,110 @@ import { customComponents as ${name} } from ${JSON.stringify(registryPath)}
|
|
|
3117
3182
|
];
|
|
3118
3183
|
}
|
|
3119
3184
|
|
|
3185
|
+
// src/source-styles.ts
|
|
3186
|
+
import postcss2 from "postcss";
|
|
3187
|
+
import selectorParser2 from "postcss-selector-parser";
|
|
3188
|
+
import ts3 from "typescript";
|
|
3189
|
+
var PLATFORM_CLASSES = /* @__PURE__ */ new Set(["navbar-link"]);
|
|
3190
|
+
var PLATFORM_IDS = /* @__PURE__ */ new Set(["footer", "navbar", "sidebar"]);
|
|
3191
|
+
var PLATFORM_CLASS_PREFIX = /^(?:mintlify[-_]|fern[-_]|docusaurus[-_]|theme-doc-|theme-code-block|DocSearch|pagination-nav|menu__)/i;
|
|
3192
|
+
var SHARED_THEME_CLASSES = /* @__PURE__ */ new Set(["dark", "light"]);
|
|
3193
|
+
var UTILITY_CLASS = /^(?:[mp][trblxy]?|w|h|min-w|max-w|min-h|max-h|text|bg|border|rounded|flex|grid|gap|space-[xy]|items|justify|overflow|truncate|hidden|block|inline|relative|absolute|sticky|z|opacity)-/;
|
|
3194
|
+
function withoutFencedCode(content) {
|
|
3195
|
+
let fence;
|
|
3196
|
+
return content.split("\n").map((line) => {
|
|
3197
|
+
const marker = line.match(/^ {0,3}(`{3,}|~{3,})/)?.[1];
|
|
3198
|
+
if (fence) {
|
|
3199
|
+
if (marker?.[0] === fence.marker && marker.length >= fence.length) fence = void 0;
|
|
3200
|
+
return "";
|
|
3201
|
+
}
|
|
3202
|
+
if (marker) {
|
|
3203
|
+
fence = { marker: marker[0], length: marker.length };
|
|
3204
|
+
return "";
|
|
3205
|
+
}
|
|
3206
|
+
return line;
|
|
3207
|
+
}).join("\n");
|
|
3208
|
+
}
|
|
3209
|
+
function authoredStyleNames(contents) {
|
|
3210
|
+
const classes = /* @__PURE__ */ new Set();
|
|
3211
|
+
const ids = /* @__PURE__ */ new Set();
|
|
3212
|
+
for (const original of contents) {
|
|
3213
|
+
const content = withoutFencedCode(original);
|
|
3214
|
+
for (const match of content.matchAll(/\b(?:className|class)\s*=\s*["']([^"']+)["']/g)) {
|
|
3215
|
+
for (const name of match[1].split(/\s+/)) if (name) classes.add(name);
|
|
3216
|
+
}
|
|
3217
|
+
for (const match of content.matchAll(/\bid\s*=\s*["']([^"']+)["']/g)) ids.add(match[1]);
|
|
3218
|
+
if (!content.includes("className={")) continue;
|
|
3219
|
+
const source = ts3.createSourceFile("component.tsx", content, ts3.ScriptTarget.Latest, true, ts3.ScriptKind.TSX);
|
|
3220
|
+
const visit = (node) => {
|
|
3221
|
+
if (ts3.isJsxAttribute(node) && ts3.isIdentifier(node.name) && node.name.text === "className" && node.initializer) {
|
|
3222
|
+
const collect = (value) => {
|
|
3223
|
+
if (ts3.isStringLiteral(value) || ts3.isNoSubstitutionTemplateLiteral(value)) {
|
|
3224
|
+
for (const name of value.text.split(/\s+/)) if (name) classes.add(name);
|
|
3225
|
+
} else ts3.forEachChild(value, collect);
|
|
3226
|
+
};
|
|
3227
|
+
collect(node.initializer);
|
|
3228
|
+
}
|
|
3229
|
+
ts3.forEachChild(node, visit);
|
|
3230
|
+
};
|
|
3231
|
+
visit(source);
|
|
3232
|
+
}
|
|
3233
|
+
return { classes, ids };
|
|
3234
|
+
}
|
|
3235
|
+
function projectAuthoredStyles(css, contents) {
|
|
3236
|
+
const names = authoredStyleNames(contents);
|
|
3237
|
+
const root = postcss2.parse(css);
|
|
3238
|
+
let omittedSelectors = 0;
|
|
3239
|
+
let rewrittenSelectors = 0;
|
|
3240
|
+
root.walkRules((rule) => {
|
|
3241
|
+
if (rule.parent?.type === "atrule" && /keyframes$/i.test(rule.parent.name)) return;
|
|
3242
|
+
const retained = [];
|
|
3243
|
+
try {
|
|
3244
|
+
selectorParser2((selectors) => {
|
|
3245
|
+
selectors.each((selector) => {
|
|
3246
|
+
let hasAuthoredAnchor = false;
|
|
3247
|
+
let hasPlatformAnchor = false;
|
|
3248
|
+
selector.walk((node) => {
|
|
3249
|
+
let ancestor = node.parent;
|
|
3250
|
+
let isNestedInPseudo = false;
|
|
3251
|
+
while (ancestor && ancestor !== selector) {
|
|
3252
|
+
if (ancestor.type === "pseudo") isNestedInPseudo = true;
|
|
3253
|
+
ancestor = ancestor.parent;
|
|
3254
|
+
}
|
|
3255
|
+
if (node.type === "class") {
|
|
3256
|
+
if (SHARED_THEME_CLASSES.has(node.value)) return;
|
|
3257
|
+
if (PLATFORM_CLASSES.has(node.value) || PLATFORM_CLASS_PREFIX.test(node.value) || UTILITY_CLASS.test(node.value) || !names.classes.has(node.value)) hasPlatformAnchor = true;
|
|
3258
|
+
else if (!isNestedInPseudo) hasAuthoredAnchor = true;
|
|
3259
|
+
} else if (node.type === "id") {
|
|
3260
|
+
if (PLATFORM_IDS.has(node.value) || !names.ids.has(node.value)) hasPlatformAnchor = true;
|
|
3261
|
+
else if (!isNestedInPseudo) hasAuthoredAnchor = true;
|
|
3262
|
+
} else if (node.type === "attribute" && node.attribute === "data-as") {
|
|
3263
|
+
node.remove();
|
|
3264
|
+
rewrittenSelectors += 1;
|
|
3265
|
+
}
|
|
3266
|
+
});
|
|
3267
|
+
if (hasAuthoredAnchor && !hasPlatformAnchor) retained.push(selector.toString());
|
|
3268
|
+
else omittedSelectors += 1;
|
|
3269
|
+
});
|
|
3270
|
+
}).processSync(rule.selector);
|
|
3271
|
+
} catch {
|
|
3272
|
+
omittedSelectors += 1;
|
|
3273
|
+
}
|
|
3274
|
+
if (retained.length) rule.selector = retained.join(", ");
|
|
3275
|
+
else rule.remove();
|
|
3276
|
+
});
|
|
3277
|
+
const hasStyleRule = (nodes) => Boolean(nodes?.some((node) => node.type === "rule" || node.type === "atrule" && hasStyleRule(node.nodes)));
|
|
3278
|
+
root.walkAtRules((rule) => {
|
|
3279
|
+
if (rule.name === "font-face" || rule.name === "property") return;
|
|
3280
|
+
if (!hasStyleRule(rule.nodes)) rule.remove();
|
|
3281
|
+
});
|
|
3282
|
+
if (omittedSelectors === 0 && rewrittenSelectors === 0) return { css, omittedSelectors };
|
|
3283
|
+
root.walkComments((comment) => {
|
|
3284
|
+
comment.remove();
|
|
3285
|
+
});
|
|
3286
|
+
return { css: root.toString(), omittedSelectors };
|
|
3287
|
+
}
|
|
3288
|
+
|
|
3120
3289
|
// src/docusaurus.ts
|
|
3121
3290
|
import { existsSync as existsSync3, lstatSync as lstatSync3, readFileSync as readFileSync3 } from "fs";
|
|
3122
3291
|
import { extname as extname4, posix as posix2 } from "path";
|
|
@@ -4115,6 +4284,47 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
4115
4284
|
message: "Mintlify navigation could not be projected; generated navigation will be used."
|
|
4116
4285
|
});
|
|
4117
4286
|
}
|
|
4287
|
+
const versionOwner = languages.length > 0 ? languages.find((entry) => entry.default === true) ?? languages[0] : navigation;
|
|
4288
|
+
const globalNavigation = objectValue2(versionOwner.global) ?? objectValue2(navigation.global);
|
|
4289
|
+
const shortcuts = Array.isArray(globalNavigation?.anchors) ? globalNavigation.anchors.flatMap((value) => {
|
|
4290
|
+
const anchor = objectValue2(value);
|
|
4291
|
+
const label = typeof anchor?.anchor === "string" ? anchor.anchor.trim() : "";
|
|
4292
|
+
const href = projectedHref(anchor?.href);
|
|
4293
|
+
if (!label || !href) return [];
|
|
4294
|
+
return [{ label, href, ...iconName(anchor?.icon) ? { icon: iconName(anchor?.icon) } : {} }];
|
|
4295
|
+
}) : [];
|
|
4296
|
+
const rawVersions = Array.isArray(versionOwner.versions) ? versionOwner.versions.map(objectValue2).filter((value) => value !== null).sort((left, right) => Number(right.default === true) - Number(left.default === true)) : [];
|
|
4297
|
+
const versionNames = rawVersions.map((entry) => typeof entry.version === "string" ? entry.version.trim() : "").filter(Boolean);
|
|
4298
|
+
const annotateVersions = (items) => items.map((item) => {
|
|
4299
|
+
const version = versionNames.find((name) => item.tab.startsWith(`${name}: `));
|
|
4300
|
+
return version ? { ...item, version, displayLabel: item.tab.slice(version.length + 2) } : item;
|
|
4301
|
+
});
|
|
4302
|
+
const firstPage = (item) => {
|
|
4303
|
+
const visit = (entries) => {
|
|
4304
|
+
for (const entry of entries) {
|
|
4305
|
+
if (typeof entry === "string") return entry;
|
|
4306
|
+
const nested = visit(entry.pages);
|
|
4307
|
+
if (nested) return nested;
|
|
4308
|
+
}
|
|
4309
|
+
return void 0;
|
|
4310
|
+
};
|
|
4311
|
+
return visit([...item.pages ?? [], ...item.groups ?? []]);
|
|
4312
|
+
};
|
|
4313
|
+
const defaultVersion = rawVersions.find((entry) => entry.default === true) ?? rawVersions[0];
|
|
4314
|
+
const versions = rawVersions.length > 1 ? rawVersions.flatMap((entry) => {
|
|
4315
|
+
const label = typeof entry.version === "string" ? entry.version.trim() : "";
|
|
4316
|
+
if (!label) return [];
|
|
4317
|
+
const candidates = tabs.filter((item) => item.tab.startsWith(`${label}: `)).map(firstPage).filter((page) => Boolean(page));
|
|
4318
|
+
const landing = candidates.find((page) => page.startsWith(`${label}/`)) ?? candidates[0];
|
|
4319
|
+
if (!landing) return [];
|
|
4320
|
+
const firstSegment = landing.split("/")[0];
|
|
4321
|
+
const prefix = firstSegment === label ? label : "";
|
|
4322
|
+
return [{ label, prefix, href: `/${landing}`, ...entry === defaultVersion ? { default: true } : {} }];
|
|
4323
|
+
}) : [];
|
|
4324
|
+
if (versions.length > 1) {
|
|
4325
|
+
tabs = annotateVersions(tabs);
|
|
4326
|
+
for (const [locale, items] of Object.entries(localizedNavigation)) localizedNavigation[locale] = annotateVersions(items);
|
|
4327
|
+
}
|
|
4118
4328
|
const redirects = Array.isArray(config.redirects) ? config.redirects.flatMap((value) => {
|
|
4119
4329
|
const redirect = objectValue2(value);
|
|
4120
4330
|
if (!redirect || typeof redirect.source !== "string" || typeof redirect.destination !== "string") return [];
|
|
@@ -4139,7 +4349,11 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
4139
4349
|
return {
|
|
4140
4350
|
docsConfig: {
|
|
4141
4351
|
tabs,
|
|
4142
|
-
...projectionTrace.rootContainerKind === "dropdowns"
|
|
4352
|
+
...projectionTrace.rootContainerKind === "dropdowns" || versions.length > 1 || shortcuts.length > 0 ? { navigation: {
|
|
4353
|
+
...projectionTrace.rootContainerKind === "dropdowns" ? { display: "dropdown" } : {},
|
|
4354
|
+
...versions.length > 1 ? { versions } : {},
|
|
4355
|
+
...shortcuts.length > 0 ? { shortcuts } : {}
|
|
4356
|
+
} } : {},
|
|
4143
4357
|
...projectedCompatibleConfig(config, warnings),
|
|
4144
4358
|
...projectedApiMdx(config, warnings),
|
|
4145
4359
|
...i18n ? { i18n } : {},
|
|
@@ -4816,9 +5030,10 @@ function descriptorSort(left, right) {
|
|
|
4816
5030
|
if (leftPosition !== rightPosition) return leftPosition - rightPosition;
|
|
4817
5031
|
return left.sourcePath.localeCompare(right.sourcePath, void 0, { numeric: true });
|
|
4818
5032
|
}
|
|
4819
|
-
function registerDoc(docId, context) {
|
|
5033
|
+
function registerDoc(docId, context, sourceDirectory) {
|
|
4820
5034
|
const key = normalizeDocId(docId);
|
|
4821
|
-
const
|
|
5035
|
+
const scopedKey = sourceDirectory && !docId.startsWith("/") ? normalizeDocId(posix2.join(sourceDirectory, key)) : void 0;
|
|
5036
|
+
const descriptor = (scopedKey ? context.descriptorByDocId.get(scopedKey) : void 0) ?? context.descriptorByDocId.get(key) ?? context.descriptors.find((page) => page.navigationId === docusaurusRouteId(key));
|
|
4822
5037
|
if (!descriptor) {
|
|
4823
5038
|
context.warnings.push({
|
|
4824
5039
|
code: "missing-page",
|
|
@@ -4830,10 +5045,10 @@ function registerDoc(docId, context) {
|
|
|
4830
5045
|
context.referencedNavigationIds.add(descriptor.navigationId);
|
|
4831
5046
|
return descriptor.navigationId;
|
|
4832
5047
|
}
|
|
4833
|
-
function generatedIndexPage(label, linkValue, context) {
|
|
5048
|
+
function generatedIndexPage(label, linkValue, context, sourceDirectory) {
|
|
4834
5049
|
const link = objectValue3(linkValue);
|
|
4835
5050
|
if (!link) return null;
|
|
4836
|
-
if (link.type === "doc" && typeof link.id === "string") return registerDoc(link.id, context);
|
|
5051
|
+
if (link.type === "doc" && typeof link.id === "string") return registerDoc(link.id, context, sourceDirectory);
|
|
4837
5052
|
if (link.type !== "generated-index") return null;
|
|
4838
5053
|
const fallback = `category/${slugifySegment(label)}`;
|
|
4839
5054
|
const unprefixedNavigationId = typeof link.slug === "string" ? routeFromSlug(link.slug, fallback) ?? fallback : fallback;
|
|
@@ -5076,7 +5291,7 @@ function autogeneratedItems(dirName, context) {
|
|
|
5076
5291
|
};
|
|
5077
5292
|
}
|
|
5078
5293
|
}
|
|
5079
|
-
const landing = generatedIndexPage(metadata.label ?? titleCase2(segment), metadata.link, context);
|
|
5294
|
+
const landing = generatedIndexPage(metadata.label ?? titleCase2(segment), metadata.link, context, directory);
|
|
5080
5295
|
if (landing && !pages2.includes(landing)) pages2.unshift(landing);
|
|
5081
5296
|
return {
|
|
5082
5297
|
position: metadata.position ?? Number.MAX_SAFE_INTEGER,
|
|
@@ -5910,6 +6125,7 @@ var FRONTMATTER_HEAD_BYTES = 65536;
|
|
|
5910
6125
|
var MAX_WITHHELD_SCAN_BYTES = MAX_PAGE_BYTES * 8;
|
|
5911
6126
|
var MAX_DROPPED_GATED_WARNINGS = 20;
|
|
5912
6127
|
var MAX_ASSET_BYTES = 25e6;
|
|
6128
|
+
var MAX_REFERENCED_ASSET_BYTES = 1e8;
|
|
5913
6129
|
var MAX_TOTAL_ASSET_BYTES = 5e8;
|
|
5914
6130
|
var GIT_LFS_POINTER_PREFIX = "version https://git-lfs.github.com/spec/v1";
|
|
5915
6131
|
function listAssetPaths(paths) {
|
|
@@ -6641,7 +6857,7 @@ function selectGroupWithinBudget(scanned, rank, warnings, allVersionPrefixes, la
|
|
|
6641
6857
|
const dropped = ranked.slice(budget).map(({ file }) => file);
|
|
6642
6858
|
if (warnings) {
|
|
6643
6859
|
const droppedPages = label === "file" ? dropped.filter((file) => isDocumentationExtension(file.relativePath)) : dropped;
|
|
6644
|
-
const noun = label === "file" ? "page" : "image or media file";
|
|
6860
|
+
const noun = label === "file" ? "page" : label === "snippet" ? "snippet file" : "image or media file";
|
|
6645
6861
|
const droppedVersions = /* @__PURE__ */ new Set();
|
|
6646
6862
|
for (const file of dropped) {
|
|
6647
6863
|
const firstSegment = file.relativePath.split("/", 1)[0];
|
|
@@ -6651,16 +6867,19 @@ function selectGroupWithinBudget(scanned, rank, warnings, allVersionPrefixes, la
|
|
|
6651
6867
|
const rest = droppedPages.length - examples.length;
|
|
6652
6868
|
warnings.push({
|
|
6653
6869
|
code: "limit-reached",
|
|
6654
|
-
message: `This repository has more than ${budget} ${label === "file" ? "files" : "assets"}, so only the first ${budget} (in navigation order, default version first) were migrated. ${droppedPages.length} ${noun}(s) were left out` + (examples.length > 0 ? `: ${examples.join(", ")}${rest > 0 ? `, and ${rest} more` : ""}` : "") + (droppedVersions.size > 0 ? ` (versions: ${[...droppedVersions].slice(0, 5).join(", ")}${droppedVersions.size > 5 ? `, and ${droppedVersions.size - 5} more` : ""})` : "") + (label === "
|
|
6870
|
+
message: `This repository has more than ${budget} ${label === "file" ? "files" : label === "snippet" ? "snippets" : "assets"}, so only the first ${budget} (in navigation order, default version first) were migrated. ${droppedPages.length} ${noun}(s) were left out` + (examples.length > 0 ? `: ${examples.join(", ")}${rest > 0 ? `, and ${rest} more` : ""}` : "") + (droppedVersions.size > 0 ? ` (versions: ${[...droppedVersions].slice(0, 5).join(", ")}${droppedVersions.size > 5 ? `, and ${droppedVersions.size - 5} more` : ""})` : "") + (label === "asset" ? ". Copy them into public/ manually if your pages use them." : ". To include them, run the migration on a smaller part of the repository with --docs-dir.")
|
|
6655
6871
|
});
|
|
6656
6872
|
}
|
|
6657
6873
|
return ranked.slice(0, budget).map(({ file }) => file);
|
|
6658
6874
|
}
|
|
6659
6875
|
function selectFilesWithinBudget(scanned, rank, warnings, allVersionPrefixes, budget = MAX_SOURCE_FILES) {
|
|
6660
6876
|
const isAsset = (file) => ASSET_EXTENSIONS.has(extname6(file.relativePath).toLowerCase());
|
|
6877
|
+
const isSnippet = (file) => file.relativePath.split("/").some((segment) => SNIPPET_DIRECTORIES.has(segment.toLowerCase()));
|
|
6878
|
+
const snippetFiles = scanned.filter((file) => !isAsset(file) && isSnippet(file));
|
|
6661
6879
|
const assetFiles = scanned.filter(isAsset);
|
|
6662
|
-
const otherFiles = scanned.filter((file) => !isAsset(file));
|
|
6880
|
+
const otherFiles = scanned.filter((file) => !isAsset(file) && !isSnippet(file));
|
|
6663
6881
|
return [
|
|
6882
|
+
...selectGroupWithinBudget(snippetFiles, rank, warnings, allVersionPrefixes, "snippet", budget),
|
|
6664
6883
|
...selectGroupWithinBudget(otherFiles, rank, warnings, allVersionPrefixes, "file", budget),
|
|
6665
6884
|
...selectGroupWithinBudget(assetFiles, rank, warnings, allVersionPrefixes, "asset", budget)
|
|
6666
6885
|
];
|
|
@@ -7159,19 +7378,26 @@ function interpolateSnippet(snippet, attributes, children) {
|
|
|
7159
7378
|
});
|
|
7160
7379
|
}).join("\n");
|
|
7161
7380
|
}
|
|
7381
|
+
function isolateFences(snippet, source, start, end) {
|
|
7382
|
+
const fence = /^\s*(?:`{3,}|~{3,})/;
|
|
7383
|
+
const lines = snippet.split("\n");
|
|
7384
|
+
const before = source.slice(source.lastIndexOf("\n", start - 1) + 1, start);
|
|
7385
|
+
const after = source.slice(end, source.indexOf("\n", end) < 0 ? void 0 : source.indexOf("\n", end));
|
|
7386
|
+
return `${fence.test(lines[0]) && /\S/.test(before) ? "\n" : ""}${snippet}${fence.test(lines[lines.length - 1]) && /\S/.test(after) ? "\n" : ""}`;
|
|
7387
|
+
}
|
|
7162
7388
|
function snippetComponentBody(source, componentName) {
|
|
7163
|
-
const parsed =
|
|
7389
|
+
const parsed = ts4.createSourceFile("snippet.tsx", source, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TSX);
|
|
7164
7390
|
for (const statement of parsed.statements) {
|
|
7165
|
-
if (!
|
|
7391
|
+
if (!ts4.isVariableStatement(statement)) continue;
|
|
7166
7392
|
for (const declaration of statement.declarationList.declarations) {
|
|
7167
|
-
if (!
|
|
7393
|
+
if (!ts4.isIdentifier(declaration.name) || declaration.name.text !== componentName) continue;
|
|
7168
7394
|
const initializer = declaration.initializer;
|
|
7169
|
-
if (!initializer || !
|
|
7170
|
-
const returned =
|
|
7395
|
+
if (!initializer || !ts4.isArrowFunction(initializer)) continue;
|
|
7396
|
+
const returned = ts4.isBlock(initializer.body) ? initializer.body.statements.find(ts4.isReturnStatement)?.expression : initializer.body;
|
|
7171
7397
|
if (!returned) continue;
|
|
7172
7398
|
let expression = returned;
|
|
7173
|
-
while (
|
|
7174
|
-
if (
|
|
7399
|
+
while (ts4.isParenthesizedExpression(expression)) expression = expression.expression;
|
|
7400
|
+
if (ts4.isJsxElement(expression) || ts4.isJsxSelfClosingElement(expression) || ts4.isJsxFragment(expression)) {
|
|
7175
7401
|
return expression.getText(parsed);
|
|
7176
7402
|
}
|
|
7177
7403
|
}
|
|
@@ -7179,31 +7405,31 @@ function snippetComponentBody(source, componentName) {
|
|
|
7179
7405
|
return source;
|
|
7180
7406
|
}
|
|
7181
7407
|
function statefulSnippetDeclaration(source, componentName) {
|
|
7182
|
-
const parsed =
|
|
7183
|
-
const isEsm = (statement2) =>
|
|
7408
|
+
const parsed = ts4.createSourceFile("snippet.tsx", source, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TSX);
|
|
7409
|
+
const isEsm = (statement2) => ts4.isImportDeclaration(statement2) || (ts4.isVariableStatement(statement2) || ts4.isFunctionDeclaration(statement2) || ts4.isClassDeclaration(statement2)) && !!ts4.getModifiers(statement2)?.some((modifier) => modifier.kind === ts4.SyntaxKind.ExportKeyword);
|
|
7184
7410
|
if (parsed.statements.length === 0 || !parsed.statements.every(isEsm)) return null;
|
|
7185
|
-
const statement = parsed.statements.find((candidate) =>
|
|
7186
|
-
if (!statement || !
|
|
7411
|
+
const statement = parsed.statements.find((candidate) => ts4.isVariableStatement(candidate) && candidate.declarationList.declarations.length === 1 && ts4.isIdentifier(candidate.declarationList.declarations[0].name) && candidate.declarationList.declarations[0].name.text === componentName);
|
|
7412
|
+
if (!statement || !ts4.isVariableStatement(statement)) return null;
|
|
7187
7413
|
const declaration = statement.declarationList.declarations[0];
|
|
7188
|
-
if (!declaration.initializer || !
|
|
7414
|
+
if (!declaration.initializer || !ts4.isArrowFunction(declaration.initializer) || !ts4.isBlock(declaration.initializer.body)) return null;
|
|
7189
7415
|
const body = declaration.initializer.body.statements;
|
|
7190
|
-
if (body.length < 2 || !body.some(
|
|
7416
|
+
if (body.length < 2 || !body.some(ts4.isReturnStatement)) return null;
|
|
7191
7417
|
return source.trim();
|
|
7192
7418
|
}
|
|
7193
7419
|
function staticNamedSnippetValues(source) {
|
|
7194
7420
|
const values = /* @__PURE__ */ new Map();
|
|
7195
|
-
const parsed =
|
|
7421
|
+
const parsed = ts4.createSourceFile("snippet.tsx", source, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TSX);
|
|
7196
7422
|
for (const statement of parsed.statements) {
|
|
7197
|
-
if (!
|
|
7423
|
+
if (!ts4.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts4.SyntaxKind.ExportKeyword)) continue;
|
|
7198
7424
|
for (const declaration of statement.declarationList.declarations) {
|
|
7199
|
-
if (!
|
|
7425
|
+
if (!ts4.isIdentifier(declaration.name) || !declaration.initializer) continue;
|
|
7200
7426
|
const expression = declaration.initializer;
|
|
7201
|
-
if (
|
|
7427
|
+
if (ts4.isStringLiteral(expression) || ts4.isNoSubstitutionTemplateLiteral(expression)) {
|
|
7202
7428
|
values.set(declaration.name.text, JSON.stringify(expression.text));
|
|
7203
|
-
} else if (
|
|
7429
|
+
} else if (ts4.isNumericLiteral(expression)) {
|
|
7204
7430
|
values.set(declaration.name.text, expression.text);
|
|
7205
|
-
} else if (expression.kind ===
|
|
7206
|
-
values.set(declaration.name.text, expression.kind ===
|
|
7431
|
+
} else if (expression.kind === ts4.SyntaxKind.TrueKeyword || expression.kind === ts4.SyntaxKind.FalseKeyword) {
|
|
7432
|
+
values.set(declaration.name.text, expression.kind === ts4.SyntaxKind.TrueKeyword ? "true" : "false");
|
|
7207
7433
|
}
|
|
7208
7434
|
}
|
|
7209
7435
|
}
|
|
@@ -7530,6 +7756,19 @@ function rewriteRepositoryAssetLinks(body, currentFile, siteRoot, onReferenced)
|
|
|
7530
7756
|
});
|
|
7531
7757
|
}
|
|
7532
7758
|
var LOCAL_EXPORT_DECLARATION = /^\s*export\s+(?:const|let|var|function|class|async\s+function)\s+([A-Za-z_$][\w$]*)/;
|
|
7759
|
+
function replaceOutsideMdxComments(body, transform) {
|
|
7760
|
+
const comment = /\{\/\*[\s\S]*?\*\/\}/g;
|
|
7761
|
+
let cursor = 0;
|
|
7762
|
+
let output = "";
|
|
7763
|
+
for (const match of body.matchAll(comment)) {
|
|
7764
|
+
output += transform(body.slice(cursor, match.index)) + match[0];
|
|
7765
|
+
cursor = match.index + match[0].length;
|
|
7766
|
+
}
|
|
7767
|
+
return output + transform(body.slice(cursor));
|
|
7768
|
+
}
|
|
7769
|
+
function replaceOutsideCodeAndMdxComments(body, transform) {
|
|
7770
|
+
return replaceOutsideCode(body, (segment) => replaceOutsideMdxComments(segment, transform));
|
|
7771
|
+
}
|
|
7533
7772
|
function locallyDeclaredNames(raw) {
|
|
7534
7773
|
const names = /* @__PURE__ */ new Set();
|
|
7535
7774
|
let codeFence = null;
|
|
@@ -7575,7 +7814,7 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7575
7814
|
});
|
|
7576
7815
|
return `{/* ${verdict.kind === "oversized" ? "Oversized" : "Unreadable"} content not inlined: ${shown} */}`;
|
|
7577
7816
|
};
|
|
7578
|
-
let withoutImports =
|
|
7817
|
+
let withoutImports = replaceOutsideCodeAndMdxComments(raw, (source2) => source2.replace(
|
|
7579
7818
|
SNIPPET_IMPORT_PATTERN,
|
|
7580
7819
|
(_statement, namedComponent, defaultComponent, sourcePath) => {
|
|
7581
7820
|
const componentName = namedComponent ?? defaultComponent;
|
|
@@ -7602,17 +7841,23 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7602
7841
|
else snippets.set(componentName, snippetComponentBody(nested, componentName));
|
|
7603
7842
|
return "";
|
|
7604
7843
|
} catch {
|
|
7844
|
+
let hasLiveUsage = false;
|
|
7845
|
+
replaceOutsideCodeAndMdxComments(raw, (segment) => {
|
|
7846
|
+
if (new RegExp(`<${componentName}(?:\\s|/?>)`).test(segment)) hasLiveUsage = true;
|
|
7847
|
+
return segment;
|
|
7848
|
+
});
|
|
7849
|
+
if (!hasLiveUsage) return "";
|
|
7605
7850
|
warnings.push({
|
|
7606
7851
|
code: "missing-page",
|
|
7607
7852
|
message: `Imported snippet ${sourcePath} could not be resolved and was left as a comment.`,
|
|
7608
7853
|
source: relative5(repositoryRoot, currentFile).replace(/\\/g, "/")
|
|
7609
7854
|
});
|
|
7610
|
-
snippets.set(componentName, `
|
|
7855
|
+
snippets.set(componentName, mdxComment(` Missing imported snippet: ${sourcePath} `));
|
|
7611
7856
|
return "";
|
|
7612
7857
|
}
|
|
7613
7858
|
}
|
|
7614
7859
|
));
|
|
7615
|
-
withoutImports =
|
|
7860
|
+
withoutImports = replaceOutsideCodeAndMdxComments(withoutImports, (source2) => source2.replace(
|
|
7616
7861
|
SNIPPET_VALUE_IMPORT_PATTERN,
|
|
7617
7862
|
(statement, names, sourcePath) => {
|
|
7618
7863
|
const bindings = names.split(",").map((name) => name.trim()).filter(Boolean).map((name) => {
|
|
@@ -7656,7 +7901,12 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7656
7901
|
));
|
|
7657
7902
|
const localNames = locallyDeclaredNames(withoutImports);
|
|
7658
7903
|
for (const [componentName, candidate] of globalAliases) {
|
|
7659
|
-
|
|
7904
|
+
let hasLiveUsage = false;
|
|
7905
|
+
replaceOutsideCodeAndMdxComments(withoutImports, (source2) => {
|
|
7906
|
+
if (new RegExp(`<${componentName}(?:\\s|/?>)`).test(source2)) hasLiveUsage = true;
|
|
7907
|
+
return source2;
|
|
7908
|
+
});
|
|
7909
|
+
if (snippets.has(componentName) || localNames.has(componentName) || gate?.(candidate)?.kind === "gated" || !hasLiveUsage) continue;
|
|
7660
7910
|
const blocked = blockInline(candidate, relative5(repositoryRoot, candidate).replace(/\\/g, "/"));
|
|
7661
7911
|
if (blocked) {
|
|
7662
7912
|
snippets.set(componentName, blocked);
|
|
@@ -7676,48 +7926,49 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7676
7926
|
if (declaration) preservedDeclarations.set(componentName, declaration);
|
|
7677
7927
|
else snippets.set(componentName, snippetComponentBody(nested, componentName));
|
|
7678
7928
|
}
|
|
7679
|
-
let result = withoutImports
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
});
|
|
7686
|
-
}
|
|
7687
|
-
result = result.replace(SNIPPET_TAG_PATTERN, (_tag, doubleQuoted, singleQuoted) => {
|
|
7688
|
-
const filePath = doubleQuoted ?? singleQuoted;
|
|
7689
|
-
try {
|
|
7690
|
-
const candidate = [
|
|
7691
|
-
() => resolveWithin(siteRoot, `snippets/${filePath}`),
|
|
7692
|
-
() => resolveSnippetPath(filePath, currentFile, repositoryRoot, siteRoot)
|
|
7693
|
-
].map((resolveCandidate) => {
|
|
7694
|
-
try {
|
|
7695
|
-
return resolveCandidate();
|
|
7696
|
-
} catch {
|
|
7697
|
-
return void 0;
|
|
7698
|
-
}
|
|
7699
|
-
}).find((path) => path !== void 0 && existsSync5(path) && lstatSync5(path).isFile());
|
|
7700
|
-
if (!candidate) throw new Error("file not found");
|
|
7701
|
-
const blocked = blockInline(candidate, filePath, `Snippet file="${filePath}"`);
|
|
7702
|
-
if (blocked) return blocked;
|
|
7703
|
-
return inlineMdxSnippets(
|
|
7704
|
-
withoutFrontmatter(readFileSync5(candidate, "utf8")),
|
|
7705
|
-
candidate,
|
|
7706
|
-
repositoryRoot,
|
|
7707
|
-
warnings,
|
|
7708
|
-
depth + 1,
|
|
7709
|
-
siteRoot,
|
|
7710
|
-
globalAliases,
|
|
7711
|
-
gate
|
|
7712
|
-
);
|
|
7713
|
-
} catch {
|
|
7714
|
-
warnings.push({
|
|
7715
|
-
code: "missing-page",
|
|
7716
|
-
message: `Snippet file="${filePath}" could not be resolved and was left as a comment.`,
|
|
7717
|
-
source: relative5(repositoryRoot, currentFile).replace(/\\/g, "/")
|
|
7929
|
+
let result = replaceOutsideCodeAndComments(withoutImports, (segment) => {
|
|
7930
|
+
for (const [componentName, snippet] of snippets) {
|
|
7931
|
+
segment = segment.replace(new RegExp(`<${componentName}((?:\\s[^>]*)?)\\s*/>`, "g"), (tag, attributes, offset, source2) => {
|
|
7932
|
+
return isolateFences(closeOpenCodeFence(interpolateSnippet(snippet, attributes)), source2, offset, offset + tag.length);
|
|
7933
|
+
}).replace(new RegExp(`<${componentName}((?:\\s[^>]*)?)>([\\s\\S]*?)<\\/${componentName}>`, "g"), (tag, attributes, children, offset, source2) => {
|
|
7934
|
+
return isolateFences(closeOpenCodeFence(interpolateSnippet(snippet, attributes, children)), source2, offset, offset + tag.length);
|
|
7718
7935
|
});
|
|
7719
|
-
return `{/* Missing snippet: ${filePath} */}`;
|
|
7720
7936
|
}
|
|
7937
|
+
return segment.replace(SNIPPET_TAG_PATTERN, (tag, doubleQuoted, singleQuoted, offset, source2) => {
|
|
7938
|
+
const filePath = doubleQuoted ?? singleQuoted;
|
|
7939
|
+
try {
|
|
7940
|
+
const candidate = [
|
|
7941
|
+
() => resolveWithin(siteRoot, `snippets/${filePath}`),
|
|
7942
|
+
() => resolveSnippetPath(filePath, currentFile, repositoryRoot, siteRoot)
|
|
7943
|
+
].map((resolveCandidate) => {
|
|
7944
|
+
try {
|
|
7945
|
+
return resolveCandidate();
|
|
7946
|
+
} catch {
|
|
7947
|
+
return void 0;
|
|
7948
|
+
}
|
|
7949
|
+
}).find((path) => path !== void 0 && existsSync5(path) && lstatSync5(path).isFile());
|
|
7950
|
+
if (!candidate) throw new Error("file not found");
|
|
7951
|
+
const blocked = blockInline(candidate, filePath, `Snippet file="${filePath}"`);
|
|
7952
|
+
if (blocked) return blocked;
|
|
7953
|
+
return isolateFences(closeOpenCodeFence(inlineMdxSnippets(
|
|
7954
|
+
withoutFrontmatter(readFileSync5(candidate, "utf8")),
|
|
7955
|
+
candidate,
|
|
7956
|
+
repositoryRoot,
|
|
7957
|
+
warnings,
|
|
7958
|
+
depth + 1,
|
|
7959
|
+
siteRoot,
|
|
7960
|
+
globalAliases,
|
|
7961
|
+
gate
|
|
7962
|
+
)), source2, offset, offset + tag.length);
|
|
7963
|
+
} catch {
|
|
7964
|
+
warnings.push({
|
|
7965
|
+
code: "missing-page",
|
|
7966
|
+
message: `Snippet file="${filePath}" could not be resolved and was left as a comment.`,
|
|
7967
|
+
source: relative5(repositoryRoot, currentFile).replace(/\\/g, "/")
|
|
7968
|
+
});
|
|
7969
|
+
return mdxComment(` Missing snippet: ${filePath} `);
|
|
7970
|
+
}
|
|
7971
|
+
});
|
|
7721
7972
|
});
|
|
7722
7973
|
if (preservedDeclarations.size > 0) {
|
|
7723
7974
|
const frontmatter = result.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/);
|
|
@@ -7726,7 +7977,7 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7726
7977
|
|
|
7727
7978
|
${result.slice(prefix.length)}`;
|
|
7728
7979
|
}
|
|
7729
|
-
return depth === 0 ? hoistMdxImports(result) : result;
|
|
7980
|
+
return depth === 0 ? hoistMdxImports(result) : closeOpenFence(result);
|
|
7730
7981
|
}
|
|
7731
7982
|
function injectOpenApiSpecs(config, specs, warnings) {
|
|
7732
7983
|
const tabs = config.tabs.map((tab) => ({ ...tab }));
|
|
@@ -7913,7 +8164,7 @@ function migrateRepository(options) {
|
|
|
7913
8164
|
const sourceBudget = options.maxSourceFiles ?? MAX_SOURCE_FILES;
|
|
7914
8165
|
const scannedFiles = scanFiles(contentRoot, repositoryDir, warnings, discoveryRank, sourceBudget);
|
|
7915
8166
|
const mintignoreFilteredFiles = mintignoreMatcher ? scannedFiles.filter((file) => !mintignoreMatcher.ignores(file.relativePath)) : scannedFiles;
|
|
7916
|
-
const
|
|
8167
|
+
const isUnreferencedSnippetModule = (file) => file.relativePath.split("/").some((segment) => SNIPPET_DIRECTORIES.has(segment.toLowerCase())) && isDocumentationExtension(file.relativePath) && !referenceOrder.has(normalizedReferenceKey(file.relativePath));
|
|
7917
8168
|
const files = discoveryRank ? selectFilesWithinBudget(mintignoreFilteredFiles, discoveryRank, warnings, allVersionPrefixes, sourceBudget) : mintignoreFilteredFiles;
|
|
7918
8169
|
if (platform === "fern" && fernProjectRoot) {
|
|
7919
8170
|
const discovered2 = new Set(files.map((file) => file.relativePath));
|
|
@@ -7992,6 +8243,10 @@ function migrateRepository(options) {
|
|
|
7992
8243
|
}
|
|
7993
8244
|
for (const file of mintignoreFilteredFiles) {
|
|
7994
8245
|
if (keptFiles.has(file) || !isDocFile(file)) continue;
|
|
8246
|
+
if (isUnreferencedSnippetModule(file)) {
|
|
8247
|
+
if (classifyPageGate(file).reason) withheldDocFiles.push(file);
|
|
8248
|
+
continue;
|
|
8249
|
+
}
|
|
7995
8250
|
droppedPageCount++;
|
|
7996
8251
|
if (!isGateCandidate(file)) {
|
|
7997
8252
|
const snippetReason = classifyPageGate(file).reason;
|
|
@@ -8214,7 +8469,7 @@ function migrateRepository(options) {
|
|
|
8214
8469
|
const publishedText = trackPublishedRefs ? raw : void 0;
|
|
8215
8470
|
const pageAssetReferences = [];
|
|
8216
8471
|
if (platform === "fern" || platform === "mintlify" || platform === "docusaurus") {
|
|
8217
|
-
raw = normalizeExplicitHeadingIds(raw);
|
|
8472
|
+
raw = normalizeExplicitHeadingIds(raw, (message) => warnings.push({ code: "invalid-page", message, source: file.relativePath }));
|
|
8218
8473
|
}
|
|
8219
8474
|
if (componentMigrator) {
|
|
8220
8475
|
const warningsBeforeTransform = warnings.length;
|
|
@@ -8226,13 +8481,7 @@ function migrateRepository(options) {
|
|
|
8226
8481
|
}
|
|
8227
8482
|
if (platform === "fern" || platform === "mintlify" || platform === "docusaurus") {
|
|
8228
8483
|
const protectedMath = protectMathBlocks(raw);
|
|
8229
|
-
if (protectedMath.
|
|
8230
|
-
warnings.push({
|
|
8231
|
-
code: "unsupported-config",
|
|
8232
|
-
message: "Math (KaTeX '$$...$$') has no renderer in Thally yet; it was kept as a fenced code block instead of being dropped.",
|
|
8233
|
-
source: relative5(repositoryDir, file.absolutePath).replace(/\\/g, "/")
|
|
8234
|
-
});
|
|
8235
|
-
} else if (protectedMath.guardTriggered) {
|
|
8484
|
+
if (protectedMath.guardTriggered) {
|
|
8236
8485
|
warnings.push({
|
|
8237
8486
|
code: "unsupported-config",
|
|
8238
8487
|
message: "A suspected math span looked like it needed converting, but doing so broke the page; the page was kept as originally authored instead.",
|
|
@@ -8324,7 +8573,7 @@ function migrateRepository(options) {
|
|
|
8324
8573
|
page.body = replaceUnknownComponents(page.body, (name) => {
|
|
8325
8574
|
warnings.push({
|
|
8326
8575
|
code: "unsupported-config",
|
|
8327
|
-
message: `
|
|
8576
|
+
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.`,
|
|
8328
8577
|
source: file.relativePath
|
|
8329
8578
|
});
|
|
8330
8579
|
});
|
|
@@ -8451,9 +8700,31 @@ function migrateRepository(options) {
|
|
|
8451
8700
|
const source = /^src\/mdx\/migrated\/[^/]+\/source\/(.+)$/.exec(file.path)?.[1];
|
|
8452
8701
|
return source ? [resolvePath(repositoryDir, source)] : [];
|
|
8453
8702
|
}));
|
|
8703
|
+
const rootStylesheetPath = platform === "mintlify" && mintlifyProjectRoot ? resolveWithin(mintlifyProjectRoot, "style.css") : void 0;
|
|
8704
|
+
const hasRootStylesheet = Boolean(rootStylesheetPath && existsSync5(rootStylesheetPath) && lstatSync5(rootStylesheetPath).isFile() && !lstatSync5(rootStylesheetPath).isSymbolicLink());
|
|
8705
|
+
let rootStyleProjection;
|
|
8706
|
+
let rootStyleProblem;
|
|
8707
|
+
if (hasRootStylesheet && rootStylesheetPath && lstatSync5(rootStylesheetPath).size <= MAX_ASSET_BYTES) {
|
|
8708
|
+
const css = readFileSync5(rootStylesheetPath, "utf8");
|
|
8709
|
+
if (/@import\b|url\s*\(\s*['"]?\s*(?:javascript:|file:)/i.test(css)) rootStyleProblem = "unsafe";
|
|
8710
|
+
else {
|
|
8711
|
+
try {
|
|
8712
|
+
rootStyleProjection = projectAuthoredStyles(css, [
|
|
8713
|
+
...pages.map((page) => page.body),
|
|
8714
|
+
...(componentMigrator?.files() ?? []).map((file) => typeof file.content === "string" ? file.content : "")
|
|
8715
|
+
]);
|
|
8716
|
+
} catch {
|
|
8717
|
+
rootStyleProblem = "parse";
|
|
8718
|
+
}
|
|
8719
|
+
}
|
|
8720
|
+
}
|
|
8721
|
+
if (trackPublishedRefs && rootStyleProjection?.css) {
|
|
8722
|
+
addPathReferences(rootStyleProjection.css, "", publishedExact, publishedLoose);
|
|
8723
|
+
}
|
|
8454
8724
|
const siteAssetPaths = /* @__PURE__ */ new Map();
|
|
8455
8725
|
const fontAssetByRelative = /* @__PURE__ */ new Map();
|
|
8456
8726
|
for (const file of [...files, ...repositoryAssets, ...fernReferencedAssets]) {
|
|
8727
|
+
if (rootStylesheetPath && file.absolutePath === rootStylesheetPath) continue;
|
|
8457
8728
|
const firstSegment = file.relativePath.split("/", 1)[0].toLowerCase();
|
|
8458
8729
|
const siteKind = platform !== "mintlify" ? void 0 : fontRelativePaths.has(file.relativePath) ? "font" : isMintlifyServedScriptOrStyle(file.relativePath) && !importedComponentSources.has(file.absolutePath) ? extname6(file.relativePath).toLowerCase() === ".css" ? "style" : "script" : void 0;
|
|
8459
8730
|
if (!siteKind && !ASSET_EXTENSIONS.has(extname6(file.relativePath).toLowerCase())) continue;
|
|
@@ -8499,7 +8770,8 @@ function migrateRepository(options) {
|
|
|
8499
8770
|
const lfsPointerAssets = [];
|
|
8500
8771
|
const ambiguouslyNamedAssets = [];
|
|
8501
8772
|
for (const { file, assetPath, size } of orderedAssetCandidates) {
|
|
8502
|
-
|
|
8773
|
+
const individualLimit = referencedAssetPaths.has(assetPath) ? MAX_REFERENCED_ASSET_BYTES : MAX_ASSET_BYTES;
|
|
8774
|
+
if (size > individualLimit || totalAssetBytes + size > MAX_TOTAL_ASSET_BYTES) {
|
|
8503
8775
|
overBudgetAssets.push(file.relativePath);
|
|
8504
8776
|
if (referencedAssetPaths.has(assetPath)) overBudgetReferenced++;
|
|
8505
8777
|
continue;
|
|
@@ -8541,7 +8813,7 @@ function migrateRepository(options) {
|
|
|
8541
8813
|
for (const entry of copiedSite.filter((item) => item.kind === "style")) {
|
|
8542
8814
|
warnings.push({
|
|
8543
8815
|
code: "unsupported-config",
|
|
8544
|
-
message: `Migration gap: custom stylesheet ${entry.path} is NOT applied. It was copied to public/${entry.path} but
|
|
8816
|
+
message: `Migration gap: custom stylesheet ${entry.path} is NOT applied. It was copied to public/${entry.path} but was not declared in docs.json stylesheets; its selectors may target Mintlify's markup. Review and port its authored rules into a Thally stylesheet.`,
|
|
8545
8817
|
source: entry.path
|
|
8546
8818
|
});
|
|
8547
8819
|
}
|
|
@@ -8559,7 +8831,7 @@ function migrateRepository(options) {
|
|
|
8559
8831
|
if (overBudgetAssets.length > 0) {
|
|
8560
8832
|
warnings.push({
|
|
8561
8833
|
code: "limit-reached",
|
|
8562
|
-
message: `${overBudgetAssets.length} asset file${overBudgetAssets.length === 1 ? " was" : "s were"} not copied because files over ${MAX_ASSET_BYTES / 1e6} MB, or beyond ${MAX_TOTAL_ASSET_BYTES / 1e6} MB in total, are skipped: ${listAssetPaths(overBudgetAssets)}. ` + (overBudgetReferenced > 0 ? `${overBudgetReferenced} of them ${overBudgetReferenced === 1 ? "is" : "are"} used by pages, so those images will be broken until you copy ${overBudgetAssets.length === 1 ? "it" : "them"}. ` : "") + `Copy ${overBudgetAssets.length === 1 ? "it" : "them"} into public/ manually.`
|
|
8834
|
+
message: `${overBudgetAssets.length} asset file${overBudgetAssets.length === 1 ? " was" : "s were"} not copied because unreferenced files over ${MAX_ASSET_BYTES / 1e6} MB, referenced files over ${MAX_REFERENCED_ASSET_BYTES / 1e6} MB, or files beyond ${MAX_TOTAL_ASSET_BYTES / 1e6} MB in total, are skipped: ${listAssetPaths(overBudgetAssets)}. ` + (overBudgetReferenced > 0 ? `${overBudgetReferenced} of them ${overBudgetReferenced === 1 ? "is" : "are"} used by pages, so those images will be broken until you copy ${overBudgetAssets.length === 1 ? "it" : "them"}. ` : "") + `Copy ${overBudgetAssets.length === 1 ? "it" : "them"} into public/ manually.`
|
|
8563
8835
|
});
|
|
8564
8836
|
}
|
|
8565
8837
|
if (lfsPointerAssets.length > 0) {
|
|
@@ -8568,7 +8840,31 @@ function migrateRepository(options) {
|
|
|
8568
8840
|
message: `${lfsPointerAssets.length} asset file${lfsPointerAssets.length === 1 ? " is a Git LFS pointer" : "s are Git LFS pointers"}, not real content, and ${lfsPointerAssets.length === 1 ? "was" : "were"} not copied (Git LFS was skipped during clone because the host has no git-lfs binary): ${listAssetPaths(lfsPointerAssets)}. Install git-lfs and re-run the migration, or copy the real files into public/ manually.`
|
|
8569
8841
|
});
|
|
8570
8842
|
}
|
|
8571
|
-
if (
|
|
8843
|
+
if (hasRootStylesheet && rootStylesheetPath && mintlifyProjectRoot) {
|
|
8844
|
+
const size = lstatSync5(rootStylesheetPath).size;
|
|
8845
|
+
if (size > MAX_ASSET_BYTES || totalAssetBytes + size > MAX_TOTAL_ASSET_BYTES) {
|
|
8846
|
+
warnings.push({ code: "limit-reached", message: "Mintlify root style.css exceeded the asset budget and was not imported.", source: "style.css" });
|
|
8847
|
+
} else if (rootStyleProblem === "unsafe") {
|
|
8848
|
+
warnings.push({ code: "unsupported-config", message: "Mintlify root style.css contains a CSS import or unsafe URL; review and import it manually.", source: "style.css" });
|
|
8849
|
+
} else if (rootStyleProblem === "parse" || !rootStyleProjection) {
|
|
8850
|
+
warnings.push({ code: "unsupported-config", message: "Mintlify root style.css could not be parsed and was not imported.", source: "style.css" });
|
|
8851
|
+
} else {
|
|
8852
|
+
if (rootStyleProjection.omittedSelectors > 0) warnings.push({
|
|
8853
|
+
code: "unsupported-config",
|
|
8854
|
+
source: "style.css",
|
|
8855
|
+
message: `Skipped ${rootStyleProjection.omittedSelectors} stylesheet selector${rootStyleProjection.omittedSelectors === 1 ? "" : "s"} that target platform-owned or unreferenced markup. Recreate any intentional shell customization with Thally configuration.`
|
|
8856
|
+
});
|
|
8857
|
+
if (rootStyleProjection.css.trim()) {
|
|
8858
|
+
const identity = createHash2("sha256").update(componentSourceIdentity(options.sourceUrl, repositoryDir, mintlifyProjectRoot)).digest("hex").slice(0, 12);
|
|
8859
|
+
const assetPath = `migrated/${identity}/style.css`;
|
|
8860
|
+
const content = Buffer.from(rootStyleProjection.css);
|
|
8861
|
+
assets.push({ path: assetPath, content });
|
|
8862
|
+
docsConfig = { ...docsConfig, stylesheets: [...docsConfig.stylesheets ?? [], `/${assetPath}`] };
|
|
8863
|
+
totalAssetBytes += content.length;
|
|
8864
|
+
}
|
|
8865
|
+
}
|
|
8866
|
+
}
|
|
8867
|
+
if (!discoveryRank && files.length >= sourceBudget) {
|
|
8572
8868
|
warnings.push({ code: "limit-reached", message: `Stopped scanning after ${sourceBudget} files, so the rest of the repository was not looked at. Run the migration on a smaller part of the repository with --docs-dir.` });
|
|
8573
8869
|
}
|
|
8574
8870
|
if (platform === "docusaurus") {
|
|
@@ -9241,6 +9537,7 @@ function mergeMigrationConfig(existing, incoming) {
|
|
|
9241
9537
|
// Collection presentation belongs to the imported information
|
|
9242
9538
|
// architecture; starter defaults must not coerce source dropdowns to tabs.
|
|
9243
9539
|
navigation: incoming.navigation ?? existing.navigation,
|
|
9540
|
+
...existing.stylesheets?.length || incoming.stylesheets?.length ? { stylesheets: [.../* @__PURE__ */ new Set([...existing.stylesheets ?? [], ...incoming.stylesheets ?? []])] } : {},
|
|
9244
9541
|
...i18n ? { i18n } : {},
|
|
9245
9542
|
// Existing providers win per provider; imported ones fill the gaps.
|
|
9246
9543
|
// A malformed (string/array) existing value must not spread into index keys.
|
|
@@ -9587,7 +9884,7 @@ function embeddedMintlifyConfig(body) {
|
|
|
9587
9884
|
function plainDescription(value) {
|
|
9588
9885
|
return value.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/[`*_>#-]/g, "").replace(/\s+/g, " ").trim().slice(0, 240);
|
|
9589
9886
|
}
|
|
9590
|
-
function
|
|
9887
|
+
function withoutFencedCode2(body) {
|
|
9591
9888
|
let fenceCharacter = "";
|
|
9592
9889
|
let fenceLength = 0;
|
|
9593
9890
|
return body.split("\n").map((line) => {
|
|
@@ -9897,7 +10194,7 @@ function sanitizeRemoteMarkdown(body) {
|
|
|
9897
10194
|
}).join("\n");
|
|
9898
10195
|
const urlSafeMarkdown = sanitizeMarkdownUrls(sanitized);
|
|
9899
10196
|
if (urlSafeMarkdown === null) return null;
|
|
9900
|
-
const executable =
|
|
10197
|
+
const executable = withoutFencedCode2(urlSafeMarkdown).replace(/\{\/\*[\s\S]*?\*\/\}/g, "").replace(/<(?:https?:\/\/|mailto:)[^>]+>/gi, "").replace(/(`+)[\s\S]*?\1/g, "");
|
|
9901
10198
|
if (/^\s*(?:import|export)\s/m.test(executable)) return null;
|
|
9902
10199
|
let hasUnsafeExpression = false;
|
|
9903
10200
|
const withoutStaticProps = executable.replace(/=\{([^{}\n]*)\}/g, (original, value) => {
|
|
@@ -10847,7 +11144,7 @@ async function migrateUrl(options) {
|
|
|
10847
11144
|
}
|
|
10848
11145
|
|
|
10849
11146
|
// src/remote-api.ts
|
|
10850
|
-
import { createHash as
|
|
11147
|
+
import { createHash as createHash3 } from "crypto";
|
|
10851
11148
|
import { lookup } from "dns/promises";
|
|
10852
11149
|
import { request } from "https";
|
|
10853
11150
|
import { isIP } from "net";
|
|
@@ -11007,7 +11304,7 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
11007
11304
|
const extension = /\.ya?ml$/i.test(url.pathname) ? "yaml" : "json";
|
|
11008
11305
|
const body = await downloadSpec(reference.url, fetcher);
|
|
11009
11306
|
const operations = parseOpenApi(body, extension);
|
|
11010
|
-
const filename = `openapi-${
|
|
11307
|
+
const filename = `openapi-${createHash3("sha256").update(reference.url).digest("hex").slice(0, 12)}.${extension}`;
|
|
11011
11308
|
assets.push({ path: `openapi/${filename}`, content: body, projectRelative: true });
|
|
11012
11309
|
for (const page of pages) {
|
|
11013
11310
|
const ref = page.openapi ? splitOpenApiRef(page.openapi) : null;
|