@thallylabs/migrate 0.2.22 → 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 +27 -0
- package/dist/index.js +386 -206
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import * as ts4 from "typescript";
|
|
|
22
22
|
// src/components.ts
|
|
23
23
|
import { createHash } from "crypto";
|
|
24
24
|
import { existsSync, lstatSync, readFileSync } from "fs";
|
|
25
|
-
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";
|
|
26
26
|
import postcss from "postcss";
|
|
27
27
|
import selectorParser from "postcss-selector-parser";
|
|
28
28
|
import remarkMdx2 from "remark-mdx";
|
|
@@ -157,6 +157,177 @@ function isThallyBuiltinComponent(name) {
|
|
|
157
157
|
return THALLY_BUILTIN_COMPONENTS.has(name) || THALLY_BUILTIN_COMPONENTS.has(name.split(".")[0]);
|
|
158
158
|
}
|
|
159
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
|
+
|
|
160
331
|
// src/mdx.ts
|
|
161
332
|
function titleFromId(id) {
|
|
162
333
|
const value = id.split("/").at(-1) ?? id;
|
|
@@ -265,7 +436,7 @@ function unwrapDocusaurusMdxCodeBlocks(body) {
|
|
|
265
436
|
return isMdxCodeBlock ? body : output.join("\n");
|
|
266
437
|
}
|
|
267
438
|
var HTML_ID = /^[^\s"'<>`{}&]+$/u;
|
|
268
|
-
function normalizeExplicitHeadingIds(raw, warn) {
|
|
439
|
+
function normalizeExplicitHeadingIds(raw, warn, options = {}) {
|
|
269
440
|
const { front, body } = splitFrontmatterBlock(raw);
|
|
270
441
|
return front + replaceOutsideCode(body, (segment) => segment.split("\n").map((line) => {
|
|
271
442
|
if (!/^[ \t]{0,3}#{1,6}[ \t]+/.test(line)) return line;
|
|
@@ -276,13 +447,15 @@ function normalizeExplicitHeadingIds(raw, warn) {
|
|
|
276
447
|
const id = trimmed.slice(marker + 3, -1);
|
|
277
448
|
const heading = trimmed.slice(0, marker).trimEnd();
|
|
278
449
|
if (/[{}]/.test(id)) return line;
|
|
279
|
-
|
|
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>
|
|
280
453
|
${heading}`;
|
|
281
454
|
warn?.(`Heading anchor {#${id}} is not a valid HTML id and was removed from "${heading.replace(/^\s*#+\s*/, "")}".`);
|
|
282
455
|
return heading;
|
|
283
456
|
}
|
|
284
457
|
}
|
|
285
|
-
if (trimmed.endsWith("*/}")) {
|
|
458
|
+
if (!options.headingMarkers && !options.keepIdComments && trimmed.endsWith("*/}")) {
|
|
286
459
|
const marker = trimmed.lastIndexOf(" {/*");
|
|
287
460
|
if (marker >= 0) {
|
|
288
461
|
const comment = trimmed.slice(marker + 4, -3).trim();
|
|
@@ -296,6 +469,44 @@ ${trimmed.slice(0, marker).trimEnd()}`;
|
|
|
296
469
|
return line;
|
|
297
470
|
}).join("\n"));
|
|
298
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
|
+
}
|
|
299
510
|
var GLOBAL_DOCUSARUS_COMPONENTS = /* @__PURE__ */ new Set([
|
|
300
511
|
"Tabs",
|
|
301
512
|
"TabItem",
|
|
@@ -1257,7 +1468,12 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
|
1257
1468
|
const runMintlify = platform === "mintlify";
|
|
1258
1469
|
const runDocusaurus = platform === "docusaurus";
|
|
1259
1470
|
const sourceBody = runDocusaurus && unwrapMdxCodeBlocks ? unwrapDocusaurusMdxCodeBlocks(body) : body;
|
|
1260
|
-
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);
|
|
1261
1477
|
if (runDocusaurus) {
|
|
1262
1478
|
rewritten = replaceOutsideCode(rewritten, (segment) => segment.replace(
|
|
1263
1479
|
/:([+\w-]+):/g,
|
|
@@ -1324,16 +1540,25 @@ function parseMarkdownPage(input) {
|
|
|
1324
1540
|
body = `${body.slice(0, heading.start)}${body.slice(heading.end)}`.trim();
|
|
1325
1541
|
}
|
|
1326
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
|
+
}
|
|
1327
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;
|
|
1328
1551
|
const sourceMode = typeof parsed.data.mode === "string" ? parsed.data.mode : void 0;
|
|
1329
1552
|
const mode = sourceMode === "frame" ? "wide" : ["default", "wide", "custom", "center", "home"].includes(sourceMode ?? "") ? sourceMode : void 0;
|
|
1330
|
-
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);
|
|
1331
1554
|
return {
|
|
1332
1555
|
id: identity.id,
|
|
1333
1556
|
navigationId: identity.navigationId,
|
|
1334
1557
|
locale: identity.locale,
|
|
1335
1558
|
title,
|
|
1336
1559
|
navTitle,
|
|
1560
|
+
icon,
|
|
1561
|
+
iconType,
|
|
1337
1562
|
description,
|
|
1338
1563
|
...input.platform === "docusaurus" || input.platform === "fern" ? { descriptionPlacement: "body" } : {},
|
|
1339
1564
|
badge,
|
|
@@ -1341,6 +1566,7 @@ function parseMarkdownPage(input) {
|
|
|
1341
1566
|
mode,
|
|
1342
1567
|
hidden: parsed.data.hidden === true ? true : void 0,
|
|
1343
1568
|
noindex: parsed.data.noindex === true || parsed.data.noindex === "true" ? true : void 0,
|
|
1569
|
+
...Object.keys(meta).length > 0 ? { meta } : {},
|
|
1344
1570
|
openapi: typeof parsed.data.openapi === "string" ? parsed.data.openapi.trim() : void 0,
|
|
1345
1571
|
...apiFrontmatter(parsed.data, input.warn),
|
|
1346
1572
|
body,
|
|
@@ -1348,9 +1574,21 @@ function parseMarkdownPage(input) {
|
|
|
1348
1574
|
...parsed.error ? { frontmatterError: parsed.error } : {}
|
|
1349
1575
|
};
|
|
1350
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
|
+
];
|
|
1351
1585
|
var AUTH_METHODS = /* @__PURE__ */ new Set(["bearer", "basic", "key", "none"]);
|
|
1352
1586
|
function apiFrontmatter(data, warn) {
|
|
1353
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
|
+
}
|
|
1354
1592
|
if (data.api !== void 0 && data.api !== null) {
|
|
1355
1593
|
if (typeof data.api === "string" && data.api.trim()) result.api = data.api.trim();
|
|
1356
1594
|
else warn?.(`The page's "api" frontmatter is not a "METHOD url-or-path" string and was dropped.`);
|
|
@@ -1363,84 +1601,6 @@ function apiFrontmatter(data, warn) {
|
|
|
1363
1601
|
return result;
|
|
1364
1602
|
}
|
|
1365
1603
|
|
|
1366
|
-
// src/path.ts
|
|
1367
|
-
import { isAbsolute, relative, resolve, sep } from "path";
|
|
1368
|
-
var SAFE_SEGMENT = /[^a-z0-9._-]+/gi;
|
|
1369
|
-
function trimTrailingSlashes(value) {
|
|
1370
|
-
let end = value.length;
|
|
1371
|
-
while (end > 0 && value.charCodeAt(end - 1) === 47) end--;
|
|
1372
|
-
return value.slice(0, end);
|
|
1373
|
-
}
|
|
1374
|
-
function trimEdgeSlashes(value) {
|
|
1375
|
-
let start = 0;
|
|
1376
|
-
let end = value.length;
|
|
1377
|
-
while (start < end && value.charCodeAt(start) === 47) start++;
|
|
1378
|
-
while (end > start && value.charCodeAt(end - 1) === 47) end--;
|
|
1379
|
-
return value.slice(start, end);
|
|
1380
|
-
}
|
|
1381
|
-
function slugifySegment(value, preserveCase = false) {
|
|
1382
|
-
let decoded = value;
|
|
1383
|
-
try {
|
|
1384
|
-
decoded = decodeURIComponent(value);
|
|
1385
|
-
} catch {
|
|
1386
|
-
}
|
|
1387
|
-
const normalized = preserveCase ? decoded : decoded.toLowerCase();
|
|
1388
|
-
return normalized.replace(/\.(?:html?|mdx?)$/i, "").replace(SAFE_SEGMENT, "-").replace(/(^-|-$)/g, "");
|
|
1389
|
-
}
|
|
1390
|
-
function pageIdFromReference(value, preserveCase = false) {
|
|
1391
|
-
const withoutQuery = value.split(/[?#]/, 1)[0].replace(/\\/g, "/").replace(/^\/+/, "");
|
|
1392
|
-
if (!withoutQuery || withoutQuery.includes("\0")) return null;
|
|
1393
|
-
const rawSegments = withoutQuery.split("/").filter(Boolean);
|
|
1394
|
-
if (rawSegments.some((segment) => segment === ".." || segment === ".")) return null;
|
|
1395
|
-
const last = rawSegments.at(-1)?.replace(/\.(?:mdx?|rst|txt)$/i, "") ?? "";
|
|
1396
|
-
const isRootLevelReadme = rawSegments.length === 1 && /^readme$/i.test(last);
|
|
1397
|
-
const collapsesToParent = /^index$/i.test(last) || isRootLevelReadme;
|
|
1398
|
-
const baseSegments = collapsesToParent ? rawSegments.slice(0, -1) : rawSegments;
|
|
1399
|
-
if (!collapsesToParent) {
|
|
1400
|
-
baseSegments[baseSegments.length - 1] = last;
|
|
1401
|
-
}
|
|
1402
|
-
const segments = baseSegments.map((segment) => slugifySegment(segment, preserveCase)).filter(Boolean);
|
|
1403
|
-
return segments.join("/") || "introduction";
|
|
1404
|
-
}
|
|
1405
|
-
function mintlifyLocalizedReference(value, locale, defaultPageIds = /* @__PURE__ */ new Set()) {
|
|
1406
|
-
const reference = value.replace(/^\/+/, "");
|
|
1407
|
-
const localePrefix = `${locale.toLowerCase()}/`;
|
|
1408
|
-
if (reference.toLowerCase().startsWith(localePrefix)) return reference.slice(localePrefix.length);
|
|
1409
|
-
const sectionPrefix = `${locale.toLowerCase()}-`;
|
|
1410
|
-
if (reference.toLowerCase().startsWith(sectionPrefix)) {
|
|
1411
|
-
const candidate = reference.slice(sectionPrefix.length);
|
|
1412
|
-
const candidateId = pageIdFromReference(candidate, true);
|
|
1413
|
-
if (candidateId && defaultPageIds.has(candidateId)) return candidate;
|
|
1414
|
-
}
|
|
1415
|
-
const segments = reference.split("/");
|
|
1416
|
-
const localeIndex = segments.findIndex((segment) => segment.toLowerCase() === locale.toLowerCase());
|
|
1417
|
-
if (localeIndex > 0) {
|
|
1418
|
-
return [...segments.slice(0, localeIndex), ...segments.slice(localeIndex + 1)].join("/");
|
|
1419
|
-
}
|
|
1420
|
-
return value;
|
|
1421
|
-
}
|
|
1422
|
-
function resolveWithin(root, candidate) {
|
|
1423
|
-
return resolveWithinRoot(root, candidate, root);
|
|
1424
|
-
}
|
|
1425
|
-
function resolveWithinRoot(baseDir, candidate, confineRoot) {
|
|
1426
|
-
if (isAbsolute(candidate) || candidate.includes("\0")) {
|
|
1427
|
-
throw new Error(`Unsafe migration path: ${candidate}`);
|
|
1428
|
-
}
|
|
1429
|
-
const target = resolve(baseDir, candidate);
|
|
1430
|
-
const fromRoot = relative(resolve(confineRoot), target);
|
|
1431
|
-
if (fromRoot === ".." || fromRoot.startsWith(`..${sep}`) || isAbsolute(fromRoot)) {
|
|
1432
|
-
throw new Error(`Migration path escapes its root: ${candidate}`);
|
|
1433
|
-
}
|
|
1434
|
-
return target;
|
|
1435
|
-
}
|
|
1436
|
-
function normalizeAssetPath(value) {
|
|
1437
|
-
const normalized = value.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
1438
|
-
if (!normalized || normalized.includes("\0")) return null;
|
|
1439
|
-
const segments = normalized.split("/").filter(Boolean);
|
|
1440
|
-
if (segments.some((segment) => segment === "." || segment === "..")) return null;
|
|
1441
|
-
return segments.join("/");
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
1604
|
// src/inline-extraction.ts
|
|
1445
1605
|
import ts from "typescript";
|
|
1446
1606
|
var SERVER_ONLY_IDENTIFIERS = /* @__PURE__ */ new Set(["process", "require", "module", "exports", "__dirname", "__filename", "Buffer"]);
|
|
@@ -2468,10 +2628,10 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2468
2628
|
}
|
|
2469
2629
|
function expandCandidates(candidate) {
|
|
2470
2630
|
const candidates = [candidate];
|
|
2471
|
-
if (!
|
|
2631
|
+
if (!extname2(candidate)) {
|
|
2472
2632
|
candidates.push(...[".tsx", ".jsx", ".ts", ".js", ".mjs", ".json"].map((extension) => candidate + extension));
|
|
2473
2633
|
candidates.push(...["index.tsx", "index.jsx", "index.ts", "index.js"].map((name) => resolve2(candidate, name)));
|
|
2474
|
-
} else if (
|
|
2634
|
+
} else if (extname2(candidate) === ".js") {
|
|
2475
2635
|
candidates.push(candidate.slice(0, -3) + ".ts", candidate.slice(0, -3) + ".tsx");
|
|
2476
2636
|
}
|
|
2477
2637
|
return candidates;
|
|
@@ -2512,7 +2672,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2512
2672
|
checkedFile(path);
|
|
2513
2673
|
const size = lstatSync(path).size;
|
|
2514
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");
|
|
2515
|
-
const extension =
|
|
2675
|
+
const extension = extname2(path).toLowerCase();
|
|
2516
2676
|
if (!CODE_EXTENSIONS.has(extension) && !DATA_EXTENSIONS.has(extension)) throw new Error(`unsupported dependency file type ${extension}`);
|
|
2517
2677
|
stagedBytes += size;
|
|
2518
2678
|
const content = readFileSync(path);
|
|
@@ -2608,7 +2768,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2608
2768
|
if (size > MAX_FILE_BYTES || copiedBytes + size > MAX_COMPONENT_BYTES || copied.size >= MAX_COMPONENT_FILES) {
|
|
2609
2769
|
throw new Error("component migration budget exceeded");
|
|
2610
2770
|
}
|
|
2611
|
-
const publicName = `migrated-${hash(relative2(confined, path))}${
|
|
2771
|
+
const publicName = `migrated-${hash(relative2(confined, path))}${extname2(path).toLowerCase()}`;
|
|
2612
2772
|
const destination = `public/${publicName}`;
|
|
2613
2773
|
if (!copied.has(destination)) {
|
|
2614
2774
|
copied.set(destination, { path: destination, content: readFileSync(path) });
|
|
@@ -2643,7 +2803,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2643
2803
|
function transform(raw, currentFile) {
|
|
2644
2804
|
const parsedFrontmatter = parseFrontmatter(raw).content;
|
|
2645
2805
|
const frontmatter = raw.slice(0, raw.length - parsedFrontmatter.length);
|
|
2646
|
-
const content = normalizeExplicitHeadingIds(normalizeIndentedFences(normalizeHtmlComments(parsedFrontmatter)));
|
|
2806
|
+
const content = normalizeExplicitHeadingIds(normalizeIndentedFences(normalizeHtmlComments(parsedFrontmatter)), void 0, { keepIdComments: true });
|
|
2647
2807
|
let tree;
|
|
2648
2808
|
try {
|
|
2649
2809
|
tree = parser.parse(content);
|
|
@@ -2761,7 +2921,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2761
2921
|
}
|
|
2762
2922
|
continue;
|
|
2763
2923
|
}
|
|
2764
|
-
if (bindings.length && RESCUABLE_ASSET_EXTENSIONS.has(
|
|
2924
|
+
if (bindings.length && RESCUABLE_ASSET_EXTENSIONS.has(extname2(specifier).toLowerCase()) && !bindings.some((binding) => usedAsJsxTagName(binding.local))) {
|
|
2765
2925
|
try {
|
|
2766
2926
|
const href = copyPublicAsset(resolveDependency(specifier, currentFile));
|
|
2767
2927
|
edits.push({
|
|
@@ -2792,7 +2952,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2792
2952
|
try {
|
|
2793
2953
|
const sourcePath = resolveDependency(specifier, currentFile);
|
|
2794
2954
|
const path = copyGraph(sourcePath);
|
|
2795
|
-
const isSvgUsedAsTag =
|
|
2955
|
+
const isSvgUsedAsTag = extname2(path).toLowerCase() === ".svg" && bindings.some((binding) => usedAsJsxTagName(binding.local));
|
|
2796
2956
|
for (const binding of bindings) {
|
|
2797
2957
|
const registerPath = isSvgUsedAsTag ? wrapSvgAsComponent(path) : path;
|
|
2798
2958
|
const registerImported = isSvgUsedAsTag ? "default" : binding.imported;
|
|
@@ -2831,7 +2991,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2831
2991
|
const importStart = node.position.start.offset + statement.getStart(ast);
|
|
2832
2992
|
const importEnd = node.position.start.offset + statement.end;
|
|
2833
2993
|
let rescuedAssetHref;
|
|
2834
|
-
if (RESCUABLE_ASSET_EXTENSIONS.has(
|
|
2994
|
+
if (RESCUABLE_ASSET_EXTENSIONS.has(extname2(specifier).toLowerCase())) {
|
|
2835
2995
|
const usedAsJsxTag = bindings.some((binding) => hasExpressionReference(/* @__PURE__ */ new Set([binding.local]), { includeDirectTags: true }));
|
|
2836
2996
|
if (!usedAsJsxTag) {
|
|
2837
2997
|
try {
|
|
@@ -3206,6 +3366,21 @@ function withoutFencedCode(content) {
|
|
|
3206
3366
|
return line;
|
|
3207
3367
|
}).join("\n");
|
|
3208
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
|
+
}
|
|
3209
3384
|
function authoredStyleNames(contents) {
|
|
3210
3385
|
const classes = /* @__PURE__ */ new Set();
|
|
3211
3386
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -3295,89 +3470,6 @@ import { parse as parseYaml2 } from "yaml";
|
|
|
3295
3470
|
// src/navigation.ts
|
|
3296
3471
|
import { existsSync as existsSync2, lstatSync as lstatSync2, readFileSync as readFileSync2, realpathSync } from "fs";
|
|
3297
3472
|
import { dirname as dirname2, extname as extname3, relative as relative3 } from "path";
|
|
3298
|
-
|
|
3299
|
-
// src/mintlify-extras.ts
|
|
3300
|
-
import { extname as extname2 } from "path";
|
|
3301
|
-
function objectValue(value) {
|
|
3302
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
3303
|
-
}
|
|
3304
|
-
var PUBLIC_FALSE_STRINGS = /* @__PURE__ */ new Set(["false", "no", "off", "0"]);
|
|
3305
|
-
function isPublicFalse(value) {
|
|
3306
|
-
return value === false || value === 0 || typeof value === "string" && PUBLIC_FALSE_STRINGS.has(value.trim().toLowerCase());
|
|
3307
|
-
}
|
|
3308
|
-
function isPublicTrue(value) {
|
|
3309
|
-
return value === true || typeof value === "string" && value.trim().toLowerCase() === "true";
|
|
3310
|
-
}
|
|
3311
|
-
function frontmatterGateReason(data) {
|
|
3312
|
-
const groups = data.groups;
|
|
3313
|
-
const hasGroups = Array.isArray(groups) ? groups.length > 0 : typeof groups === "string" ? groups.trim() !== "" : groups !== void 0 && groups !== null && groups !== false;
|
|
3314
|
-
if (hasGroups) return "frontmatter `groups` restricts it to authenticated groups";
|
|
3315
|
-
if (isPublicFalse(data.public)) return "frontmatter `public: false`";
|
|
3316
|
-
return void 0;
|
|
3317
|
-
}
|
|
3318
|
-
function navigationGateReason(node) {
|
|
3319
|
-
const groups = node.groups;
|
|
3320
|
-
const isContainer = (entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) && ["group", "pages", "tab", "groups", "page", "root", "menu", "href"].some((key) => key in entry);
|
|
3321
|
-
const restricted = typeof groups === "string" ? groups.trim() !== "" : Array.isArray(groups) && groups.length > 0 && !groups.every(isContainer);
|
|
3322
|
-
if (restricted) return "its navigation container sets `groups`";
|
|
3323
|
-
if (isPublicFalse(node.public)) return "its navigation container sets `public: false`";
|
|
3324
|
-
return void 0;
|
|
3325
|
-
}
|
|
3326
|
-
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;
|
|
3327
|
-
var BUILD_OUTPUT_SEGMENTS = /* @__PURE__ */ new Set(["dist", "build", "coverage"]);
|
|
3328
|
-
var FONT_EXTENSIONS = /* @__PURE__ */ new Set([".woff", ".woff2", ".ttf", ".otf"]);
|
|
3329
|
-
function isMintlifyServedScriptOrStyle(relativePath) {
|
|
3330
|
-
const extension = extname2(relativePath).toLowerCase();
|
|
3331
|
-
if (extension !== ".css" && extension !== ".js") return false;
|
|
3332
|
-
const segments = relativePath.split("/");
|
|
3333
|
-
if (segments.slice(0, -1).some((segment) => BUILD_OUTPUT_SEGMENTS.has(segment.toLowerCase()))) return false;
|
|
3334
|
-
return extension === ".css" || !CONFIG_BASENAME.test(segments[segments.length - 1]);
|
|
3335
|
-
}
|
|
3336
|
-
function mintlifyFontSources(config) {
|
|
3337
|
-
const fonts = objectValue(config?.fonts);
|
|
3338
|
-
if (!fonts) return [];
|
|
3339
|
-
const found = [];
|
|
3340
|
-
for (const entry of [fonts, objectValue(fonts.heading), objectValue(fonts.body)]) {
|
|
3341
|
-
if (!entry || typeof entry.source !== "string" || !entry.source.trim()) continue;
|
|
3342
|
-
const source = entry.source.trim();
|
|
3343
|
-
const family = typeof entry.family === "string" ? entry.family : "a font";
|
|
3344
|
-
const remote = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(source);
|
|
3345
|
-
const path = remote || /^[a-z]:[\\/]/i.test(source) ? null : normalizeAssetPath(source);
|
|
3346
|
-
found.push({ family, source, path: path && FONT_EXTENSIONS.has(extname2(path).toLowerCase()) ? path : null, remote });
|
|
3347
|
-
}
|
|
3348
|
-
return found;
|
|
3349
|
-
}
|
|
3350
|
-
function mintlifyAppearance(config, warnings) {
|
|
3351
|
-
const appearance = objectValue(config.appearance);
|
|
3352
|
-
const legacy = objectValue(config.modeToggle);
|
|
3353
|
-
const result = {};
|
|
3354
|
-
const isMode = (value) => value === "system" || value === "light" || value === "dark";
|
|
3355
|
-
const skip = (field, value) => {
|
|
3356
|
-
warnings.push({
|
|
3357
|
-
code: "unsupported-config",
|
|
3358
|
-
message: `Ignored invalid ${field} value ${JSON.stringify(value)?.slice(0, 40)}; the appearance default was left unchanged.`
|
|
3359
|
-
});
|
|
3360
|
-
};
|
|
3361
|
-
if (appearance?.default !== void 0) {
|
|
3362
|
-
if (isMode(appearance.default)) result.default = appearance.default;
|
|
3363
|
-
else skip("appearance.default", appearance.default);
|
|
3364
|
-
} else if (legacy?.default !== void 0) {
|
|
3365
|
-
if (isMode(legacy.default)) result.default = legacy.default;
|
|
3366
|
-
else skip("modeToggle.default", legacy.default);
|
|
3367
|
-
}
|
|
3368
|
-
if (appearance?.strict !== void 0) {
|
|
3369
|
-
if (typeof appearance.strict === "boolean") {
|
|
3370
|
-
if (appearance.strict) result.showToggle = false;
|
|
3371
|
-
} else skip("appearance.strict", appearance.strict);
|
|
3372
|
-
} else if (legacy?.isHidden !== void 0) {
|
|
3373
|
-
if (typeof legacy.isHidden === "boolean") {
|
|
3374
|
-
if (legacy.isHidden) result.showToggle = false;
|
|
3375
|
-
} else skip("modeToggle.isHidden", legacy.isHidden);
|
|
3376
|
-
}
|
|
3377
|
-
return result;
|
|
3378
|
-
}
|
|
3379
|
-
|
|
3380
|
-
// src/navigation.ts
|
|
3381
3473
|
var MAX_MINTLIFY_CONFIG_BYTES = 2e7;
|
|
3382
3474
|
function addMintlifyDirectoryRedirects(config, pages) {
|
|
3383
3475
|
const pageIds = new Set(pages.map((page) => page.id));
|
|
@@ -3448,34 +3540,37 @@ function addMintlifyHomepageRedirects(config, pages) {
|
|
|
3448
3540
|
}
|
|
3449
3541
|
}
|
|
3450
3542
|
const homepage = config.tabs.filter((tab) => !tab.hidden).map((tab) => firstPage([...tab.pages ?? [], ...tab.groups ?? []])).find(Boolean);
|
|
3451
|
-
if (!homepage
|
|
3543
|
+
if (!homepage) return config;
|
|
3452
3544
|
const redirects = [...config.redirects ?? []];
|
|
3453
3545
|
const sources = new Set(redirects.map((redirect) => redirect.source.replace(/\/$/, "") || "/"));
|
|
3454
|
-
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)];
|
|
3455
3547
|
for (const locale of roots) {
|
|
3456
3548
|
const source = locale ? `/${locale}` : "/";
|
|
3457
3549
|
if (sources.has(source)) continue;
|
|
3458
|
-
redirects.push({ source, destination: `${locale ? `/${locale}` : ""}/${homepage}`, permanent:
|
|
3550
|
+
redirects.push({ source, destination: `${locale ? `/${locale}` : ""}/${homepage}`, permanent: true });
|
|
3459
3551
|
}
|
|
3460
3552
|
return { ...config, redirects };
|
|
3461
3553
|
}
|
|
3462
3554
|
var LANGUAGE_LABELS = {
|
|
3463
|
-
ar: "
|
|
3464
|
-
de: "
|
|
3555
|
+
ar: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629",
|
|
3556
|
+
de: "Deutsch",
|
|
3465
3557
|
en: "English",
|
|
3466
|
-
es: "
|
|
3467
|
-
fr: "
|
|
3468
|
-
hi: "
|
|
3469
|
-
it: "
|
|
3470
|
-
ja: "
|
|
3471
|
-
ko: "
|
|
3472
|
-
nl: "
|
|
3473
|
-
pl: "
|
|
3474
|
-
pt: "
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
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"
|
|
3479
3574
|
};
|
|
3480
3575
|
function objectValue2(value) {
|
|
3481
3576
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -3940,11 +4035,26 @@ function convertContainerToTabs(containerValue, context, fallbackTab, trace, dep
|
|
|
3940
4035
|
}] : [];
|
|
3941
4036
|
}
|
|
3942
4037
|
function projectedTheme(value) {
|
|
3943
|
-
if (value === "maple") return "maple";
|
|
3944
|
-
if (["
|
|
4038
|
+
if (value === "maple" || value === "aspen") return "maple";
|
|
4039
|
+
if (["luma", "sequoia"].includes(String(value))) return "sharp";
|
|
3945
4040
|
if (["almond", "palm"].includes(String(value))) return "minimal";
|
|
3946
4041
|
return typeof value === "string" ? "default" : void 0;
|
|
3947
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
|
+
}
|
|
3948
4058
|
function projectedNavbar(value) {
|
|
3949
4059
|
const navbar = objectValue2(value);
|
|
3950
4060
|
if (!navbar) return void 0;
|
|
@@ -3960,7 +4070,8 @@ function projectedNavbar(value) {
|
|
|
3960
4070
|
const primaryHref = projectedHref(primaryValue?.href);
|
|
3961
4071
|
const primary = primaryValue && primaryHref ? {
|
|
3962
4072
|
label: typeof primaryValue.label === "string" ? primaryValue.label : primaryValue.type === "github" ? "GitHub" : "Get started",
|
|
3963
|
-
href: primaryHref
|
|
4073
|
+
href: primaryHref,
|
|
4074
|
+
...primaryValue.type === "github" ? { type: "github" } : {}
|
|
3964
4075
|
} : void 0;
|
|
3965
4076
|
return links.length > 0 || primary ? { ...links.length > 0 ? { links } : {}, ...primary ? { primary } : {} } : void 0;
|
|
3966
4077
|
}
|
|
@@ -4040,8 +4151,16 @@ function projectedCompatibleConfig(config, warnings) {
|
|
|
4040
4151
|
const headingFont = projectedFont(objectValue2(config.fonts)?.heading);
|
|
4041
4152
|
const feedback = objectValue2(config.feedback);
|
|
4042
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;
|
|
4043
4162
|
const iconLibrary = objectValue2(config.icons)?.library;
|
|
4044
|
-
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;
|
|
4045
4164
|
const docsNavbar = projectedNavbar(config.navbar);
|
|
4046
4165
|
const legacyRaw = legacyTopbarNavbar(config);
|
|
4047
4166
|
const legacyNavbar = projectedNavbar(legacyRaw);
|
|
@@ -4069,6 +4188,8 @@ function projectedCompatibleConfig(config, warnings) {
|
|
|
4069
4188
|
const projectedNavigation = navbarLinks.length > 0 || navbar?.primary ? { ...navbarLinks.length > 0 ? { links: navbarLinks } : {}, ...navbar?.primary ? { primary: navbar.primary } : {} } : void 0;
|
|
4070
4189
|
return {
|
|
4071
4190
|
...projectedTheme(config.theme) ? { theme: projectedTheme(config.theme) } : {},
|
|
4191
|
+
...projectedContextual.length > 0 ? { contextual: { options: projectedContextual } } : {},
|
|
4192
|
+
...projectedColors(config.colors) ? { colors: projectedColors(config.colors) } : {},
|
|
4072
4193
|
...projectedIconLibrary ? { icons: { library: projectedIconLibrary } } : {},
|
|
4073
4194
|
...bannerContent ? {
|
|
4074
4195
|
banner: {
|
|
@@ -4086,10 +4207,19 @@ function projectedCompatibleConfig(config, warnings) {
|
|
|
4086
4207
|
...projectedNavigation ? { navbar: projectedNavigation } : {},
|
|
4087
4208
|
...projectedFooter(config.footer) ? { footer: projectedFooter(config.footer) } : {},
|
|
4088
4209
|
...bodyFont || headingFont ? { fonts: { ...bodyFont ? { body: bodyFont } : {}, ...headingFont ? { heading: headingFont } : {} } } : {},
|
|
4089
|
-
|
|
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 } : {} },
|
|
4090
4213
|
...typeof feedback?.thumbsRating === "boolean" ? { feedback: { thumbsRating: feedback.thumbsRating } } : {}
|
|
4091
4214
|
};
|
|
4092
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
|
+
}
|
|
4093
4223
|
function projectedApiMdx(config, warnings) {
|
|
4094
4224
|
const mdx = objectValue2(objectValue2(config.api)?.mdx);
|
|
4095
4225
|
if (!mdx) return {};
|
|
@@ -4319,7 +4449,7 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
4319
4449
|
if (!landing) return [];
|
|
4320
4450
|
const firstSegment = landing.split("/")[0];
|
|
4321
4451
|
const prefix = firstSegment === label ? label : "";
|
|
4322
|
-
return [{ label, prefix, href: `/${landing}`, ...entry === defaultVersion ? { default: true } : {} }];
|
|
4452
|
+
return [{ label, prefix, href: `/${landing}`, ...entry === defaultVersion ? { default: true } : {}, ...entry.hidden === true ? { hidden: true } : {} }];
|
|
4323
4453
|
}) : [];
|
|
4324
4454
|
if (versions.length > 1) {
|
|
4325
4455
|
tabs = annotateVersions(tabs);
|
|
@@ -4355,7 +4485,7 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
4355
4485
|
...shortcuts.length > 0 ? { shortcuts } : {}
|
|
4356
4486
|
} } : {},
|
|
4357
4487
|
...projectedCompatibleConfig(config, warnings),
|
|
4358
|
-
...
|
|
4488
|
+
...projectedApi(config, warnings),
|
|
4359
4489
|
...i18n ? { i18n } : {},
|
|
4360
4490
|
...redirects.length > 0 ? { redirects } : {}
|
|
4361
4491
|
},
|
|
@@ -7004,12 +7134,22 @@ function mintlifyTopLevelApiReferences(config) {
|
|
|
7004
7134
|
}
|
|
7005
7135
|
return references;
|
|
7006
7136
|
}
|
|
7007
|
-
function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs) {
|
|
7137
|
+
function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, pages = []) {
|
|
7008
7138
|
if (!mintlifyConfig) return [];
|
|
7009
7139
|
const references = [
|
|
7010
7140
|
...mintlifyTopLevelApiReferences(mintlifyConfig),
|
|
7011
7141
|
...mintlifyNavigationApiReferences(mintlifyConfig)
|
|
7012
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
|
+
}
|
|
7013
7153
|
const seen = /* @__PURE__ */ new Set();
|
|
7014
7154
|
const specs = [];
|
|
7015
7155
|
for (const reference of references) {
|
|
@@ -7059,6 +7199,7 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs) {
|
|
|
7059
7199
|
parentTab: reference.parentTab,
|
|
7060
7200
|
icon: reference.icon,
|
|
7061
7201
|
hidden: reference.hidden,
|
|
7202
|
+
...reference.pageOnly ? { pageOnly: true } : {},
|
|
7062
7203
|
sourcePath: match.relativePath,
|
|
7063
7204
|
directory: reference.directory
|
|
7064
7205
|
});
|
|
@@ -7568,11 +7709,12 @@ function preserveLinkedAnchors(pages) {
|
|
|
7568
7709
|
const tableCell = line.match(/^ {0,3}\|\s*([^|]+?)\s*\|/);
|
|
7569
7710
|
if (tableCell && !/^[:\s-]+$/.test(tableCell[1])) tableCells.push({ index, text: tableCell[1] });
|
|
7570
7711
|
const match = line.match(/^ {0,3}#{1,6}\s+(.+?)\s*#*\s*$/);
|
|
7571
|
-
return match ? { index, text: match[1] } : null;
|
|
7712
|
+
return match ? { index, text: match[1].replace(/\s*\{\/\*\s*#\S+?\s*\*\/\}$/, "") } : null;
|
|
7572
7713
|
}).filter((entry) => entry !== null);
|
|
7573
7714
|
const existing = /* @__PURE__ */ new Set();
|
|
7574
7715
|
replaceOutsideCode(page.body, (text2) => {
|
|
7575
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]);
|
|
7576
7718
|
return text2;
|
|
7577
7719
|
});
|
|
7578
7720
|
const candidateIndexes = /* @__PURE__ */ new Map();
|
|
@@ -7715,7 +7857,11 @@ function repositoryAssetHref(value, currentFile, siteRoot, onReferenced) {
|
|
|
7715
7857
|
}
|
|
7716
7858
|
if (!ASSET_EXTENSIONS.has(extname6(decodedPath).toLowerCase())) return null;
|
|
7717
7859
|
try {
|
|
7718
|
-
|
|
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
|
+
}
|
|
7719
7865
|
const realRoot = realpathSync2(siteRoot);
|
|
7720
7866
|
const realCandidate = realpathSync2(candidate);
|
|
7721
7867
|
const realRelative = relative5(realRoot, realCandidate);
|
|
@@ -8469,7 +8615,11 @@ function migrateRepository(options) {
|
|
|
8469
8615
|
const publishedText = trackPublishedRefs ? raw : void 0;
|
|
8470
8616
|
const pageAssetReferences = [];
|
|
8471
8617
|
if (platform === "fern" || platform === "mintlify" || platform === "docusaurus") {
|
|
8472
|
-
raw = normalizeExplicitHeadingIds(
|
|
8618
|
+
raw = normalizeExplicitHeadingIds(
|
|
8619
|
+
raw,
|
|
8620
|
+
(message) => warnings.push({ code: "invalid-page", message, source: file.relativePath }),
|
|
8621
|
+
{ headingMarkers: platform === "mintlify" }
|
|
8622
|
+
);
|
|
8473
8623
|
}
|
|
8474
8624
|
if (componentMigrator) {
|
|
8475
8625
|
const warningsBeforeTransform = warnings.length;
|
|
@@ -8703,15 +8853,19 @@ function migrateRepository(options) {
|
|
|
8703
8853
|
const rootStylesheetPath = platform === "mintlify" && mintlifyProjectRoot ? resolveWithin(mintlifyProjectRoot, "style.css") : void 0;
|
|
8704
8854
|
const hasRootStylesheet = Boolean(rootStylesheetPath && existsSync5(rootStylesheetPath) && lstatSync5(rootStylesheetPath).isFile() && !lstatSync5(rootStylesheetPath).isSymbolicLink());
|
|
8705
8855
|
let rootStyleProjection;
|
|
8856
|
+
let rootNavbarButtons = [];
|
|
8706
8857
|
let rootStyleProblem;
|
|
8707
8858
|
if (hasRootStylesheet && rootStylesheetPath && lstatSync5(rootStylesheetPath).size <= MAX_ASSET_BYTES) {
|
|
8708
8859
|
const css = readFileSync5(rootStylesheetPath, "utf8");
|
|
8709
8860
|
if (/@import\b|url\s*\(\s*['"]?\s*(?:javascript:|file:)/i.test(css)) rootStyleProblem = "unsafe";
|
|
8710
8861
|
else {
|
|
8711
8862
|
try {
|
|
8863
|
+
rootNavbarButtons = navbarLinkButtons(css);
|
|
8712
8864
|
rootStyleProjection = projectAuthoredStyles(css, [
|
|
8713
8865
|
...pages.map((page) => page.body),
|
|
8714
|
-
...(componentMigrator?.files() ?? []).map((file) => typeof file.content === "string" ? file.content : "")
|
|
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"))
|
|
8715
8869
|
]);
|
|
8716
8870
|
} catch {
|
|
8717
8871
|
rootStyleProblem = "parse";
|
|
@@ -8849,6 +9003,18 @@ function migrateRepository(options) {
|
|
|
8849
9003
|
} else if (rootStyleProblem === "parse" || !rootStyleProjection) {
|
|
8850
9004
|
warnings.push({ code: "unsupported-config", message: "Mintlify root style.css could not be parsed and was not imported.", source: "style.css" });
|
|
8851
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
|
+
}
|
|
8852
9018
|
if (rootStyleProjection.omittedSelectors > 0) warnings.push({
|
|
8853
9019
|
code: "unsupported-config",
|
|
8854
9020
|
source: "style.css",
|
|
@@ -8999,7 +9165,9 @@ function migrateRepository(options) {
|
|
|
8999
9165
|
source: path
|
|
9000
9166
|
});
|
|
9001
9167
|
};
|
|
9002
|
-
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);
|
|
9003
9171
|
for (const spec of resolvedSpecs) {
|
|
9004
9172
|
if (!assets.some((asset) => asset.path === specAssetPath(spec.filename))) {
|
|
9005
9173
|
assets.push(specAsset(spec.filename, spec.content));
|
|
@@ -9032,6 +9200,14 @@ function migrateRepository(options) {
|
|
|
9032
9200
|
}
|
|
9033
9201
|
}
|
|
9034
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
|
+
}
|
|
9035
9211
|
rewriteMintlifyPageSpecRefs(pages, pageSpecs, new Set(remoteApiSpecs.map((spec) => spec.url)), warnings);
|
|
9036
9212
|
}
|
|
9037
9213
|
if (platform === "mintlify") {
|
|
@@ -9447,6 +9623,8 @@ function renderPage(bundle, page) {
|
|
|
9447
9623
|
"---",
|
|
9448
9624
|
`title: ${yamlString(page.title)}`,
|
|
9449
9625
|
page.navTitle ? `navTitle: ${yamlString(page.navTitle)}` : null,
|
|
9626
|
+
page.icon ? `icon: ${yamlString(page.icon)}` : null,
|
|
9627
|
+
page.iconType ? `iconType: ${yamlString(page.iconType)}` : null,
|
|
9450
9628
|
`description: ${yamlString(page.description)}`,
|
|
9451
9629
|
page.descriptionPlacement === "body" ? "descriptionPlacement: body" : null,
|
|
9452
9630
|
page.badge ? `badge: ${yamlString(page.badge)}` : null,
|
|
@@ -9454,9 +9632,11 @@ function renderPage(bundle, page) {
|
|
|
9454
9632
|
page.mode ? `mode: ${yamlString(page.mode)}` : null,
|
|
9455
9633
|
page.hidden ? "hidden: true" : null,
|
|
9456
9634
|
page.noindex ? "noindex: true" : null,
|
|
9635
|
+
...Object.entries(page.meta ?? {}).map(([field, value]) => `${field}: ${yamlString(value)}`),
|
|
9457
9636
|
page.openapi ? `openapi: ${yamlString(page.openapi)}` : null,
|
|
9458
9637
|
page.api ? `api: ${yamlString(page.api)}` : null,
|
|
9459
9638
|
page.authMethod ? `authMethod: ${yamlString(page.authMethod)}` : null,
|
|
9639
|
+
page.playground ? `playground: ${yamlString(page.playground)}` : null,
|
|
9460
9640
|
bundle.sourceKind === "url" ? `source: ${yamlString(page.source)}` : null,
|
|
9461
9641
|
"---",
|
|
9462
9642
|
"",
|