@thallylabs/migrate 0.2.21 → 0.2.23
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 +43 -0
- package/dist/index.js +729 -279
- 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,12 +17,12 @@ 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";
|
|
23
24
|
import { existsSync, lstatSync, readFileSync } from "fs";
|
|
24
|
-
import { basename, dirname, extname, relative as relative2, resolve as resolve2 } from "path";
|
|
25
|
+
import { basename, dirname, extname as extname2, relative as relative2, resolve as resolve2 } from "path";
|
|
25
26
|
import postcss from "postcss";
|
|
26
27
|
import selectorParser from "postcss-selector-parser";
|
|
27
28
|
import remarkMdx2 from "remark-mdx";
|
|
@@ -156,6 +157,177 @@ function isThallyBuiltinComponent(name) {
|
|
|
156
157
|
return THALLY_BUILTIN_COMPONENTS.has(name) || THALLY_BUILTIN_COMPONENTS.has(name.split(".")[0]);
|
|
157
158
|
}
|
|
158
159
|
|
|
160
|
+
// src/mintlify-extras.ts
|
|
161
|
+
import { extname } from "path";
|
|
162
|
+
|
|
163
|
+
// src/path.ts
|
|
164
|
+
import { isAbsolute, relative, resolve, sep } from "path";
|
|
165
|
+
var SAFE_SEGMENT = /[^a-z0-9._-]+/gi;
|
|
166
|
+
function trimTrailingSlashes(value) {
|
|
167
|
+
let end = value.length;
|
|
168
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) end--;
|
|
169
|
+
return value.slice(0, end);
|
|
170
|
+
}
|
|
171
|
+
function trimEdgeSlashes(value) {
|
|
172
|
+
let start = 0;
|
|
173
|
+
let end = value.length;
|
|
174
|
+
while (start < end && value.charCodeAt(start) === 47) start++;
|
|
175
|
+
while (end > start && value.charCodeAt(end - 1) === 47) end--;
|
|
176
|
+
return value.slice(start, end);
|
|
177
|
+
}
|
|
178
|
+
function slugifySegment(value, preserveCase = false) {
|
|
179
|
+
let decoded = value;
|
|
180
|
+
try {
|
|
181
|
+
decoded = decodeURIComponent(value);
|
|
182
|
+
} catch {
|
|
183
|
+
}
|
|
184
|
+
const normalized = preserveCase ? decoded : decoded.toLowerCase();
|
|
185
|
+
return normalized.replace(/\.(?:html?|mdx?)$/i, "").replace(SAFE_SEGMENT, "-").replace(/(^-|-$)/g, "");
|
|
186
|
+
}
|
|
187
|
+
function pageIdFromReference(value, preserveCase = false) {
|
|
188
|
+
const withoutQuery = value.split(/[?#]/, 1)[0].replace(/\\/g, "/").replace(/^\/+/, "");
|
|
189
|
+
if (!withoutQuery || withoutQuery.includes("\0")) return null;
|
|
190
|
+
const rawSegments = withoutQuery.split("/").filter(Boolean);
|
|
191
|
+
if (rawSegments.some((segment) => segment === ".." || segment === ".")) return null;
|
|
192
|
+
const last = rawSegments.at(-1)?.replace(/\.(?:mdx?|rst|txt)$/i, "") ?? "";
|
|
193
|
+
const isRootLevelReadme = rawSegments.length === 1 && /^readme$/i.test(last);
|
|
194
|
+
const collapsesToParent = /^index$/i.test(last) || isRootLevelReadme;
|
|
195
|
+
const baseSegments = collapsesToParent ? rawSegments.slice(0, -1) : rawSegments;
|
|
196
|
+
if (!collapsesToParent) {
|
|
197
|
+
baseSegments[baseSegments.length - 1] = last;
|
|
198
|
+
}
|
|
199
|
+
const segments = baseSegments.map((segment) => slugifySegment(segment, preserveCase)).filter(Boolean);
|
|
200
|
+
return segments.join("/") || "introduction";
|
|
201
|
+
}
|
|
202
|
+
function mintlifyLocalizedReference(value, locale, defaultPageIds = /* @__PURE__ */ new Set()) {
|
|
203
|
+
const reference = value.replace(/^\/+/, "");
|
|
204
|
+
const localePrefix = `${locale.toLowerCase()}/`;
|
|
205
|
+
if (reference.toLowerCase().startsWith(localePrefix)) return reference.slice(localePrefix.length);
|
|
206
|
+
const sectionPrefix = `${locale.toLowerCase()}-`;
|
|
207
|
+
if (reference.toLowerCase().startsWith(sectionPrefix)) {
|
|
208
|
+
const candidate = reference.slice(sectionPrefix.length);
|
|
209
|
+
const candidateId = pageIdFromReference(candidate, true);
|
|
210
|
+
if (candidateId && defaultPageIds.has(candidateId)) return candidate;
|
|
211
|
+
}
|
|
212
|
+
const segments = reference.split("/");
|
|
213
|
+
const localeIndex = segments.findIndex((segment) => segment.toLowerCase() === locale.toLowerCase());
|
|
214
|
+
if (localeIndex > 0) {
|
|
215
|
+
return [...segments.slice(0, localeIndex), ...segments.slice(localeIndex + 1)].join("/");
|
|
216
|
+
}
|
|
217
|
+
return value;
|
|
218
|
+
}
|
|
219
|
+
function resolveWithin(root, candidate) {
|
|
220
|
+
return resolveWithinRoot(root, candidate, root);
|
|
221
|
+
}
|
|
222
|
+
function resolveWithinRoot(baseDir, candidate, confineRoot) {
|
|
223
|
+
if (isAbsolute(candidate) || candidate.includes("\0")) {
|
|
224
|
+
throw new Error(`Unsafe migration path: ${candidate}`);
|
|
225
|
+
}
|
|
226
|
+
const target = resolve(baseDir, candidate);
|
|
227
|
+
const fromRoot = relative(resolve(confineRoot), target);
|
|
228
|
+
if (fromRoot === ".." || fromRoot.startsWith(`..${sep}`) || isAbsolute(fromRoot)) {
|
|
229
|
+
throw new Error(`Migration path escapes its root: ${candidate}`);
|
|
230
|
+
}
|
|
231
|
+
return target;
|
|
232
|
+
}
|
|
233
|
+
function normalizeAssetPath(value) {
|
|
234
|
+
const normalized = value.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
235
|
+
if (!normalized || normalized.includes("\0")) return null;
|
|
236
|
+
const segments = normalized.split("/").filter(Boolean);
|
|
237
|
+
if (segments.some((segment) => segment === "." || segment === "..")) return null;
|
|
238
|
+
return segments.join("/");
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// src/mintlify-extras.ts
|
|
242
|
+
function objectValue(value) {
|
|
243
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
244
|
+
}
|
|
245
|
+
var PUBLIC_FALSE_STRINGS = /* @__PURE__ */ new Set(["false", "no", "off", "0"]);
|
|
246
|
+
function isPublicFalse(value) {
|
|
247
|
+
return value === false || value === 0 || typeof value === "string" && PUBLIC_FALSE_STRINGS.has(value.trim().toLowerCase());
|
|
248
|
+
}
|
|
249
|
+
function isPublicTrue(value) {
|
|
250
|
+
return value === true || typeof value === "string" && value.trim().toLowerCase() === "true";
|
|
251
|
+
}
|
|
252
|
+
function frontmatterGateReason(data) {
|
|
253
|
+
const groups = data.groups;
|
|
254
|
+
const hasGroups = Array.isArray(groups) ? groups.length > 0 : typeof groups === "string" ? groups.trim() !== "" : groups !== void 0 && groups !== null && groups !== false;
|
|
255
|
+
if (hasGroups) return "frontmatter `groups` restricts it to authenticated groups";
|
|
256
|
+
if (isPublicFalse(data.public)) return "frontmatter `public: false`";
|
|
257
|
+
return void 0;
|
|
258
|
+
}
|
|
259
|
+
function navigationGateReason(node) {
|
|
260
|
+
const groups = node.groups;
|
|
261
|
+
const isContainer = (entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) && ["group", "pages", "tab", "groups", "page", "root", "menu", "href"].some((key) => key in entry);
|
|
262
|
+
const restricted = typeof groups === "string" ? groups.trim() !== "" : Array.isArray(groups) && groups.length > 0 && !groups.every(isContainer);
|
|
263
|
+
if (restricted) return "its navigation container sets `groups`";
|
|
264
|
+
if (isPublicFalse(node.public)) return "its navigation container sets `public: false`";
|
|
265
|
+
return void 0;
|
|
266
|
+
}
|
|
267
|
+
var CONFIG_BASENAME = /(?:^|[.-])(?:config|rc)\.[cm]?js$|^(?:tailwind|postcss|next|eslint|prettier|babel|webpack|vite|vitest|jest|rollup|gulpfile|gruntfile|stylelint|commitlint|lint-staged|svgo|metro)[.-]/i;
|
|
268
|
+
var BUILD_OUTPUT_SEGMENTS = /* @__PURE__ */ new Set(["dist", "build", "coverage"]);
|
|
269
|
+
var FONT_EXTENSIONS = /* @__PURE__ */ new Set([".woff", ".woff2", ".ttf", ".otf"]);
|
|
270
|
+
function isMintlifyServedScriptOrStyle(relativePath) {
|
|
271
|
+
const extension = extname(relativePath).toLowerCase();
|
|
272
|
+
if (extension !== ".css" && extension !== ".js") return false;
|
|
273
|
+
const segments = relativePath.split("/");
|
|
274
|
+
if (segments.slice(0, -1).some((segment) => BUILD_OUTPUT_SEGMENTS.has(segment.toLowerCase()))) return false;
|
|
275
|
+
return extension === ".css" || !CONFIG_BASENAME.test(segments[segments.length - 1]);
|
|
276
|
+
}
|
|
277
|
+
function mintlifyFontSources(config) {
|
|
278
|
+
const fonts = objectValue(config?.fonts);
|
|
279
|
+
if (!fonts) return [];
|
|
280
|
+
const found = [];
|
|
281
|
+
for (const entry of [fonts, objectValue(fonts.heading), objectValue(fonts.body)]) {
|
|
282
|
+
if (!entry || typeof entry.source !== "string" || !entry.source.trim()) continue;
|
|
283
|
+
const source = entry.source.trim();
|
|
284
|
+
const family = typeof entry.family === "string" ? entry.family : "a font";
|
|
285
|
+
const remote = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(source);
|
|
286
|
+
const path = remote || /^[a-z]:[\\/]/i.test(source) ? null : normalizeAssetPath(source);
|
|
287
|
+
found.push({ family, source, path: path && FONT_EXTENSIONS.has(extname(path).toLowerCase()) ? path : null, remote });
|
|
288
|
+
}
|
|
289
|
+
return found;
|
|
290
|
+
}
|
|
291
|
+
function mintlifyAppearance(config, warnings) {
|
|
292
|
+
const appearance = objectValue(config.appearance);
|
|
293
|
+
const legacy = objectValue(config.modeToggle);
|
|
294
|
+
const result = {};
|
|
295
|
+
const isMode = (value) => value === "system" || value === "light" || value === "dark";
|
|
296
|
+
const skip = (field, value) => {
|
|
297
|
+
warnings.push({
|
|
298
|
+
code: "unsupported-config",
|
|
299
|
+
message: `Ignored invalid ${field} value ${JSON.stringify(value)?.slice(0, 40)}; the appearance default was left unchanged.`
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
if (appearance?.default !== void 0) {
|
|
303
|
+
if (isMode(appearance.default)) result.default = appearance.default;
|
|
304
|
+
else skip("appearance.default", appearance.default);
|
|
305
|
+
} else if (legacy?.default !== void 0) {
|
|
306
|
+
if (isMode(legacy.default)) result.default = legacy.default;
|
|
307
|
+
else skip("modeToggle.default", legacy.default);
|
|
308
|
+
}
|
|
309
|
+
if (appearance?.strict !== void 0) {
|
|
310
|
+
if (typeof appearance.strict === "boolean") {
|
|
311
|
+
if (appearance.strict) result.showToggle = false;
|
|
312
|
+
} else skip("appearance.strict", appearance.strict);
|
|
313
|
+
} else if (legacy?.isHidden !== void 0) {
|
|
314
|
+
if (typeof legacy.isHidden === "boolean") {
|
|
315
|
+
if (legacy.isHidden) result.showToggle = false;
|
|
316
|
+
} else skip("modeToggle.isHidden", legacy.isHidden);
|
|
317
|
+
}
|
|
318
|
+
return result;
|
|
319
|
+
}
|
|
320
|
+
function playgroundDisplay(value, where, warn) {
|
|
321
|
+
const mode = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
322
|
+
if (mode === "interactive" || mode === "simple" || mode === "none") return mode;
|
|
323
|
+
if (mode === "auth") {
|
|
324
|
+
warn?.(`${where} "auth" shows the playground only to signed-in readers, which Thally cannot tell; migrated as "simple" (no playground).`);
|
|
325
|
+
return "simple";
|
|
326
|
+
}
|
|
327
|
+
warn?.(`${where} ${JSON.stringify(value)} is not one of interactive, simple, none, auth and was dropped.`);
|
|
328
|
+
return void 0;
|
|
329
|
+
}
|
|
330
|
+
|
|
159
331
|
// src/mdx.ts
|
|
160
332
|
function titleFromId(id) {
|
|
161
333
|
const value = id.split("/").at(-1) ?? id;
|
|
@@ -264,7 +436,7 @@ function unwrapDocusaurusMdxCodeBlocks(body) {
|
|
|
264
436
|
return isMdxCodeBlock ? body : output.join("\n");
|
|
265
437
|
}
|
|
266
438
|
var HTML_ID = /^[^\s"'<>`{}&]+$/u;
|
|
267
|
-
function normalizeExplicitHeadingIds(raw, warn) {
|
|
439
|
+
function normalizeExplicitHeadingIds(raw, warn, options = {}) {
|
|
268
440
|
const { front, body } = splitFrontmatterBlock(raw);
|
|
269
441
|
return front + replaceOutsideCode(body, (segment) => segment.split("\n").map((line) => {
|
|
270
442
|
if (!/^[ \t]{0,3}#{1,6}[ \t]+/.test(line)) return line;
|
|
@@ -275,13 +447,15 @@ function normalizeExplicitHeadingIds(raw, warn) {
|
|
|
275
447
|
const id = trimmed.slice(marker + 3, -1);
|
|
276
448
|
const heading = trimmed.slice(0, marker).trimEnd();
|
|
277
449
|
if (/[{}]/.test(id)) return line;
|
|
278
|
-
|
|
450
|
+
const usable = options.headingMarkers ? id && !/\s/.test(id) && !id.includes("*/") : HTML_ID.test(id);
|
|
451
|
+
if (usable && options.headingMarkers) return `${heading} ${headingIdMarker(id)}`;
|
|
452
|
+
if (usable) return `<a id="${id}"></a>
|
|
279
453
|
${heading}`;
|
|
280
454
|
warn?.(`Heading anchor {#${id}} is not a valid HTML id and was removed from "${heading.replace(/^\s*#+\s*/, "")}".`);
|
|
281
455
|
return heading;
|
|
282
456
|
}
|
|
283
457
|
}
|
|
284
|
-
if (trimmed.endsWith("*/}")) {
|
|
458
|
+
if (!options.headingMarkers && !options.keepIdComments && trimmed.endsWith("*/}")) {
|
|
285
459
|
const marker = trimmed.lastIndexOf(" {/*");
|
|
286
460
|
if (marker >= 0) {
|
|
287
461
|
const comment = trimmed.slice(marker + 4, -3).trim();
|
|
@@ -295,6 +469,44 @@ ${trimmed.slice(0, marker).trimEnd()}`;
|
|
|
295
469
|
return line;
|
|
296
470
|
}).join("\n"));
|
|
297
471
|
}
|
|
472
|
+
function headingIdMarker(id) {
|
|
473
|
+
return `{/* #${id} */}`;
|
|
474
|
+
}
|
|
475
|
+
function mintlifyHeadingSlug(text2) {
|
|
476
|
+
return text2.replace(/\u200b/g, "").normalize("NFC").trim().toLowerCase().replace(/[.\s]+/g, "-").replace(/-{2,}/g, "-").replace(/^-|-$/g, "").replace(/[^\p{L}\p{M}\p{N}_\-+&/\u2019\u201c\u201d\u2014\u2013\u2192]/gu, "");
|
|
477
|
+
}
|
|
478
|
+
function thallyHeadingSlug(text2) {
|
|
479
|
+
return text2.normalize("NFC").toLowerCase().replace(/[^\p{L}\p{M}\p{N}]+/gu, "-").replace(/(^-|-$)/g, "");
|
|
480
|
+
}
|
|
481
|
+
function typesetQuotes(text2) {
|
|
482
|
+
return text2.split(/(`[^`]*`|<[^>]*>|\]\([^)]*\))/).map((part, index) => {
|
|
483
|
+
if (index % 2) return part;
|
|
484
|
+
return part.replace(/(^|[\s([{\u2014\u2013])"/g, "$1\u201C").replace(/"/g, "\u201D").replace(/(^|[\s([{\u2014\u2013\u201c])'(?=\S)/g, "$1\u2018").replace(/'/g, "\u2019");
|
|
485
|
+
}).join("");
|
|
486
|
+
}
|
|
487
|
+
function plainHeadingText(source) {
|
|
488
|
+
return source.replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/<\/?[A-Za-z][^>]*>/g, "").replace(/`([^`]*)`/g, "$1").replace(/(\*\*|__|~~|\*)/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/\\([\\`*_{}[\]()#+.!&<>|~-])/g, "$1");
|
|
489
|
+
}
|
|
490
|
+
function markMintlifyHeadings(body) {
|
|
491
|
+
let fence;
|
|
492
|
+
return body.split("\n").map((line) => {
|
|
493
|
+
const marker = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
494
|
+
if (marker) {
|
|
495
|
+
if (!fence) fence = marker[1];
|
|
496
|
+
else if (marker[1][0] === fence[0] && marker[1].length >= fence.length && /^\s*$/.test(line.slice(marker[0].length))) fence = void 0;
|
|
497
|
+
return line;
|
|
498
|
+
}
|
|
499
|
+
if (fence) return line;
|
|
500
|
+
const heading = line.match(/^( {0,3}#{2,6}[ \t]+)(.+?)(?:[ \t]+#+)?[ \t]*$/);
|
|
501
|
+
if (!heading) return line;
|
|
502
|
+
const explicit = heading[2].match(/^(.*?)([ \t]*\{\/\*[ \t]*#\S+[ \t]*\*\/\})$/);
|
|
503
|
+
const source = typesetQuotes(explicit ? explicit[1] : heading[2]);
|
|
504
|
+
if (explicit) return `${heading[1]}${source}${explicit[2]}`;
|
|
505
|
+
const text2 = plainHeadingText(source);
|
|
506
|
+
const id = mintlifyHeadingSlug(text2);
|
|
507
|
+
return `${heading[1]}${source}${id && id !== thallyHeadingSlug(text2) ? ` ${headingIdMarker(id)}` : ""}`;
|
|
508
|
+
}).join("\n");
|
|
509
|
+
}
|
|
298
510
|
var GLOBAL_DOCUSARUS_COMPONENTS = /* @__PURE__ */ new Set([
|
|
299
511
|
"Tabs",
|
|
300
512
|
"TabItem",
|
|
@@ -428,6 +640,9 @@ function bracketDelta(line) {
|
|
|
428
640
|
return delta;
|
|
429
641
|
}
|
|
430
642
|
var ESM_OPEN = /^(?:import|export)\b/;
|
|
643
|
+
function latexElement(source, block = false) {
|
|
644
|
+
return `<Latex${block ? " block" : ""}>{${JSON.stringify(source)}}</Latex>`;
|
|
645
|
+
}
|
|
431
646
|
function protectMathBlocks(raw) {
|
|
432
647
|
const { front, body } = splitFrontmatterBlock(raw);
|
|
433
648
|
const lines = body.split(/\r\n|\r|\n/);
|
|
@@ -442,7 +657,7 @@ function protectMathBlocks(raw) {
|
|
|
442
657
|
const trimmed = line.trim();
|
|
443
658
|
if (mathBlockDelimiter) {
|
|
444
659
|
if (trimmed === mathBlockDelimiter) {
|
|
445
|
-
output.push("
|
|
660
|
+
output.push(latexElement(mathLines.join("\n"), true));
|
|
446
661
|
mathBlockDelimiter = null;
|
|
447
662
|
mathLines = [];
|
|
448
663
|
converted = true;
|
|
@@ -484,11 +699,11 @@ function protectMathBlocks(raw) {
|
|
|
484
699
|
(whole, block, inline) => {
|
|
485
700
|
if (block !== void 0) {
|
|
486
701
|
converted = true;
|
|
487
|
-
return
|
|
702
|
+
return latexElement(unmask(block));
|
|
488
703
|
}
|
|
489
704
|
if (inline !== void 0 && hasTexSignal(unmask(inline))) {
|
|
490
705
|
converted = true;
|
|
491
|
-
return
|
|
706
|
+
return latexElement(unmask(inline));
|
|
492
707
|
}
|
|
493
708
|
return whole;
|
|
494
709
|
}
|
|
@@ -1222,17 +1437,55 @@ function injectReactHookImports(body) {
|
|
|
1222
1437
|
|
|
1223
1438
|
${body}` : body;
|
|
1224
1439
|
}
|
|
1440
|
+
function normalizeFlowParagraphContainers(body) {
|
|
1441
|
+
if (!body.includes("<p")) return body;
|
|
1442
|
+
let tree;
|
|
1443
|
+
try {
|
|
1444
|
+
tree = descriptionParser.parse(body);
|
|
1445
|
+
} catch {
|
|
1446
|
+
return body;
|
|
1447
|
+
}
|
|
1448
|
+
const edits = [];
|
|
1449
|
+
function visit(node) {
|
|
1450
|
+
if (node.type === "mdxJsxFlowElement" && node.name === "p" && node.children?.some((child) => child.type === "paragraph" || child.type === "list" || child.type === "mdxJsxFlowElement")) {
|
|
1451
|
+
const start = node.position?.start.offset;
|
|
1452
|
+
const end = node.position?.end.offset;
|
|
1453
|
+
if (start !== void 0 && end !== void 0 && body.slice(start, start + 2) === "<p") {
|
|
1454
|
+
const closing = body.slice(start, end).match(/<\/p\s*>\s*$/i);
|
|
1455
|
+
if (closing?.index !== void 0) {
|
|
1456
|
+
edits.push({ offset: start + 1, value: "div" });
|
|
1457
|
+
edits.push({ offset: start + closing.index + 2, value: "div" });
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
for (const child of node.children ?? []) visit(child);
|
|
1462
|
+
}
|
|
1463
|
+
visit(tree);
|
|
1464
|
+
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);
|
|
1465
|
+
}
|
|
1225
1466
|
function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
1226
1467
|
const runFern = platform === "fern";
|
|
1227
1468
|
const runMintlify = platform === "mintlify";
|
|
1228
1469
|
const runDocusaurus = platform === "docusaurus";
|
|
1229
1470
|
const sourceBody = runDocusaurus && unwrapMdxCodeBlocks ? unwrapDocusaurusMdxCodeBlocks(body) : body;
|
|
1230
|
-
let rewritten = normalizeDocusaurusAdmonitions(normalizeExplicitHeadingIds(
|
|
1471
|
+
let rewritten = normalizeDocusaurusAdmonitions(normalizeExplicitHeadingIds(
|
|
1472
|
+
runFern ? normalizeFernFileTrees(normalizeFernCallouts(normalizeNestedCodeFences(sourceBody))) : normalizeNestedCodeFences(sourceBody),
|
|
1473
|
+
void 0,
|
|
1474
|
+
{ headingMarkers: runMintlify }
|
|
1475
|
+
));
|
|
1476
|
+
if (runMintlify) rewritten = markMintlifyHeadings(rewritten);
|
|
1231
1477
|
if (runDocusaurus) {
|
|
1232
1478
|
rewritten = replaceOutsideCode(rewritten, (segment) => segment.replace(
|
|
1233
1479
|
/:([+\w-]+):/g,
|
|
1234
1480
|
(shortcode, name) => nameToEmoji[name] ?? shortcode
|
|
1235
1481
|
));
|
|
1482
|
+
rewritten = replaceOutsideCode(rewritten, (segment) => segment.replace(
|
|
1483
|
+
/\b(href|src)=\{\s*require\(\s*(['"])@docusaurus\/useBaseUrl\2\s*\)\.default\(\s*(['"])([^'"]+)\3\s*\)\s*\}/g,
|
|
1484
|
+
(original, attribute, _moduleQuote, _pathQuote, path) => {
|
|
1485
|
+
if (!/^[\w./~%-]+$/.test(path) || path.split("/").includes("..")) return original;
|
|
1486
|
+
return `${attribute}="/${path.replace(/^\.\//, "").replace(/^\/+/, "")}"`;
|
|
1487
|
+
}
|
|
1488
|
+
));
|
|
1236
1489
|
rewritten = normalizeDocusaurusTabBlocks(normalizeDocusaurusTabs(removeGlobalDocusaurusImports(rewritten)));
|
|
1237
1490
|
rewritten = replaceOutsideCode(rewritten, (segment) => segment.replace(
|
|
1238
1491
|
/\bimport\s+([A-Za-z_$][\w$]*)\s+from\s+(['"])(@site\/[^'"]+)\2\s*;?/g,
|
|
@@ -1269,7 +1522,7 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
|
1269
1522
|
return normalizeMdx(body, platform, false);
|
|
1270
1523
|
}
|
|
1271
1524
|
}
|
|
1272
|
-
return normalized;
|
|
1525
|
+
return normalizeFlowParagraphContainers(normalized);
|
|
1273
1526
|
}
|
|
1274
1527
|
function parseMarkdownPage(input) {
|
|
1275
1528
|
const parsed = parseFrontmatter(input.raw);
|
|
@@ -1287,16 +1540,25 @@ function parseMarkdownPage(input) {
|
|
|
1287
1540
|
body = `${body.slice(0, heading.start)}${body.slice(heading.end)}`.trim();
|
|
1288
1541
|
}
|
|
1289
1542
|
const navTitle = typeof parsed.data.sidebarTitle === "string" && parsed.data.sidebarTitle.trim() ? parsed.data.sidebarTitle.trim() : typeof parsed.data.navTitle === "string" && parsed.data.navTitle.trim() ? parsed.data.navTitle.trim() : void 0;
|
|
1543
|
+
const icon = typeof parsed.data.icon === "string" && parsed.data.icon.trim() ? parsed.data.icon.trim() : void 0;
|
|
1544
|
+
const iconType = icon && ["regular", "solid", "outline", "brands"].includes(String(parsed.data.iconType)) ? parsed.data.iconType : void 0;
|
|
1545
|
+
const meta = {};
|
|
1546
|
+
for (const [source, field] of PAGE_META_FIELDS) {
|
|
1547
|
+
const value = parsed.data[source];
|
|
1548
|
+
if (typeof value === "string" && value.trim()) meta[field] = value.trim();
|
|
1549
|
+
}
|
|
1290
1550
|
const badge = typeof parsed.data.tag === "string" && parsed.data.tag.trim() ? parsed.data.tag.trim() : typeof parsed.data.badge === "string" && parsed.data.badge.trim() ? parsed.data.badge.trim() : void 0;
|
|
1291
1551
|
const sourceMode = typeof parsed.data.mode === "string" ? parsed.data.mode : void 0;
|
|
1292
1552
|
const mode = sourceMode === "frame" ? "wide" : ["default", "wide", "custom", "center", "home"].includes(sourceMode ?? "") ? sourceMode : void 0;
|
|
1293
|
-
const description = typeof parsed.data.description === "string" && parsed.data.description.trim() ? parsed.data.description.trim() : firstParagraph(body);
|
|
1553
|
+
const description = typeof parsed.data.description === "string" && parsed.data.description.trim() ? parsed.data.description.trim() : typeof parsed.data.openapi === "string" && parsed.data.openapi.trim() ? "" : firstParagraph(body);
|
|
1294
1554
|
return {
|
|
1295
1555
|
id: identity.id,
|
|
1296
1556
|
navigationId: identity.navigationId,
|
|
1297
1557
|
locale: identity.locale,
|
|
1298
1558
|
title,
|
|
1299
1559
|
navTitle,
|
|
1560
|
+
icon,
|
|
1561
|
+
iconType,
|
|
1300
1562
|
description,
|
|
1301
1563
|
...input.platform === "docusaurus" || input.platform === "fern" ? { descriptionPlacement: "body" } : {},
|
|
1302
1564
|
badge,
|
|
@@ -1304,6 +1566,7 @@ function parseMarkdownPage(input) {
|
|
|
1304
1566
|
mode,
|
|
1305
1567
|
hidden: parsed.data.hidden === true ? true : void 0,
|
|
1306
1568
|
noindex: parsed.data.noindex === true || parsed.data.noindex === "true" ? true : void 0,
|
|
1569
|
+
...Object.keys(meta).length > 0 ? { meta } : {},
|
|
1307
1570
|
openapi: typeof parsed.data.openapi === "string" ? parsed.data.openapi.trim() : void 0,
|
|
1308
1571
|
...apiFrontmatter(parsed.data, input.warn),
|
|
1309
1572
|
body,
|
|
@@ -1311,9 +1574,21 @@ function parseMarkdownPage(input) {
|
|
|
1311
1574
|
...parsed.error ? { frontmatterError: parsed.error } : {}
|
|
1312
1575
|
};
|
|
1313
1576
|
}
|
|
1577
|
+
var PAGE_META_FIELDS = [
|
|
1578
|
+
["og:title", "ogTitle"],
|
|
1579
|
+
["og:description", "ogDescription"],
|
|
1580
|
+
["og:image", "ogImage"],
|
|
1581
|
+
["twitter:title", "twitterTitle"],
|
|
1582
|
+
["twitter:description", "twitterDescription"],
|
|
1583
|
+
["twitter:image", "twitterImage"]
|
|
1584
|
+
];
|
|
1314
1585
|
var AUTH_METHODS = /* @__PURE__ */ new Set(["bearer", "basic", "key", "none"]);
|
|
1315
1586
|
function apiFrontmatter(data, warn) {
|
|
1316
1587
|
const result = {};
|
|
1588
|
+
if (data.playground !== void 0 && data.playground !== null) {
|
|
1589
|
+
const display = playgroundDisplay(data.playground, `The page's "playground" frontmatter`, warn);
|
|
1590
|
+
if (display) result.playground = display;
|
|
1591
|
+
}
|
|
1317
1592
|
if (data.api !== void 0 && data.api !== null) {
|
|
1318
1593
|
if (typeof data.api === "string" && data.api.trim()) result.api = data.api.trim();
|
|
1319
1594
|
else warn?.(`The page's "api" frontmatter is not a "METHOD url-or-path" string and was dropped.`);
|
|
@@ -1326,84 +1601,6 @@ function apiFrontmatter(data, warn) {
|
|
|
1326
1601
|
return result;
|
|
1327
1602
|
}
|
|
1328
1603
|
|
|
1329
|
-
// src/path.ts
|
|
1330
|
-
import { isAbsolute, relative, resolve, sep } from "path";
|
|
1331
|
-
var SAFE_SEGMENT = /[^a-z0-9._-]+/gi;
|
|
1332
|
-
function trimTrailingSlashes(value) {
|
|
1333
|
-
let end = value.length;
|
|
1334
|
-
while (end > 0 && value.charCodeAt(end - 1) === 47) end--;
|
|
1335
|
-
return value.slice(0, end);
|
|
1336
|
-
}
|
|
1337
|
-
function trimEdgeSlashes(value) {
|
|
1338
|
-
let start = 0;
|
|
1339
|
-
let end = value.length;
|
|
1340
|
-
while (start < end && value.charCodeAt(start) === 47) start++;
|
|
1341
|
-
while (end > start && value.charCodeAt(end - 1) === 47) end--;
|
|
1342
|
-
return value.slice(start, end);
|
|
1343
|
-
}
|
|
1344
|
-
function slugifySegment(value, preserveCase = false) {
|
|
1345
|
-
let decoded = value;
|
|
1346
|
-
try {
|
|
1347
|
-
decoded = decodeURIComponent(value);
|
|
1348
|
-
} catch {
|
|
1349
|
-
}
|
|
1350
|
-
const normalized = preserveCase ? decoded : decoded.toLowerCase();
|
|
1351
|
-
return normalized.replace(/\.(?:html?|mdx?)$/i, "").replace(SAFE_SEGMENT, "-").replace(/(^-|-$)/g, "");
|
|
1352
|
-
}
|
|
1353
|
-
function pageIdFromReference(value, preserveCase = false) {
|
|
1354
|
-
const withoutQuery = value.split(/[?#]/, 1)[0].replace(/\\/g, "/").replace(/^\/+/, "");
|
|
1355
|
-
if (!withoutQuery || withoutQuery.includes("\0")) return null;
|
|
1356
|
-
const rawSegments = withoutQuery.split("/").filter(Boolean);
|
|
1357
|
-
if (rawSegments.some((segment) => segment === ".." || segment === ".")) return null;
|
|
1358
|
-
const last = rawSegments.at(-1)?.replace(/\.(?:mdx?|rst|txt)$/i, "") ?? "";
|
|
1359
|
-
const isRootLevelReadme = rawSegments.length === 1 && /^readme$/i.test(last);
|
|
1360
|
-
const collapsesToParent = /^index$/i.test(last) || isRootLevelReadme;
|
|
1361
|
-
const baseSegments = collapsesToParent ? rawSegments.slice(0, -1) : rawSegments;
|
|
1362
|
-
if (!collapsesToParent) {
|
|
1363
|
-
baseSegments[baseSegments.length - 1] = last;
|
|
1364
|
-
}
|
|
1365
|
-
const segments = baseSegments.map((segment) => slugifySegment(segment, preserveCase)).filter(Boolean);
|
|
1366
|
-
return segments.join("/") || "introduction";
|
|
1367
|
-
}
|
|
1368
|
-
function mintlifyLocalizedReference(value, locale, defaultPageIds = /* @__PURE__ */ new Set()) {
|
|
1369
|
-
const reference = value.replace(/^\/+/, "");
|
|
1370
|
-
const localePrefix = `${locale.toLowerCase()}/`;
|
|
1371
|
-
if (reference.toLowerCase().startsWith(localePrefix)) return reference.slice(localePrefix.length);
|
|
1372
|
-
const sectionPrefix = `${locale.toLowerCase()}-`;
|
|
1373
|
-
if (reference.toLowerCase().startsWith(sectionPrefix)) {
|
|
1374
|
-
const candidate = reference.slice(sectionPrefix.length);
|
|
1375
|
-
const candidateId = pageIdFromReference(candidate, true);
|
|
1376
|
-
if (candidateId && defaultPageIds.has(candidateId)) return candidate;
|
|
1377
|
-
}
|
|
1378
|
-
const segments = reference.split("/");
|
|
1379
|
-
const localeIndex = segments.findIndex((segment) => segment.toLowerCase() === locale.toLowerCase());
|
|
1380
|
-
if (localeIndex > 0) {
|
|
1381
|
-
return [...segments.slice(0, localeIndex), ...segments.slice(localeIndex + 1)].join("/");
|
|
1382
|
-
}
|
|
1383
|
-
return value;
|
|
1384
|
-
}
|
|
1385
|
-
function resolveWithin(root, candidate) {
|
|
1386
|
-
return resolveWithinRoot(root, candidate, root);
|
|
1387
|
-
}
|
|
1388
|
-
function resolveWithinRoot(baseDir, candidate, confineRoot) {
|
|
1389
|
-
if (isAbsolute(candidate) || candidate.includes("\0")) {
|
|
1390
|
-
throw new Error(`Unsafe migration path: ${candidate}`);
|
|
1391
|
-
}
|
|
1392
|
-
const target = resolve(baseDir, candidate);
|
|
1393
|
-
const fromRoot = relative(resolve(confineRoot), target);
|
|
1394
|
-
if (fromRoot === ".." || fromRoot.startsWith(`..${sep}`) || isAbsolute(fromRoot)) {
|
|
1395
|
-
throw new Error(`Migration path escapes its root: ${candidate}`);
|
|
1396
|
-
}
|
|
1397
|
-
return target;
|
|
1398
|
-
}
|
|
1399
|
-
function normalizeAssetPath(value) {
|
|
1400
|
-
const normalized = value.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
1401
|
-
if (!normalized || normalized.includes("\0")) return null;
|
|
1402
|
-
const segments = normalized.split("/").filter(Boolean);
|
|
1403
|
-
if (segments.some((segment) => segment === "." || segment === "..")) return null;
|
|
1404
|
-
return segments.join("/");
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
1604
|
// src/inline-extraction.ts
|
|
1408
1605
|
import ts from "typescript";
|
|
1409
1606
|
var SERVER_ONLY_IDENTIFIERS = /* @__PURE__ */ new Set(["process", "require", "module", "exports", "__dirname", "__filename", "Buffer"]);
|
|
@@ -2205,26 +2402,33 @@ function hash(value) {
|
|
|
2205
2402
|
function portableSpecifier(path) {
|
|
2206
2403
|
return path.replace(/\.tsx?$/, "");
|
|
2207
2404
|
}
|
|
2208
|
-
function
|
|
2405
|
+
function sanitizeCssModuleSelectors(css) {
|
|
2209
2406
|
const root = postcss.parse(css);
|
|
2407
|
+
let omitted = 0;
|
|
2210
2408
|
root.walkRules((rule) => {
|
|
2211
|
-
rule.
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
if (
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2409
|
+
if (rule.parent?.type === "atrule" && /keyframes$/i.test(rule.parent.name)) return;
|
|
2410
|
+
if (/^:export$|^:import\(/.test(rule.selector.trim())) return;
|
|
2411
|
+
const selectors = selectorParser().astSync(rule.selector);
|
|
2412
|
+
selectors.each((selector) => {
|
|
2413
|
+
let hasLocalClassOrId = false;
|
|
2414
|
+
selector.walk((node) => {
|
|
2415
|
+
if (node.type !== "class" && node.type !== "id") return;
|
|
2416
|
+
let parent = node.parent;
|
|
2417
|
+
while (parent) {
|
|
2418
|
+
if (parent.type === "pseudo" && parent.value === ":global") return;
|
|
2419
|
+
parent = parent.parent;
|
|
2420
|
+
}
|
|
2421
|
+
hasLocalClassOrId = true;
|
|
2224
2422
|
});
|
|
2225
|
-
|
|
2423
|
+
if (!hasLocalClassOrId) {
|
|
2424
|
+
selector.remove();
|
|
2425
|
+
omitted++;
|
|
2426
|
+
}
|
|
2427
|
+
});
|
|
2428
|
+
if (selectors.nodes.length === 0) rule.remove();
|
|
2429
|
+
else rule.selector = selectors.toString();
|
|
2226
2430
|
});
|
|
2227
|
-
return root.toString();
|
|
2431
|
+
return { css: root.toString(), omitted };
|
|
2228
2432
|
}
|
|
2229
2433
|
function sourceFile(source, filename) {
|
|
2230
2434
|
return ts2.createSourceFile(
|
|
@@ -2424,10 +2628,10 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2424
2628
|
}
|
|
2425
2629
|
function expandCandidates(candidate) {
|
|
2426
2630
|
const candidates = [candidate];
|
|
2427
|
-
if (!
|
|
2631
|
+
if (!extname2(candidate)) {
|
|
2428
2632
|
candidates.push(...[".tsx", ".jsx", ".ts", ".js", ".mjs", ".json"].map((extension) => candidate + extension));
|
|
2429
2633
|
candidates.push(...["index.tsx", "index.jsx", "index.ts", "index.js"].map((name) => resolve2(candidate, name)));
|
|
2430
|
-
} else if (
|
|
2634
|
+
} else if (extname2(candidate) === ".js") {
|
|
2431
2635
|
candidates.push(candidate.slice(0, -3) + ".ts", candidate.slice(0, -3) + ".tsx");
|
|
2432
2636
|
}
|
|
2433
2637
|
return candidates;
|
|
@@ -2455,6 +2659,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2455
2659
|
}
|
|
2456
2660
|
function copyGraph(entry) {
|
|
2457
2661
|
const staged = /* @__PURE__ */ new Map();
|
|
2662
|
+
const stagedWarnings = [];
|
|
2458
2663
|
let stagedBytes = 0;
|
|
2459
2664
|
function stageShim(filename, content) {
|
|
2460
2665
|
const shimDestination = `${destinationRoot}/shims/${filename}`;
|
|
@@ -2467,7 +2672,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2467
2672
|
checkedFile(path);
|
|
2468
2673
|
const size = lstatSync(path).size;
|
|
2469
2674
|
if (size > MAX_FILE_BYTES || copiedBytes + stagedBytes + size > MAX_COMPONENT_BYTES || copied.size + staged.size >= MAX_COMPONENT_FILES) throw new Error("component migration budget exceeded");
|
|
2470
|
-
const extension =
|
|
2675
|
+
const extension = extname2(path).toLowerCase();
|
|
2471
2676
|
if (!CODE_EXTENSIONS.has(extension) && !DATA_EXTENSIONS.has(extension)) throw new Error(`unsupported dependency file type ${extension}`);
|
|
2472
2677
|
stagedBytes += size;
|
|
2473
2678
|
const content = readFileSync(path);
|
|
@@ -2475,13 +2680,14 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2475
2680
|
if (!CODE_EXTENSIONS.has(extension)) {
|
|
2476
2681
|
if (extension === ".css" && /@import\b|url\s*\(/i.test(content.toString("utf8"))) throw new Error("CSS resource dependencies require manual migration");
|
|
2477
2682
|
if (extension === ".css" && path.toLowerCase().endsWith(".module.css")) {
|
|
2478
|
-
let
|
|
2683
|
+
let sanitized;
|
|
2479
2684
|
try {
|
|
2480
|
-
|
|
2685
|
+
sanitized = sanitizeCssModuleSelectors(content.toString("utf8"));
|
|
2481
2686
|
} catch {
|
|
2482
2687
|
throw new Error("CSS module could not be parsed to check for Turbopack-safe selectors");
|
|
2483
2688
|
}
|
|
2484
|
-
|
|
2689
|
+
if (sanitized.omitted > 0) stagedWarnings.push({ path, omitted: sanitized.omitted });
|
|
2690
|
+
staged.set(destination, { path: destination, content: sanitized.css });
|
|
2485
2691
|
}
|
|
2486
2692
|
return;
|
|
2487
2693
|
}
|
|
@@ -2550,6 +2756,9 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2550
2756
|
}
|
|
2551
2757
|
visit(entry);
|
|
2552
2758
|
for (const [path, file] of staged) copied.set(path, file);
|
|
2759
|
+
for (const { path, omitted } of stagedWarnings) {
|
|
2760
|
+
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);
|
|
2761
|
+
}
|
|
2553
2762
|
copiedBytes += stagedBytes;
|
|
2554
2763
|
return outputPath(entry);
|
|
2555
2764
|
}
|
|
@@ -2559,7 +2768,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2559
2768
|
if (size > MAX_FILE_BYTES || copiedBytes + size > MAX_COMPONENT_BYTES || copied.size >= MAX_COMPONENT_FILES) {
|
|
2560
2769
|
throw new Error("component migration budget exceeded");
|
|
2561
2770
|
}
|
|
2562
|
-
const publicName = `migrated-${hash(relative2(confined, path))}${
|
|
2771
|
+
const publicName = `migrated-${hash(relative2(confined, path))}${extname2(path).toLowerCase()}`;
|
|
2563
2772
|
const destination = `public/${publicName}`;
|
|
2564
2773
|
if (!copied.has(destination)) {
|
|
2565
2774
|
copied.set(destination, { path: destination, content: readFileSync(path) });
|
|
@@ -2594,7 +2803,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2594
2803
|
function transform(raw, currentFile) {
|
|
2595
2804
|
const parsedFrontmatter = parseFrontmatter(raw).content;
|
|
2596
2805
|
const frontmatter = raw.slice(0, raw.length - parsedFrontmatter.length);
|
|
2597
|
-
const content = normalizeExplicitHeadingIds(normalizeIndentedFences(normalizeHtmlComments(parsedFrontmatter)));
|
|
2806
|
+
const content = normalizeExplicitHeadingIds(normalizeIndentedFences(normalizeHtmlComments(parsedFrontmatter)), void 0, { keepIdComments: true });
|
|
2598
2807
|
let tree;
|
|
2599
2808
|
try {
|
|
2600
2809
|
tree = parser.parse(content);
|
|
@@ -2712,7 +2921,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2712
2921
|
}
|
|
2713
2922
|
continue;
|
|
2714
2923
|
}
|
|
2715
|
-
if (bindings.length && RESCUABLE_ASSET_EXTENSIONS.has(
|
|
2924
|
+
if (bindings.length && RESCUABLE_ASSET_EXTENSIONS.has(extname2(specifier).toLowerCase()) && !bindings.some((binding) => usedAsJsxTagName(binding.local))) {
|
|
2716
2925
|
try {
|
|
2717
2926
|
const href = copyPublicAsset(resolveDependency(specifier, currentFile));
|
|
2718
2927
|
edits.push({
|
|
@@ -2743,7 +2952,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2743
2952
|
try {
|
|
2744
2953
|
const sourcePath = resolveDependency(specifier, currentFile);
|
|
2745
2954
|
const path = copyGraph(sourcePath);
|
|
2746
|
-
const isSvgUsedAsTag =
|
|
2955
|
+
const isSvgUsedAsTag = extname2(path).toLowerCase() === ".svg" && bindings.some((binding) => usedAsJsxTagName(binding.local));
|
|
2747
2956
|
for (const binding of bindings) {
|
|
2748
2957
|
const registerPath = isSvgUsedAsTag ? wrapSvgAsComponent(path) : path;
|
|
2749
2958
|
const registerImported = isSvgUsedAsTag ? "default" : binding.imported;
|
|
@@ -2782,7 +2991,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2782
2991
|
const importStart = node.position.start.offset + statement.getStart(ast);
|
|
2783
2992
|
const importEnd = node.position.start.offset + statement.end;
|
|
2784
2993
|
let rescuedAssetHref;
|
|
2785
|
-
if (RESCUABLE_ASSET_EXTENSIONS.has(
|
|
2994
|
+
if (RESCUABLE_ASSET_EXTENSIONS.has(extname2(specifier).toLowerCase())) {
|
|
2786
2995
|
const usedAsJsxTag = bindings.some((binding) => hasExpressionReference(/* @__PURE__ */ new Set([binding.local]), { includeDirectTags: true }));
|
|
2787
2996
|
if (!usedAsJsxTag) {
|
|
2788
2997
|
try {
|
|
@@ -2803,7 +3012,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2803
3012
|
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);
|
|
2804
3013
|
} else {
|
|
2805
3014
|
edits.push({ start: importStart, end: importEnd, value: "" });
|
|
2806
|
-
warn(`
|
|
3015
|
+
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);
|
|
2807
3016
|
}
|
|
2808
3017
|
}
|
|
2809
3018
|
}
|
|
@@ -3133,6 +3342,125 @@ import { customComponents as ${name} } from ${JSON.stringify(registryPath)}
|
|
|
3133
3342
|
];
|
|
3134
3343
|
}
|
|
3135
3344
|
|
|
3345
|
+
// src/source-styles.ts
|
|
3346
|
+
import postcss2 from "postcss";
|
|
3347
|
+
import selectorParser2 from "postcss-selector-parser";
|
|
3348
|
+
import ts3 from "typescript";
|
|
3349
|
+
var PLATFORM_CLASSES = /* @__PURE__ */ new Set(["navbar-link"]);
|
|
3350
|
+
var PLATFORM_IDS = /* @__PURE__ */ new Set(["footer", "navbar", "sidebar"]);
|
|
3351
|
+
var PLATFORM_CLASS_PREFIX = /^(?:mintlify[-_]|fern[-_]|docusaurus[-_]|theme-doc-|theme-code-block|DocSearch|pagination-nav|menu__)/i;
|
|
3352
|
+
var SHARED_THEME_CLASSES = /* @__PURE__ */ new Set(["dark", "light"]);
|
|
3353
|
+
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)-/;
|
|
3354
|
+
function withoutFencedCode(content) {
|
|
3355
|
+
let fence;
|
|
3356
|
+
return content.split("\n").map((line) => {
|
|
3357
|
+
const marker = line.match(/^ {0,3}(`{3,}|~{3,})/)?.[1];
|
|
3358
|
+
if (fence) {
|
|
3359
|
+
if (marker?.[0] === fence.marker && marker.length >= fence.length) fence = void 0;
|
|
3360
|
+
return "";
|
|
3361
|
+
}
|
|
3362
|
+
if (marker) {
|
|
3363
|
+
fence = { marker: marker[0], length: marker.length };
|
|
3364
|
+
return "";
|
|
3365
|
+
}
|
|
3366
|
+
return line;
|
|
3367
|
+
}).join("\n");
|
|
3368
|
+
}
|
|
3369
|
+
function navbarLinkButtons(css) {
|
|
3370
|
+
const buttons = [];
|
|
3371
|
+
postcss2.parse(css).walkRules((rule) => {
|
|
3372
|
+
const match = /^(?:li)?\.navbar-link\s+a\[href(\*)?=["']([^"']+)["']\]$/.exec(rule.selector.trim());
|
|
3373
|
+
if (!match) return;
|
|
3374
|
+
let background;
|
|
3375
|
+
let color;
|
|
3376
|
+
rule.walkDecls((decl) => {
|
|
3377
|
+
if (decl.prop === "background-color" || decl.prop === "background") background = decl.value;
|
|
3378
|
+
else if (decl.prop === "color") color = decl.value;
|
|
3379
|
+
});
|
|
3380
|
+
if (background) buttons.push({ href: match[2], exact: !match[1], background, ...color ? { color } : {} });
|
|
3381
|
+
});
|
|
3382
|
+
return buttons;
|
|
3383
|
+
}
|
|
3384
|
+
function authoredStyleNames(contents) {
|
|
3385
|
+
const classes = /* @__PURE__ */ new Set();
|
|
3386
|
+
const ids = /* @__PURE__ */ new Set();
|
|
3387
|
+
for (const original of contents) {
|
|
3388
|
+
const content = withoutFencedCode(original);
|
|
3389
|
+
for (const match of content.matchAll(/\b(?:className|class)\s*=\s*["']([^"']+)["']/g)) {
|
|
3390
|
+
for (const name of match[1].split(/\s+/)) if (name) classes.add(name);
|
|
3391
|
+
}
|
|
3392
|
+
for (const match of content.matchAll(/\bid\s*=\s*["']([^"']+)["']/g)) ids.add(match[1]);
|
|
3393
|
+
if (!content.includes("className={")) continue;
|
|
3394
|
+
const source = ts3.createSourceFile("component.tsx", content, ts3.ScriptTarget.Latest, true, ts3.ScriptKind.TSX);
|
|
3395
|
+
const visit = (node) => {
|
|
3396
|
+
if (ts3.isJsxAttribute(node) && ts3.isIdentifier(node.name) && node.name.text === "className" && node.initializer) {
|
|
3397
|
+
const collect = (value) => {
|
|
3398
|
+
if (ts3.isStringLiteral(value) || ts3.isNoSubstitutionTemplateLiteral(value)) {
|
|
3399
|
+
for (const name of value.text.split(/\s+/)) if (name) classes.add(name);
|
|
3400
|
+
} else ts3.forEachChild(value, collect);
|
|
3401
|
+
};
|
|
3402
|
+
collect(node.initializer);
|
|
3403
|
+
}
|
|
3404
|
+
ts3.forEachChild(node, visit);
|
|
3405
|
+
};
|
|
3406
|
+
visit(source);
|
|
3407
|
+
}
|
|
3408
|
+
return { classes, ids };
|
|
3409
|
+
}
|
|
3410
|
+
function projectAuthoredStyles(css, contents) {
|
|
3411
|
+
const names = authoredStyleNames(contents);
|
|
3412
|
+
const root = postcss2.parse(css);
|
|
3413
|
+
let omittedSelectors = 0;
|
|
3414
|
+
let rewrittenSelectors = 0;
|
|
3415
|
+
root.walkRules((rule) => {
|
|
3416
|
+
if (rule.parent?.type === "atrule" && /keyframes$/i.test(rule.parent.name)) return;
|
|
3417
|
+
const retained = [];
|
|
3418
|
+
try {
|
|
3419
|
+
selectorParser2((selectors) => {
|
|
3420
|
+
selectors.each((selector) => {
|
|
3421
|
+
let hasAuthoredAnchor = false;
|
|
3422
|
+
let hasPlatformAnchor = false;
|
|
3423
|
+
selector.walk((node) => {
|
|
3424
|
+
let ancestor = node.parent;
|
|
3425
|
+
let isNestedInPseudo = false;
|
|
3426
|
+
while (ancestor && ancestor !== selector) {
|
|
3427
|
+
if (ancestor.type === "pseudo") isNestedInPseudo = true;
|
|
3428
|
+
ancestor = ancestor.parent;
|
|
3429
|
+
}
|
|
3430
|
+
if (node.type === "class") {
|
|
3431
|
+
if (SHARED_THEME_CLASSES.has(node.value)) return;
|
|
3432
|
+
if (PLATFORM_CLASSES.has(node.value) || PLATFORM_CLASS_PREFIX.test(node.value) || UTILITY_CLASS.test(node.value) || !names.classes.has(node.value)) hasPlatformAnchor = true;
|
|
3433
|
+
else if (!isNestedInPseudo) hasAuthoredAnchor = true;
|
|
3434
|
+
} else if (node.type === "id") {
|
|
3435
|
+
if (PLATFORM_IDS.has(node.value) || !names.ids.has(node.value)) hasPlatformAnchor = true;
|
|
3436
|
+
else if (!isNestedInPseudo) hasAuthoredAnchor = true;
|
|
3437
|
+
} else if (node.type === "attribute" && node.attribute === "data-as") {
|
|
3438
|
+
node.remove();
|
|
3439
|
+
rewrittenSelectors += 1;
|
|
3440
|
+
}
|
|
3441
|
+
});
|
|
3442
|
+
if (hasAuthoredAnchor && !hasPlatformAnchor) retained.push(selector.toString());
|
|
3443
|
+
else omittedSelectors += 1;
|
|
3444
|
+
});
|
|
3445
|
+
}).processSync(rule.selector);
|
|
3446
|
+
} catch {
|
|
3447
|
+
omittedSelectors += 1;
|
|
3448
|
+
}
|
|
3449
|
+
if (retained.length) rule.selector = retained.join(", ");
|
|
3450
|
+
else rule.remove();
|
|
3451
|
+
});
|
|
3452
|
+
const hasStyleRule = (nodes) => Boolean(nodes?.some((node) => node.type === "rule" || node.type === "atrule" && hasStyleRule(node.nodes)));
|
|
3453
|
+
root.walkAtRules((rule) => {
|
|
3454
|
+
if (rule.name === "font-face" || rule.name === "property") return;
|
|
3455
|
+
if (!hasStyleRule(rule.nodes)) rule.remove();
|
|
3456
|
+
});
|
|
3457
|
+
if (omittedSelectors === 0 && rewrittenSelectors === 0) return { css, omittedSelectors };
|
|
3458
|
+
root.walkComments((comment) => {
|
|
3459
|
+
comment.remove();
|
|
3460
|
+
});
|
|
3461
|
+
return { css: root.toString(), omittedSelectors };
|
|
3462
|
+
}
|
|
3463
|
+
|
|
3136
3464
|
// src/docusaurus.ts
|
|
3137
3465
|
import { existsSync as existsSync3, lstatSync as lstatSync3, readFileSync as readFileSync3 } from "fs";
|
|
3138
3466
|
import { extname as extname4, posix as posix2 } from "path";
|
|
@@ -3142,89 +3470,6 @@ import { parse as parseYaml2 } from "yaml";
|
|
|
3142
3470
|
// src/navigation.ts
|
|
3143
3471
|
import { existsSync as existsSync2, lstatSync as lstatSync2, readFileSync as readFileSync2, realpathSync } from "fs";
|
|
3144
3472
|
import { dirname as dirname2, extname as extname3, relative as relative3 } from "path";
|
|
3145
|
-
|
|
3146
|
-
// src/mintlify-extras.ts
|
|
3147
|
-
import { extname as extname2 } from "path";
|
|
3148
|
-
function objectValue(value) {
|
|
3149
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
3150
|
-
}
|
|
3151
|
-
var PUBLIC_FALSE_STRINGS = /* @__PURE__ */ new Set(["false", "no", "off", "0"]);
|
|
3152
|
-
function isPublicFalse(value) {
|
|
3153
|
-
return value === false || value === 0 || typeof value === "string" && PUBLIC_FALSE_STRINGS.has(value.trim().toLowerCase());
|
|
3154
|
-
}
|
|
3155
|
-
function isPublicTrue(value) {
|
|
3156
|
-
return value === true || typeof value === "string" && value.trim().toLowerCase() === "true";
|
|
3157
|
-
}
|
|
3158
|
-
function frontmatterGateReason(data) {
|
|
3159
|
-
const groups = data.groups;
|
|
3160
|
-
const hasGroups = Array.isArray(groups) ? groups.length > 0 : typeof groups === "string" ? groups.trim() !== "" : groups !== void 0 && groups !== null && groups !== false;
|
|
3161
|
-
if (hasGroups) return "frontmatter `groups` restricts it to authenticated groups";
|
|
3162
|
-
if (isPublicFalse(data.public)) return "frontmatter `public: false`";
|
|
3163
|
-
return void 0;
|
|
3164
|
-
}
|
|
3165
|
-
function navigationGateReason(node) {
|
|
3166
|
-
const groups = node.groups;
|
|
3167
|
-
const isContainer = (entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) && ["group", "pages", "tab", "groups", "page", "root", "menu", "href"].some((key) => key in entry);
|
|
3168
|
-
const restricted = typeof groups === "string" ? groups.trim() !== "" : Array.isArray(groups) && groups.length > 0 && !groups.every(isContainer);
|
|
3169
|
-
if (restricted) return "its navigation container sets `groups`";
|
|
3170
|
-
if (isPublicFalse(node.public)) return "its navigation container sets `public: false`";
|
|
3171
|
-
return void 0;
|
|
3172
|
-
}
|
|
3173
|
-
var CONFIG_BASENAME = /(?:^|[.-])(?:config|rc)\.[cm]?js$|^(?:tailwind|postcss|next|eslint|prettier|babel|webpack|vite|vitest|jest|rollup|gulpfile|gruntfile|stylelint|commitlint|lint-staged|svgo|metro)[.-]/i;
|
|
3174
|
-
var BUILD_OUTPUT_SEGMENTS = /* @__PURE__ */ new Set(["dist", "build", "coverage"]);
|
|
3175
|
-
var FONT_EXTENSIONS = /* @__PURE__ */ new Set([".woff", ".woff2", ".ttf", ".otf"]);
|
|
3176
|
-
function isMintlifyServedScriptOrStyle(relativePath) {
|
|
3177
|
-
const extension = extname2(relativePath).toLowerCase();
|
|
3178
|
-
if (extension !== ".css" && extension !== ".js") return false;
|
|
3179
|
-
const segments = relativePath.split("/");
|
|
3180
|
-
if (segments.slice(0, -1).some((segment) => BUILD_OUTPUT_SEGMENTS.has(segment.toLowerCase()))) return false;
|
|
3181
|
-
return extension === ".css" || !CONFIG_BASENAME.test(segments[segments.length - 1]);
|
|
3182
|
-
}
|
|
3183
|
-
function mintlifyFontSources(config) {
|
|
3184
|
-
const fonts = objectValue(config?.fonts);
|
|
3185
|
-
if (!fonts) return [];
|
|
3186
|
-
const found = [];
|
|
3187
|
-
for (const entry of [fonts, objectValue(fonts.heading), objectValue(fonts.body)]) {
|
|
3188
|
-
if (!entry || typeof entry.source !== "string" || !entry.source.trim()) continue;
|
|
3189
|
-
const source = entry.source.trim();
|
|
3190
|
-
const family = typeof entry.family === "string" ? entry.family : "a font";
|
|
3191
|
-
const remote = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(source);
|
|
3192
|
-
const path = remote || /^[a-z]:[\\/]/i.test(source) ? null : normalizeAssetPath(source);
|
|
3193
|
-
found.push({ family, source, path: path && FONT_EXTENSIONS.has(extname2(path).toLowerCase()) ? path : null, remote });
|
|
3194
|
-
}
|
|
3195
|
-
return found;
|
|
3196
|
-
}
|
|
3197
|
-
function mintlifyAppearance(config, warnings) {
|
|
3198
|
-
const appearance = objectValue(config.appearance);
|
|
3199
|
-
const legacy = objectValue(config.modeToggle);
|
|
3200
|
-
const result = {};
|
|
3201
|
-
const isMode = (value) => value === "system" || value === "light" || value === "dark";
|
|
3202
|
-
const skip = (field, value) => {
|
|
3203
|
-
warnings.push({
|
|
3204
|
-
code: "unsupported-config",
|
|
3205
|
-
message: `Ignored invalid ${field} value ${JSON.stringify(value)?.slice(0, 40)}; the appearance default was left unchanged.`
|
|
3206
|
-
});
|
|
3207
|
-
};
|
|
3208
|
-
if (appearance?.default !== void 0) {
|
|
3209
|
-
if (isMode(appearance.default)) result.default = appearance.default;
|
|
3210
|
-
else skip("appearance.default", appearance.default);
|
|
3211
|
-
} else if (legacy?.default !== void 0) {
|
|
3212
|
-
if (isMode(legacy.default)) result.default = legacy.default;
|
|
3213
|
-
else skip("modeToggle.default", legacy.default);
|
|
3214
|
-
}
|
|
3215
|
-
if (appearance?.strict !== void 0) {
|
|
3216
|
-
if (typeof appearance.strict === "boolean") {
|
|
3217
|
-
if (appearance.strict) result.showToggle = false;
|
|
3218
|
-
} else skip("appearance.strict", appearance.strict);
|
|
3219
|
-
} else if (legacy?.isHidden !== void 0) {
|
|
3220
|
-
if (typeof legacy.isHidden === "boolean") {
|
|
3221
|
-
if (legacy.isHidden) result.showToggle = false;
|
|
3222
|
-
} else skip("modeToggle.isHidden", legacy.isHidden);
|
|
3223
|
-
}
|
|
3224
|
-
return result;
|
|
3225
|
-
}
|
|
3226
|
-
|
|
3227
|
-
// src/navigation.ts
|
|
3228
3473
|
var MAX_MINTLIFY_CONFIG_BYTES = 2e7;
|
|
3229
3474
|
function addMintlifyDirectoryRedirects(config, pages) {
|
|
3230
3475
|
const pageIds = new Set(pages.map((page) => page.id));
|
|
@@ -3295,34 +3540,37 @@ function addMintlifyHomepageRedirects(config, pages) {
|
|
|
3295
3540
|
}
|
|
3296
3541
|
}
|
|
3297
3542
|
const homepage = config.tabs.filter((tab) => !tab.hidden).map((tab) => firstPage([...tab.pages ?? [], ...tab.groups ?? []])).find(Boolean);
|
|
3298
|
-
if (!homepage
|
|
3543
|
+
if (!homepage) return config;
|
|
3299
3544
|
const redirects = [...config.redirects ?? []];
|
|
3300
3545
|
const sources = new Set(redirects.map((redirect) => redirect.source.replace(/\/$/, "") || "/"));
|
|
3301
|
-
const roots = ["", ...(config.i18n?.locales ?? []).filter((locale) => locale.code !== config.i18n?.defaultLocale).map((locale) => locale.code)];
|
|
3546
|
+
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)];
|
|
3302
3547
|
for (const locale of roots) {
|
|
3303
3548
|
const source = locale ? `/${locale}` : "/";
|
|
3304
3549
|
if (sources.has(source)) continue;
|
|
3305
|
-
redirects.push({ source, destination: `${locale ? `/${locale}` : ""}/${homepage}`, permanent:
|
|
3550
|
+
redirects.push({ source, destination: `${locale ? `/${locale}` : ""}/${homepage}`, permanent: true });
|
|
3306
3551
|
}
|
|
3307
3552
|
return { ...config, redirects };
|
|
3308
3553
|
}
|
|
3309
3554
|
var LANGUAGE_LABELS = {
|
|
3310
|
-
ar: "
|
|
3311
|
-
de: "
|
|
3555
|
+
ar: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629",
|
|
3556
|
+
de: "Deutsch",
|
|
3312
3557
|
en: "English",
|
|
3313
|
-
es: "
|
|
3314
|
-
fr: "
|
|
3315
|
-
hi: "
|
|
3316
|
-
it: "
|
|
3317
|
-
ja: "
|
|
3318
|
-
ko: "
|
|
3319
|
-
nl: "
|
|
3320
|
-
pl: "
|
|
3321
|
-
pt: "
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3558
|
+
es: "Espa\xF1ol",
|
|
3559
|
+
fr: "Fran\xE7ais",
|
|
3560
|
+
hi: "\u0939\u093F\u0928\u094D\u0926\u0940",
|
|
3561
|
+
it: "Italiano",
|
|
3562
|
+
ja: "\u65E5\u672C\u8A9E",
|
|
3563
|
+
ko: "\uD55C\uAD6D\uC5B4",
|
|
3564
|
+
nl: "Nederlands",
|
|
3565
|
+
pl: "Polski",
|
|
3566
|
+
pt: "Portugu\xEAs",
|
|
3567
|
+
"pt-BR": "Portugu\xEAs (BR)",
|
|
3568
|
+
ru: "\u0420\u0443\u0441\u0441\u043A\u0438\u0439",
|
|
3569
|
+
tr: "T\xFCrk\xE7e",
|
|
3570
|
+
uk: "\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430",
|
|
3571
|
+
zh: "\u7B80\u4F53\u4E2D\u6587",
|
|
3572
|
+
"zh-Hans": "\u7B80\u4F53\u4E2D\u6587",
|
|
3573
|
+
"zh-Hant": "\u7E41\u9AD4\u4E2D\u6587"
|
|
3326
3574
|
};
|
|
3327
3575
|
function objectValue2(value) {
|
|
3328
3576
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -3787,11 +4035,26 @@ function convertContainerToTabs(containerValue, context, fallbackTab, trace, dep
|
|
|
3787
4035
|
}] : [];
|
|
3788
4036
|
}
|
|
3789
4037
|
function projectedTheme(value) {
|
|
3790
|
-
if (value === "maple") return "maple";
|
|
3791
|
-
if (["
|
|
4038
|
+
if (value === "maple" || value === "aspen") return "maple";
|
|
4039
|
+
if (["luma", "sequoia"].includes(String(value))) return "sharp";
|
|
3792
4040
|
if (["almond", "palm"].includes(String(value))) return "minimal";
|
|
3793
4041
|
return typeof value === "string" ? "default" : void 0;
|
|
3794
4042
|
}
|
|
4043
|
+
function projectedColors(value) {
|
|
4044
|
+
const colors = objectValue2(value);
|
|
4045
|
+
if (!colors) return void 0;
|
|
4046
|
+
const hex = (entry) => {
|
|
4047
|
+
const match = typeof entry === "string" ? /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(entry.trim()) : null;
|
|
4048
|
+
if (!match) return void 0;
|
|
4049
|
+
const digits = match[1].length === 3 ? [...match[1]].map((digit) => digit + digit).join("") : match[1];
|
|
4050
|
+
return `#${digits.toLowerCase()}`;
|
|
4051
|
+
};
|
|
4052
|
+
const primary = hex(colors.primary);
|
|
4053
|
+
const light = hex(colors.light) ?? primary;
|
|
4054
|
+
const dark = hex(colors.dark) ?? primary;
|
|
4055
|
+
if (!primary) return void 0;
|
|
4056
|
+
return { light: { accent: primary, primary: dark ?? primary }, dark: { accent: light ?? primary, primary: light ?? primary } };
|
|
4057
|
+
}
|
|
3795
4058
|
function projectedNavbar(value) {
|
|
3796
4059
|
const navbar = objectValue2(value);
|
|
3797
4060
|
if (!navbar) return void 0;
|
|
@@ -3807,7 +4070,8 @@ function projectedNavbar(value) {
|
|
|
3807
4070
|
const primaryHref = projectedHref(primaryValue?.href);
|
|
3808
4071
|
const primary = primaryValue && primaryHref ? {
|
|
3809
4072
|
label: typeof primaryValue.label === "string" ? primaryValue.label : primaryValue.type === "github" ? "GitHub" : "Get started",
|
|
3810
|
-
href: primaryHref
|
|
4073
|
+
href: primaryHref,
|
|
4074
|
+
...primaryValue.type === "github" ? { type: "github" } : {}
|
|
3811
4075
|
} : void 0;
|
|
3812
4076
|
return links.length > 0 || primary ? { ...links.length > 0 ? { links } : {}, ...primary ? { primary } : {} } : void 0;
|
|
3813
4077
|
}
|
|
@@ -3887,8 +4151,16 @@ function projectedCompatibleConfig(config, warnings) {
|
|
|
3887
4151
|
const headingFont = projectedFont(objectValue2(config.fonts)?.heading);
|
|
3888
4152
|
const feedback = objectValue2(config.feedback);
|
|
3889
4153
|
const seo = objectValue2(config.seo);
|
|
4154
|
+
const contextualOptions = Array.isArray(objectValue2(config.contextual)?.options) ? objectValue2(config.contextual).options : [];
|
|
4155
|
+
const projectedContextual = contextualOptions.filter((option) => typeof option === "string" && ["copy", "view", "chatgpt", "claude", "perplexity"].includes(option));
|
|
4156
|
+
const droppedContextual = contextualOptions.filter((option) => !projectedContextual.includes(option));
|
|
4157
|
+
if (droppedContextual.length > 0) {
|
|
4158
|
+
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" });
|
|
4159
|
+
}
|
|
4160
|
+
const metatagEntries = Object.entries(objectValue2(seo?.metatags) ?? {}).filter((entry) => /^[\w:.-]+$/.test(entry[0]) && typeof entry[1] === "string" && entry[1].length <= 1e3);
|
|
4161
|
+
const projectedMetatags = metatagEntries.length > 0 ? Object.fromEntries(metatagEntries) : void 0;
|
|
3890
4162
|
const iconLibrary = objectValue2(config.icons)?.library;
|
|
3891
|
-
const projectedIconLibrary = ["lucide", "fontawesome", "tabler"].includes(String(iconLibrary)) ? String(iconLibrary) : void 0;
|
|
4163
|
+
const projectedIconLibrary = iconLibrary === void 0 ? "fontawesome" : ["lucide", "fontawesome", "tabler"].includes(String(iconLibrary)) ? String(iconLibrary) : void 0;
|
|
3892
4164
|
const docsNavbar = projectedNavbar(config.navbar);
|
|
3893
4165
|
const legacyRaw = legacyTopbarNavbar(config);
|
|
3894
4166
|
const legacyNavbar = projectedNavbar(legacyRaw);
|
|
@@ -3916,6 +4188,8 @@ function projectedCompatibleConfig(config, warnings) {
|
|
|
3916
4188
|
const projectedNavigation = navbarLinks.length > 0 || navbar?.primary ? { ...navbarLinks.length > 0 ? { links: navbarLinks } : {}, ...navbar?.primary ? { primary: navbar.primary } : {} } : void 0;
|
|
3917
4189
|
return {
|
|
3918
4190
|
...projectedTheme(config.theme) ? { theme: projectedTheme(config.theme) } : {},
|
|
4191
|
+
...projectedContextual.length > 0 ? { contextual: { options: projectedContextual } } : {},
|
|
4192
|
+
...projectedColors(config.colors) ? { colors: projectedColors(config.colors) } : {},
|
|
3919
4193
|
...projectedIconLibrary ? { icons: { library: projectedIconLibrary } } : {},
|
|
3920
4194
|
...bannerContent ? {
|
|
3921
4195
|
banner: {
|
|
@@ -3933,10 +4207,19 @@ function projectedCompatibleConfig(config, warnings) {
|
|
|
3933
4207
|
...projectedNavigation ? { navbar: projectedNavigation } : {},
|
|
3934
4208
|
...projectedFooter(config.footer) ? { footer: projectedFooter(config.footer) } : {},
|
|
3935
4209
|
...bodyFont || headingFont ? { fonts: { ...bodyFont ? { body: bodyFont } : {}, ...headingFont ? { heading: headingFont } : {} } } : {},
|
|
3936
|
-
|
|
4210
|
+
// Mintlify titles pages "<title> - <site name>" unless `og:title` overrides them,
|
|
4211
|
+
// and its sitemap lists navigation pages only.
|
|
4212
|
+
seo: { ...seo?.indexing === "all" ? { indexing: "all" } : {}, titleSeparator: " - ", sitemap: "navigable", ...projectedMetatags ? { metatags: projectedMetatags } : {} },
|
|
3937
4213
|
...typeof feedback?.thumbsRating === "boolean" ? { feedback: { thumbsRating: feedback.thumbsRating } } : {}
|
|
3938
4214
|
};
|
|
3939
4215
|
}
|
|
4216
|
+
function projectedApi(config, warnings) {
|
|
4217
|
+
const mdx = projectedApiMdx(config, warnings).api?.mdx;
|
|
4218
|
+
const raw = objectValue2(objectValue2(config.api)?.playground)?.display;
|
|
4219
|
+
const display = raw === void 0 ? void 0 : playgroundDisplay(raw, "api.playground.display", (message) => warnings.push({ code: "unsupported-config", message }));
|
|
4220
|
+
if (!mdx && !display) return {};
|
|
4221
|
+
return { api: { ...mdx ? { mdx } : {}, ...display ? { playground: { display } } : {} } };
|
|
4222
|
+
}
|
|
3940
4223
|
function projectedApiMdx(config, warnings) {
|
|
3941
4224
|
const mdx = objectValue2(objectValue2(config.api)?.mdx);
|
|
3942
4225
|
if (!mdx) return {};
|
|
@@ -4131,6 +4414,47 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
4131
4414
|
message: "Mintlify navigation could not be projected; generated navigation will be used."
|
|
4132
4415
|
});
|
|
4133
4416
|
}
|
|
4417
|
+
const versionOwner = languages.length > 0 ? languages.find((entry) => entry.default === true) ?? languages[0] : navigation;
|
|
4418
|
+
const globalNavigation = objectValue2(versionOwner.global) ?? objectValue2(navigation.global);
|
|
4419
|
+
const shortcuts = Array.isArray(globalNavigation?.anchors) ? globalNavigation.anchors.flatMap((value) => {
|
|
4420
|
+
const anchor = objectValue2(value);
|
|
4421
|
+
const label = typeof anchor?.anchor === "string" ? anchor.anchor.trim() : "";
|
|
4422
|
+
const href = projectedHref(anchor?.href);
|
|
4423
|
+
if (!label || !href) return [];
|
|
4424
|
+
return [{ label, href, ...iconName(anchor?.icon) ? { icon: iconName(anchor?.icon) } : {} }];
|
|
4425
|
+
}) : [];
|
|
4426
|
+
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)) : [];
|
|
4427
|
+
const versionNames = rawVersions.map((entry) => typeof entry.version === "string" ? entry.version.trim() : "").filter(Boolean);
|
|
4428
|
+
const annotateVersions = (items) => items.map((item) => {
|
|
4429
|
+
const version = versionNames.find((name) => item.tab.startsWith(`${name}: `));
|
|
4430
|
+
return version ? { ...item, version, displayLabel: item.tab.slice(version.length + 2) } : item;
|
|
4431
|
+
});
|
|
4432
|
+
const firstPage = (item) => {
|
|
4433
|
+
const visit = (entries) => {
|
|
4434
|
+
for (const entry of entries) {
|
|
4435
|
+
if (typeof entry === "string") return entry;
|
|
4436
|
+
const nested = visit(entry.pages);
|
|
4437
|
+
if (nested) return nested;
|
|
4438
|
+
}
|
|
4439
|
+
return void 0;
|
|
4440
|
+
};
|
|
4441
|
+
return visit([...item.pages ?? [], ...item.groups ?? []]);
|
|
4442
|
+
};
|
|
4443
|
+
const defaultVersion = rawVersions.find((entry) => entry.default === true) ?? rawVersions[0];
|
|
4444
|
+
const versions = rawVersions.length > 1 ? rawVersions.flatMap((entry) => {
|
|
4445
|
+
const label = typeof entry.version === "string" ? entry.version.trim() : "";
|
|
4446
|
+
if (!label) return [];
|
|
4447
|
+
const candidates = tabs.filter((item) => item.tab.startsWith(`${label}: `)).map(firstPage).filter((page) => Boolean(page));
|
|
4448
|
+
const landing = candidates.find((page) => page.startsWith(`${label}/`)) ?? candidates[0];
|
|
4449
|
+
if (!landing) return [];
|
|
4450
|
+
const firstSegment = landing.split("/")[0];
|
|
4451
|
+
const prefix = firstSegment === label ? label : "";
|
|
4452
|
+
return [{ label, prefix, href: `/${landing}`, ...entry === defaultVersion ? { default: true } : {}, ...entry.hidden === true ? { hidden: true } : {} }];
|
|
4453
|
+
}) : [];
|
|
4454
|
+
if (versions.length > 1) {
|
|
4455
|
+
tabs = annotateVersions(tabs);
|
|
4456
|
+
for (const [locale, items] of Object.entries(localizedNavigation)) localizedNavigation[locale] = annotateVersions(items);
|
|
4457
|
+
}
|
|
4134
4458
|
const redirects = Array.isArray(config.redirects) ? config.redirects.flatMap((value) => {
|
|
4135
4459
|
const redirect = objectValue2(value);
|
|
4136
4460
|
if (!redirect || typeof redirect.source !== "string" || typeof redirect.destination !== "string") return [];
|
|
@@ -4155,9 +4479,13 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
4155
4479
|
return {
|
|
4156
4480
|
docsConfig: {
|
|
4157
4481
|
tabs,
|
|
4158
|
-
...projectionTrace.rootContainerKind === "dropdowns"
|
|
4482
|
+
...projectionTrace.rootContainerKind === "dropdowns" || versions.length > 1 || shortcuts.length > 0 ? { navigation: {
|
|
4483
|
+
...projectionTrace.rootContainerKind === "dropdowns" ? { display: "dropdown" } : {},
|
|
4484
|
+
...versions.length > 1 ? { versions } : {},
|
|
4485
|
+
...shortcuts.length > 0 ? { shortcuts } : {}
|
|
4486
|
+
} } : {},
|
|
4159
4487
|
...projectedCompatibleConfig(config, warnings),
|
|
4160
|
-
...
|
|
4488
|
+
...projectedApi(config, warnings),
|
|
4161
4489
|
...i18n ? { i18n } : {},
|
|
4162
4490
|
...redirects.length > 0 ? { redirects } : {}
|
|
4163
4491
|
},
|
|
@@ -4832,9 +5160,10 @@ function descriptorSort(left, right) {
|
|
|
4832
5160
|
if (leftPosition !== rightPosition) return leftPosition - rightPosition;
|
|
4833
5161
|
return left.sourcePath.localeCompare(right.sourcePath, void 0, { numeric: true });
|
|
4834
5162
|
}
|
|
4835
|
-
function registerDoc(docId, context) {
|
|
5163
|
+
function registerDoc(docId, context, sourceDirectory) {
|
|
4836
5164
|
const key = normalizeDocId(docId);
|
|
4837
|
-
const
|
|
5165
|
+
const scopedKey = sourceDirectory && !docId.startsWith("/") ? normalizeDocId(posix2.join(sourceDirectory, key)) : void 0;
|
|
5166
|
+
const descriptor = (scopedKey ? context.descriptorByDocId.get(scopedKey) : void 0) ?? context.descriptorByDocId.get(key) ?? context.descriptors.find((page) => page.navigationId === docusaurusRouteId(key));
|
|
4838
5167
|
if (!descriptor) {
|
|
4839
5168
|
context.warnings.push({
|
|
4840
5169
|
code: "missing-page",
|
|
@@ -4846,10 +5175,10 @@ function registerDoc(docId, context) {
|
|
|
4846
5175
|
context.referencedNavigationIds.add(descriptor.navigationId);
|
|
4847
5176
|
return descriptor.navigationId;
|
|
4848
5177
|
}
|
|
4849
|
-
function generatedIndexPage(label, linkValue, context) {
|
|
5178
|
+
function generatedIndexPage(label, linkValue, context, sourceDirectory) {
|
|
4850
5179
|
const link = objectValue3(linkValue);
|
|
4851
5180
|
if (!link) return null;
|
|
4852
|
-
if (link.type === "doc" && typeof link.id === "string") return registerDoc(link.id, context);
|
|
5181
|
+
if (link.type === "doc" && typeof link.id === "string") return registerDoc(link.id, context, sourceDirectory);
|
|
4853
5182
|
if (link.type !== "generated-index") return null;
|
|
4854
5183
|
const fallback = `category/${slugifySegment(label)}`;
|
|
4855
5184
|
const unprefixedNavigationId = typeof link.slug === "string" ? routeFromSlug(link.slug, fallback) ?? fallback : fallback;
|
|
@@ -5092,7 +5421,7 @@ function autogeneratedItems(dirName, context) {
|
|
|
5092
5421
|
};
|
|
5093
5422
|
}
|
|
5094
5423
|
}
|
|
5095
|
-
const landing = generatedIndexPage(metadata.label ?? titleCase2(segment), metadata.link, context);
|
|
5424
|
+
const landing = generatedIndexPage(metadata.label ?? titleCase2(segment), metadata.link, context, directory);
|
|
5096
5425
|
if (landing && !pages2.includes(landing)) pages2.unshift(landing);
|
|
5097
5426
|
return {
|
|
5098
5427
|
position: metadata.position ?? Number.MAX_SAFE_INTEGER,
|
|
@@ -5926,6 +6255,7 @@ var FRONTMATTER_HEAD_BYTES = 65536;
|
|
|
5926
6255
|
var MAX_WITHHELD_SCAN_BYTES = MAX_PAGE_BYTES * 8;
|
|
5927
6256
|
var MAX_DROPPED_GATED_WARNINGS = 20;
|
|
5928
6257
|
var MAX_ASSET_BYTES = 25e6;
|
|
6258
|
+
var MAX_REFERENCED_ASSET_BYTES = 1e8;
|
|
5929
6259
|
var MAX_TOTAL_ASSET_BYTES = 5e8;
|
|
5930
6260
|
var GIT_LFS_POINTER_PREFIX = "version https://git-lfs.github.com/spec/v1";
|
|
5931
6261
|
function listAssetPaths(paths) {
|
|
@@ -6804,12 +7134,22 @@ function mintlifyTopLevelApiReferences(config) {
|
|
|
6804
7134
|
}
|
|
6805
7135
|
return references;
|
|
6806
7136
|
}
|
|
6807
|
-
function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs) {
|
|
7137
|
+
function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, pages = []) {
|
|
6808
7138
|
if (!mintlifyConfig) return [];
|
|
6809
7139
|
const references = [
|
|
6810
7140
|
...mintlifyTopLevelApiReferences(mintlifyConfig),
|
|
6811
7141
|
...mintlifyNavigationApiReferences(mintlifyConfig)
|
|
6812
7142
|
];
|
|
7143
|
+
const specKey = (value) => value.split(/[?#]/, 1)[0].replace(/\\/g, "/").replace(/^(?:\.\/)+/, "").replace(/^\/+/, "");
|
|
7144
|
+
const known = new Set(references.map((reference) => specKey(reference.value)));
|
|
7145
|
+
for (const page of pages) {
|
|
7146
|
+
const specRef = page.openapi ? splitOpenApiRef(page.openapi)?.specRef : void 0;
|
|
7147
|
+
if (!specRef || /^[a-z][a-z0-9+.-]*:/i.test(specRef)) continue;
|
|
7148
|
+
const key = specKey(specRef);
|
|
7149
|
+
if (known.has(key) || !files.some((file) => file.relativePath === key)) continue;
|
|
7150
|
+
known.add(key);
|
|
7151
|
+
references.push({ value: key, kind: "openapi", tabLabel: `OpenAPI: ${key}`, hidden: true, pageOnly: true });
|
|
7152
|
+
}
|
|
6813
7153
|
const seen = /* @__PURE__ */ new Set();
|
|
6814
7154
|
const specs = [];
|
|
6815
7155
|
for (const reference of references) {
|
|
@@ -6859,6 +7199,7 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs) {
|
|
|
6859
7199
|
parentTab: reference.parentTab,
|
|
6860
7200
|
icon: reference.icon,
|
|
6861
7201
|
hidden: reference.hidden,
|
|
7202
|
+
...reference.pageOnly ? { pageOnly: true } : {},
|
|
6862
7203
|
sourcePath: match.relativePath,
|
|
6863
7204
|
directory: reference.directory
|
|
6864
7205
|
});
|
|
@@ -7186,18 +7527,18 @@ function isolateFences(snippet, source, start, end) {
|
|
|
7186
7527
|
return `${fence.test(lines[0]) && /\S/.test(before) ? "\n" : ""}${snippet}${fence.test(lines[lines.length - 1]) && /\S/.test(after) ? "\n" : ""}`;
|
|
7187
7528
|
}
|
|
7188
7529
|
function snippetComponentBody(source, componentName) {
|
|
7189
|
-
const parsed =
|
|
7530
|
+
const parsed = ts4.createSourceFile("snippet.tsx", source, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TSX);
|
|
7190
7531
|
for (const statement of parsed.statements) {
|
|
7191
|
-
if (!
|
|
7532
|
+
if (!ts4.isVariableStatement(statement)) continue;
|
|
7192
7533
|
for (const declaration of statement.declarationList.declarations) {
|
|
7193
|
-
if (!
|
|
7534
|
+
if (!ts4.isIdentifier(declaration.name) || declaration.name.text !== componentName) continue;
|
|
7194
7535
|
const initializer = declaration.initializer;
|
|
7195
|
-
if (!initializer || !
|
|
7196
|
-
const returned =
|
|
7536
|
+
if (!initializer || !ts4.isArrowFunction(initializer)) continue;
|
|
7537
|
+
const returned = ts4.isBlock(initializer.body) ? initializer.body.statements.find(ts4.isReturnStatement)?.expression : initializer.body;
|
|
7197
7538
|
if (!returned) continue;
|
|
7198
7539
|
let expression = returned;
|
|
7199
|
-
while (
|
|
7200
|
-
if (
|
|
7540
|
+
while (ts4.isParenthesizedExpression(expression)) expression = expression.expression;
|
|
7541
|
+
if (ts4.isJsxElement(expression) || ts4.isJsxSelfClosingElement(expression) || ts4.isJsxFragment(expression)) {
|
|
7201
7542
|
return expression.getText(parsed);
|
|
7202
7543
|
}
|
|
7203
7544
|
}
|
|
@@ -7205,31 +7546,31 @@ function snippetComponentBody(source, componentName) {
|
|
|
7205
7546
|
return source;
|
|
7206
7547
|
}
|
|
7207
7548
|
function statefulSnippetDeclaration(source, componentName) {
|
|
7208
|
-
const parsed =
|
|
7209
|
-
const isEsm = (statement2) =>
|
|
7549
|
+
const parsed = ts4.createSourceFile("snippet.tsx", source, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TSX);
|
|
7550
|
+
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);
|
|
7210
7551
|
if (parsed.statements.length === 0 || !parsed.statements.every(isEsm)) return null;
|
|
7211
|
-
const statement = parsed.statements.find((candidate) =>
|
|
7212
|
-
if (!statement || !
|
|
7552
|
+
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);
|
|
7553
|
+
if (!statement || !ts4.isVariableStatement(statement)) return null;
|
|
7213
7554
|
const declaration = statement.declarationList.declarations[0];
|
|
7214
|
-
if (!declaration.initializer || !
|
|
7555
|
+
if (!declaration.initializer || !ts4.isArrowFunction(declaration.initializer) || !ts4.isBlock(declaration.initializer.body)) return null;
|
|
7215
7556
|
const body = declaration.initializer.body.statements;
|
|
7216
|
-
if (body.length < 2 || !body.some(
|
|
7557
|
+
if (body.length < 2 || !body.some(ts4.isReturnStatement)) return null;
|
|
7217
7558
|
return source.trim();
|
|
7218
7559
|
}
|
|
7219
7560
|
function staticNamedSnippetValues(source) {
|
|
7220
7561
|
const values = /* @__PURE__ */ new Map();
|
|
7221
|
-
const parsed =
|
|
7562
|
+
const parsed = ts4.createSourceFile("snippet.tsx", source, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TSX);
|
|
7222
7563
|
for (const statement of parsed.statements) {
|
|
7223
|
-
if (!
|
|
7564
|
+
if (!ts4.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts4.SyntaxKind.ExportKeyword)) continue;
|
|
7224
7565
|
for (const declaration of statement.declarationList.declarations) {
|
|
7225
|
-
if (!
|
|
7566
|
+
if (!ts4.isIdentifier(declaration.name) || !declaration.initializer) continue;
|
|
7226
7567
|
const expression = declaration.initializer;
|
|
7227
|
-
if (
|
|
7568
|
+
if (ts4.isStringLiteral(expression) || ts4.isNoSubstitutionTemplateLiteral(expression)) {
|
|
7228
7569
|
values.set(declaration.name.text, JSON.stringify(expression.text));
|
|
7229
|
-
} else if (
|
|
7570
|
+
} else if (ts4.isNumericLiteral(expression)) {
|
|
7230
7571
|
values.set(declaration.name.text, expression.text);
|
|
7231
|
-
} else if (expression.kind ===
|
|
7232
|
-
values.set(declaration.name.text, expression.kind ===
|
|
7572
|
+
} else if (expression.kind === ts4.SyntaxKind.TrueKeyword || expression.kind === ts4.SyntaxKind.FalseKeyword) {
|
|
7573
|
+
values.set(declaration.name.text, expression.kind === ts4.SyntaxKind.TrueKeyword ? "true" : "false");
|
|
7233
7574
|
}
|
|
7234
7575
|
}
|
|
7235
7576
|
}
|
|
@@ -7368,11 +7709,12 @@ function preserveLinkedAnchors(pages) {
|
|
|
7368
7709
|
const tableCell = line.match(/^ {0,3}\|\s*([^|]+?)\s*\|/);
|
|
7369
7710
|
if (tableCell && !/^[:\s-]+$/.test(tableCell[1])) tableCells.push({ index, text: tableCell[1] });
|
|
7370
7711
|
const match = line.match(/^ {0,3}#{1,6}\s+(.+?)\s*#*\s*$/);
|
|
7371
|
-
return match ? { index, text: match[1] } : null;
|
|
7712
|
+
return match ? { index, text: match[1].replace(/\s*\{\/\*\s*#\S+?\s*\*\/\}$/, "") } : null;
|
|
7372
7713
|
}).filter((entry) => entry !== null);
|
|
7373
7714
|
const existing = /* @__PURE__ */ new Set();
|
|
7374
7715
|
replaceOutsideCode(page.body, (text2) => {
|
|
7375
7716
|
for (const match of text2.matchAll(/\bid=(?:"([^"]+)"|'([^']+)')/g)) existing.add(match[1] ?? match[2]);
|
|
7717
|
+
for (const match of text2.matchAll(/\{\/\*\s*#(\S+?)\s*\*\/\}/g)) existing.add(match[1]);
|
|
7376
7718
|
return text2;
|
|
7377
7719
|
});
|
|
7378
7720
|
const candidateIndexes = /* @__PURE__ */ new Map();
|
|
@@ -7515,7 +7857,11 @@ function repositoryAssetHref(value, currentFile, siteRoot, onReferenced) {
|
|
|
7515
7857
|
}
|
|
7516
7858
|
if (!ASSET_EXTENSIONS.has(extname6(decodedPath).toLowerCase())) return null;
|
|
7517
7859
|
try {
|
|
7518
|
-
|
|
7860
|
+
let candidate = decodedPath.startsWith("/") ? resolveWithin(siteRoot, decodedPath.replace(/^\/+/, "")) : resolveWithinRoot(dirname4(currentFile), decodedPath, siteRoot);
|
|
7861
|
+
if (!decodedPath.startsWith("/") && !existsSync5(candidate)) {
|
|
7862
|
+
const fromRoot = resolveWithin(siteRoot, decodedPath.replace(/^(?:\.\/)+/, ""));
|
|
7863
|
+
if (existsSync5(fromRoot)) candidate = fromRoot;
|
|
7864
|
+
}
|
|
7519
7865
|
const realRoot = realpathSync2(siteRoot);
|
|
7520
7866
|
const realCandidate = realpathSync2(candidate);
|
|
7521
7867
|
const realRelative = relative5(realRoot, realCandidate);
|
|
@@ -7556,6 +7902,19 @@ function rewriteRepositoryAssetLinks(body, currentFile, siteRoot, onReferenced)
|
|
|
7556
7902
|
});
|
|
7557
7903
|
}
|
|
7558
7904
|
var LOCAL_EXPORT_DECLARATION = /^\s*export\s+(?:const|let|var|function|class|async\s+function)\s+([A-Za-z_$][\w$]*)/;
|
|
7905
|
+
function replaceOutsideMdxComments(body, transform) {
|
|
7906
|
+
const comment = /\{\/\*[\s\S]*?\*\/\}/g;
|
|
7907
|
+
let cursor = 0;
|
|
7908
|
+
let output = "";
|
|
7909
|
+
for (const match of body.matchAll(comment)) {
|
|
7910
|
+
output += transform(body.slice(cursor, match.index)) + match[0];
|
|
7911
|
+
cursor = match.index + match[0].length;
|
|
7912
|
+
}
|
|
7913
|
+
return output + transform(body.slice(cursor));
|
|
7914
|
+
}
|
|
7915
|
+
function replaceOutsideCodeAndMdxComments(body, transform) {
|
|
7916
|
+
return replaceOutsideCode(body, (segment) => replaceOutsideMdxComments(segment, transform));
|
|
7917
|
+
}
|
|
7559
7918
|
function locallyDeclaredNames(raw) {
|
|
7560
7919
|
const names = /* @__PURE__ */ new Set();
|
|
7561
7920
|
let codeFence = null;
|
|
@@ -7601,7 +7960,7 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7601
7960
|
});
|
|
7602
7961
|
return `{/* ${verdict.kind === "oversized" ? "Oversized" : "Unreadable"} content not inlined: ${shown} */}`;
|
|
7603
7962
|
};
|
|
7604
|
-
let withoutImports =
|
|
7963
|
+
let withoutImports = replaceOutsideCodeAndMdxComments(raw, (source2) => source2.replace(
|
|
7605
7964
|
SNIPPET_IMPORT_PATTERN,
|
|
7606
7965
|
(_statement, namedComponent, defaultComponent, sourcePath) => {
|
|
7607
7966
|
const componentName = namedComponent ?? defaultComponent;
|
|
@@ -7628,6 +7987,12 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7628
7987
|
else snippets.set(componentName, snippetComponentBody(nested, componentName));
|
|
7629
7988
|
return "";
|
|
7630
7989
|
} catch {
|
|
7990
|
+
let hasLiveUsage = false;
|
|
7991
|
+
replaceOutsideCodeAndMdxComments(raw, (segment) => {
|
|
7992
|
+
if (new RegExp(`<${componentName}(?:\\s|/?>)`).test(segment)) hasLiveUsage = true;
|
|
7993
|
+
return segment;
|
|
7994
|
+
});
|
|
7995
|
+
if (!hasLiveUsage) return "";
|
|
7631
7996
|
warnings.push({
|
|
7632
7997
|
code: "missing-page",
|
|
7633
7998
|
message: `Imported snippet ${sourcePath} could not be resolved and was left as a comment.`,
|
|
@@ -7638,7 +8003,7 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7638
8003
|
}
|
|
7639
8004
|
}
|
|
7640
8005
|
));
|
|
7641
|
-
withoutImports =
|
|
8006
|
+
withoutImports = replaceOutsideCodeAndMdxComments(withoutImports, (source2) => source2.replace(
|
|
7642
8007
|
SNIPPET_VALUE_IMPORT_PATTERN,
|
|
7643
8008
|
(statement, names, sourcePath) => {
|
|
7644
8009
|
const bindings = names.split(",").map((name) => name.trim()).filter(Boolean).map((name) => {
|
|
@@ -7682,7 +8047,12 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7682
8047
|
));
|
|
7683
8048
|
const localNames = locallyDeclaredNames(withoutImports);
|
|
7684
8049
|
for (const [componentName, candidate] of globalAliases) {
|
|
7685
|
-
|
|
8050
|
+
let hasLiveUsage = false;
|
|
8051
|
+
replaceOutsideCodeAndMdxComments(withoutImports, (source2) => {
|
|
8052
|
+
if (new RegExp(`<${componentName}(?:\\s|/?>)`).test(source2)) hasLiveUsage = true;
|
|
8053
|
+
return source2;
|
|
8054
|
+
});
|
|
8055
|
+
if (snippets.has(componentName) || localNames.has(componentName) || gate?.(candidate)?.kind === "gated" || !hasLiveUsage) continue;
|
|
7686
8056
|
const blocked = blockInline(candidate, relative5(repositoryRoot, candidate).replace(/\\/g, "/"));
|
|
7687
8057
|
if (blocked) {
|
|
7688
8058
|
snippets.set(componentName, blocked);
|
|
@@ -7705,9 +8075,9 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7705
8075
|
let result = replaceOutsideCodeAndComments(withoutImports, (segment) => {
|
|
7706
8076
|
for (const [componentName, snippet] of snippets) {
|
|
7707
8077
|
segment = segment.replace(new RegExp(`<${componentName}((?:\\s[^>]*)?)\\s*/>`, "g"), (tag, attributes, offset, source2) => {
|
|
7708
|
-
return isolateFences(interpolateSnippet(snippet, attributes), source2, offset, offset + tag.length);
|
|
8078
|
+
return isolateFences(closeOpenCodeFence(interpolateSnippet(snippet, attributes)), source2, offset, offset + tag.length);
|
|
7709
8079
|
}).replace(new RegExp(`<${componentName}((?:\\s[^>]*)?)>([\\s\\S]*?)<\\/${componentName}>`, "g"), (tag, attributes, children, offset, source2) => {
|
|
7710
|
-
return isolateFences(interpolateSnippet(snippet, attributes, children), source2, offset, offset + tag.length);
|
|
8080
|
+
return isolateFences(closeOpenCodeFence(interpolateSnippet(snippet, attributes, children)), source2, offset, offset + tag.length);
|
|
7711
8081
|
});
|
|
7712
8082
|
}
|
|
7713
8083
|
return segment.replace(SNIPPET_TAG_PATTERN, (tag, doubleQuoted, singleQuoted, offset, source2) => {
|
|
@@ -7726,7 +8096,7 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7726
8096
|
if (!candidate) throw new Error("file not found");
|
|
7727
8097
|
const blocked = blockInline(candidate, filePath, `Snippet file="${filePath}"`);
|
|
7728
8098
|
if (blocked) return blocked;
|
|
7729
|
-
return isolateFences(inlineMdxSnippets(
|
|
8099
|
+
return isolateFences(closeOpenCodeFence(inlineMdxSnippets(
|
|
7730
8100
|
withoutFrontmatter(readFileSync5(candidate, "utf8")),
|
|
7731
8101
|
candidate,
|
|
7732
8102
|
repositoryRoot,
|
|
@@ -7735,7 +8105,7 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
|
|
|
7735
8105
|
siteRoot,
|
|
7736
8106
|
globalAliases,
|
|
7737
8107
|
gate
|
|
7738
|
-
), source2, offset, offset + tag.length);
|
|
8108
|
+
)), source2, offset, offset + tag.length);
|
|
7739
8109
|
} catch {
|
|
7740
8110
|
warnings.push({
|
|
7741
8111
|
code: "missing-page",
|
|
@@ -7940,7 +8310,7 @@ function migrateRepository(options) {
|
|
|
7940
8310
|
const sourceBudget = options.maxSourceFiles ?? MAX_SOURCE_FILES;
|
|
7941
8311
|
const scannedFiles = scanFiles(contentRoot, repositoryDir, warnings, discoveryRank, sourceBudget);
|
|
7942
8312
|
const mintignoreFilteredFiles = mintignoreMatcher ? scannedFiles.filter((file) => !mintignoreMatcher.ignores(file.relativePath)) : scannedFiles;
|
|
7943
|
-
const
|
|
8313
|
+
const isUnreferencedSnippetModule = (file) => file.relativePath.split("/").some((segment) => SNIPPET_DIRECTORIES.has(segment.toLowerCase())) && isDocumentationExtension(file.relativePath) && !referenceOrder.has(normalizedReferenceKey(file.relativePath));
|
|
7944
8314
|
const files = discoveryRank ? selectFilesWithinBudget(mintignoreFilteredFiles, discoveryRank, warnings, allVersionPrefixes, sourceBudget) : mintignoreFilteredFiles;
|
|
7945
8315
|
if (platform === "fern" && fernProjectRoot) {
|
|
7946
8316
|
const discovered2 = new Set(files.map((file) => file.relativePath));
|
|
@@ -8019,6 +8389,10 @@ function migrateRepository(options) {
|
|
|
8019
8389
|
}
|
|
8020
8390
|
for (const file of mintignoreFilteredFiles) {
|
|
8021
8391
|
if (keptFiles.has(file) || !isDocFile(file)) continue;
|
|
8392
|
+
if (isUnreferencedSnippetModule(file)) {
|
|
8393
|
+
if (classifyPageGate(file).reason) withheldDocFiles.push(file);
|
|
8394
|
+
continue;
|
|
8395
|
+
}
|
|
8022
8396
|
droppedPageCount++;
|
|
8023
8397
|
if (!isGateCandidate(file)) {
|
|
8024
8398
|
const snippetReason = classifyPageGate(file).reason;
|
|
@@ -8241,7 +8615,11 @@ function migrateRepository(options) {
|
|
|
8241
8615
|
const publishedText = trackPublishedRefs ? raw : void 0;
|
|
8242
8616
|
const pageAssetReferences = [];
|
|
8243
8617
|
if (platform === "fern" || platform === "mintlify" || platform === "docusaurus") {
|
|
8244
|
-
raw = normalizeExplicitHeadingIds(
|
|
8618
|
+
raw = normalizeExplicitHeadingIds(
|
|
8619
|
+
raw,
|
|
8620
|
+
(message) => warnings.push({ code: "invalid-page", message, source: file.relativePath }),
|
|
8621
|
+
{ headingMarkers: platform === "mintlify" }
|
|
8622
|
+
);
|
|
8245
8623
|
}
|
|
8246
8624
|
if (componentMigrator) {
|
|
8247
8625
|
const warningsBeforeTransform = warnings.length;
|
|
@@ -8253,13 +8631,7 @@ function migrateRepository(options) {
|
|
|
8253
8631
|
}
|
|
8254
8632
|
if (platform === "fern" || platform === "mintlify" || platform === "docusaurus") {
|
|
8255
8633
|
const protectedMath = protectMathBlocks(raw);
|
|
8256
|
-
if (protectedMath.
|
|
8257
|
-
warnings.push({
|
|
8258
|
-
code: "unsupported-config",
|
|
8259
|
-
message: "Math (KaTeX '$$...$$') has no renderer in Thally yet; it was kept as a fenced code block instead of being dropped.",
|
|
8260
|
-
source: relative5(repositoryDir, file.absolutePath).replace(/\\/g, "/")
|
|
8261
|
-
});
|
|
8262
|
-
} else if (protectedMath.guardTriggered) {
|
|
8634
|
+
if (protectedMath.guardTriggered) {
|
|
8263
8635
|
warnings.push({
|
|
8264
8636
|
code: "unsupported-config",
|
|
8265
8637
|
message: "A suspected math span looked like it needed converting, but doing so broke the page; the page was kept as originally authored instead.",
|
|
@@ -8351,7 +8723,7 @@ function migrateRepository(options) {
|
|
|
8351
8723
|
page.body = replaceUnknownComponents(page.body, (name) => {
|
|
8352
8724
|
warnings.push({
|
|
8353
8725
|
code: "unsupported-config",
|
|
8354
|
-
message: `
|
|
8726
|
+
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.`,
|
|
8355
8727
|
source: file.relativePath
|
|
8356
8728
|
});
|
|
8357
8729
|
});
|
|
@@ -8478,9 +8850,35 @@ function migrateRepository(options) {
|
|
|
8478
8850
|
const source = /^src\/mdx\/migrated\/[^/]+\/source\/(.+)$/.exec(file.path)?.[1];
|
|
8479
8851
|
return source ? [resolvePath(repositoryDir, source)] : [];
|
|
8480
8852
|
}));
|
|
8853
|
+
const rootStylesheetPath = platform === "mintlify" && mintlifyProjectRoot ? resolveWithin(mintlifyProjectRoot, "style.css") : void 0;
|
|
8854
|
+
const hasRootStylesheet = Boolean(rootStylesheetPath && existsSync5(rootStylesheetPath) && lstatSync5(rootStylesheetPath).isFile() && !lstatSync5(rootStylesheetPath).isSymbolicLink());
|
|
8855
|
+
let rootStyleProjection;
|
|
8856
|
+
let rootNavbarButtons = [];
|
|
8857
|
+
let rootStyleProblem;
|
|
8858
|
+
if (hasRootStylesheet && rootStylesheetPath && lstatSync5(rootStylesheetPath).size <= MAX_ASSET_BYTES) {
|
|
8859
|
+
const css = readFileSync5(rootStylesheetPath, "utf8");
|
|
8860
|
+
if (/@import\b|url\s*\(\s*['"]?\s*(?:javascript:|file:)/i.test(css)) rootStyleProblem = "unsafe";
|
|
8861
|
+
else {
|
|
8862
|
+
try {
|
|
8863
|
+
rootNavbarButtons = navbarLinkButtons(css);
|
|
8864
|
+
rootStyleProjection = projectAuthoredStyles(css, [
|
|
8865
|
+
...pages.map((page) => page.body),
|
|
8866
|
+
...(componentMigrator?.files() ?? []).map((file) => typeof file.content === "string" ? file.content : ""),
|
|
8867
|
+
// Site-wide scripts build markup of their own (a CTA card, say) that the stylesheet is meant for.
|
|
8868
|
+
...files.filter((file) => isMintlifyServedScriptOrStyle(file.relativePath) && extname6(file.relativePath).toLowerCase() === ".js" && lstatSync5(file.absolutePath).size <= MAX_PAGE_BYTES).map((file) => readFileSync5(file.absolutePath, "utf8"))
|
|
8869
|
+
]);
|
|
8870
|
+
} catch {
|
|
8871
|
+
rootStyleProblem = "parse";
|
|
8872
|
+
}
|
|
8873
|
+
}
|
|
8874
|
+
}
|
|
8875
|
+
if (trackPublishedRefs && rootStyleProjection?.css) {
|
|
8876
|
+
addPathReferences(rootStyleProjection.css, "", publishedExact, publishedLoose);
|
|
8877
|
+
}
|
|
8481
8878
|
const siteAssetPaths = /* @__PURE__ */ new Map();
|
|
8482
8879
|
const fontAssetByRelative = /* @__PURE__ */ new Map();
|
|
8483
8880
|
for (const file of [...files, ...repositoryAssets, ...fernReferencedAssets]) {
|
|
8881
|
+
if (rootStylesheetPath && file.absolutePath === rootStylesheetPath) continue;
|
|
8484
8882
|
const firstSegment = file.relativePath.split("/", 1)[0].toLowerCase();
|
|
8485
8883
|
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;
|
|
8486
8884
|
if (!siteKind && !ASSET_EXTENSIONS.has(extname6(file.relativePath).toLowerCase())) continue;
|
|
@@ -8526,7 +8924,8 @@ function migrateRepository(options) {
|
|
|
8526
8924
|
const lfsPointerAssets = [];
|
|
8527
8925
|
const ambiguouslyNamedAssets = [];
|
|
8528
8926
|
for (const { file, assetPath, size } of orderedAssetCandidates) {
|
|
8529
|
-
|
|
8927
|
+
const individualLimit = referencedAssetPaths.has(assetPath) ? MAX_REFERENCED_ASSET_BYTES : MAX_ASSET_BYTES;
|
|
8928
|
+
if (size > individualLimit || totalAssetBytes + size > MAX_TOTAL_ASSET_BYTES) {
|
|
8530
8929
|
overBudgetAssets.push(file.relativePath);
|
|
8531
8930
|
if (referencedAssetPaths.has(assetPath)) overBudgetReferenced++;
|
|
8532
8931
|
continue;
|
|
@@ -8568,7 +8967,7 @@ function migrateRepository(options) {
|
|
|
8568
8967
|
for (const entry of copiedSite.filter((item) => item.kind === "style")) {
|
|
8569
8968
|
warnings.push({
|
|
8570
8969
|
code: "unsupported-config",
|
|
8571
|
-
message: `Migration gap: custom stylesheet ${entry.path} is NOT applied. It was copied to public/${entry.path} but
|
|
8970
|
+
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.`,
|
|
8572
8971
|
source: entry.path
|
|
8573
8972
|
});
|
|
8574
8973
|
}
|
|
@@ -8586,7 +8985,7 @@ function migrateRepository(options) {
|
|
|
8586
8985
|
if (overBudgetAssets.length > 0) {
|
|
8587
8986
|
warnings.push({
|
|
8588
8987
|
code: "limit-reached",
|
|
8589
|
-
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.`
|
|
8988
|
+
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.`
|
|
8590
8989
|
});
|
|
8591
8990
|
}
|
|
8592
8991
|
if (lfsPointerAssets.length > 0) {
|
|
@@ -8595,7 +8994,43 @@ function migrateRepository(options) {
|
|
|
8595
8994
|
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.`
|
|
8596
8995
|
});
|
|
8597
8996
|
}
|
|
8598
|
-
if (
|
|
8997
|
+
if (hasRootStylesheet && rootStylesheetPath && mintlifyProjectRoot) {
|
|
8998
|
+
const size = lstatSync5(rootStylesheetPath).size;
|
|
8999
|
+
if (size > MAX_ASSET_BYTES || totalAssetBytes + size > MAX_TOTAL_ASSET_BYTES) {
|
|
9000
|
+
warnings.push({ code: "limit-reached", message: "Mintlify root style.css exceeded the asset budget and was not imported.", source: "style.css" });
|
|
9001
|
+
} else if (rootStyleProblem === "unsafe") {
|
|
9002
|
+
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" });
|
|
9003
|
+
} else if (rootStyleProblem === "parse" || !rootStyleProjection) {
|
|
9004
|
+
warnings.push({ code: "unsupported-config", message: "Mintlify root style.css could not be parsed and was not imported.", source: "style.css" });
|
|
9005
|
+
} else {
|
|
9006
|
+
if (rootNavbarButtons.length > 0 && docsConfig.navbar?.links) {
|
|
9007
|
+
docsConfig = {
|
|
9008
|
+
...docsConfig,
|
|
9009
|
+
navbar: {
|
|
9010
|
+
...docsConfig.navbar,
|
|
9011
|
+
links: docsConfig.navbar.links.map((link) => {
|
|
9012
|
+
const rule = rootNavbarButtons.find((entry) => entry.exact ? link.href === entry.href : link.href.includes(entry.href));
|
|
9013
|
+
return rule ? { ...link, button: { background: rule.background, ...rule.color ? { color: rule.color } : {} } } : link;
|
|
9014
|
+
})
|
|
9015
|
+
}
|
|
9016
|
+
};
|
|
9017
|
+
}
|
|
9018
|
+
if (rootStyleProjection.omittedSelectors > 0) warnings.push({
|
|
9019
|
+
code: "unsupported-config",
|
|
9020
|
+
source: "style.css",
|
|
9021
|
+
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.`
|
|
9022
|
+
});
|
|
9023
|
+
if (rootStyleProjection.css.trim()) {
|
|
9024
|
+
const identity = createHash2("sha256").update(componentSourceIdentity(options.sourceUrl, repositoryDir, mintlifyProjectRoot)).digest("hex").slice(0, 12);
|
|
9025
|
+
const assetPath = `migrated/${identity}/style.css`;
|
|
9026
|
+
const content = Buffer.from(rootStyleProjection.css);
|
|
9027
|
+
assets.push({ path: assetPath, content });
|
|
9028
|
+
docsConfig = { ...docsConfig, stylesheets: [...docsConfig.stylesheets ?? [], `/${assetPath}`] };
|
|
9029
|
+
totalAssetBytes += content.length;
|
|
9030
|
+
}
|
|
9031
|
+
}
|
|
9032
|
+
}
|
|
9033
|
+
if (!discoveryRank && files.length >= sourceBudget) {
|
|
8599
9034
|
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.` });
|
|
8600
9035
|
}
|
|
8601
9036
|
if (platform === "docusaurus") {
|
|
@@ -8730,7 +9165,9 @@ function migrateRepository(options) {
|
|
|
8730
9165
|
source: path
|
|
8731
9166
|
});
|
|
8732
9167
|
};
|
|
8733
|
-
const
|
|
9168
|
+
const allSpecs = resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteApiSpecs, pages);
|
|
9169
|
+
const resolvedSpecs = allSpecs.filter((spec) => !spec.pageOnly);
|
|
9170
|
+
const pageOnlySpecs = allSpecs.filter((spec) => spec.pageOnly);
|
|
8734
9171
|
for (const spec of resolvedSpecs) {
|
|
8735
9172
|
if (!assets.some((asset) => asset.path === specAssetPath(spec.filename))) {
|
|
8736
9173
|
assets.push(specAsset(spec.filename, spec.content));
|
|
@@ -8763,6 +9200,14 @@ function migrateRepository(options) {
|
|
|
8763
9200
|
}
|
|
8764
9201
|
}
|
|
8765
9202
|
}
|
|
9203
|
+
for (const spec of pageOnlySpecs) {
|
|
9204
|
+
if (!assets.some((asset) => asset.path === specAssetPath(spec.filename))) assets.push(specAsset(spec.filename, spec.content));
|
|
9205
|
+
if (withheldSpecRefs.some((ref) => specRefMatches(ref, spec.sourcePath, spec.filename, true))) warnSharedSpec(spec.sourcePath);
|
|
9206
|
+
}
|
|
9207
|
+
if (pageOnlySpecs.length > 0) {
|
|
9208
|
+
docsConfig = injectOpenApiSpecs(docsConfig, pageOnlySpecs, warnings);
|
|
9209
|
+
pageSpecs = [...pageSpecs, ...pageOnlySpecs];
|
|
9210
|
+
}
|
|
8766
9211
|
rewriteMintlifyPageSpecRefs(pages, pageSpecs, new Set(remoteApiSpecs.map((spec) => spec.url)), warnings);
|
|
8767
9212
|
}
|
|
8768
9213
|
if (platform === "mintlify") {
|
|
@@ -9178,6 +9623,8 @@ function renderPage(bundle, page) {
|
|
|
9178
9623
|
"---",
|
|
9179
9624
|
`title: ${yamlString(page.title)}`,
|
|
9180
9625
|
page.navTitle ? `navTitle: ${yamlString(page.navTitle)}` : null,
|
|
9626
|
+
page.icon ? `icon: ${yamlString(page.icon)}` : null,
|
|
9627
|
+
page.iconType ? `iconType: ${yamlString(page.iconType)}` : null,
|
|
9181
9628
|
`description: ${yamlString(page.description)}`,
|
|
9182
9629
|
page.descriptionPlacement === "body" ? "descriptionPlacement: body" : null,
|
|
9183
9630
|
page.badge ? `badge: ${yamlString(page.badge)}` : null,
|
|
@@ -9185,9 +9632,11 @@ function renderPage(bundle, page) {
|
|
|
9185
9632
|
page.mode ? `mode: ${yamlString(page.mode)}` : null,
|
|
9186
9633
|
page.hidden ? "hidden: true" : null,
|
|
9187
9634
|
page.noindex ? "noindex: true" : null,
|
|
9635
|
+
...Object.entries(page.meta ?? {}).map(([field, value]) => `${field}: ${yamlString(value)}`),
|
|
9188
9636
|
page.openapi ? `openapi: ${yamlString(page.openapi)}` : null,
|
|
9189
9637
|
page.api ? `api: ${yamlString(page.api)}` : null,
|
|
9190
9638
|
page.authMethod ? `authMethod: ${yamlString(page.authMethod)}` : null,
|
|
9639
|
+
page.playground ? `playground: ${yamlString(page.playground)}` : null,
|
|
9191
9640
|
bundle.sourceKind === "url" ? `source: ${yamlString(page.source)}` : null,
|
|
9192
9641
|
"---",
|
|
9193
9642
|
"",
|
|
@@ -9268,6 +9717,7 @@ function mergeMigrationConfig(existing, incoming) {
|
|
|
9268
9717
|
// Collection presentation belongs to the imported information
|
|
9269
9718
|
// architecture; starter defaults must not coerce source dropdowns to tabs.
|
|
9270
9719
|
navigation: incoming.navigation ?? existing.navigation,
|
|
9720
|
+
...existing.stylesheets?.length || incoming.stylesheets?.length ? { stylesheets: [.../* @__PURE__ */ new Set([...existing.stylesheets ?? [], ...incoming.stylesheets ?? []])] } : {},
|
|
9271
9721
|
...i18n ? { i18n } : {},
|
|
9272
9722
|
// Existing providers win per provider; imported ones fill the gaps.
|
|
9273
9723
|
// A malformed (string/array) existing value must not spread into index keys.
|
|
@@ -9614,7 +10064,7 @@ function embeddedMintlifyConfig(body) {
|
|
|
9614
10064
|
function plainDescription(value) {
|
|
9615
10065
|
return value.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/[`*_>#-]/g, "").replace(/\s+/g, " ").trim().slice(0, 240);
|
|
9616
10066
|
}
|
|
9617
|
-
function
|
|
10067
|
+
function withoutFencedCode2(body) {
|
|
9618
10068
|
let fenceCharacter = "";
|
|
9619
10069
|
let fenceLength = 0;
|
|
9620
10070
|
return body.split("\n").map((line) => {
|
|
@@ -9924,7 +10374,7 @@ function sanitizeRemoteMarkdown(body) {
|
|
|
9924
10374
|
}).join("\n");
|
|
9925
10375
|
const urlSafeMarkdown = sanitizeMarkdownUrls(sanitized);
|
|
9926
10376
|
if (urlSafeMarkdown === null) return null;
|
|
9927
|
-
const executable =
|
|
10377
|
+
const executable = withoutFencedCode2(urlSafeMarkdown).replace(/\{\/\*[\s\S]*?\*\/\}/g, "").replace(/<(?:https?:\/\/|mailto:)[^>]+>/gi, "").replace(/(`+)[\s\S]*?\1/g, "");
|
|
9928
10378
|
if (/^\s*(?:import|export)\s/m.test(executable)) return null;
|
|
9929
10379
|
let hasUnsafeExpression = false;
|
|
9930
10380
|
const withoutStaticProps = executable.replace(/=\{([^{}\n]*)\}/g, (original, value) => {
|
|
@@ -10874,7 +11324,7 @@ async function migrateUrl(options) {
|
|
|
10874
11324
|
}
|
|
10875
11325
|
|
|
10876
11326
|
// src/remote-api.ts
|
|
10877
|
-
import { createHash as
|
|
11327
|
+
import { createHash as createHash3 } from "crypto";
|
|
10878
11328
|
import { lookup } from "dns/promises";
|
|
10879
11329
|
import { request } from "https";
|
|
10880
11330
|
import { isIP } from "net";
|
|
@@ -11034,7 +11484,7 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
11034
11484
|
const extension = /\.ya?ml$/i.test(url.pathname) ? "yaml" : "json";
|
|
11035
11485
|
const body = await downloadSpec(reference.url, fetcher);
|
|
11036
11486
|
const operations = parseOpenApi(body, extension);
|
|
11037
|
-
const filename = `openapi-${
|
|
11487
|
+
const filename = `openapi-${createHash3("sha256").update(reference.url).digest("hex").slice(0, 12)}.${extension}`;
|
|
11038
11488
|
assets.push({ path: `openapi/${filename}`, content: body, projectRelative: true });
|
|
11039
11489
|
for (const page of pages) {
|
|
11040
11490
|
const ref = page.openapi ? splitOpenApiRef(page.openapi) : null;
|