@thallylabs/migrate 0.2.17 → 0.2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/dist/index.d.ts +55 -1
- package/dist/index.js +345 -49
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -326,8 +326,8 @@ function leadingPageHeading(body) {
|
|
|
326
326
|
const root = descriptionParser.parse(body);
|
|
327
327
|
const first = root.children?.find((node) => node.type !== "mdxjsEsm" && node.type !== "html");
|
|
328
328
|
if (first?.type !== "heading" || first.depth !== 1) return void 0;
|
|
329
|
-
const
|
|
330
|
-
const title =
|
|
329
|
+
const text2 = (node) => node.type === "mdxTextExpression" || node.type === "mdxFlowExpression" ? "" : node.value ?? (node.children ?? []).map(text2).join("");
|
|
330
|
+
const title = text2(first).replace(/\s+/g, " ").trim();
|
|
331
331
|
const start = first.position?.start.offset;
|
|
332
332
|
const end = first.position?.end.offset;
|
|
333
333
|
return title && start !== void 0 && end !== void 0 ? { title, start, end } : void 0;
|
|
@@ -400,16 +400,16 @@ function collectEsmBindingsByPattern(source, declared) {
|
|
|
400
400
|
var FENCE_OPEN = /^(`{3,}|~{3,})/;
|
|
401
401
|
function maskInlineSpansForMath(line) {
|
|
402
402
|
const blocks = [];
|
|
403
|
-
const stash = (
|
|
404
|
-
blocks.push(
|
|
403
|
+
const stash = (text2) => {
|
|
404
|
+
blocks.push(text2);
|
|
405
405
|
return `\0${blocks.length - 1}\0`;
|
|
406
406
|
};
|
|
407
407
|
const codeMasked = line.split(/(`[^`]*`)/).map((segment, index) => index % 2 === 1 ? stash(segment) : segment).join("");
|
|
408
408
|
const tagMasked = codeMasked.replace(/<\/?[a-zA-Z][^<>]*>/g, stash);
|
|
409
|
-
const masked = [tagMasked, tagMasked].reduce((
|
|
409
|
+
const masked = [tagMasked, tagMasked].reduce((text2) => text2.replace(/(?<!\$)\{[^{}]*\}/g, stash), tagMasked);
|
|
410
410
|
return {
|
|
411
411
|
masked,
|
|
412
|
-
unmask: (
|
|
412
|
+
unmask: (text2) => text2.replace(/\u0000(\d+)\u0000/g, (_match, index) => blocks[Number(index)])
|
|
413
413
|
};
|
|
414
414
|
}
|
|
415
415
|
var TEX_SIGNAL = /\\[a-zA-Z]|[\^_{]/;
|
|
@@ -562,11 +562,11 @@ function splitFrontmatterBlock(raw) {
|
|
|
562
562
|
return { front: bom + source.slice(0, end), body: source.slice(end) };
|
|
563
563
|
}
|
|
564
564
|
var MIGRATED_COMPONENT_TAG = /^Migrated[0-9a-f]{12}$/;
|
|
565
|
-
function isSelfClosingJsx(
|
|
566
|
-
return /\/>\s*$/.test(
|
|
565
|
+
function isSelfClosingJsx(text2) {
|
|
566
|
+
return /\/>\s*$/.test(text2);
|
|
567
567
|
}
|
|
568
|
-
function renameTagOccurrences(
|
|
569
|
-
let result =
|
|
568
|
+
function renameTagOccurrences(text2, name, newName) {
|
|
569
|
+
let result = text2;
|
|
570
570
|
const openIndex = result.indexOf(`<${name}`);
|
|
571
571
|
if (openIndex >= 0) result = `${result.slice(0, openIndex + 1)}${newName}${result.slice(openIndex + 1 + name.length)}`;
|
|
572
572
|
const closeIndex = result.lastIndexOf(`</${name}`);
|
|
@@ -612,9 +612,9 @@ function replaceUnknownComponents(raw, warn, options = {}) {
|
|
|
612
612
|
if (start === void 0 || end === void 0) return "";
|
|
613
613
|
const isJsx = node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement";
|
|
614
614
|
const tagRoot = node.name ? node.name.split(".")[0] : void 0;
|
|
615
|
-
const
|
|
615
|
+
const text2 = body.slice(start, end);
|
|
616
616
|
if (isJsx && tagRoot === "Link" && !declared.has("Link")) {
|
|
617
|
-
if (isSelfClosingJsx(
|
|
617
|
+
if (isSelfClosingJsx(text2) || !node.children?.length) return renameTagOccurrences(text2, node.name, "a");
|
|
618
618
|
const openEnd = node.children[0].position?.start.offset ?? start;
|
|
619
619
|
const closeStart = node.children.at(-1).position?.end.offset ?? end;
|
|
620
620
|
return renameTagOccurrences(body.slice(start, openEnd), node.name, "a") + renderChildrenSpan(node.children, openEnd, closeStart, body, renderNode) + renameTagOccurrences(body.slice(closeStart, end), node.name, "a");
|
|
@@ -624,7 +624,7 @@ function replaceUnknownComponents(raw, warn, options = {}) {
|
|
|
624
624
|
warned.add(node.name);
|
|
625
625
|
warn(node.name);
|
|
626
626
|
}
|
|
627
|
-
if (isSelfClosingJsx(
|
|
627
|
+
if (isSelfClosingJsx(text2)) return "";
|
|
628
628
|
if (!node.children?.length) return "<div></div>";
|
|
629
629
|
const openEnd = node.children[0].position?.start.offset ?? start;
|
|
630
630
|
const closeStart = node.children.at(-1).position?.end.offset ?? end;
|
|
@@ -635,7 +635,7 @@ ${children}
|
|
|
635
635
|
|
|
636
636
|
</div>` : `<div>${children}</div>`;
|
|
637
637
|
}
|
|
638
|
-
if (!node.children?.length) return
|
|
638
|
+
if (!node.children?.length) return text2;
|
|
639
639
|
return renderChildrenSpan(node.children, start, end, body, renderNode);
|
|
640
640
|
};
|
|
641
641
|
return front + renderNode(root);
|
|
@@ -643,8 +643,8 @@ ${children}
|
|
|
643
643
|
function maskCode(body) {
|
|
644
644
|
const source = body.replace(/\u0000/g, "");
|
|
645
645
|
const blocks = [];
|
|
646
|
-
const stash = (
|
|
647
|
-
blocks.push(
|
|
646
|
+
const stash = (text2) => {
|
|
647
|
+
blocks.push(text2);
|
|
648
648
|
return `\0${blocks.length - 1}\0`;
|
|
649
649
|
};
|
|
650
650
|
const lines = [];
|
|
@@ -671,7 +671,7 @@ function maskCode(body) {
|
|
|
671
671
|
if (fenceBuffer.length) lines.push(stash(fenceBuffer.join("\n")));
|
|
672
672
|
return {
|
|
673
673
|
masked: lines.join("\n"),
|
|
674
|
-
unmask: (
|
|
674
|
+
unmask: (text2) => text2.replace(/\u0000(\d+)\u0000/g, (_match, index) => blocks[Number(index)])
|
|
675
675
|
};
|
|
676
676
|
}
|
|
677
677
|
function replaceOutsideCode(body, transform) {
|
|
@@ -690,7 +690,7 @@ function rewriteFernRelativePageLinks(body, currentSourcePath, routesBySourcePat
|
|
|
690
690
|
const route = candidates.map((candidate) => routesBySourcePath.get(candidate)).find(Boolean);
|
|
691
691
|
return route ? `/${route.replace(/^\/+/, "")}${suffix}` : target;
|
|
692
692
|
};
|
|
693
|
-
return replaceOutsideCode(body, (
|
|
693
|
+
return replaceOutsideCode(body, (text2) => text2.replace(
|
|
694
694
|
/(\]\()(<[^>\n]+>|[^\s)]+)(?=\s|\))/g,
|
|
695
695
|
(_match, opening, target) => `${opening}${target.startsWith("<") && target.endsWith(">") ? `<${rewrite(target.slice(1, -1))}>` : rewrite(target)}`
|
|
696
696
|
).replace(
|
|
@@ -1290,11 +1290,26 @@ function parseMarkdownPage(input) {
|
|
|
1290
1290
|
hidden: parsed.data.hidden === true ? true : void 0,
|
|
1291
1291
|
noindex: parsed.data.noindex === true || parsed.data.noindex === "true" ? true : void 0,
|
|
1292
1292
|
openapi: typeof parsed.data.openapi === "string" ? parsed.data.openapi.trim() : void 0,
|
|
1293
|
+
...apiFrontmatter(parsed.data, input.warn),
|
|
1293
1294
|
body,
|
|
1294
1295
|
source: input.source,
|
|
1295
1296
|
...parsed.error ? { frontmatterError: parsed.error } : {}
|
|
1296
1297
|
};
|
|
1297
1298
|
}
|
|
1299
|
+
var AUTH_METHODS = /* @__PURE__ */ new Set(["bearer", "basic", "key", "none"]);
|
|
1300
|
+
function apiFrontmatter(data, warn) {
|
|
1301
|
+
const result = {};
|
|
1302
|
+
if (data.api !== void 0 && data.api !== null) {
|
|
1303
|
+
if (typeof data.api === "string" && data.api.trim()) result.api = data.api.trim();
|
|
1304
|
+
else warn?.(`The page's "api" frontmatter is not a "METHOD url-or-path" string and was dropped.`);
|
|
1305
|
+
}
|
|
1306
|
+
if (data.authMethod !== void 0 && data.authMethod !== null) {
|
|
1307
|
+
const method = typeof data.authMethod === "string" ? data.authMethod.trim().toLowerCase() : "";
|
|
1308
|
+
if (AUTH_METHODS.has(method)) result.authMethod = method;
|
|
1309
|
+
else warn?.(`The page's "authMethod" frontmatter ${JSON.stringify(data.authMethod)} is not one of bearer, basic, key, none and was dropped.`);
|
|
1310
|
+
}
|
|
1311
|
+
return result;
|
|
1312
|
+
}
|
|
1298
1313
|
|
|
1299
1314
|
// src/path.ts
|
|
1300
1315
|
import { isAbsolute, relative, resolve, sep } from "path";
|
|
@@ -2165,7 +2180,7 @@ const MintlifyComponents = {
|
|
|
2165
2180
|
}
|
|
2166
2181
|
function applyReplacements(source, replacements) {
|
|
2167
2182
|
return replacements.sort((a, b) => b.start - a.start).reduce(
|
|
2168
|
-
(
|
|
2183
|
+
(text2, edit) => text2.slice(0, edit.start) + edit.value + text2.slice(edit.end),
|
|
2169
2184
|
source
|
|
2170
2185
|
);
|
|
2171
2186
|
}
|
|
@@ -2454,14 +2469,14 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2454
2469
|
}
|
|
2455
2470
|
return;
|
|
2456
2471
|
}
|
|
2457
|
-
const
|
|
2458
|
-
const syntax = ts2.transpileModule(
|
|
2472
|
+
const text2 = content.toString("utf8");
|
|
2473
|
+
const syntax = ts2.transpileModule(text2, {
|
|
2459
2474
|
fileName: path,
|
|
2460
2475
|
reportDiagnostics: true,
|
|
2461
2476
|
compilerOptions: { jsx: ts2.JsxEmit.Preserve, target: ts2.ScriptTarget.ESNext, module: ts2.ModuleKind.ESNext }
|
|
2462
2477
|
});
|
|
2463
2478
|
if (syntax.diagnostics?.some((diagnostic) => diagnostic.category === ts2.DiagnosticCategory.Error)) throw new Error("component source contains unsupported JavaScript or TypeScript syntax");
|
|
2464
|
-
const ast = sourceFile(
|
|
2479
|
+
const ast = sourceFile(text2, path);
|
|
2465
2480
|
if (ast.statements.some((statement) => ts2.isExpressionStatement(statement) && ts2.isStringLiteral(statement.expression) && statement.expression.text === "use server")) throw new Error("server-only component modules require manual migration");
|
|
2466
2481
|
const edits = [];
|
|
2467
2482
|
function dependency(literal, importDeclaration) {
|
|
@@ -2509,7 +2524,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
|
|
|
2509
2524
|
ts2.forEachChild(node, inspect);
|
|
2510
2525
|
}
|
|
2511
2526
|
inspect(ast);
|
|
2512
|
-
const replaced = applyReplacements(
|
|
2527
|
+
const replaced = applyReplacements(text2, edits);
|
|
2513
2528
|
const shebangMatch = /^#!.*\r?\n/.exec(replaced);
|
|
2514
2529
|
const prologue = "// @ts-nocheck\n'use client';\n\n";
|
|
2515
2530
|
staged.set(destination, {
|
|
@@ -3016,10 +3031,10 @@ ${inlineSource}` });
|
|
|
3016
3031
|
const start = node.position.start.offset;
|
|
3017
3032
|
const end = node.position.end.offset;
|
|
3018
3033
|
if (extracted.some((item) => start >= item.node.position.start.offset && end <= item.node.position.end.offset)) return;
|
|
3019
|
-
const
|
|
3020
|
-
const opening =
|
|
3034
|
+
const text2 = content.slice(start, end);
|
|
3035
|
+
const opening = text2.indexOf(`<${node.name}`);
|
|
3021
3036
|
if (opening >= 0) edits.push({ start: start + opening + 1, end: start + opening + 1 + node.name.length, value: replacement });
|
|
3022
|
-
const closing =
|
|
3037
|
+
const closing = text2.lastIndexOf(`</${node.name}`);
|
|
3023
3038
|
if (closing >= 0) edits.push({ start: start + closing + 2, end: start + closing + 2 + node.name.length, value: replacement });
|
|
3024
3039
|
});
|
|
3025
3040
|
walk(tree, (node) => {
|
|
@@ -3906,6 +3921,39 @@ function projectedCompatibleConfig(config, warnings) {
|
|
|
3906
3921
|
...typeof feedback?.thumbsRating === "boolean" ? { feedback: { thumbsRating: feedback.thumbsRating } } : {}
|
|
3907
3922
|
};
|
|
3908
3923
|
}
|
|
3924
|
+
function projectedApiMdx(config, warnings) {
|
|
3925
|
+
const mdx = objectValue2(objectValue2(config.api)?.mdx);
|
|
3926
|
+
if (!mdx) return {};
|
|
3927
|
+
const warn = (message) => warnings.push({ code: "unsupported-config", message });
|
|
3928
|
+
const rawServers = mdx.server === void 0 ? [] : Array.isArray(mdx.server) ? mdx.server : [mdx.server];
|
|
3929
|
+
const servers = rawServers.filter((entry) => {
|
|
3930
|
+
const valid = typeof entry === "string" && /^https?:\/\/[^\s/@?#]+(?:\/[^\s?#]*)?$/i.test(entry.trim());
|
|
3931
|
+
if (!valid) warn(`api.mdx.server entry ${JSON.stringify(entry)} is not an absolute http(s) URL and was dropped.`);
|
|
3932
|
+
return valid;
|
|
3933
|
+
}).map((entry) => entry.trim());
|
|
3934
|
+
const auth = objectValue2(mdx.auth);
|
|
3935
|
+
const method = typeof auth?.method === "string" ? auth.method.toLowerCase() : void 0;
|
|
3936
|
+
const name = typeof auth?.name === "string" && auth.name.trim() ? auth.name.trim() : void 0;
|
|
3937
|
+
let projectedAuth;
|
|
3938
|
+
if (mdx.auth !== void 0 && auth && method !== void 0) {
|
|
3939
|
+
if (method === "bearer" || method === "basic" || method === "key" && name) {
|
|
3940
|
+
projectedAuth = { method, ...name ? { name } : {} };
|
|
3941
|
+
} else {
|
|
3942
|
+
warn(`api.mdx.auth method ${JSON.stringify(auth.method)} is not supported (bearer, basic, or key with a name) and was dropped.`);
|
|
3943
|
+
}
|
|
3944
|
+
} else if (mdx.auth !== void 0 && !auth) {
|
|
3945
|
+
warn("api.mdx.auth is not an object and was dropped.");
|
|
3946
|
+
}
|
|
3947
|
+
if (servers.length === 0 && !projectedAuth) return {};
|
|
3948
|
+
return {
|
|
3949
|
+
api: {
|
|
3950
|
+
mdx: {
|
|
3951
|
+
...servers.length > 0 ? { server: servers.length === 1 && typeof mdx.server === "string" ? servers[0] : servers } : {},
|
|
3952
|
+
...projectedAuth ? { auth: projectedAuth } : {}
|
|
3953
|
+
}
|
|
3954
|
+
}
|
|
3955
|
+
};
|
|
3956
|
+
}
|
|
3909
3957
|
var NEXT_REDIRECT_PARAM_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
3910
3958
|
function translateRedirectWildcards(source, destination) {
|
|
3911
3959
|
const sourceSegments = source.split("/");
|
|
@@ -4093,6 +4141,7 @@ function projectMintlifyNavigation(config, options = {}) {
|
|
|
4093
4141
|
tabs,
|
|
4094
4142
|
...projectionTrace.rootContainerKind === "dropdowns" ? { navigation: { display: "dropdown" } } : {},
|
|
4095
4143
|
...projectedCompatibleConfig(config, warnings),
|
|
4144
|
+
...projectedApiMdx(config, warnings),
|
|
4096
4145
|
...i18n ? { i18n } : {},
|
|
4097
4146
|
...redirects.length > 0 ? { redirects } : {}
|
|
4098
4147
|
},
|
|
@@ -5141,9 +5190,9 @@ function announcementMarkdown(message) {
|
|
|
5141
5190
|
links.set(marker, destination && label ? `[${escapeText(label)}](${destination})` : escapeText(label));
|
|
5142
5191
|
document(element).replaceWith(marker);
|
|
5143
5192
|
});
|
|
5144
|
-
let
|
|
5145
|
-
for (const [marker, link] of links)
|
|
5146
|
-
return
|
|
5193
|
+
let text2 = escapeText(document("body").text());
|
|
5194
|
+
for (const [marker, link] of links) text2 = text2.replaceAll(marker, link);
|
|
5195
|
+
return text2.trim();
|
|
5147
5196
|
}
|
|
5148
5197
|
function objectValue4(value) {
|
|
5149
5198
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -5661,6 +5710,199 @@ function projectFernNavigation(input) {
|
|
|
5661
5710
|
};
|
|
5662
5711
|
}
|
|
5663
5712
|
|
|
5713
|
+
// src/openapi-ref.ts
|
|
5714
|
+
function unquote(value) {
|
|
5715
|
+
const trimmed = value.trim();
|
|
5716
|
+
const quote = trimmed[0];
|
|
5717
|
+
return (quote === '"' || quote === "'") && trimmed.length >= 2 && trimmed.endsWith(quote) ? trimmed.slice(1, -1).trim() : trimmed;
|
|
5718
|
+
}
|
|
5719
|
+
function splitOpenApiRef(raw) {
|
|
5720
|
+
const value = unquote(raw);
|
|
5721
|
+
const match = /^(?:(.+?)\s+)?((?:webhook\s+[^\s/]\S*)|(?:[A-Za-z]+\s+\/.*))$/i.exec(value);
|
|
5722
|
+
if (!match) return null;
|
|
5723
|
+
const specRef = match[1] ? unquote(match[1]) : void 0;
|
|
5724
|
+
return { ...specRef ? { specRef } : {}, operation: match[2] };
|
|
5725
|
+
}
|
|
5726
|
+
function specRefBaseName(specRef) {
|
|
5727
|
+
return specRef.trim().replace(/\\/g, "/").split(/[?#]/, 1)[0].split("/").filter(Boolean).pop()?.toLowerCase() ?? "";
|
|
5728
|
+
}
|
|
5729
|
+
function withSpecRef(ref, specRef) {
|
|
5730
|
+
return `${specRef} ${ref.operation}`;
|
|
5731
|
+
}
|
|
5732
|
+
|
|
5733
|
+
// src/analytics.ts
|
|
5734
|
+
var GA4_ID = /^G-[A-Z0-9]{4,20}$/;
|
|
5735
|
+
var GTM_ID = /^GTM-[A-Z0-9]{4,12}$/;
|
|
5736
|
+
var POSTHOG_KEY = /^phc_[A-Za-z0-9]{20,64}$/;
|
|
5737
|
+
var HOSTNAME_LABEL = "[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?";
|
|
5738
|
+
var HOSTNAME = new RegExp(`^${HOSTNAME_LABEL}(?:\\.${HOSTNAME_LABEL})*$`);
|
|
5739
|
+
var SAFE_PATH = /^\/[A-Za-z0-9._~\-/]*$/;
|
|
5740
|
+
var MAX_PLAUSIBLE_DOMAINS = 10;
|
|
5741
|
+
var SUPPORTED = ["ga4", "gtm", "posthog", "plausible"];
|
|
5742
|
+
var LEGACY_GA4_ALIAS = "googleAnalytics";
|
|
5743
|
+
function own(record, key) {
|
|
5744
|
+
return Object.prototype.hasOwnProperty.call(record, key) ? record[key] : void 0;
|
|
5745
|
+
}
|
|
5746
|
+
function isRecord(value) {
|
|
5747
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
5748
|
+
}
|
|
5749
|
+
function redact(value) {
|
|
5750
|
+
if (typeof value !== "string") return Array.isArray(value) ? "array" : value === null ? "null" : typeof value;
|
|
5751
|
+
return value.length === 0 ? "empty string" : `"${value.trim().slice(0, 4).replace(/[^\x20-\x7e]/g, "?")}..." (${value.length} chars)`;
|
|
5752
|
+
}
|
|
5753
|
+
function isPublicHostname(hostname) {
|
|
5754
|
+
return !/(^|\.)localhost$/.test(hostname) && !/(^|\.)\d+$/.test(hostname) && !hostname.includes(":") && !hostname.startsWith("[");
|
|
5755
|
+
}
|
|
5756
|
+
function normalizeHttpsUrl(value, allowPath) {
|
|
5757
|
+
if (!/^https:\/\//i.test(value) || /[?#\\]/.test(value)) return null;
|
|
5758
|
+
let url;
|
|
5759
|
+
try {
|
|
5760
|
+
url = new URL(value);
|
|
5761
|
+
} catch {
|
|
5762
|
+
return null;
|
|
5763
|
+
}
|
|
5764
|
+
if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash) return null;
|
|
5765
|
+
if (!HOSTNAME.test(url.hostname) || !isPublicHostname(url.hostname) || url.port === "0") return null;
|
|
5766
|
+
const fullPath = /^https:\/\/[^/]*(\/.*)?$/i.exec(value)?.[1] ?? "";
|
|
5767
|
+
if (fullPath.includes("//")) return null;
|
|
5768
|
+
const path = fullPath.replace(/\/+$/, "");
|
|
5769
|
+
if (path && (!allowPath || !SAFE_PATH.test(path) || path.split("/").some((s) => s === ".." || s === "."))) return null;
|
|
5770
|
+
return `${url.origin}${path}`;
|
|
5771
|
+
}
|
|
5772
|
+
function normalizeDomains(value) {
|
|
5773
|
+
const parts = value.split(",").map((part) => part.trim().toLowerCase());
|
|
5774
|
+
if (parts.length > MAX_PLAUSIBLE_DOMAINS) return null;
|
|
5775
|
+
return parts.every((part) => part.length <= 253 && HOSTNAME.test(part)) ? parts.join(",") : null;
|
|
5776
|
+
}
|
|
5777
|
+
function normalizeServer(value) {
|
|
5778
|
+
if (/^https:\/\//i.test(value)) {
|
|
5779
|
+
const origin2 = normalizeHttpsUrl(value, false);
|
|
5780
|
+
return origin2 ? origin2.replace(/^https:\/\//, "") : null;
|
|
5781
|
+
}
|
|
5782
|
+
const bare = /^([a-z0-9.-]+)(?::(\d{1,5}))?$/i.exec(value);
|
|
5783
|
+
if (!bare || bare[2] !== void 0 && (Number(bare[2]) < 1 || Number(bare[2]) > 65535)) return null;
|
|
5784
|
+
const origin = normalizeHttpsUrl(`https://${bare[1].toLowerCase()}${bare[2] === void 0 ? "" : `:${Number(bare[2])}`}`, false);
|
|
5785
|
+
return origin ? origin.replace(/^https:\/\//, "") : null;
|
|
5786
|
+
}
|
|
5787
|
+
function text(value) {
|
|
5788
|
+
return typeof value === "string" && value.trim() && value.length <= 2048 ? value.trim() : null;
|
|
5789
|
+
}
|
|
5790
|
+
function projectMintlifyIntegrations(config) {
|
|
5791
|
+
if (!isRecord(config)) return { warnings: [] };
|
|
5792
|
+
try {
|
|
5793
|
+
return project(config);
|
|
5794
|
+
} catch {
|
|
5795
|
+
return { warnings: [{ code: "unsupported-config", message: "Mintlify analytics configuration could not be read; analytics were not imported." }] };
|
|
5796
|
+
}
|
|
5797
|
+
}
|
|
5798
|
+
function project(config) {
|
|
5799
|
+
const warnings = [];
|
|
5800
|
+
const warn = (message) => warnings.push({ code: "unsupported-config", message });
|
|
5801
|
+
const sources = [];
|
|
5802
|
+
for (const [label, key] of [["integrations", "integrations"], ["analytics", "analytics"]]) {
|
|
5803
|
+
const value = own(config, key);
|
|
5804
|
+
if (value === void 0) continue;
|
|
5805
|
+
if (isRecord(value)) sources.push({ label, block: value });
|
|
5806
|
+
else warn(`Mintlify ${label} must be an object (found ${redact(value)}); analytics from it were not imported.`);
|
|
5807
|
+
}
|
|
5808
|
+
const integrations = {};
|
|
5809
|
+
const pick = (name) => {
|
|
5810
|
+
const found = [];
|
|
5811
|
+
for (const source of sources) {
|
|
5812
|
+
let value = own(source.block, name);
|
|
5813
|
+
if (value === void 0 && name === "ga4" && source.label === "analytics") value = own(source.block, LEGACY_GA4_ALIAS);
|
|
5814
|
+
if (value !== void 0) found.push({ label: `${source.label}.${name}`, value });
|
|
5815
|
+
}
|
|
5816
|
+
if (found.length > 1) {
|
|
5817
|
+
warn(`Mintlify ${found[0].label} and ${found[1].label} are both set; using ${found[0].label} for ${name}.`);
|
|
5818
|
+
}
|
|
5819
|
+
return found;
|
|
5820
|
+
};
|
|
5821
|
+
const field = (label, block, key, required) => {
|
|
5822
|
+
const raw = own(block, key);
|
|
5823
|
+
if (raw === void 0) {
|
|
5824
|
+
if (required) warn(`Mintlify ${label}.${key} is missing; ${label} was not imported.`);
|
|
5825
|
+
return required ? null : void 0;
|
|
5826
|
+
}
|
|
5827
|
+
const value = text(raw);
|
|
5828
|
+
if (value === null) warn(`Mintlify ${label}.${key} is not a usable string (found ${redact(raw)}); ${label} was not imported.`);
|
|
5829
|
+
return value;
|
|
5830
|
+
};
|
|
5831
|
+
const objectFor = (entry) => {
|
|
5832
|
+
if (isRecord(entry.value)) return entry.value;
|
|
5833
|
+
warn(`Mintlify ${entry.label} must be an object (found ${redact(entry.value)}); provider was not imported.`);
|
|
5834
|
+
return null;
|
|
5835
|
+
};
|
|
5836
|
+
const ga4 = pick("ga4")[0];
|
|
5837
|
+
const ga4Block = ga4 ? objectFor(ga4) : null;
|
|
5838
|
+
if (ga4 && ga4Block) {
|
|
5839
|
+
const id = field(ga4.label, ga4Block, "measurementId", true);
|
|
5840
|
+
if (id && GA4_ID.test(id)) integrations.ga4 = { measurementId: id };
|
|
5841
|
+
else if (id) warn(`Mintlify ${ga4.label}.measurementId ${redact(id)} is not a GA4 ID (G-XXXXXXXXXX); Universal Analytics and lowercase IDs are not imported.`);
|
|
5842
|
+
}
|
|
5843
|
+
const gtm = pick("gtm")[0];
|
|
5844
|
+
const gtmBlock = gtm ? objectFor(gtm) : null;
|
|
5845
|
+
if (gtm && gtmBlock) {
|
|
5846
|
+
const id = field(gtm.label, gtmBlock, "tagId", true);
|
|
5847
|
+
if (id && GTM_ID.test(id)) integrations.gtm = { tagId: id };
|
|
5848
|
+
else if (id) warn(`Mintlify ${gtm.label}.tagId ${redact(id)} is not a GTM container ID (GTM-XXXXXXX); GTM was not imported.`);
|
|
5849
|
+
}
|
|
5850
|
+
const plausible = pick("plausible")[0];
|
|
5851
|
+
const plausibleBlock = plausible ? objectFor(plausible) : null;
|
|
5852
|
+
if (plausible && plausibleBlock) {
|
|
5853
|
+
const domainRaw = field(plausible.label, plausibleBlock, "domain", true);
|
|
5854
|
+
const serverRaw = field(plausible.label, plausibleBlock, "server", false);
|
|
5855
|
+
const domain = domainRaw ? normalizeDomains(domainRaw) : null;
|
|
5856
|
+
const server = serverRaw ? normalizeServer(serverRaw) : serverRaw;
|
|
5857
|
+
if (domainRaw && !domain) warn(`Mintlify ${plausible.label}.domain ${redact(domainRaw)} must be hostname(s) without a protocol or path; Plausible was not imported.`);
|
|
5858
|
+
if (serverRaw && !server) warn(`Mintlify ${plausible.label}.server ${redact(serverRaw)} must be a hostname; Plausible was not imported.`);
|
|
5859
|
+
if (domain && server !== null) integrations.plausible = { domain, ...server ? { server } : {} };
|
|
5860
|
+
}
|
|
5861
|
+
const posthog = pick("posthog")[0];
|
|
5862
|
+
const posthogBlock = posthog ? objectFor(posthog) : null;
|
|
5863
|
+
if (posthog && posthogBlock) {
|
|
5864
|
+
const key = field(posthog.label, posthogBlock, "apiKey", true);
|
|
5865
|
+
const hostRaw = field(posthog.label, posthogBlock, "apiHost", false);
|
|
5866
|
+
const host = hostRaw ? normalizeHttpsUrl(hostRaw, true) : hostRaw;
|
|
5867
|
+
const recording = own(posthogBlock, "sessionRecording");
|
|
5868
|
+
if (recording !== void 0 && typeof recording !== "boolean") warn(`Mintlify ${posthog.label}.sessionRecording must be a boolean (found ${redact(recording)}); session recording disabled.`);
|
|
5869
|
+
if (key && !POSTHOG_KEY.test(key)) warn(`Mintlify ${posthog.label}.apiKey ${redact(key)} is not a PostHog project key (phc_...); PostHog was not imported.`);
|
|
5870
|
+
if (hostRaw && !host) warn(`Mintlify ${posthog.label}.apiHost ${redact(hostRaw)} must be an https URL without credentials, query, or fragment; PostHog was not imported.`);
|
|
5871
|
+
if (key && POSTHOG_KEY.test(key) && host !== null) {
|
|
5872
|
+
integrations.posthog = {
|
|
5873
|
+
apiKey: key,
|
|
5874
|
+
...host ? { apiHost: host } : {},
|
|
5875
|
+
// Fail closed: a present non-boolean value turns recording off.
|
|
5876
|
+
...recording !== void 0 ? { sessionRecording: recording === true } : {}
|
|
5877
|
+
};
|
|
5878
|
+
}
|
|
5879
|
+
}
|
|
5880
|
+
const unsupported = /* @__PURE__ */ new Set();
|
|
5881
|
+
for (const source of sources) {
|
|
5882
|
+
for (const key of Object.keys(source.block)) {
|
|
5883
|
+
if (SUPPORTED.includes(key)) continue;
|
|
5884
|
+
if (key === LEGACY_GA4_ALIAS && source.label === "analytics") continue;
|
|
5885
|
+
unsupported.add(/^[A-Za-z0-9_-]{1,40}$/.test(key) ? key : "(invalid name)");
|
|
5886
|
+
}
|
|
5887
|
+
}
|
|
5888
|
+
if (unsupported.size > 0) {
|
|
5889
|
+
const names = [...unsupported].slice(0, 30);
|
|
5890
|
+
warn(`Mintlify analytics/integration providers Thally cannot render were not imported: ${names.join(", ")}${unsupported.size > names.length ? ", ..." : ""}. Supported: ga4, gtm, posthog, plausible.`);
|
|
5891
|
+
}
|
|
5892
|
+
return { ...Object.keys(integrations).length > 0 ? { integrations } : {}, warnings };
|
|
5893
|
+
}
|
|
5894
|
+
function validateIntegrations(integrations) {
|
|
5895
|
+
if (integrations === void 0) return [];
|
|
5896
|
+
const result = projectMintlifyIntegrations({ integrations });
|
|
5897
|
+
const messages = result.warnings.map(
|
|
5898
|
+
(warning) => warning.message.replace(/^Mintlify analytics\/integration providers Thally cannot render were not imported: /, "docs.json integrations: Thally does not support these providers, so they will not be rendered: ").replace(/^Mintlify /, "docs.json ").replace(/\b(?:was|were|are) not imported\b/g, "will not be rendered")
|
|
5899
|
+
);
|
|
5900
|
+
if (result.integrations?.ga4 && result.integrations.gtm) {
|
|
5901
|
+
messages.push("docs.json integrations enable both ga4 and gtm; a GA4 tag inside the GTM container would double-count page views.");
|
|
5902
|
+
}
|
|
5903
|
+
return messages;
|
|
5904
|
+
}
|
|
5905
|
+
|
|
5664
5906
|
// src/repository.ts
|
|
5665
5907
|
var MAX_SOURCE_FILES = 5e3;
|
|
5666
5908
|
var MAX_PAGE_BYTES = 2e6;
|
|
@@ -6477,8 +6719,8 @@ var PATH_SEPARATORS = /[\s"'()<>[\]{}=,;:|\\`*!?#&]+/;
|
|
|
6477
6719
|
function publicAssetKey(repoRelative) {
|
|
6478
6720
|
return repoRelative.split("/", 1)[0].toLowerCase() === "public" ? repoRelative.slice("public/".length) : repoRelative;
|
|
6479
6721
|
}
|
|
6480
|
-
function addPathReferences(
|
|
6481
|
-
for (const word of
|
|
6722
|
+
function addPathReferences(text2, baseDir, exact, loose) {
|
|
6723
|
+
for (const word of text2.split(PATH_SEPARATORS)) {
|
|
6482
6724
|
let token = word.replace(/\.+$/, "");
|
|
6483
6725
|
if (!/\.[a-z0-9]{2,5}$/i.test(token) || token.startsWith("//")) continue;
|
|
6484
6726
|
if (token.includes("%")) {
|
|
@@ -6520,8 +6762,8 @@ function classifyApiSpec(path) {
|
|
|
6520
6762
|
} catch {
|
|
6521
6763
|
return "unknown";
|
|
6522
6764
|
}
|
|
6523
|
-
const
|
|
6524
|
-
const topLevel =
|
|
6765
|
+
const text2 = buffer.toString("utf8", 0, bytesRead);
|
|
6766
|
+
const topLevel = text2.match(/^(?:openapi|swagger|asyncapi)\s*:/m)?.[0] ?? text2.match(/^\s*\{\s*"(?:openapi|swagger|asyncapi)"\s*:/m)?.[0];
|
|
6525
6767
|
if (!topLevel) return "unknown";
|
|
6526
6768
|
return /asyncapi/i.test(topLevel) ? "asyncapi" : "openapi";
|
|
6527
6769
|
}
|
|
@@ -6619,6 +6861,27 @@ function resolveMintlifyApiSpecs(mintlifyConfig, files, warnings, remoteSpecs) {
|
|
|
6619
6861
|
}
|
|
6620
6862
|
return specs;
|
|
6621
6863
|
}
|
|
6864
|
+
function rewriteMintlifyPageSpecRefs(pages, specs, remoteUrls, warnings) {
|
|
6865
|
+
for (const page of pages) {
|
|
6866
|
+
const ref = page.openapi ? splitOpenApiRef(page.openapi) : null;
|
|
6867
|
+
if (!ref?.specRef) continue;
|
|
6868
|
+
if (/^https?:\/\//i.test(ref.specRef)) {
|
|
6869
|
+
if (!remoteUrls.has(ref.specRef)) {
|
|
6870
|
+
warnings.push({ code: "unsupported-config", message: `Page "${page.id}" references the remote OpenAPI spec "${ref.specRef}", which is not referenced from docs.json and was not migrated; the page will not render an endpoint.`, source: page.source });
|
|
6871
|
+
}
|
|
6872
|
+
continue;
|
|
6873
|
+
}
|
|
6874
|
+
const key = ref.specRef.split(/[?#]/, 1)[0].replace(/\\/g, "/").replace(/^(?:\.\/)+/, "").replace(/^\/+/, "");
|
|
6875
|
+
const byPath = specs.find((spec) => spec.sourcePath === key);
|
|
6876
|
+
const byName = specs.filter((spec) => spec.filename.toLowerCase() === specRefBaseName(key));
|
|
6877
|
+
const match = byPath ?? (byName.length === 1 ? byName[0] : void 0);
|
|
6878
|
+
if (match) {
|
|
6879
|
+
page.openapi = withSpecRef(ref, specAssetPath(match.filename));
|
|
6880
|
+
} else {
|
|
6881
|
+
warnings.push({ code: "unsupported-config", message: `Page "${page.id}" references the OpenAPI spec "${ref.specRef}", which is not referenced from docs.json and was not migrated; the page will not render an endpoint. Add the spec to a tab's api setting.`, source: page.source });
|
|
6882
|
+
}
|
|
6883
|
+
}
|
|
6884
|
+
}
|
|
6622
6885
|
var OPENAPI_HTTP_METHODS = ["get", "post", "put", "patch", "delete", "options", "head", "trace"];
|
|
6623
6886
|
var FERN_CRUD_METHOD_NAMES = {
|
|
6624
6887
|
findall: "list",
|
|
@@ -7009,12 +7272,12 @@ function externalizeMissingFernLinks(body, pageIds, sourceSiteUrl, externalized)
|
|
|
7009
7272
|
return target;
|
|
7010
7273
|
}
|
|
7011
7274
|
};
|
|
7012
|
-
return replaceOutsideCode(body, (
|
|
7275
|
+
return replaceOutsideCode(body, (text2) => text2.replace(/(\]\()\/(?!\/)([^\s)]+)(\))/g, (_match, before, target, after) => `${before}${rewrite(`/${target}`)}${after}`).replace(/(\b(?:href|to)=(['"]))\/(?!\/)([^'"\n]+)\2/g, (_match, before, quote, target) => `${before}${rewrite(`/${target}`)}${quote}`));
|
|
7013
7276
|
}
|
|
7014
7277
|
function stripFernBasePathFromLinks(body, basePath) {
|
|
7015
7278
|
if (!basePath) return body;
|
|
7016
7279
|
const escaped = basePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7017
|
-
return replaceOutsideCode(body, (
|
|
7280
|
+
return replaceOutsideCode(body, (text2) => text2.replace(new RegExp(`(\\]\\()${escaped}(?=\\/|[)#?])`, "g"), (match, prefix, offset, source) => prefix + (source[offset + match.length] === "/" ? "" : "/")).replace(new RegExp(`(\\b(?:href|to)=["'])${escaped}(?=\\/|["'#?])`, "g"), (match, prefix, offset, source) => prefix + (source[offset + match.length] === "/" ? "" : "/")));
|
|
7018
7281
|
}
|
|
7019
7282
|
function rewriteMintlifyMountedLinks(body, pageIds) {
|
|
7020
7283
|
const rewrite = (target) => {
|
|
@@ -7031,7 +7294,7 @@ function rewriteMintlifyMountedLinks(body, pageIds) {
|
|
|
7031
7294
|
}
|
|
7032
7295
|
return target;
|
|
7033
7296
|
};
|
|
7034
|
-
return replaceOutsideCode(body, (
|
|
7297
|
+
return replaceOutsideCode(body, (text2) => text2.replace(/(\]\()(\/[^\s)]+)(\))/g, (_match, before, target, after) => `${before}${rewrite(target)}${after}`).replace(/(\b(?:href|to)=(['"]))(\/[^'"\n]+)\2/g, (_match, before, quote, target) => `${before}${rewrite(target)}${quote}`));
|
|
7035
7298
|
}
|
|
7036
7299
|
function preserveLinkedAnchors(pages) {
|
|
7037
7300
|
const pageById = new Map(pages.map((page) => [page.id, page]));
|
|
@@ -7055,10 +7318,10 @@ function preserveLinkedAnchors(pages) {
|
|
|
7055
7318
|
if (id !== currentId) crossPageRequests.add(`${id}#${fragment}`);
|
|
7056
7319
|
};
|
|
7057
7320
|
for (const page of pages) {
|
|
7058
|
-
replaceOutsideCode(page.body, (
|
|
7059
|
-
for (const match of
|
|
7060
|
-
for (const match of
|
|
7061
|
-
return
|
|
7321
|
+
replaceOutsideCode(page.body, (text2) => {
|
|
7322
|
+
for (const match of text2.matchAll(/\]\(([^)\s]+)\)/g)) addTarget(match[1], page.id);
|
|
7323
|
+
for (const match of text2.matchAll(/\b(?:href|to)=(['"])([^'"\n]+)\1/g)) addTarget(match[2], page.id);
|
|
7324
|
+
return text2;
|
|
7062
7325
|
});
|
|
7063
7326
|
}
|
|
7064
7327
|
const comparable = (value) => value.replace(/&(?:lt|gt|amp|quot);/g, " ").toLowerCase().replace(/[^\p{L}\p{N}]+/gu, "");
|
|
@@ -7082,9 +7345,9 @@ function preserveLinkedAnchors(pages) {
|
|
|
7082
7345
|
return match ? { index, text: match[1] } : null;
|
|
7083
7346
|
}).filter((entry) => entry !== null);
|
|
7084
7347
|
const existing = /* @__PURE__ */ new Set();
|
|
7085
|
-
replaceOutsideCode(page.body, (
|
|
7086
|
-
for (const match of
|
|
7087
|
-
return
|
|
7348
|
+
replaceOutsideCode(page.body, (text2) => {
|
|
7349
|
+
for (const match of text2.matchAll(/\bid=(?:"([^"]+)"|'([^']+)')/g)) existing.add(match[1] ?? match[2]);
|
|
7350
|
+
return text2;
|
|
7088
7351
|
});
|
|
7089
7352
|
const candidateIndexes = /* @__PURE__ */ new Map();
|
|
7090
7353
|
for (const heading of headings) {
|
|
@@ -7246,7 +7509,7 @@ function repositoryAssetHref(value, currentFile, siteRoot, onReferenced) {
|
|
|
7246
7509
|
}
|
|
7247
7510
|
}
|
|
7248
7511
|
function rewriteFernIdRenameLinks(body, renames) {
|
|
7249
|
-
return replaceOutsideCode(body, (
|
|
7512
|
+
return replaceOutsideCode(body, (text2) => {
|
|
7250
7513
|
const rewriteTarget = (target) => {
|
|
7251
7514
|
const suffixIndex = target.search(/[?#]/);
|
|
7252
7515
|
const path = (suffixIndex >= 0 ? target.slice(0, suffixIndex) : target).replace(/^\/+/, "");
|
|
@@ -7254,7 +7517,7 @@ function rewriteFernIdRenameLinks(body, renames) {
|
|
|
7254
7517
|
const renamed = renames.get(path);
|
|
7255
7518
|
return renamed ? `/${renamed}${suffix}` : target;
|
|
7256
7519
|
};
|
|
7257
|
-
return
|
|
7520
|
+
return text2.replace(/(\]\()\/([^\s)]+)(?=[\s)]|$)/g, (_match, prefix, target) => `${prefix}${rewriteTarget(`/${target}`)}`).replace(/(\bhref=")\/([^"]+)(")/g, (_match, prefix, target, suffix) => `${prefix}${rewriteTarget(`/${target}`)}${suffix}`);
|
|
7258
7521
|
});
|
|
7259
7522
|
}
|
|
7260
7523
|
function rewriteRepositoryAssetLinks(body, currentFile, siteRoot, onReferenced) {
|
|
@@ -7986,6 +8249,7 @@ function migrateRepository(options) {
|
|
|
7986
8249
|
const page = parseMarkdownPage({
|
|
7987
8250
|
id,
|
|
7988
8251
|
navigationId,
|
|
8252
|
+
warn: (message) => warnings.push({ code: "unsupported-config", message, source: relative5(repositoryDir, file.absolutePath).replace(/\\/g, "/") }),
|
|
7989
8253
|
...locale ? { locale } : {},
|
|
7990
8254
|
raw,
|
|
7991
8255
|
platform,
|
|
@@ -8446,6 +8710,7 @@ function migrateRepository(options) {
|
|
|
8446
8710
|
}
|
|
8447
8711
|
if (withheldSpecRefs.some((ref) => specRefMatches(ref, spec.sourcePath, spec.filename, true))) warnSharedSpec(spec.sourcePath);
|
|
8448
8712
|
}
|
|
8713
|
+
let pageSpecs = resolvedSpecs;
|
|
8449
8714
|
if (resolvedSpecs.length > 0) {
|
|
8450
8715
|
docsConfig = injectOpenApiSpecs(docsConfig, resolvedSpecs, warnings);
|
|
8451
8716
|
const { operationLinks, prefixLandings } = apiOperationLinkMap(
|
|
@@ -8466,10 +8731,12 @@ function migrateRepository(options) {
|
|
|
8466
8731
|
assets.push(specAsset(filename, readFileSync5(fallback.absolutePath)));
|
|
8467
8732
|
}
|
|
8468
8733
|
docsConfig = injectOpenApiSpecs(docsConfig, [{ filename }]);
|
|
8734
|
+
pageSpecs = [{ filename, sourcePath: fallback.relativePath }];
|
|
8469
8735
|
if (withheldSpecRefs.some(matches)) warnSharedSpec(fallback.relativePath);
|
|
8470
8736
|
}
|
|
8471
8737
|
}
|
|
8472
8738
|
}
|
|
8739
|
+
rewriteMintlifyPageSpecRefs(pages, pageSpecs, new Set(remoteApiSpecs.map((spec) => spec.url)), warnings);
|
|
8473
8740
|
}
|
|
8474
8741
|
if (platform === "mintlify") {
|
|
8475
8742
|
const sources = new Set((docsConfig.redirects ?? []).map((redirect) => redirect.source));
|
|
@@ -8778,6 +9045,9 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}` : "No importable Markdown
|
|
|
8778
9045
|
docsConfig = { ...docsConfig, navbar: { ...docsConfig.navbar, logo: null } };
|
|
8779
9046
|
}
|
|
8780
9047
|
if (mintlifyConfig) {
|
|
9048
|
+
const analytics = projectMintlifyIntegrations(mintlifyConfig);
|
|
9049
|
+
warnings.push(...analytics.warnings);
|
|
9050
|
+
if (analytics.integrations) docsConfig = { ...docsConfig, integrations: analytics.integrations };
|
|
8781
9051
|
const appearance = mintlifyAppearance(mintlifyConfig, warnings);
|
|
8782
9052
|
if (Object.keys(appearance).length > 0) {
|
|
8783
9053
|
docsConfig = { ...docsConfig, appearance: { ...docsConfig.appearance, ...appearance } };
|
|
@@ -8889,6 +9159,8 @@ function renderPage(bundle, page) {
|
|
|
8889
9159
|
page.hidden ? "hidden: true" : null,
|
|
8890
9160
|
page.noindex ? "noindex: true" : null,
|
|
8891
9161
|
page.openapi ? `openapi: ${yamlString(page.openapi)}` : null,
|
|
9162
|
+
page.api ? `api: ${yamlString(page.api)}` : null,
|
|
9163
|
+
page.authMethod ? `authMethod: ${yamlString(page.authMethod)}` : null,
|
|
8892
9164
|
bundle.sourceKind === "url" ? `source: ${yamlString(page.source)}` : null,
|
|
8893
9165
|
"---",
|
|
8894
9166
|
"",
|
|
@@ -8896,6 +9168,9 @@ function renderPage(bundle, page) {
|
|
|
8896
9168
|
""
|
|
8897
9169
|
].filter((line) => line !== null).join("\n");
|
|
8898
9170
|
}
|
|
9171
|
+
function isIntegrationsObject(value) {
|
|
9172
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
9173
|
+
}
|
|
8899
9174
|
function mergeMigrationConfig(existing, incoming) {
|
|
8900
9175
|
const tabs = existing.tabs.filter((tab) => tab.tab.toLowerCase() !== "changelog");
|
|
8901
9176
|
const names = new Set(tabs.map((tab) => tab.tab.toLowerCase()));
|
|
@@ -8966,7 +9241,15 @@ function mergeMigrationConfig(existing, incoming) {
|
|
|
8966
9241
|
// Collection presentation belongs to the imported information
|
|
8967
9242
|
// architecture; starter defaults must not coerce source dropdowns to tabs.
|
|
8968
9243
|
navigation: incoming.navigation ?? existing.navigation,
|
|
8969
|
-
...i18n ? { i18n } : {}
|
|
9244
|
+
...i18n ? { i18n } : {},
|
|
9245
|
+
// Existing providers win per provider; imported ones fill the gaps.
|
|
9246
|
+
// A malformed (string/array) existing value must not spread into index keys.
|
|
9247
|
+
...isIntegrationsObject(existing.integrations) || isIntegrationsObject(incoming.integrations) ? {
|
|
9248
|
+
integrations: {
|
|
9249
|
+
...isIntegrationsObject(incoming.integrations) ? incoming.integrations : {},
|
|
9250
|
+
...isIntegrationsObject(existing.integrations) ? existing.integrations : {}
|
|
9251
|
+
}
|
|
9252
|
+
} : {}
|
|
8970
9253
|
};
|
|
8971
9254
|
}
|
|
8972
9255
|
function renderMigrationFiles(bundle, options = {}) {
|
|
@@ -9957,7 +10240,7 @@ ${fence}
|
|
|
9957
10240
|
}
|
|
9958
10241
|
});
|
|
9959
10242
|
const escape = turndown.escape.bind(turndown);
|
|
9960
|
-
turndown.escape = (
|
|
10243
|
+
turndown.escape = (text2) => escape(text2).replace(/[<{]/g, (match) => `\\${match}`);
|
|
9961
10244
|
const body = turndown.turndown(root.html() ?? "").trim();
|
|
9962
10245
|
if (!title || body.length < 40 && $("article").length === 0) return { page: null, links };
|
|
9963
10246
|
return {
|
|
@@ -10510,6 +10793,11 @@ async function migrateUrl(options) {
|
|
|
10510
10793
|
topLevelNavigation
|
|
10511
10794
|
});
|
|
10512
10795
|
if (sourceMintlifyProjection) warnings.push(...sourceMintlifyProjection.warnings);
|
|
10796
|
+
if (sourceMintlifyConfig) {
|
|
10797
|
+
const analytics = projectMintlifyIntegrations(sourceMintlifyConfig);
|
|
10798
|
+
warnings.push(...analytics.warnings);
|
|
10799
|
+
if (analytics.integrations) docsConfig.integrations = analytics.integrations;
|
|
10800
|
+
}
|
|
10513
10801
|
if (docusaurusRedirects.length > 0) {
|
|
10514
10802
|
docsConfig.redirects = [...new Map(docusaurusRedirects.map((redirect) => [
|
|
10515
10803
|
`${redirect.source}:${redirect.destination}`,
|
|
@@ -10658,8 +10946,8 @@ async function downloadSpec(value, fetcher) {
|
|
|
10658
10946
|
throw new Error("Remote OpenAPI spec redirected too many times.");
|
|
10659
10947
|
}
|
|
10660
10948
|
function parseOpenApi(content, extension) {
|
|
10661
|
-
const
|
|
10662
|
-
const parsed = extension === "yaml" || !
|
|
10949
|
+
const text2 = content.toString("utf8");
|
|
10950
|
+
const parsed = extension === "yaml" || !text2.trimStart().startsWith("{") ? parseYaml6(text2) : JSON.parse(text2);
|
|
10663
10951
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("OpenAPI spec is not an object.");
|
|
10664
10952
|
const document = parsed;
|
|
10665
10953
|
if (typeof document.openapi !== "string" || !/^3\./.test(document.openapi)) {
|
|
@@ -10700,6 +10988,7 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
10700
10988
|
const tabs = bundle.docsConfig.tabs.map((tab) => ({ ...tab }));
|
|
10701
10989
|
const redirects = [...bundle.docsConfig.redirects ?? []];
|
|
10702
10990
|
const warnings = [...bundle.warnings];
|
|
10991
|
+
const pages = bundle.pages.map((page) => ({ ...page }));
|
|
10703
10992
|
const authoredLinks = /* @__PURE__ */ new Set();
|
|
10704
10993
|
for (const page of bundle.pages) {
|
|
10705
10994
|
for (const match of page.body.matchAll(/\/[a-z0-9_/-]+/gi)) {
|
|
@@ -10720,6 +11009,10 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
10720
11009
|
const operations = parseOpenApi(body, extension);
|
|
10721
11010
|
const filename = `openapi-${createHash2("sha256").update(reference.url).digest("hex").slice(0, 12)}.${extension}`;
|
|
10722
11011
|
assets.push({ path: `openapi/${filename}`, content: body, projectRelative: true });
|
|
11012
|
+
for (const page of pages) {
|
|
11013
|
+
const ref = page.openapi ? splitOpenApiRef(page.openapi) : null;
|
|
11014
|
+
if (ref?.specRef === reference.url) page.openapi = withSpecRef(ref, `openapi/${filename}`);
|
|
11015
|
+
}
|
|
10723
11016
|
const tab = reference.tabLabel ? tabs.find((candidate) => candidate.tab === reference.tabLabel) : tabs.find((candidate) => candidate.tab.toLowerCase().includes("api"));
|
|
10724
11017
|
if (tab) tab.api = { source: `openapi/${filename}` };
|
|
10725
11018
|
else insertApiTab(tabs, { tab: reference.tabLabel ?? "API Reference", ...reference.icon ? { icon: reference.icon } : {}, ...reference.hidden ? { hidden: true } : {}, api: { source: `openapi/${filename}` } }, reference.parentTab);
|
|
@@ -10748,6 +11041,7 @@ async function hydrateRemoteApiSpecs(bundle, fetcher) {
|
|
|
10748
11041
|
}
|
|
10749
11042
|
return {
|
|
10750
11043
|
...bundle,
|
|
11044
|
+
pages,
|
|
10751
11045
|
assets,
|
|
10752
11046
|
docsConfig: { ...bundle.docsConfig, tabs, ...redirects.length > 0 ? { redirects } : {} },
|
|
10753
11047
|
warnings
|
|
@@ -10769,11 +11063,13 @@ export {
|
|
|
10769
11063
|
parseGitHubRepositoryUrl,
|
|
10770
11064
|
parseMarkdownPage,
|
|
10771
11065
|
projectFernNavigation,
|
|
11066
|
+
projectMintlifyIntegrations,
|
|
10772
11067
|
projectMintlifyNavigation,
|
|
10773
11068
|
pruneMissingNavigationPages,
|
|
10774
11069
|
readFernConfig,
|
|
10775
11070
|
readMintlifyConfig,
|
|
10776
11071
|
renderMigrationFiles,
|
|
11072
|
+
validateIntegrations,
|
|
10777
11073
|
validateMigrationUrl
|
|
10778
11074
|
};
|
|
10779
11075
|
//# sourceMappingURL=index.js.map
|