@thallylabs/migrate 0.2.22 → 0.2.24
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 +40 -7
- package/dist/index.js +539 -238
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16,13 +16,13 @@ import {
|
|
|
16
16
|
} from "fs";
|
|
17
17
|
import { createRequire } from "module";
|
|
18
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";
|
|
19
|
-
import { parse as
|
|
19
|
+
import { parse as parseYaml5 } from "yaml";
|
|
20
20
|
import * as ts4 from "typescript";
|
|
21
21
|
|
|
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" requires reader sign-in, which Thally does not support. Migrated as "simple" (no Try it). Set it to "interactive" to allow everyone.`);
|
|
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
|
-
warn?.(`Heading anchor {#${id}} is not a valid HTML id and was removed from "${heading.replace(/^\s*#+\s*/, "")}".`);
|
|
454
|
+
warn?.(`Heading anchor {#${id}} ${options.headingMarkers ? 'contains whitespace or "*/"' : "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(/\{\/\*[\s\S]*?\*\/\}/g, " ").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,35 @@ 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, warnings) {
|
|
4044
|
+
const colors = objectValue2(value);
|
|
4045
|
+
if (!colors) {
|
|
4046
|
+
if (value !== void 0) warnings.push({ code: "unsupported-config", message: "colors is not an object with a primary hex colour and was dropped.", source: "docs.json" });
|
|
4047
|
+
return void 0;
|
|
4048
|
+
}
|
|
4049
|
+
const hex = (entry, key) => {
|
|
4050
|
+
const match = typeof entry === "string" ? /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(entry.trim()) : null;
|
|
4051
|
+
if (!match) {
|
|
4052
|
+
if (entry !== void 0) warnings.push({ code: "unsupported-config", message: `colors.${key} ${JSON.stringify(entry)} is not a 3- or 6-digit hex colour (for example #16a34a) and was dropped.`, source: "docs.json" });
|
|
4053
|
+
return void 0;
|
|
4054
|
+
}
|
|
4055
|
+
const digits = match[1].length === 3 ? [...match[1]].map((digit) => digit + digit).join("") : match[1];
|
|
4056
|
+
return `#${digits.toLowerCase()}`;
|
|
4057
|
+
};
|
|
4058
|
+
const primary = hex(colors.primary, "primary");
|
|
4059
|
+
const light = hex(colors.light, "light") ?? primary;
|
|
4060
|
+
const dark = hex(colors.dark, "dark") ?? primary;
|
|
4061
|
+
if (!primary) {
|
|
4062
|
+
if (colors.primary === void 0) warnings.push({ code: "unsupported-config", message: "colors has no primary hex colour, so none of its colours were migrated.", source: "docs.json" });
|
|
4063
|
+
return void 0;
|
|
4064
|
+
}
|
|
4065
|
+
return { light: { accent: primary, primary: dark ?? primary }, dark: { accent: light ?? primary, primary: light ?? primary } };
|
|
4066
|
+
}
|
|
3948
4067
|
function projectedNavbar(value) {
|
|
3949
4068
|
const navbar = objectValue2(value);
|
|
3950
4069
|
if (!navbar) return void 0;
|
|
@@ -3960,7 +4079,8 @@ function projectedNavbar(value) {
|
|
|
3960
4079
|
const primaryHref = projectedHref(primaryValue?.href);
|
|
3961
4080
|
const primary = primaryValue && primaryHref ? {
|
|
3962
4081
|
label: typeof primaryValue.label === "string" ? primaryValue.label : primaryValue.type === "github" ? "GitHub" : "Get started",
|
|
3963
|
-
href: primaryHref
|
|
4082
|
+
href: primaryHref,
|
|
4083
|
+
...primaryValue.type === "github" ? { type: "github" } : {}
|
|
3964
4084
|
} : void 0;
|
|
3965
4085
|
return links.length > 0 || primary ? { ...links.length > 0 ? { links } : {}, ...primary ? { primary } : {} } : void 0;
|
|
3966
4086
|
}
|
|
@@ -4040,8 +4160,24 @@ function projectedCompatibleConfig(config, warnings) {
|
|
|
4040
4160
|
const headingFont = projectedFont(objectValue2(config.fonts)?.heading);
|
|
4041
4161
|
const feedback = objectValue2(config.feedback);
|
|
4042
4162
|
const seo = objectValue2(config.seo);
|
|
4163
|
+
const contextualOptions = Array.isArray(objectValue2(config.contextual)?.options) ? objectValue2(config.contextual).options : [];
|
|
4164
|
+
const projectedContextual = contextualOptions.filter((option) => typeof option === "string" && ["copy", "view", "chatgpt", "claude", "perplexity"].includes(option));
|
|
4165
|
+
const droppedContextual = contextualOptions.filter((option) => !projectedContextual.includes(option));
|
|
4166
|
+
if (droppedContextual.length > 0) {
|
|
4167
|
+
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" });
|
|
4168
|
+
}
|
|
4169
|
+
const rawMetatags = Object.entries(objectValue2(seo?.metatags) ?? {});
|
|
4170
|
+
const httpEquivNames = /* @__PURE__ */ new Set(["refresh", "set-cookie", "location", "content-security-policy", "content-security-policy-report-only", "content-type", "default-style", "x-ua-compatible"]);
|
|
4171
|
+
const validMetatag = (entry) => /^[\w:.-]+$/.test(entry[0]) && !entry[0].toLowerCase().startsWith("http-equiv") && !httpEquivNames.has(entry[0].toLowerCase()) && typeof entry[1] === "string" && entry[1].length <= 1e3 && ![...entry[1]].some((character) => character.charCodeAt(0) < 32);
|
|
4172
|
+
const metatagEntries = rawMetatags.filter(validMetatag);
|
|
4173
|
+
const droppedMetatags = rawMetatags.filter((entry) => !validMetatag(entry)).map(([key]) => key);
|
|
4174
|
+
if (droppedMetatags.length > 0) {
|
|
4175
|
+
warnings.push({ code: "unsupported-config", message: `seo.metatags entries were dropped because the name is not a plain meta name, is an http-equiv directive, or the value is not a string of at most 1000 characters: ${droppedMetatags.join(", ")}.`, source: "docs.json" });
|
|
4176
|
+
}
|
|
4177
|
+
const projectedMetatags = metatagEntries.length > 0 ? Object.fromEntries(metatagEntries) : void 0;
|
|
4178
|
+
const projectedColorsValue = projectedColors(config.colors, warnings);
|
|
4043
4179
|
const iconLibrary = objectValue2(config.icons)?.library;
|
|
4044
|
-
const projectedIconLibrary = ["lucide", "fontawesome", "tabler"].includes(String(iconLibrary)) ? String(iconLibrary) : void 0;
|
|
4180
|
+
const projectedIconLibrary = iconLibrary === void 0 ? "fontawesome" : ["lucide", "fontawesome", "tabler"].includes(String(iconLibrary)) ? String(iconLibrary) : void 0;
|
|
4045
4181
|
const docsNavbar = projectedNavbar(config.navbar);
|
|
4046
4182
|
const legacyRaw = legacyTopbarNavbar(config);
|
|
4047
4183
|
const legacyNavbar = projectedNavbar(legacyRaw);
|
|
@@ -4069,6 +4205,8 @@ function projectedCompatibleConfig(config, warnings) {
|
|
|
4069
4205
|
const projectedNavigation = navbarLinks.length > 0 || navbar?.primary ? { ...navbarLinks.length > 0 ? { links: navbarLinks } : {}, ...navbar?.primary ? { primary: navbar.primary } : {} } : void 0;
|
|
4070
4206
|
return {
|
|
4071
4207
|
...projectedTheme(config.theme) ? { theme: projectedTheme(config.theme) } : {},
|
|
4208
|
+
...projectedContextual.length > 0 ? { contextual: { options: projectedContextual } } : {},
|
|
4209
|
+
...projectedColorsValue ? { colors: projectedColorsValue } : {},
|
|
4072
4210
|
...projectedIconLibrary ? { icons: { library: projectedIconLibrary } } : {},
|
|
4073
4211
|
...bannerContent ? {
|
|
4074
4212
|
banner: {
|
|
@@ -4086,10 +4224,19 @@ function projectedCompatibleConfig(config, warnings) {
|
|
|
4086
4224
|
...projectedNavigation ? { navbar: projectedNavigation } : {},
|
|
4087
4225
|
...projectedFooter(config.footer) ? { footer: projectedFooter(config.footer) } : {},
|
|
4088
4226
|
...bodyFont || headingFont ? { fonts: { ...bodyFont ? { body: bodyFont } : {}, ...headingFont ? { heading: headingFont } : {} } } : {},
|
|
4089
|
-
|
|
4227
|
+
// Mintlify titles pages "<title> - <site name>" unless `og:title` overrides them,
|
|
4228
|
+
// and its sitemap lists navigation pages only.
|
|
4229
|
+
seo: { ...seo?.indexing === "all" ? { indexing: "all" } : {}, titleSeparator: " - ", sitemap: "navigable", ...projectedMetatags ? { metatags: projectedMetatags } : {} },
|
|
4090
4230
|
...typeof feedback?.thumbsRating === "boolean" ? { feedback: { thumbsRating: feedback.thumbsRating } } : {}
|
|
4091
4231
|
};
|
|
4092
4232
|
}
|
|
4233
|
+
function projectedApi(config, warnings) {
|
|
4234
|
+
const mdx = projectedApiMdx(config, warnings).api?.mdx;
|
|
4235
|
+
const raw = objectValue2(objectValue2(config.api)?.playground)?.display;
|
|
4236
|
+
const display = raw === void 0 ? void 0 : playgroundDisplay(raw, "api.playground.display", (message) => warnings.push({ code: "unsupported-config", message }));
|
|
4237
|
+
if (!mdx && !display) return {};
|
|
4238
|
+
return { api: { ...mdx ? { mdx } : {}, ...display ? { playground: { display } } : {} } };
|
|
4239
|
+
}
|
|
4093
4240
|
function projectedApiMdx(config, warnings) {
|
|
4094
4241
|
const mdx = objectValue2(objectValue2(config.api)?.mdx);
|
|
4095
4242
|
if (!mdx) return {};
|
|
@@ -4319,7 +4466,7 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
4319
4466
|
if (!landing) return [];
|
|
4320
4467
|
const firstSegment = landing.split("/")[0];
|
|
4321
4468
|
const prefix = firstSegment === label ? label : "";
|
|
4322
|
-
return [{ label, prefix, href: `/${landing}`, ...entry === defaultVersion ? { default: true } : {} }];
|
|
4469
|
+
return [{ label, prefix, href: `/${landing}`, ...entry === defaultVersion ? { default: true } : {}, ...entry.hidden === true ? { hidden: true } : {} }];
|
|
4323
4470
|
}) : [];
|
|
4324
4471
|
if (versions.length > 1) {
|
|
4325
4472
|
tabs = annotateVersions(tabs);
|
|
@@ -4355,7 +4502,7 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
4355
4502
|
...shortcuts.length > 0 ? { shortcuts } : {}
|
|
4356
4503
|
} } : {},
|
|
4357
4504
|
...projectedCompatibleConfig(config, warnings),
|
|
4358
|
-
...
|
|
4505
|
+
...projectedApi(config, warnings),
|
|
4359
4506
|
...i18n ? { i18n } : {},
|
|
4360
4507
|
...redirects.length > 0 ? { redirects } : {}
|
|
4361
4508
|
},
|
|
@@ -5945,6 +6092,68 @@ function withSpecRef(ref, specRef) {
|
|
|
5945
6092
|
return `${specRef} ${ref.operation}`;
|
|
5946
6093
|
}
|
|
5947
6094
|
|
|
6095
|
+
// src/spec-exclude.ts
|
|
6096
|
+
import { parse as parseYaml4, stringify as stringifyYaml } from "yaml";
|
|
6097
|
+
function specRefMatches(ref, specPath, specFilename, isDefault) {
|
|
6098
|
+
const prefix = /^(?:(\S+)\s+)?(?:GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS|TRACE|WEBHOOK)\s/i.exec(`${ref} `)?.[1];
|
|
6099
|
+
if (!prefix) return isDefault;
|
|
6100
|
+
const wanted = prefix.replace(/^\/+/, "").toLowerCase();
|
|
6101
|
+
const lowerPath = specPath.toLowerCase();
|
|
6102
|
+
return lowerPath === wanted || lowerPath.endsWith(`/${wanted}`) || specFilename.toLowerCase() === wanted;
|
|
6103
|
+
}
|
|
6104
|
+
function operationKey(operation) {
|
|
6105
|
+
const [first, ...rest] = operation.trim().split(/\s+/);
|
|
6106
|
+
return `${first.toLowerCase()} ${rest.join(" ")}`;
|
|
6107
|
+
}
|
|
6108
|
+
function keysFor(spec, refs) {
|
|
6109
|
+
return [...new Set(
|
|
6110
|
+
refs.filter((ref) => specRefMatches(ref, spec.sourcePath, spec.filename, true)).map((ref) => splitOpenApiRef(ref)?.operation).filter((op) => !!op).map(operationKey)
|
|
6111
|
+
)];
|
|
6112
|
+
}
|
|
6113
|
+
function withheldOperationKeys(spec, withheldRefs, keptRefs) {
|
|
6114
|
+
const kept = keysFor(spec, keptRefs);
|
|
6115
|
+
return { withheld: keysFor(spec, withheldRefs).filter((key) => !kept.includes(key)), kept };
|
|
6116
|
+
}
|
|
6117
|
+
function markExcluded(content, operationKeys, keptKeys = []) {
|
|
6118
|
+
const untouched = { content, excluded: [] };
|
|
6119
|
+
if (operationKeys.length === 0) return untouched;
|
|
6120
|
+
const text2 = content.toString("utf8");
|
|
6121
|
+
let doc;
|
|
6122
|
+
try {
|
|
6123
|
+
doc = parseYaml4(text2);
|
|
6124
|
+
} catch {
|
|
6125
|
+
return untouched;
|
|
6126
|
+
}
|
|
6127
|
+
if (!doc || typeof doc !== "object") return untouched;
|
|
6128
|
+
const excluded = [];
|
|
6129
|
+
for (const key of operationKeys) {
|
|
6130
|
+
const [method, ...rest] = key.split(" ");
|
|
6131
|
+
const name = rest.join(" ");
|
|
6132
|
+
if (method === "webhook") {
|
|
6133
|
+
const entry2 = doc.webhooks?.[name] ?? doc["x-webhooks"]?.[name];
|
|
6134
|
+
if (entry2 && typeof entry2 === "object") {
|
|
6135
|
+
entry2["x-excluded"] = true;
|
|
6136
|
+
excluded.push(`WEBHOOK ${name}`);
|
|
6137
|
+
}
|
|
6138
|
+
continue;
|
|
6139
|
+
}
|
|
6140
|
+
const entry = doc.paths?.[name];
|
|
6141
|
+
if (!entry || typeof entry !== "object") continue;
|
|
6142
|
+
const target = typeof entry.$ref === "string" ? keptKeys.some((k) => k.slice(k.indexOf(" ") + 1) === name) ? void 0 : entry : entry[method];
|
|
6143
|
+
if (target && typeof target === "object") {
|
|
6144
|
+
target["x-excluded"] = true;
|
|
6145
|
+
excluded.push(`${method.toUpperCase()} ${name}`);
|
|
6146
|
+
}
|
|
6147
|
+
}
|
|
6148
|
+
if (excluded.length === 0) return untouched;
|
|
6149
|
+
const out = text2.trimStart().startsWith("{") ? `${JSON.stringify(doc, null, 2)}
|
|
6150
|
+
` : stringifyYaml(doc);
|
|
6151
|
+
return { content: Buffer.from(out), excluded };
|
|
6152
|
+
}
|
|
6153
|
+
function sharedSpecMessage(path, excluded = []) {
|
|
6154
|
+
return excluded.length ? `OpenAPI spec ${path} is shared with access-restricted pages and is published, but ${excluded.length} operation(s) documented only on those pages were withheld from it (${excluded.join(", ")}). Review the rest of the spec before publishing.` : `OpenAPI spec ${path} is shared with access-restricted pages and is published; it may describe restricted endpoints. Review it before publishing.`;
|
|
6155
|
+
}
|
|
6156
|
+
|
|
5948
6157
|
// src/analytics.ts
|
|
5949
6158
|
var GA4_ID = /^G-[A-Z0-9]{4,20}$/;
|
|
5950
6159
|
var GTM_ID = /^GTM-[A-Z0-9]{4,12}$/;
|
|
@@ -6926,12 +7135,23 @@ function normalizedReferenceKey(value) {
|
|
|
6926
7135
|
function exactReferenceKey(value) {
|
|
6927
7136
|
return value.split(/[?#]/, 1)[0].replace(/^\/+/, "").replace(/\\/g, "/").replace(/\.(?:mdx?|rst|txt)$/i, "");
|
|
6928
7137
|
}
|
|
6929
|
-
function
|
|
6930
|
-
const
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
7138
|
+
function navigationOperationRefs(config) {
|
|
7139
|
+
const refs = [];
|
|
7140
|
+
const visit = (node) => {
|
|
7141
|
+
if (typeof node === "string") {
|
|
7142
|
+
if (splitOpenApiRef(node)) refs.push(node);
|
|
7143
|
+
} else if (Array.isArray(node)) node.forEach(visit);
|
|
7144
|
+
else if (node && typeof node === "object") {
|
|
7145
|
+
if (navigationGateReason(node)) return;
|
|
7146
|
+
Object.values(node).forEach(visit);
|
|
7147
|
+
}
|
|
7148
|
+
};
|
|
7149
|
+
visit(config?.navigation);
|
|
7150
|
+
return refs;
|
|
7151
|
+
}
|
|
7152
|
+
function excludeWithheldOperations(spec, withheldRefs, keptRefs) {
|
|
7153
|
+
const { withheld, kept } = withheldOperationKeys(spec, withheldRefs, keptRefs);
|
|
7154
|
+
return markExcluded(spec.content, withheld, kept);
|
|
6935
7155
|
}
|
|
6936
7156
|
var TOKEN_SEPARATORS = /[\s"'()<>[\]{}=,;:|\\/`*!?#&]+/;
|
|
6937
7157
|
var PATH_SEPARATORS = /[\s"'()<>[\]{}=,;:|\\`*!?#&]+/;
|
|
@@ -7004,12 +7224,22 @@ function mintlifyTopLevelApiReferences(config) {
|
|
|
7004
7224
|
}
|
|
7005
7225
|
return references;
|
|
7006
7226
|
}
|
|
7007
|
-
function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs) {
|
|
7227
|
+
function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs, pages = []) {
|
|
7008
7228
|
if (!mintlifyConfig) return [];
|
|
7009
7229
|
const references = [
|
|
7010
7230
|
...mintlifyTopLevelApiReferences(mintlifyConfig),
|
|
7011
7231
|
...mintlifyNavigationApiReferences(mintlifyConfig)
|
|
7012
7232
|
];
|
|
7233
|
+
const specKey = (value) => value.split(/[?#]/, 1)[0].replace(/\\/g, "/").replace(/^(?:\.\/)+/, "").replace(/^\/+/, "");
|
|
7234
|
+
const known = new Set(references.map((reference) => specKey(reference.value)));
|
|
7235
|
+
for (const page of pages) {
|
|
7236
|
+
const specRef = page.openapi ? splitOpenApiRef(page.openapi)?.specRef : void 0;
|
|
7237
|
+
if (!specRef || /^[a-z][a-z0-9+.-]*:/i.test(specRef)) continue;
|
|
7238
|
+
const key = specKey(specRef);
|
|
7239
|
+
if (known.has(key) || !files.some((file) => file.relativePath === key)) continue;
|
|
7240
|
+
known.add(key);
|
|
7241
|
+
references.push({ value: key, kind: "openapi", tabLabel: `OpenAPI: ${key}`, hidden: true, pageOnly: true });
|
|
7242
|
+
}
|
|
7013
7243
|
const seen = /* @__PURE__ */ new Set();
|
|
7014
7244
|
const specs = [];
|
|
7015
7245
|
for (const reference of references) {
|
|
@@ -7059,6 +7289,7 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs) {
|
|
|
7059
7289
|
parentTab: reference.parentTab,
|
|
7060
7290
|
icon: reference.icon,
|
|
7061
7291
|
hidden: reference.hidden,
|
|
7292
|
+
...reference.pageOnly ? { pageOnly: true } : {},
|
|
7062
7293
|
sourcePath: match.relativePath,
|
|
7063
7294
|
directory: reference.directory
|
|
7064
7295
|
});
|
|
@@ -7080,7 +7311,7 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs) {
|
|
|
7080
7311
|
}
|
|
7081
7312
|
return specs;
|
|
7082
7313
|
}
|
|
7083
|
-
function rewriteMintlifyPageSpecRefs(pages, specs, remoteUrls, warnings) {
|
|
7314
|
+
function rewriteMintlifyPageSpecRefs(pages, specs, remoteUrls, warnings, explainMissing = () => "no such file was found") {
|
|
7084
7315
|
for (const page of pages) {
|
|
7085
7316
|
const ref = page.openapi ? splitOpenApiRef(page.openapi) : null;
|
|
7086
7317
|
if (!ref?.specRef) continue;
|
|
@@ -7097,7 +7328,7 @@ function rewriteMintlifyPageSpecRefs(pages, specs, remoteUrls, warnings) {
|
|
|
7097
7328
|
if (match) {
|
|
7098
7329
|
page.openapi = withSpecRef(ref, specAssetPath(match.filename));
|
|
7099
7330
|
} else {
|
|
7100
|
-
warnings.push({ code: "unsupported-config", message: `Page "${page.id}" references the OpenAPI spec "${ref.specRef}", which
|
|
7331
|
+
warnings.push({ code: "unsupported-config", message: `Page "${page.id}" references the OpenAPI spec "${ref.specRef}", which was not migrated (${explainMissing(key)}); the page will not render an endpoint.`, source: page.source });
|
|
7101
7332
|
}
|
|
7102
7333
|
}
|
|
7103
7334
|
}
|
|
@@ -7122,7 +7353,7 @@ function slugifyApiSpecId(value) {
|
|
|
7122
7353
|
function parseOpenApiOperationsForLinking(content) {
|
|
7123
7354
|
let document;
|
|
7124
7355
|
try {
|
|
7125
|
-
document =
|
|
7356
|
+
document = parseYaml5(content.toString("utf8"));
|
|
7126
7357
|
} catch {
|
|
7127
7358
|
return [];
|
|
7128
7359
|
}
|
|
@@ -7254,7 +7485,7 @@ function fernGeneratorsUnsupportedSpecPaths(config) {
|
|
|
7254
7485
|
}
|
|
7255
7486
|
function readFernGeneratorsConfig(path) {
|
|
7256
7487
|
if (!existsSync5(path) || !lstatSync5(path).isFile() || lstatSync5(path).size > MAX_FERN_GENERATORS_BYTES) return null;
|
|
7257
|
-
const parsed =
|
|
7488
|
+
const parsed = parseYaml5(readFileSync5(path, "utf8"));
|
|
7258
7489
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
7259
7490
|
}
|
|
7260
7491
|
function fernOpenApiCandidateDirs(fernRoot, apiName, apiNameExplicit) {
|
|
@@ -7568,11 +7799,12 @@ function preserveLinkedAnchors(pages) {
|
|
|
7568
7799
|
const tableCell = line.match(/^ {0,3}\|\s*([^|]+?)\s*\|/);
|
|
7569
7800
|
if (tableCell && !/^[:\s-]+$/.test(tableCell[1])) tableCells.push({ index, text: tableCell[1] });
|
|
7570
7801
|
const match = line.match(/^ {0,3}#{1,6}\s+(.+?)\s*#*\s*$/);
|
|
7571
|
-
return match ? { index, text: match[1] } : null;
|
|
7802
|
+
return match ? { index, text: match[1].replace(/\s*\{\/\*\s*#\S+?\s*\*\/\}$/, "") } : null;
|
|
7572
7803
|
}).filter((entry) => entry !== null);
|
|
7573
7804
|
const existing = /* @__PURE__ */ new Set();
|
|
7574
7805
|
replaceOutsideCode(page.body, (text2) => {
|
|
7575
7806
|
for (const match of text2.matchAll(/\bid=(?:"([^"]+)"|'([^']+)')/g)) existing.add(match[1] ?? match[2]);
|
|
7807
|
+
for (const match of text2.matchAll(/\{\/\*\s*#(\S+?)\s*\*\/\}/g)) existing.add(match[1]);
|
|
7576
7808
|
return text2;
|
|
7577
7809
|
});
|
|
7578
7810
|
const candidateIndexes = /* @__PURE__ */ new Map();
|
|
@@ -7700,7 +7932,7 @@ function globalSnippetAliases(files, repositoryRoot, siteRoot) {
|
|
|
7700
7932
|
}
|
|
7701
7933
|
return aliases;
|
|
7702
7934
|
}
|
|
7703
|
-
function repositoryAssetHref(value, currentFile, siteRoot, onReferenced) {
|
|
7935
|
+
function repositoryAssetHref(value, currentFile, siteRoot, onReferenced, onRootFallback) {
|
|
7704
7936
|
const isBracketed = value.startsWith("<") && value.endsWith(">");
|
|
7705
7937
|
const raw = isBracketed ? value.slice(1, -1) : value;
|
|
7706
7938
|
if (!raw || raw.startsWith("#") || /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(raw)) return null;
|
|
@@ -7715,7 +7947,15 @@ function repositoryAssetHref(value, currentFile, siteRoot, onReferenced) {
|
|
|
7715
7947
|
}
|
|
7716
7948
|
if (!ASSET_EXTENSIONS.has(extname6(decodedPath).toLowerCase())) return null;
|
|
7717
7949
|
try {
|
|
7718
|
-
|
|
7950
|
+
let usedRootFallback = false;
|
|
7951
|
+
let candidate = decodedPath.startsWith("/") ? resolveWithin(siteRoot, decodedPath.replace(/^\/+/, "")) : resolveWithinRoot(dirname4(currentFile), decodedPath, siteRoot);
|
|
7952
|
+
if (!decodedPath.startsWith("/") && !existsSync5(candidate)) {
|
|
7953
|
+
const fromRoot = resolveWithin(siteRoot, decodedPath.replace(/^(?:\.\/)+/, ""));
|
|
7954
|
+
if (existsSync5(fromRoot)) {
|
|
7955
|
+
candidate = fromRoot;
|
|
7956
|
+
usedRootFallback = true;
|
|
7957
|
+
}
|
|
7958
|
+
}
|
|
7719
7959
|
const realRoot = realpathSync2(siteRoot);
|
|
7720
7960
|
const realCandidate = realpathSync2(candidate);
|
|
7721
7961
|
const realRelative = relative5(realRoot, realCandidate);
|
|
@@ -7728,6 +7968,7 @@ function repositoryAssetHref(value, currentFile, siteRoot, onReferenced) {
|
|
|
7728
7968
|
const onDiskRelative = relative5(realRoot, realpathSync2.native(candidate)).replace(/\\/g, "/");
|
|
7729
7969
|
const onDisk = onDiskRelative.toLowerCase() === siteRelative.toLowerCase() ? normalizeAssetPath(onDiskRelative) : null;
|
|
7730
7970
|
onReferenced?.(normalized, onDisk ?? void 0);
|
|
7971
|
+
if (usedRootFallback) onRootFallback?.(decodedPath, normalized);
|
|
7731
7972
|
const rewritten = `/${normalized}${suffix}`;
|
|
7732
7973
|
return isBracketed ? `<${rewritten}>` : rewritten;
|
|
7733
7974
|
} catch {
|
|
@@ -7746,12 +7987,12 @@ function rewriteFernIdRenameLinks(body, renames) {
|
|
|
7746
7987
|
return text2.replace(/(\]\()\/([^\s)]+)(?=[\s)]|$)/g, (_match, prefix, target) => `${prefix}${rewriteTarget(`/${target}`)}`).replace(/(\bhref=")\/([^"]+)(")/g, (_match, prefix, target, suffix) => `${prefix}${rewriteTarget(`/${target}`)}${suffix}`);
|
|
7747
7988
|
});
|
|
7748
7989
|
}
|
|
7749
|
-
function rewriteRepositoryAssetLinks(body, currentFile, siteRoot, onReferenced) {
|
|
7990
|
+
function rewriteRepositoryAssetLinks(body, currentFile, siteRoot, onReferenced, onRootFallback) {
|
|
7750
7991
|
return body.replace(/(!?\[[^\]]*\]\()(<[^>]+>|[^)\s]+)([^)]*\))/g, (original, opening, destination, closing) => {
|
|
7751
|
-
const rewritten = repositoryAssetHref(destination, currentFile, siteRoot, onReferenced);
|
|
7992
|
+
const rewritten = repositoryAssetHref(destination, currentFile, siteRoot, onReferenced, onRootFallback);
|
|
7752
7993
|
return rewritten ? `${opening}${rewritten}${closing}` : original;
|
|
7753
7994
|
}).replace(/\b(src|img|image|href)=(['"])([^'"]+)\2/g, (original, property, quote, destination) => {
|
|
7754
|
-
const rewritten = repositoryAssetHref(destination, currentFile, siteRoot, onReferenced);
|
|
7995
|
+
const rewritten = repositoryAssetHref(destination, currentFile, siteRoot, onReferenced, onRootFallback);
|
|
7755
7996
|
return rewritten ? `${property}=${quote}${rewritten}${quote}` : original;
|
|
7756
7997
|
});
|
|
7757
7998
|
}
|
|
@@ -8469,7 +8710,11 @@ function migrateRepository(options) {
|
|
|
8469
8710
|
const publishedText = trackPublishedRefs ? raw : void 0;
|
|
8470
8711
|
const pageAssetReferences = [];
|
|
8471
8712
|
if (platform === "fern" || platform === "mintlify" || platform === "docusaurus") {
|
|
8472
|
-
raw = normalizeExplicitHeadingIds(
|
|
8713
|
+
raw = normalizeExplicitHeadingIds(
|
|
8714
|
+
raw,
|
|
8715
|
+
(message) => warnings.push({ code: "invalid-page", message, source: file.relativePath }),
|
|
8716
|
+
{ headingMarkers: platform === "mintlify" }
|
|
8717
|
+
);
|
|
8473
8718
|
}
|
|
8474
8719
|
if (componentMigrator) {
|
|
8475
8720
|
const warningsBeforeTransform = warnings.length;
|
|
@@ -8556,6 +8801,8 @@ function migrateRepository(options) {
|
|
|
8556
8801
|
if (platform === "mintlify" && mintlifyProjectRoot) {
|
|
8557
8802
|
page.body = rewriteRepositoryAssetLinks(page.body, file.absolutePath, mintlifyProjectRoot, (assetPath, onDiskSpelling) => {
|
|
8558
8803
|
pageAssetReferences.push(publicAssetKey(onDiskSpelling ?? assetPath));
|
|
8804
|
+
}, (spelled, used) => {
|
|
8805
|
+
warnings.push({ code: "unsupported-config", message: `"${spelled}" was not found beside this page; the file "${used}" in the site root was used instead and will be published.`, source: file.relativePath });
|
|
8559
8806
|
});
|
|
8560
8807
|
}
|
|
8561
8808
|
if (platform === "fern" && fernProjectRoot) {
|
|
@@ -8703,15 +8950,19 @@ function migrateRepository(options) {
|
|
|
8703
8950
|
const rootStylesheetPath = platform === "mintlify" && mintlifyProjectRoot ? resolveWithin(mintlifyProjectRoot, "style.css") : void 0;
|
|
8704
8951
|
const hasRootStylesheet = Boolean(rootStylesheetPath && existsSync5(rootStylesheetPath) && lstatSync5(rootStylesheetPath).isFile() && !lstatSync5(rootStylesheetPath).isSymbolicLink());
|
|
8705
8952
|
let rootStyleProjection;
|
|
8953
|
+
let rootNavbarButtons = [];
|
|
8706
8954
|
let rootStyleProblem;
|
|
8707
8955
|
if (hasRootStylesheet && rootStylesheetPath && lstatSync5(rootStylesheetPath).size <= MAX_ASSET_BYTES) {
|
|
8708
8956
|
const css = readFileSync5(rootStylesheetPath, "utf8");
|
|
8709
8957
|
if (/@import\b|url\s*\(\s*['"]?\s*(?:javascript:|file:)/i.test(css)) rootStyleProblem = "unsafe";
|
|
8710
8958
|
else {
|
|
8711
8959
|
try {
|
|
8960
|
+
rootNavbarButtons = navbarLinkButtons(css);
|
|
8712
8961
|
rootStyleProjection = projectAuthoredStyles(css, [
|
|
8713
8962
|
...pages.map((page) => page.body),
|
|
8714
|
-
...(componentMigrator?.files() ?? []).map((file) => typeof file.content === "string" ? file.content : "")
|
|
8963
|
+
...(componentMigrator?.files() ?? []).map((file) => typeof file.content === "string" ? file.content : ""),
|
|
8964
|
+
// Site-wide scripts build markup of their own (a CTA card, say) that the stylesheet is meant for.
|
|
8965
|
+
...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
8966
|
]);
|
|
8716
8967
|
} catch {
|
|
8717
8968
|
rootStyleProblem = "parse";
|
|
@@ -8849,6 +9100,18 @@ function migrateRepository(options) {
|
|
|
8849
9100
|
} else if (rootStyleProblem === "parse" || !rootStyleProjection) {
|
|
8850
9101
|
warnings.push({ code: "unsupported-config", message: "Mintlify root style.css could not be parsed and was not imported.", source: "style.css" });
|
|
8851
9102
|
} else {
|
|
9103
|
+
if (rootNavbarButtons.length > 0 && docsConfig.navbar?.links) {
|
|
9104
|
+
docsConfig = {
|
|
9105
|
+
...docsConfig,
|
|
9106
|
+
navbar: {
|
|
9107
|
+
...docsConfig.navbar,
|
|
9108
|
+
links: docsConfig.navbar.links.map((link) => {
|
|
9109
|
+
const rule = rootNavbarButtons.find((entry) => entry.exact ? link.href === entry.href : link.href.includes(entry.href));
|
|
9110
|
+
return rule ? { ...link, button: { background: rule.background, ...rule.color ? { color: rule.color } : {} } } : link;
|
|
9111
|
+
})
|
|
9112
|
+
}
|
|
9113
|
+
};
|
|
9114
|
+
}
|
|
8852
9115
|
if (rootStyleProjection.omittedSelectors > 0) warnings.push({
|
|
8853
9116
|
code: "unsupported-config",
|
|
8854
9117
|
source: "style.css",
|
|
@@ -8992,19 +9255,31 @@ function migrateRepository(options) {
|
|
|
8992
9255
|
rewriteApiLinksInPages(pages, operationLinks, prefixLandings, warnings);
|
|
8993
9256
|
}
|
|
8994
9257
|
} else if (platform === "mintlify") {
|
|
8995
|
-
const warnSharedSpec = (path) => {
|
|
8996
|
-
warnings.push({
|
|
8997
|
-
code: "gated-page",
|
|
8998
|
-
message: `OpenAPI spec ${path} is shared with access-restricted pages and is published; it may describe restricted endpoints. Review it before publishing.`,
|
|
8999
|
-
source: path
|
|
9000
|
-
});
|
|
9258
|
+
const warnSharedSpec = (path, excluded = []) => {
|
|
9259
|
+
warnings.push({ code: "gated-page", message: sharedSpecMessage(path, excluded), source: path });
|
|
9001
9260
|
};
|
|
9002
|
-
const
|
|
9261
|
+
const keptSpecRefs = [...publishedSpecRefs, ...navigationOperationRefs(mintlifyConfig)];
|
|
9262
|
+
const allSpecs = resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteApiSpecs, pages);
|
|
9263
|
+
for (const remote of remoteApiSpecs) {
|
|
9264
|
+
const { withheld, kept } = withheldOperationKeys({ sourcePath: remote.url, filename: remote.url }, withheldSpecRefs, keptSpecRefs);
|
|
9265
|
+
if (withheld.length > 0) {
|
|
9266
|
+
remote.withheldOperations = withheld;
|
|
9267
|
+
remote.keptOperations = kept;
|
|
9268
|
+
}
|
|
9269
|
+
}
|
|
9270
|
+
const withheldOperations = /* @__PURE__ */ new Map();
|
|
9271
|
+
for (const spec of allSpecs) {
|
|
9272
|
+
const result = excludeWithheldOperations(spec, withheldSpecRefs, keptSpecRefs);
|
|
9273
|
+
spec.content = result.content;
|
|
9274
|
+
withheldOperations.set(spec, result.excluded);
|
|
9275
|
+
}
|
|
9276
|
+
const resolvedSpecs = allSpecs.filter((spec) => !spec.pageOnly);
|
|
9277
|
+
const pageOnlySpecs = allSpecs.filter((spec) => spec.pageOnly);
|
|
9003
9278
|
for (const spec of resolvedSpecs) {
|
|
9004
9279
|
if (!assets.some((asset) => asset.path === specAssetPath(spec.filename))) {
|
|
9005
9280
|
assets.push(specAsset(spec.filename, spec.content));
|
|
9006
9281
|
}
|
|
9007
|
-
if (withheldSpecRefs.some((ref) => specRefMatches(ref, spec.sourcePath, spec.filename, true))) warnSharedSpec(spec.sourcePath);
|
|
9282
|
+
if (withheldSpecRefs.some((ref) => specRefMatches(ref, spec.sourcePath, spec.filename, true))) warnSharedSpec(spec.sourcePath, withheldOperations.get(spec));
|
|
9008
9283
|
}
|
|
9009
9284
|
let pageSpecs = resolvedSpecs;
|
|
9010
9285
|
if (resolvedSpecs.length > 0) {
|
|
@@ -9023,16 +9298,35 @@ function migrateRepository(options) {
|
|
|
9023
9298
|
quarantinedFiles.push({ path: `${QUARANTINE_DIRECTORY}/assets/${specAssetPath(filename)}`, content: readFileSync5(fallback.absolutePath) });
|
|
9024
9299
|
withheldAssetCount++;
|
|
9025
9300
|
} else {
|
|
9301
|
+
const pruned = excludeWithheldOperations({ sourcePath: fallback.relativePath, filename, content: readFileSync5(fallback.absolutePath) }, withheldSpecRefs, keptSpecRefs);
|
|
9026
9302
|
if (!assets.some((asset) => asset.path === specAssetPath(filename))) {
|
|
9027
|
-
assets.push(specAsset(filename,
|
|
9303
|
+
assets.push(specAsset(filename, pruned.content));
|
|
9028
9304
|
}
|
|
9029
9305
|
docsConfig = injectOpenApiSpecs(docsConfig, [{ filename }]);
|
|
9030
9306
|
pageSpecs = [{ filename, sourcePath: fallback.relativePath }];
|
|
9031
|
-
if (withheldSpecRefs.some(matches)) warnSharedSpec(fallback.relativePath);
|
|
9307
|
+
if (withheldSpecRefs.some(matches)) warnSharedSpec(fallback.relativePath, pruned.excluded);
|
|
9032
9308
|
}
|
|
9033
9309
|
}
|
|
9034
9310
|
}
|
|
9035
|
-
|
|
9311
|
+
for (const spec of pageOnlySpecs) {
|
|
9312
|
+
if (!assets.some((asset) => asset.path === specAssetPath(spec.filename))) assets.push(specAsset(spec.filename, spec.content));
|
|
9313
|
+
if (withheldSpecRefs.some((ref) => specRefMatches(ref, spec.sourcePath, spec.filename, true))) warnSharedSpec(spec.sourcePath, withheldOperations.get(spec));
|
|
9314
|
+
}
|
|
9315
|
+
if (pageOnlySpecs.length > 0) {
|
|
9316
|
+
docsConfig = injectOpenApiSpecs(docsConfig, pageOnlySpecs, warnings);
|
|
9317
|
+
pageSpecs = [...pageSpecs, ...pageOnlySpecs];
|
|
9318
|
+
}
|
|
9319
|
+
const explainMissingSpec = (key) => {
|
|
9320
|
+
const sameName = scannedFiles.find((file) => file.relativePath.toLowerCase() === key.toLowerCase());
|
|
9321
|
+
if (sameName && sameName.relativePath !== key) return `paths are case-sensitive; the file is at "${sameName.relativePath}"`;
|
|
9322
|
+
if (sameName && mintignoreMatcher?.ignores(sameName.relativePath)) return "the file is excluded by .mintignore";
|
|
9323
|
+
try {
|
|
9324
|
+
if (lstatSync5(resolvePath(repositoryDir, key)).isSymbolicLink()) return "the file is a symbolic link, which is never followed";
|
|
9325
|
+
} catch {
|
|
9326
|
+
}
|
|
9327
|
+
return sameName ? "the file could not be read as an OpenAPI document" : `no file exists at "${key}"`;
|
|
9328
|
+
};
|
|
9329
|
+
rewriteMintlifyPageSpecRefs(pages, pageSpecs, new Set(remoteApiSpecs.map((spec) => spec.url)), warnings, explainMissingSpec);
|
|
9036
9330
|
}
|
|
9037
9331
|
if (platform === "mintlify") {
|
|
9038
9332
|
const sources = new Set((docsConfig.redirects ?? []).map((redirect) => redirect.source));
|
|
@@ -9447,6 +9741,8 @@ function renderPage(bundle, page) {
|
|
|
9447
9741
|
"---",
|
|
9448
9742
|
`title: ${yamlString(page.title)}`,
|
|
9449
9743
|
page.navTitle ? `navTitle: ${yamlString(page.navTitle)}` : null,
|
|
9744
|
+
page.icon ? `icon: ${yamlString(page.icon)}` : null,
|
|
9745
|
+
page.iconType ? `iconType: ${yamlString(page.iconType)}` : null,
|
|
9450
9746
|
`description: ${yamlString(page.description)}`,
|
|
9451
9747
|
page.descriptionPlacement === "body" ? "descriptionPlacement: body" : null,
|
|
9452
9748
|
page.badge ? `badge: ${yamlString(page.badge)}` : null,
|
|
@@ -9454,9 +9750,11 @@ function renderPage(bundle, page) {
|
|
|
9454
9750
|
page.mode ? `mode: ${yamlString(page.mode)}` : null,
|
|
9455
9751
|
page.hidden ? "hidden: true" : null,
|
|
9456
9752
|
page.noindex ? "noindex: true" : null,
|
|
9753
|
+
...Object.entries(page.meta ?? {}).map(([field, value]) => `${field}: ${yamlString(value)}`),
|
|
9457
9754
|
page.openapi ? `openapi: ${yamlString(page.openapi)}` : null,
|
|
9458
9755
|
page.api ? `api: ${yamlString(page.api)}` : null,
|
|
9459
9756
|
page.authMethod ? `authMethod: ${yamlString(page.authMethod)}` : null,
|
|
9757
|
+
page.playground ? `playground: ${yamlString(page.playground)}` : null,
|
|
9460
9758
|
bundle.sourceKind === "url" ? `source: ${yamlString(page.source)}` : null,
|
|
9461
9759
|
"---",
|
|
9462
9760
|
"",
|
|
@@ -9570,7 +9868,7 @@ import remarkMdx3 from "remark-mdx";
|
|
|
9570
9868
|
import remarkParse3 from "remark-parse";
|
|
9571
9869
|
import TurndownService from "turndown";
|
|
9572
9870
|
import { unified as unified3 } from "unified";
|
|
9573
|
-
import { parse as
|
|
9871
|
+
import { parse as parseYaml6, stringify as stringifyYaml2 } from "yaml";
|
|
9574
9872
|
var DEFAULT_MAX_PAGES = 1e3;
|
|
9575
9873
|
var DEFAULT_MAX_TOTAL_BYTES = 1e8;
|
|
9576
9874
|
var MAX_DISCOVERED_URLS = 5e3;
|
|
@@ -10295,7 +10593,7 @@ function extractEmbeddedOpenApi(content) {
|
|
|
10295
10593
|
const match = fencePattern.exec(content);
|
|
10296
10594
|
if (!match) return { content };
|
|
10297
10595
|
try {
|
|
10298
|
-
const parsed =
|
|
10596
|
+
const parsed = parseYaml6(match[5], { maxAliasCount: 50 });
|
|
10299
10597
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return { content };
|
|
10300
10598
|
const document = parsed;
|
|
10301
10599
|
if (typeof document.openapi !== "string" && typeof document.swagger !== "string") return { content };
|
|
@@ -10409,7 +10707,7 @@ function mergeEmbeddedOpenApi(fragments) {
|
|
|
10409
10707
|
if (Object.keys(combinedPaths).length === 0) return null;
|
|
10410
10708
|
if (Object.keys(combinedComponents).length === 0) delete combined.components;
|
|
10411
10709
|
if (tags.size > 0) combined.tags = [...tags.values()];
|
|
10412
|
-
return new TextEncoder().encode(
|
|
10710
|
+
return new TextEncoder().encode(stringifyYaml2(combined));
|
|
10413
10711
|
}
|
|
10414
10712
|
function htmlPage(document, id) {
|
|
10415
10713
|
const $ = load2(document.body);
|
|
@@ -11148,7 +11446,7 @@ import { createHash as createHash3 } from "crypto";
|
|
|
11148
11446
|
import { lookup } from "dns/promises";
|
|
11149
11447
|
import { request } from "https";
|
|
11150
11448
|
import { isIP } from "net";
|
|
11151
|
-
import { parse as
|
|
11449
|
+
import { parse as parseYaml7 } from "yaml";
|
|
11152
11450
|
var MAX_SPEC_BYTES = 25e6;
|
|
11153
11451
|
var MAX_REDIRECTS = 3;
|
|
11154
11452
|
function isPublicAddress(address, family) {
|
|
@@ -11244,7 +11542,7 @@ async function downloadSpec(value, fetcher) {
|
|
|
11244
11542
|
}
|
|
11245
11543
|
function parseOpenApi(content, extension) {
|
|
11246
11544
|
const text2 = content.toString("utf8");
|
|
11247
|
-
const parsed = extension === "yaml" || !text2.trimStart().startsWith("{") ?
|
|
11545
|
+
const parsed = extension === "yaml" || !text2.trimStart().startsWith("{") ? parseYaml7(text2) : JSON.parse(text2);
|
|
11248
11546
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("OpenAPI spec is not an object.");
|
|
11249
11547
|
const document = parsed;
|
|
11250
11548
|
if (typeof document.openapi !== "string" || !/^3\./.test(document.openapi)) {
|
|
@@ -11302,7 +11600,10 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
11302
11600
|
try {
|
|
11303
11601
|
const url = validatedSpecUrl(reference.url);
|
|
11304
11602
|
const extension = /\.ya?ml$/i.test(url.pathname) ? "yaml" : "json";
|
|
11305
|
-
const
|
|
11603
|
+
const downloaded = await downloadSpec(reference.url, fetcher);
|
|
11604
|
+
const pruned = markExcluded(downloaded, reference.withheldOperations ?? [], reference.keptOperations);
|
|
11605
|
+
const body = pruned.content;
|
|
11606
|
+
if (reference.withheldOperations?.length) warnings.push({ code: "gated-page", message: sharedSpecMessage(reference.url, pruned.excluded), source: reference.url });
|
|
11306
11607
|
const operations = parseOpenApi(body, extension);
|
|
11307
11608
|
const filename = `openapi-${createHash3("sha256").update(reference.url).digest("hex").slice(0, 12)}.${extension}`;
|
|
11308
11609
|
assets.push({ path: `openapi/${filename}`, content: body, projectRelative: true });
|