@thallylabs/migrate 0.2.42 → 0.2.44
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 +223 -26
- package/dist/index.d.ts +63 -4
- package/dist/index.js +2890 -1166
- package/dist/index.js.map +1 -1
- package/dist/url-migration.d.ts +2 -2
- package/dist/url-migration.js +413 -69
- package/dist/url-migration.js.map +1 -1
- package/dist/{url-run-CPzQfjRW.d.ts → url-run-D-E4dr2h.d.ts} +9 -1
- package/package.json +2 -1
package/dist/url-migration.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// src/url-run.ts
|
|
2
|
-
import { createHash as
|
|
2
|
+
import { createHash as createHash5 } from "crypto";
|
|
3
3
|
import { load as load7 } from "cheerio";
|
|
4
4
|
import { parse as parse2, postprocess, preprocess } from "micromark";
|
|
5
|
-
import
|
|
5
|
+
import remarkParse5 from "remark-parse";
|
|
6
6
|
import remarkMdx4 from "remark-mdx";
|
|
7
|
-
import { unified as
|
|
7
|
+
import { unified as unified5 } from "unified";
|
|
8
8
|
|
|
9
9
|
// src/navigation.ts
|
|
10
10
|
import { existsSync, lstatSync, readFileSync, realpathSync as realpathSync2 } from "fs";
|
|
@@ -56,6 +56,32 @@ function playgroundDisplay(value, where, warn) {
|
|
|
56
56
|
return void 0;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
// src/redirects.ts
|
|
60
|
+
function trimTrailingSlashes(route) {
|
|
61
|
+
let end = route.length;
|
|
62
|
+
while (end > 0 && route[end - 1] === "/") end--;
|
|
63
|
+
return route.slice(0, end);
|
|
64
|
+
}
|
|
65
|
+
function exactRoute(route) {
|
|
66
|
+
return route.startsWith("/") && !/[?:*#()[\]{}]/.test(route) ? trimTrailingSlashes(route) || "/" : null;
|
|
67
|
+
}
|
|
68
|
+
function literalRoute(route) {
|
|
69
|
+
return exactRoute(route)?.toLowerCase() ?? null;
|
|
70
|
+
}
|
|
71
|
+
function resolveDotSegments(route) {
|
|
72
|
+
const segments = [];
|
|
73
|
+
for (const segment of route.split("/").slice(1)) {
|
|
74
|
+
const dots = segment.replace(/%2e/gi, ".");
|
|
75
|
+
if (dots === "..") segments.pop();
|
|
76
|
+
else if (dots !== ".") segments.push(segment);
|
|
77
|
+
}
|
|
78
|
+
return `/${segments.join("/")}`;
|
|
79
|
+
}
|
|
80
|
+
function destinationRoute(destination) {
|
|
81
|
+
const route = destination.startsWith("//") ? null : exactRoute(destination.split(/[?#]/, 1)[0]);
|
|
82
|
+
return route === null ? null : resolveDotSegments(route);
|
|
83
|
+
}
|
|
84
|
+
|
|
59
85
|
// src/navigation.ts
|
|
60
86
|
function titleCase(value) {
|
|
61
87
|
return value.split(/[-_]/).map((word) => ["api", "cli", "sdk", "ui"].includes(word.toLowerCase()) ? word.toUpperCase() : word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
@@ -497,15 +523,15 @@ function createMigrationAssetCache() {
|
|
|
497
523
|
load(url, acquire) {
|
|
498
524
|
const existing = get(url);
|
|
499
525
|
if (existing) return existing;
|
|
500
|
-
const
|
|
526
|
+
const request2 = Promise.resolve().then(acquire).then((asset) => {
|
|
501
527
|
pending.delete(url);
|
|
502
528
|
return remember(url, asset);
|
|
503
529
|
}, (error) => {
|
|
504
530
|
pending.delete(url);
|
|
505
531
|
throw error;
|
|
506
532
|
});
|
|
507
|
-
pending.set(url,
|
|
508
|
-
return
|
|
533
|
+
pending.set(url, request2);
|
|
534
|
+
return request2;
|
|
509
535
|
},
|
|
510
536
|
delete(url) {
|
|
511
537
|
settled.delete(url);
|
|
@@ -1270,9 +1296,9 @@ function recoverFlightArticleCode($, root) {
|
|
|
1270
1296
|
const projectionBudget = expansionBudget();
|
|
1271
1297
|
recoverFlightTreeTabs($, root, projectionBudget);
|
|
1272
1298
|
const renderedHeadings = root.find("h1,h2,h3,h4,h5,h6").toArray().filter((node) => $(node).attr("data-thally-static-disclosure-heading") === void 0);
|
|
1273
|
-
const
|
|
1299
|
+
const headingText2 = renderedHeadings.map((node) => labelText($(node).text()));
|
|
1274
1300
|
const existingCode = root.find("pre").toArray().map((node) => renderedCode($, node));
|
|
1275
|
-
if (!
|
|
1301
|
+
if (!headingText2.length || !existingCode.length) return;
|
|
1276
1302
|
const prose = root.clone();
|
|
1277
1303
|
prose.find("pre,button,script,style,nav,footer,aside").remove();
|
|
1278
1304
|
const renderedProse = labelText(prose.text());
|
|
@@ -1285,7 +1311,7 @@ function recoverFlightArticleCode($, root) {
|
|
|
1285
1311
|
const anchor = /\s+\[#([A-Za-z\d_.:-]+)\]$/.exec(text2);
|
|
1286
1312
|
return anchor && $(renderedHeadings[index]).attr("id") === anchor[1] ? text2.slice(0, anchor.index) : text2;
|
|
1287
1313
|
});
|
|
1288
|
-
if (JSON.stringify(headings) !== JSON.stringify(
|
|
1314
|
+
if (JSON.stringify(headings) !== JSON.stringify(headingText2)) continue;
|
|
1289
1315
|
let proseCursor = 0;
|
|
1290
1316
|
let hasMatchingProse = true;
|
|
1291
1317
|
for (const paragraph of nodes.filter((node) => node.type === "paragraph" || node.type === "tableCell")) {
|
|
@@ -1884,29 +1910,42 @@ function projectMigrationMedia(html, base) {
|
|
|
1884
1910
|
}
|
|
1885
1911
|
|
|
1886
1912
|
// src/url-identity.ts
|
|
1887
|
-
import { createHash as
|
|
1913
|
+
import { createHash as createHash4 } from "crypto";
|
|
1888
1914
|
import { load as load6 } from "cheerio";
|
|
1889
1915
|
|
|
1890
1916
|
// src/url.ts
|
|
1891
1917
|
import { load as load5 } from "cheerio";
|
|
1892
1918
|
import remarkMdx3 from "remark-mdx";
|
|
1893
|
-
import
|
|
1919
|
+
import remarkParse4 from "remark-parse";
|
|
1894
1920
|
import TurndownService from "turndown";
|
|
1895
|
-
import { unified as
|
|
1896
|
-
import { parse as
|
|
1921
|
+
import { unified as unified4 } from "unified";
|
|
1922
|
+
import { parse as parseYaml3, stringify as stringifyYaml2 } from "yaml";
|
|
1923
|
+
|
|
1924
|
+
// src/url-openapi.ts
|
|
1925
|
+
import { createHash as createHash2 } from "crypto";
|
|
1926
|
+
|
|
1927
|
+
// src/remote-spec.ts
|
|
1928
|
+
import { lookup } from "dns/promises";
|
|
1929
|
+
import { request } from "https";
|
|
1930
|
+
import { isIP } from "net";
|
|
1931
|
+
import { createGunzip } from "zlib";
|
|
1932
|
+
|
|
1933
|
+
// src/spec-exclude.ts
|
|
1934
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
1897
1935
|
|
|
1898
1936
|
// src/analytics.ts
|
|
1899
1937
|
var HOSTNAME_LABEL = "[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?";
|
|
1900
1938
|
var HOSTNAME = new RegExp(`^${HOSTNAME_LABEL}(?:\\.${HOSTNAME_LABEL})*$`);
|
|
1901
1939
|
|
|
1902
1940
|
// src/mdx.ts
|
|
1941
|
+
import { analyze } from "eslint-scope";
|
|
1903
1942
|
import { posix } from "path";
|
|
1904
1943
|
import { compileSync } from "@mdx-js/mdx";
|
|
1905
1944
|
import { nameToEmoji } from "gemoji";
|
|
1906
1945
|
import remarkGfm2 from "remark-gfm";
|
|
1907
1946
|
import remarkMdx2 from "remark-mdx";
|
|
1908
|
-
import
|
|
1909
|
-
import { unified as
|
|
1947
|
+
import remarkParse3 from "remark-parse";
|
|
1948
|
+
import { unified as unified3 } from "unified";
|
|
1910
1949
|
|
|
1911
1950
|
// src/builtin-components.ts
|
|
1912
1951
|
var THALLY_BUILTIN_COMPONENTS = /* @__PURE__ */ new Set([
|
|
@@ -2343,13 +2382,13 @@ function unresolvedExpressionNames(expression, pageNames) {
|
|
|
2343
2382
|
}
|
|
2344
2383
|
|
|
2345
2384
|
// src/frontmatter.ts
|
|
2346
|
-
import { parse as
|
|
2385
|
+
import { parse as parseYaml2 } from "yaml";
|
|
2347
2386
|
function salvageFrontmatterLines(matter) {
|
|
2348
2387
|
const data = {};
|
|
2349
2388
|
for (const line of matter.split(/\r?\n/)) {
|
|
2350
2389
|
if (!/^[A-Za-z_][\w-]*:\s?/.test(line)) continue;
|
|
2351
2390
|
try {
|
|
2352
|
-
const parsedLine =
|
|
2391
|
+
const parsedLine = parseYaml2(line);
|
|
2353
2392
|
if (parsedLine && typeof parsedLine === "object" && !Array.isArray(parsedLine)) {
|
|
2354
2393
|
Object.assign(data, parsedLine);
|
|
2355
2394
|
}
|
|
@@ -2373,7 +2412,7 @@ function parseFrontmatter(raw) {
|
|
|
2373
2412
|
return { content, data: {} };
|
|
2374
2413
|
}
|
|
2375
2414
|
try {
|
|
2376
|
-
const parsed =
|
|
2415
|
+
const parsed = parseYaml2(matter);
|
|
2377
2416
|
return {
|
|
2378
2417
|
content,
|
|
2379
2418
|
data: parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {}
|
|
@@ -2387,18 +2426,136 @@ function parseFrontmatter(raw) {
|
|
|
2387
2426
|
}
|
|
2388
2427
|
}
|
|
2389
2428
|
|
|
2429
|
+
// src/source-styles.ts
|
|
2430
|
+
import postcss from "postcss";
|
|
2431
|
+
import selectorParser from "postcss-selector-parser";
|
|
2432
|
+
import ts2 from "typescript";
|
|
2433
|
+
var CONTENT_CONTAINER = ".thally-docs-prose";
|
|
2434
|
+
var SOURCE_PAGE_ATTRIBUTE = "data-thally-source-page";
|
|
2435
|
+
var SCOPE = `:where(${CONTENT_CONTAINER}, [${SOURCE_PAGE_ATTRIBUTE}])`;
|
|
2436
|
+
|
|
2437
|
+
// src/fence-meta.ts
|
|
2438
|
+
import remarkParse2 from "remark-parse";
|
|
2439
|
+
import { unified as unified2 } from "unified";
|
|
2440
|
+
function delimitedEnd(meta, start) {
|
|
2441
|
+
const opening = meta[start];
|
|
2442
|
+
if (opening === '"' || opening === "'") {
|
|
2443
|
+
let close = start + 1;
|
|
2444
|
+
while (close < meta.length && meta[close] !== opening) close += meta[close] === "\\" && meta[close + 1] === opening ? 2 : 1;
|
|
2445
|
+
return close < meta.length ? close + 1 : close;
|
|
2446
|
+
}
|
|
2447
|
+
if (opening !== "{") return void 0;
|
|
2448
|
+
let depth = 0;
|
|
2449
|
+
let quote = "";
|
|
2450
|
+
for (let index = start; index < meta.length; index++) {
|
|
2451
|
+
const char = meta[index];
|
|
2452
|
+
if (quote) {
|
|
2453
|
+
if (char === quote) quote = "";
|
|
2454
|
+
} else if (char === '"' || char === "'") quote = char;
|
|
2455
|
+
else if (char === "{") depth++;
|
|
2456
|
+
else if (char === "}" && --depth === 0) return index + 1;
|
|
2457
|
+
}
|
|
2458
|
+
return meta.length;
|
|
2459
|
+
}
|
|
2460
|
+
function tokens(meta) {
|
|
2461
|
+
const result = [];
|
|
2462
|
+
let index = 0;
|
|
2463
|
+
while (index < meta.length) {
|
|
2464
|
+
if (/\s/.test(meta[index])) {
|
|
2465
|
+
index++;
|
|
2466
|
+
continue;
|
|
2467
|
+
}
|
|
2468
|
+
const start = index;
|
|
2469
|
+
const delimited = delimitedEnd(meta, index);
|
|
2470
|
+
if (delimited !== void 0) {
|
|
2471
|
+
result.push({ start, end: delimited, value: meta.slice(start, delimited), quoted: meta[start] !== "{", group: meta[start] === "{" });
|
|
2472
|
+
index = delimited;
|
|
2473
|
+
continue;
|
|
2474
|
+
}
|
|
2475
|
+
const key = /^([A-Za-z][\w-]*)=/.exec(meta.slice(index));
|
|
2476
|
+
if (key) {
|
|
2477
|
+
index += key[0].length;
|
|
2478
|
+
const groupEnd = delimitedEnd(meta, index);
|
|
2479
|
+
if (groupEnd !== void 0) index = groupEnd;
|
|
2480
|
+
else while (index < meta.length && !/\s/.test(meta[index])) index++;
|
|
2481
|
+
result.push({ start, end: index, key: key[1], value: meta.slice(start, index) });
|
|
2482
|
+
continue;
|
|
2483
|
+
}
|
|
2484
|
+
while (index < meta.length && !/\s/.test(meta[index])) {
|
|
2485
|
+
if (index > start && meta[index] === "{" && /^\{[\d,\s-]*\}/.test(meta.slice(index))) break;
|
|
2486
|
+
index++;
|
|
2487
|
+
}
|
|
2488
|
+
result.push({ start, end: index, value: meta.slice(start, index) });
|
|
2489
|
+
}
|
|
2490
|
+
return result;
|
|
2491
|
+
}
|
|
2492
|
+
function normalizeMintlifyCodeFences(body, warn) {
|
|
2493
|
+
const tree = unified2().use(remarkParse2).parse(body);
|
|
2494
|
+
const edits = [];
|
|
2495
|
+
const removed = /* @__PURE__ */ new Set();
|
|
2496
|
+
const unknown = /* @__PURE__ */ new Set();
|
|
2497
|
+
const supported = /* @__PURE__ */ new Set(["title", "filename", "framework", "tag", "icon", "highlight", "focus", "wrap", "lines", "expandable", "nocopy"]);
|
|
2498
|
+
function visit(node) {
|
|
2499
|
+
if (node.type === "code" && node.position?.start.offset !== void 0) {
|
|
2500
|
+
const start = node.position.start.offset;
|
|
2501
|
+
const lineEnd = body.indexOf("\n", start);
|
|
2502
|
+
const end = lineEnd < 0 ? body.length : lineEnd;
|
|
2503
|
+
const line = body.slice(start, end);
|
|
2504
|
+
const opening = /^([`~]{3,}[^\s]*)([ \t]+)(.*?)(\r?)$/.exec(line);
|
|
2505
|
+
if (opening) {
|
|
2506
|
+
const meta = opening[3];
|
|
2507
|
+
const kept = tokens(meta).filter((token) => {
|
|
2508
|
+
if (token.key === "theme" || !token.key && !token.quoted && !token.group && token.value === "twoslash") {
|
|
2509
|
+
removed.add(token.key ?? token.value);
|
|
2510
|
+
return false;
|
|
2511
|
+
}
|
|
2512
|
+
if (token.key && !supported.has(token.key)) unknown.add(token.key);
|
|
2513
|
+
return true;
|
|
2514
|
+
});
|
|
2515
|
+
const normalized = kept.map((token) => meta.slice(token.start, token.end)).join(" ");
|
|
2516
|
+
if (normalized !== meta && kept.length !== tokens(meta).length) edits.push({ start, end, value: `${opening[1]}${normalized ? ` ${normalized}` : ""}${opening[4]}` });
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
for (const child of node.children ?? []) visit(child);
|
|
2520
|
+
}
|
|
2521
|
+
visit(tree);
|
|
2522
|
+
if (removed.size) warn?.(`Removed unsupported Mintlify code-fence options: ${[...removed].join(", ")}. Code examples and supported display options were preserved.`);
|
|
2523
|
+
if (unknown.size) warn?.(`Unsupported Mintlify code-fence options are ignored: ${[...unknown].join(", ")}. Review these renderer-specific options.`);
|
|
2524
|
+
return edits.sort((a, b) => b.start - a.start).reduce((text2, edit) => text2.slice(0, edit.start) + edit.value + text2.slice(edit.end), body);
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2390
2527
|
// src/mdx.ts
|
|
2391
2528
|
function titleFromId(id) {
|
|
2392
2529
|
const value = id.split("/").at(-1) ?? id;
|
|
2393
2530
|
if (value === "introduction") return "Introduction";
|
|
2394
2531
|
return value.split(/[-_]/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
2395
2532
|
}
|
|
2396
|
-
var descriptionParser =
|
|
2397
|
-
function plainText(node) {
|
|
2533
|
+
var descriptionParser = unified3().use(remarkParse3).use(remarkGfm2).use(remarkMdx2);
|
|
2534
|
+
function plainText(node, elements) {
|
|
2535
|
+
if (elements && (node.type === "mdxJsxTextElement" || node.type === "mdxJsxFlowElement")) {
|
|
2536
|
+
elements.found = true;
|
|
2537
|
+
return "";
|
|
2538
|
+
}
|
|
2398
2539
|
if (node.type === "text" || node.type === "inlineCode") return node.value ?? "";
|
|
2399
2540
|
if (node.type === "image") return node.alt ?? "";
|
|
2400
2541
|
if (node.type === "break") return " ";
|
|
2401
|
-
return (node.children ?? []).map(plainText).join("");
|
|
2542
|
+
return (node.children ?? []).map((child) => plainText(child, elements)).join("");
|
|
2543
|
+
}
|
|
2544
|
+
function headingText(content, definitions, elements) {
|
|
2545
|
+
const references = [...content.matchAll(/\[([^\]\n]+)\]/g)].map((match) => definitions?.get(match[1].trim().replace(/\s+/g, " ").toLowerCase()) ?? "").join("\n");
|
|
2546
|
+
try {
|
|
2547
|
+
return plainText(descriptionParser.parse(`# ${content}
|
|
2548
|
+
|
|
2549
|
+
${references}`), elements).trim();
|
|
2550
|
+
} catch {
|
|
2551
|
+
return content;
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
function mdxTextWithoutInlineElements(content, definitions) {
|
|
2555
|
+
if (!/<[A-Za-z]/.test(content)) return void 0;
|
|
2556
|
+
const elements = { found: false };
|
|
2557
|
+
const text2 = headingText(content, definitions, elements);
|
|
2558
|
+
return elements.found && /[\p{L}\p{M}\p{N}]/u.test(text2) ? text2 : void 0;
|
|
2402
2559
|
}
|
|
2403
2560
|
function firstParagraph(content) {
|
|
2404
2561
|
function findParagraph(node) {
|
|
@@ -2418,6 +2575,23 @@ function firstParagraph(content) {
|
|
|
2418
2575
|
return "";
|
|
2419
2576
|
}
|
|
2420
2577
|
}
|
|
2578
|
+
var linkParser = unified3().use(remarkParse3);
|
|
2579
|
+
function withoutMarkdownLinks(text2) {
|
|
2580
|
+
const links = [];
|
|
2581
|
+
const collect = (node) => {
|
|
2582
|
+
if (node.type === "link") {
|
|
2583
|
+
const first = node.children?.[0]?.position?.start.offset;
|
|
2584
|
+
const last = node.children?.at(-1)?.position?.end.offset;
|
|
2585
|
+
const start = node.position?.start.offset;
|
|
2586
|
+
const end = node.position?.end.offset;
|
|
2587
|
+
if (start !== void 0 && end !== void 0) links.push({ start, end, textStart: first ?? start, textEnd: last ?? start });
|
|
2588
|
+
return;
|
|
2589
|
+
}
|
|
2590
|
+
for (const child of node.children ?? []) collect(child);
|
|
2591
|
+
};
|
|
2592
|
+
collect(linkParser.parse(text2));
|
|
2593
|
+
return links.reduceRight((result, link) => result.slice(0, link.start) + result.slice(link.textStart, link.textEnd) + result.slice(link.end), text2);
|
|
2594
|
+
}
|
|
2421
2595
|
function docusaurusAdmonitionTag(kind) {
|
|
2422
2596
|
if (kind === "danger") return "Error";
|
|
2423
2597
|
if (kind === "info") return "Info";
|
|
@@ -2622,9 +2796,9 @@ ${trimmed.slice(0, marker).trimEnd()}`;
|
|
|
2622
2796
|
function headingIdMarker(id) {
|
|
2623
2797
|
return `{/* #${id} */}`;
|
|
2624
2798
|
}
|
|
2625
|
-
var HEADING_ID_WORD = /[\p{L}\p{M}\p{N}_
|
|
2799
|
+
var HEADING_ID_WORD = /[\p{L}\p{M}\p{N}_+&/@%=<>|\u2019\u201c\u201d\u2014\u2013\u2192\u2026]/u;
|
|
2626
2800
|
function mintlifyHeadingSlug(text2) {
|
|
2627
|
-
const chars = [...text2.replace(/[\u200b*]/g, "").normalize("NFC").trim().toLowerCase()];
|
|
2801
|
+
const chars = [...text2.replace(/[\u200b*]/g, "").replace(/(?<=[\p{L}\p{M}\p{N}_])\(s\)(?![\p{L}\p{M}\p{N}_])/gu, "s").normalize("NFC").trim().toLowerCase()];
|
|
2628
2802
|
const isWord = (char) => char !== void 0 && HEADING_ID_WORD.test(char);
|
|
2629
2803
|
let id = "";
|
|
2630
2804
|
let afterDash = false;
|
|
@@ -2636,11 +2810,11 @@ function mintlifyHeadingSlug(text2) {
|
|
|
2636
2810
|
if (isWord(char)) {
|
|
2637
2811
|
id += char;
|
|
2638
2812
|
afterDash = false;
|
|
2639
|
-
} else if (/[\s-]/.test(char) || char === "." && isWord(after) || char === "(" && isWord(before) && (isWord(after) || after === "{") || char === ")" && after !== void 0 && !/\s/.test(after)) {
|
|
2813
|
+
} else if (/[\s-]/.test(char) || char === "." && (isWord(after) || after === ",") || char === "(" && isWord(before) && (isWord(after) || after === "{") || char === ")" && after !== void 0 && !/\s/.test(after)) {
|
|
2640
2814
|
if (id && !afterDash) id += "-";
|
|
2641
2815
|
afterDash = true;
|
|
2642
2816
|
endsWithDash = true;
|
|
2643
|
-
} else if (char === "{" || char === ":" || char === '"') {
|
|
2817
|
+
} else if (char === "{" || char === ":" || char === '"' || char === ",") {
|
|
2644
2818
|
afterDash = false;
|
|
2645
2819
|
}
|
|
2646
2820
|
});
|
|
@@ -2650,17 +2824,77 @@ function thallyHeadingSlug(text2) {
|
|
|
2650
2824
|
return text2.normalize("NFC").toLowerCase().replace(/[^\p{L}\p{M}\p{N}]+/gu, "-").replace(/(^-|-$)/g, "");
|
|
2651
2825
|
}
|
|
2652
2826
|
function typesetQuotes(text2) {
|
|
2827
|
+
const opensClosed = text2.startsWith('"') && !text2.trimEnd().endsWith('"');
|
|
2653
2828
|
return text2.split(/(`[^`]*`|<[^>]*>|\]\([^)]*\))/).map((part, index) => {
|
|
2654
2829
|
if (index % 2) return part;
|
|
2655
|
-
return part.replace(/(^|[\s([{\u2014\u2013])"/g, "
|
|
2830
|
+
return part.replace(/(^|[\s([{\u2014\u2013])"/g, (match, before) => opensClosed && index === 0 && before === "" ? match : `${before}\u201C`).replace(/"/g, "\u201D").replace(/(^|[\s([{\u2014\u2013\u201c])'(?=\S)(?!<|<)/g, "$1\u2018").replace(/'/g, "\u2019");
|
|
2656
2831
|
}).join("");
|
|
2657
2832
|
}
|
|
2833
|
+
function typesetEllipses(text2) {
|
|
2834
|
+
return text2.split(/(`[^`]*`|<[^>]*>|\]\([^)]*\))/).map((part, index) => index % 2 ? part : part.replace(/\.{3}/g, "\u2026")).join("");
|
|
2835
|
+
}
|
|
2658
2836
|
function plainHeadingText(source) {
|
|
2659
|
-
|
|
2837
|
+
const unlinked = !source.includes("`") ? source : source.replace(/(`[^`]*`)|!?\[((?:`[^`]*`|[^\]`])*)\]\([^)]*\)/g, (_match, code, text2 = "") => code ?? text2);
|
|
2838
|
+
return unlinked.split(/(`[^`]*`)/).map((part, index) => index % 2 ? part.slice(1, -1) : part.replace(/\{\/\*[\s\S]*?\*\/\}/g, " ").replace(/!?\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/<\/?[A-Za-z][^>]*>/g, "").replace(/(?<!\\)(\*\*|__|~~|\*)/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/\\([\\`*_{}[\]()#+.!&<>|~-])/g, "$1")).join("");
|
|
2839
|
+
}
|
|
2840
|
+
function staticAttributeString(value) {
|
|
2841
|
+
if (typeof value === "string") return value;
|
|
2842
|
+
const expression = value?.value;
|
|
2843
|
+
if (typeof expression !== "string") return void 0;
|
|
2844
|
+
return expression.match(/^\s*(?:"([^"\\]*)"|'([^'\\]*)'|`((?:[^`\\$]|\$(?!\{))*)`)\s*$/)?.slice(1).find((part) => part !== void 0);
|
|
2845
|
+
}
|
|
2846
|
+
function pageIdClaims(body) {
|
|
2847
|
+
let tree;
|
|
2848
|
+
try {
|
|
2849
|
+
tree = descriptionParser.parse(body);
|
|
2850
|
+
} catch {
|
|
2851
|
+
return { free: () => false };
|
|
2852
|
+
}
|
|
2853
|
+
const owners = /* @__PURE__ */ new Map();
|
|
2854
|
+
const headingLines = /* @__PURE__ */ new Set();
|
|
2855
|
+
let claims = 0;
|
|
2856
|
+
const root = (id) => id.toLowerCase().replace(/-\d+$/, "");
|
|
2857
|
+
const claim = (owner, ...ids) => {
|
|
2858
|
+
for (const id of ids) {
|
|
2859
|
+
const key = root(id);
|
|
2860
|
+
const held = owners.get(key);
|
|
2861
|
+
if (!key) continue;
|
|
2862
|
+
if (!held) owners.set(key, { owner, shared: false });
|
|
2863
|
+
else if (held.owner !== owner) held.shared = true;
|
|
2864
|
+
}
|
|
2865
|
+
};
|
|
2866
|
+
const visit = (node) => {
|
|
2867
|
+
const line = node.position?.start.line ?? 0;
|
|
2868
|
+
if (node.type === "heading" && (node.depth ?? 0) >= 2) {
|
|
2869
|
+
headingLines.add(line);
|
|
2870
|
+
const text2 = typesetQuotes(plainText(node));
|
|
2871
|
+
claim(`heading ${line}`, mintlifyHeadingSlug(text2), thallyHeadingSlug(text2), thallyHeadingSlug(plainText(node, { found: false })));
|
|
2872
|
+
for (const child of node.children ?? []) {
|
|
2873
|
+
const authored = child.type === "mdxTextExpression" ? child.value?.match(/^\s*\/\*\s*#(\S+?)\s*\*\/\s*$/)?.[1] : void 0;
|
|
2874
|
+
if (authored) claim(`claim ${claims++}`, authored);
|
|
2875
|
+
}
|
|
2876
|
+
} else if (node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") {
|
|
2877
|
+
for (const { type, name, value } of node.attributes ?? []) {
|
|
2878
|
+
const text2 = type === "mdxJsxAttribute" ? staticAttributeString(value) : void 0;
|
|
2879
|
+
if (text2 === void 0) continue;
|
|
2880
|
+
if (name === "id") claim(`claim ${claims++}`, text2);
|
|
2881
|
+
else if (name === "title") claim(`claim ${claims++}`, mintlifyHeadingSlug(text2), thallyHeadingSlug(text2));
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
for (const child of node.children ?? []) visit(child);
|
|
2885
|
+
};
|
|
2886
|
+
visit(tree);
|
|
2887
|
+
return {
|
|
2888
|
+
free: (id, line) => {
|
|
2889
|
+
const held = owners.get(root(id));
|
|
2890
|
+
return headingLines.has(line) && (!held || held.owner === `heading ${line}` && !held.shared);
|
|
2891
|
+
}
|
|
2892
|
+
};
|
|
2660
2893
|
}
|
|
2661
2894
|
function markMintlifyHeadings(body) {
|
|
2662
2895
|
let fence;
|
|
2663
|
-
|
|
2896
|
+
let claims;
|
|
2897
|
+
return body.split("\n").map((line, index) => {
|
|
2664
2898
|
const marker = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
2665
2899
|
if (marker) {
|
|
2666
2900
|
if (!fence) fence = marker[1];
|
|
@@ -2674,8 +2908,13 @@ function markMintlifyHeadings(body) {
|
|
|
2674
2908
|
const source = typesetQuotes(explicit ? explicit[1] : heading[2]);
|
|
2675
2909
|
if (explicit) return `${heading[1]}${source}${explicit[2]}`;
|
|
2676
2910
|
const text2 = plainHeadingText(source);
|
|
2677
|
-
const id = mintlifyHeadingSlug(
|
|
2678
|
-
|
|
2911
|
+
const id = mintlifyHeadingSlug(plainHeadingText(typesetEllipses(source)));
|
|
2912
|
+
let marked = id !== thallyHeadingSlug(text2);
|
|
2913
|
+
if (id && !marked) {
|
|
2914
|
+
const visible = mdxTextWithoutInlineElements(source);
|
|
2915
|
+
if (visible !== void 0 && id !== thallyHeadingSlug(visible)) marked = (claims ??= pageIdClaims(body)).free(id, index + 1);
|
|
2916
|
+
}
|
|
2917
|
+
return `${heading[1]}${source}${id && marked ? ` ${headingIdMarker(id)}` : ""}`;
|
|
2679
2918
|
}).join("\n");
|
|
2680
2919
|
}
|
|
2681
2920
|
var GLOBAL_DOCUSARUS_COMPONENTS = /* @__PURE__ */ new Set([
|
|
@@ -2691,6 +2930,7 @@ function removeGlobalDocusaurusImports(body) {
|
|
|
2691
2930
|
(statement, component) => GLOBAL_DOCUSARUS_COMPONENTS.has(component) ? "" : statement
|
|
2692
2931
|
));
|
|
2693
2932
|
}
|
|
2933
|
+
var PLAIN_TEXT = new RegExp("^\\p{L}(?:[\\p{L}\\p{N} ,.;'?%$=+-]*[\\p{L}\\p{N}.])?$", "u");
|
|
2694
2934
|
function leadingPageHeading(body) {
|
|
2695
2935
|
if (!/^ {0,3}(?:#(?:[ \t]|$)|=+[ \t\r]*$)/m.test(body)) return void 0;
|
|
2696
2936
|
try {
|
|
@@ -2803,6 +3043,27 @@ function normalizeFernFileTrees(body) {
|
|
|
2803
3043
|
}
|
|
2804
3044
|
));
|
|
2805
3045
|
}
|
|
3046
|
+
function unwrapHtmlCommentInMdxComment(body) {
|
|
3047
|
+
return replaceOutsideCode(body, (text2) => {
|
|
3048
|
+
const opener = /\{\s*\/\*\s*<!--/g;
|
|
3049
|
+
const closer = /\s*\*\/\s*\}/y;
|
|
3050
|
+
let out = "";
|
|
3051
|
+
let copied = 0;
|
|
3052
|
+
let dash = -2;
|
|
3053
|
+
let star = -2;
|
|
3054
|
+
for (let found = opener.exec(text2); found; found = opener.exec(text2)) {
|
|
3055
|
+
const inner = opener.lastIndex;
|
|
3056
|
+
if (dash !== -1 && dash < inner) dash = text2.indexOf("-->", inner);
|
|
3057
|
+
if (dash === -1) break;
|
|
3058
|
+
if (star !== -1 && star < inner) star = text2.indexOf("*/", inner);
|
|
3059
|
+
closer.lastIndex = dash + 3;
|
|
3060
|
+
if (star !== -1 && star < dash || !closer.test(text2)) continue;
|
|
3061
|
+
out += `${text2.slice(copied, found.index)}{/*${text2.slice(inner, dash)}*/}`;
|
|
3062
|
+
copied = opener.lastIndex = closer.lastIndex;
|
|
3063
|
+
}
|
|
3064
|
+
return out + text2.slice(copied);
|
|
3065
|
+
});
|
|
3066
|
+
}
|
|
2806
3067
|
function normalizeFernCallouts(body) {
|
|
2807
3068
|
return replaceOutsideCode(body, (whole) => {
|
|
2808
3069
|
const openTags = [];
|
|
@@ -3367,6 +3628,7 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
|
3367
3628
|
rewritten = rewritten.replace(/^\n{2,}/, "\n");
|
|
3368
3629
|
}
|
|
3369
3630
|
if (runMintlify) rewritten = normalizeMintlifyParameterAnchors(rewritten);
|
|
3631
|
+
rewritten = unwrapHtmlCommentInMdxComment(rewritten);
|
|
3370
3632
|
rewritten = replaceOutsideCode(rewritten, (segment) => {
|
|
3371
3633
|
let result = convertHtmlStyleAttributes(segment).replace(/<!--([\s\S]*?)-->/g, (_match, content) => mdxComment(content)).replace(/<Danger(\s[^>]*)?>/g, "<Error$1>").replace(/<\/Danger>/g, "</Error>").replace(/<Warn(\s[^>]*)?>/g, "<Warning$1>").replace(/<\/Warn>/g, "</Warning>").replace(/<Tree\.Folder/g, "<Folder").replace(/<\/Tree\.Folder>/g, "</Folder>").replace(/<Tree\.File/g, "<File").replace(/<\/Tree\.File>/g, "</File>");
|
|
3372
3634
|
if (runDocusaurus) {
|
|
@@ -3396,8 +3658,15 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
|
|
|
3396
3658
|
}
|
|
3397
3659
|
return normalizeFlowParagraphContainers(normalized);
|
|
3398
3660
|
}
|
|
3661
|
+
var SITE_PATH_LINK = /^\/(?:[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*\/?)?(?:\?(?:[A-Za-z0-9._~=&-]|%[0-9A-Fa-f]{2})*)?(?:#[A-Za-z0-9._~-]+)?$/;
|
|
3662
|
+
var MAX_SITE_PATH_LINK_LENGTH = 2e3;
|
|
3663
|
+
function sitePathLink(url) {
|
|
3664
|
+
if (url.length > MAX_SITE_PATH_LINK_LENGTH || url.includes("__ESC_") || !SITE_PATH_LINK.test(url)) return void 0;
|
|
3665
|
+
return url.split(/[?#]/, 1)[0].split("/").some((segment) => segment === "." || segment === "..") ? void 0 : url;
|
|
3666
|
+
}
|
|
3399
3667
|
function externalPageUrl(value) {
|
|
3400
3668
|
const url = typeof value === "string" ? value.trim() : "";
|
|
3669
|
+
if (url.startsWith("/")) return sitePathLink(url);
|
|
3401
3670
|
if (!/^https?:\/\/[^\s]+$/i.test(url)) return void 0;
|
|
3402
3671
|
try {
|
|
3403
3672
|
new URL(url);
|
|
@@ -3408,16 +3677,46 @@ function externalPageUrl(value) {
|
|
|
3408
3677
|
}
|
|
3409
3678
|
function parseMarkdownPage(input) {
|
|
3410
3679
|
const parsed = parseFrontmatter(input.raw);
|
|
3680
|
+
if (input.platform === "mintlify") {
|
|
3681
|
+
const supported = /* @__PURE__ */ new Set([
|
|
3682
|
+
"title",
|
|
3683
|
+
"description",
|
|
3684
|
+
"sidebarTitle",
|
|
3685
|
+
"navTitle",
|
|
3686
|
+
"icon",
|
|
3687
|
+
"iconType",
|
|
3688
|
+
"tag",
|
|
3689
|
+
"badge",
|
|
3690
|
+
"keywords",
|
|
3691
|
+
"mode",
|
|
3692
|
+
"hidden",
|
|
3693
|
+
"noindex",
|
|
3694
|
+
"url",
|
|
3695
|
+
"openapi",
|
|
3696
|
+
"api",
|
|
3697
|
+
"authMethod",
|
|
3698
|
+
"playground",
|
|
3699
|
+
// Access settings are enforced by the repository classifier, never lost here.
|
|
3700
|
+
"groups",
|
|
3701
|
+
"public",
|
|
3702
|
+
...PAGE_META_FIELDS.map(([field]) => field)
|
|
3703
|
+
]);
|
|
3704
|
+
const dropped = Object.keys(parsed.data).filter((key) => !supported.has(key));
|
|
3705
|
+
if (dropped.length) input.warn?.(`Unsupported Mintlify frontmatter fields were omitted: ${dropped.join(", ")}. Review their behavior before publishing.`);
|
|
3706
|
+
}
|
|
3411
3707
|
const fallbackIdentity = {
|
|
3412
3708
|
id: input.id,
|
|
3413
3709
|
navigationId: input.navigationId ?? input.id,
|
|
3414
3710
|
...input.locale ? { locale: input.locale } : {}
|
|
3415
3711
|
};
|
|
3416
3712
|
const identity = input.resolveIdentity?.(parsed.data, fallbackIdentity) ?? fallbackIdentity;
|
|
3417
|
-
const
|
|
3713
|
+
const normalized = normalizeMdx(parsed.content, input.platform);
|
|
3714
|
+
const body = removeUndefinedExpressions(injectReactHookImports(input.platform === "mintlify" ? normalizeMintlifyCodeFences(normalized, input.warn) : normalized), input.warn).trim();
|
|
3418
3715
|
const keywords = Array.isArray(parsed.data.keywords) ? parsed.data.keywords.filter((value) => typeof value === "string") : [];
|
|
3419
3716
|
const heading = leadingPageHeading(body);
|
|
3420
|
-
const
|
|
3717
|
+
const authoredTitle = typeof parsed.data.title === "string" && parsed.data.title.trim() ? parsed.data.title.trim() : heading?.title;
|
|
3718
|
+
const title = authoredTitle ?? titleFromId(identity.navigationId);
|
|
3719
|
+
const namesOperation = typeof parsed.data.openapi === "string" && Boolean(parsed.data.openapi.trim());
|
|
3421
3720
|
const sidebarTitle = input.platform === "docusaurus" ? parsed.data.sidebar_label : parsed.data.sidebarTitle;
|
|
3422
3721
|
const navTitle = typeof sidebarTitle === "string" && sidebarTitle.trim() ? sidebarTitle.trim() : typeof parsed.data.navTitle === "string" && parsed.data.navTitle.trim() ? parsed.data.navTitle.trim() : void 0;
|
|
3423
3722
|
const icon = typeof parsed.data.icon === "string" && parsed.data.icon.trim() ? parsed.data.icon.trim() : void 0;
|
|
@@ -3430,18 +3729,25 @@ function parseMarkdownPage(input) {
|
|
|
3430
3729
|
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;
|
|
3431
3730
|
const sourceMode = typeof parsed.data.mode === "string" ? parsed.data.mode : void 0;
|
|
3432
3731
|
const mode = sourceMode === "frame" ? "wide" : ["default", "wide", "custom", "center", "home"].includes(sourceMode ?? "") ? sourceMode : void 0;
|
|
3732
|
+
if (input.platform === "mintlify" && typeof parsed.data.url === "string" && parsed.data.url.trim().startsWith("/") && !externalPageUrl(parsed.data.url)) {
|
|
3733
|
+
const shown = parsed.data.url.trim();
|
|
3734
|
+
input.warn?.(`Page "${identity.id}": its "url" frontmatter ${JSON.stringify(shown.length > 80 ? `${shown.slice(0, 80)}...` : shown)} was not turned into a link, so the page was kept with its own content. Only a site path made of letters, digits and . _ ~ - segments, with an optional ?key=value query and #id fragment, can become a link.`);
|
|
3735
|
+
}
|
|
3433
3736
|
const externalUrl = input.platform === "mintlify" ? externalPageUrl(parsed.data.url) : void 0;
|
|
3434
|
-
const
|
|
3737
|
+
const authoredDescription = typeof parsed.data.description === "string" && parsed.data.description.trim() ? parsed.data.description.trim() : void 0;
|
|
3738
|
+
const description = authoredDescription ?? (namesOperation ? "" : firstParagraph(body));
|
|
3435
3739
|
const page = {
|
|
3436
3740
|
id: identity.id,
|
|
3437
3741
|
navigationId: identity.navigationId,
|
|
3438
3742
|
locale: identity.locale,
|
|
3439
3743
|
title,
|
|
3744
|
+
...authoredTitle === void 0 && namesOperation ? { titleFromFileName: true } : {},
|
|
3440
3745
|
navTitle,
|
|
3441
3746
|
icon,
|
|
3442
3747
|
iconType,
|
|
3443
3748
|
description,
|
|
3444
|
-
|
|
3749
|
+
// A description taken from the body is the paragraph the body already shows, so it must not also appear under the title.
|
|
3750
|
+
...input.platform === "docusaurus" || input.platform === "fern" || authoredDescription === void 0 && description !== "" ? { descriptionPlacement: "body" } : {},
|
|
3445
3751
|
badge,
|
|
3446
3752
|
keywords,
|
|
3447
3753
|
mode,
|
|
@@ -3456,6 +3762,12 @@ function parseMarkdownPage(input) {
|
|
|
3456
3762
|
source: input.source,
|
|
3457
3763
|
...parsed.error ? { frontmatterError: parsed.error } : {}
|
|
3458
3764
|
};
|
|
3765
|
+
const writtenDescription = typeof parsed.data.description === "string" ? parsed.data.description.trim() : "";
|
|
3766
|
+
const plainDescription2 = withoutMarkdownLinks(writtenDescription);
|
|
3767
|
+
if (plainDescription2 !== writtenDescription) {
|
|
3768
|
+
page.description = plainDescription2;
|
|
3769
|
+
input.warn?.(`Page "${identity.id}": its description had links, which Thally shows as plain text; the link text was kept.`);
|
|
3770
|
+
}
|
|
3459
3771
|
resolvePageDisplayHeading(page, input.platform);
|
|
3460
3772
|
return page;
|
|
3461
3773
|
}
|
|
@@ -3487,7 +3799,7 @@ function apiFrontmatter(data, warn) {
|
|
|
3487
3799
|
}
|
|
3488
3800
|
|
|
3489
3801
|
// src/url-static-content.ts
|
|
3490
|
-
import { createHash as
|
|
3802
|
+
import { createHash as createHash3 } from "crypto";
|
|
3491
3803
|
import { load as load4 } from "cheerio";
|
|
3492
3804
|
function projectMigrationSvg(html) {
|
|
3493
3805
|
const $ = load4(html, { xmlMode: true }, false);
|
|
@@ -3496,7 +3808,7 @@ function projectMigrationSvg(html) {
|
|
|
3496
3808
|
if (svg.attr("xmlns") === void 0) svg.attr("xmlns", "http://www.w3.org/2000/svg");
|
|
3497
3809
|
const content = Buffer.from($.xml(svg));
|
|
3498
3810
|
if (!isPassiveSvg(content)) return null;
|
|
3499
|
-
const sha256 =
|
|
3811
|
+
const sha256 = createHash3("sha256").update(content).digest("hex");
|
|
3500
3812
|
const labelled = (svg.attr("aria-labelledby") ?? "").split(/\s+/).filter(Boolean).map((id) => svg.find("[id]").filter((_index, node) => $(node).attr("id") === id).text().trim()).filter(Boolean);
|
|
3501
3813
|
const alternative = svg.attr("aria-label")?.trim() || labelled.join(" ") || svg.children("title").text().trim() || svg.children("desc").text().trim() || svg.find("text").text().trim();
|
|
3502
3814
|
return { asset: { path: `migration-assets/${sha256}.svg`, content }, alternative };
|
|
@@ -3688,8 +4000,8 @@ var MINTLIFY_ARTICLE_LABELS = [
|
|
|
3688
4000
|
{ baseUrl: "Select base URL", permalink: "Navigate to header" },
|
|
3689
4001
|
{ baseUrl: "\u9009\u62E9\u57FA\u7840URL", permalink: "\u5BFC\u822A\u5230\u6807\u9898" }
|
|
3690
4002
|
];
|
|
3691
|
-
var remoteMarkdownParser =
|
|
3692
|
-
var embeddedOpenApiParser =
|
|
4003
|
+
var remoteMarkdownParser = unified4().use(remarkParse4).use(remarkMdx3);
|
|
4004
|
+
var embeddedOpenApiParser = unified4().use(remarkParse4);
|
|
3693
4005
|
function validateMigrationUrl(value) {
|
|
3694
4006
|
let url;
|
|
3695
4007
|
try {
|
|
@@ -3729,10 +4041,10 @@ async function readResponseBody(response) {
|
|
|
3729
4041
|
}
|
|
3730
4042
|
return new TextDecoder().decode(body);
|
|
3731
4043
|
}
|
|
3732
|
-
var defaultMigrationFetcher = async (url,
|
|
4044
|
+
var defaultMigrationFetcher = async (url, request2) => {
|
|
3733
4045
|
const response = await fetch(url, {
|
|
3734
4046
|
headers: {
|
|
3735
|
-
Accept:
|
|
4047
|
+
Accept: request2.accept,
|
|
3736
4048
|
"User-Agent": "Thally-Migrate/1.0 (+https://thally.io)"
|
|
3737
4049
|
},
|
|
3738
4050
|
redirect: "follow",
|
|
@@ -4206,7 +4518,7 @@ function extractEmbeddedOpenApi(content) {
|
|
|
4206
4518
|
const opening = lines[0].match(/^ {0,3}(`{3,}|~{3,})/);
|
|
4207
4519
|
const closing = lines.at(-1)?.match(/^ {0,3}(`{3,}|~{3,})[\t ]*$/);
|
|
4208
4520
|
if (!opening || !closing || opening[1][0] !== closing[1][0] || closing[1].length < opening[1].length) return { content };
|
|
4209
|
-
const parsed =
|
|
4521
|
+
const parsed = parseYaml3(node.value ?? "", { maxAliasCount: 50 });
|
|
4210
4522
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return { content };
|
|
4211
4523
|
const document = parsed;
|
|
4212
4524
|
if (typeof document.openapi !== "string" && typeof document.swagger !== "string") return { content };
|
|
@@ -4667,6 +4979,8 @@ ${fence}
|
|
|
4667
4979
|
navigationId: id,
|
|
4668
4980
|
title,
|
|
4669
4981
|
description: description || plainDescription(body) || `Documentation imported from ${document.finalUrl.hostname}.`,
|
|
4982
|
+
// A description taken from the page text is already in the body; only one the site published is shown under the title.
|
|
4983
|
+
...description ? {} : { descriptionPlacement: "body" },
|
|
4670
4984
|
keywords: [],
|
|
4671
4985
|
body,
|
|
4672
4986
|
source: document.finalUrl.toString()
|
|
@@ -4736,7 +5050,7 @@ function observedMigrationArticleIdentity(document) {
|
|
|
4736
5050
|
canonical2.pathname = canonical2.pathname.replace(/\/+$/, "") || "/";
|
|
4737
5051
|
const removed = [...source.searchParams].filter(([key, value]) => !canonical2.searchParams.getAll(key).includes(value));
|
|
4738
5052
|
const sectionAnchor = removed.length === 1 && anchors.includes(removed[0][1]) ? removed[0][1] : void 0;
|
|
4739
|
-
return { canonicalUrl: canonical2.href, articleSha256:
|
|
5053
|
+
return { canonicalUrl: canonical2.href, articleSha256: createHash4("sha256").update(payload).digest("hex"), ...sectionAnchor ? { sectionAnchor } : {} };
|
|
4740
5054
|
}
|
|
4741
5055
|
|
|
4742
5056
|
// src/url-api-schema-controls.ts
|
|
@@ -4829,8 +5143,8 @@ function apiSchemaTabGroups(body, document, operation) {
|
|
|
4829
5143
|
let schema;
|
|
4830
5144
|
let scope;
|
|
4831
5145
|
if (title === "body") {
|
|
4832
|
-
const
|
|
4833
|
-
schema = object2(object2(
|
|
5146
|
+
const request2 = resolve2(document, selected.requestBody);
|
|
5147
|
+
schema = object2(object2(request2?.content)?.[media[0]])?.schema;
|
|
4834
5148
|
scope = `request:${media[0]}`;
|
|
4835
5149
|
} else if (title === "response") {
|
|
4836
5150
|
const statuses = heading.find('button[aria-haspopup="menu"]').toArray().map((button) => $(button).text().trim()).filter((text2) => /^(?:[1-5]\d{2}|default)$/.test(text2));
|
|
@@ -4929,8 +5243,8 @@ function apiSchemaDisclosureGroups(body, document, operation) {
|
|
|
4929
5243
|
schemas = [object2(object2(response?.content)?.[media[0]])?.schema];
|
|
4930
5244
|
prefix = "response";
|
|
4931
5245
|
} else if (media.length === 1 && !statuses.length) {
|
|
4932
|
-
const
|
|
4933
|
-
schemas = [object2(object2(
|
|
5246
|
+
const request2 = resolve2(document, selected.requestBody);
|
|
5247
|
+
schemas = [object2(object2(request2?.content)?.[media[0]])?.schema];
|
|
4934
5248
|
prefix = "body";
|
|
4935
5249
|
} else if (!media.length && !statuses.length) {
|
|
4936
5250
|
const head = $(chain[0]).find(".param-head[id]").filter((_index, element) => $(element).closest(fieldSelector)[0] === chain[0]).first().attr("id") ?? "";
|
|
@@ -5063,8 +5377,8 @@ function apiOperationCodeControls(body, specification, operation) {
|
|
|
5063
5377
|
const metadata = object2(resolveValue(value));
|
|
5064
5378
|
const declaration = resolveValue(metadata?.openapi);
|
|
5065
5379
|
if (typeof declaration !== "string") return false;
|
|
5066
|
-
const
|
|
5067
|
-
return
|
|
5380
|
+
const tokens2 = declaration.trim().split(/\s+/);
|
|
5381
|
+
return tokens2.at(-2)?.toLowerCase() === operation.method.toLowerCase() && tokens2.at(-1) === operation.path;
|
|
5068
5382
|
};
|
|
5069
5383
|
const active = /* @__PURE__ */ new Set();
|
|
5070
5384
|
const visit = (input, provider, group, depth, owners = []) => {
|
|
@@ -5110,9 +5424,9 @@ function apiOperationCodeControls(body, specification, operation) {
|
|
|
5110
5424
|
const hint = object2(resolveValue(scope?.pageMetadata)), metadata = object2(resolveValue(props.pageMetadata));
|
|
5111
5425
|
const declaration = resolveValue(hint?.openapi);
|
|
5112
5426
|
if (typeof declaration !== "string" || typeof hint?.href !== "string" || !hint.href || hint.href !== metadata?.href) return false;
|
|
5113
|
-
const
|
|
5427
|
+
const tokens2 = declaration.trim().split(/\s+/);
|
|
5114
5428
|
const template = (path) => path.split("/").map((segment) => /^\{[^{}\/]+\}$/.test(segment) ? "{}" : segment).join("/");
|
|
5115
|
-
return
|
|
5429
|
+
return tokens2.at(-2)?.toLowerCase() === operation.method.toLowerCase() && template(tokens2.at(-1) ?? "") === template(operation.path);
|
|
5116
5430
|
})()) generatedControllers += 1;
|
|
5117
5431
|
}
|
|
5118
5432
|
let local = group;
|
|
@@ -5221,14 +5535,14 @@ function apiOperationCodeControls(body, specification, operation) {
|
|
|
5221
5535
|
|
|
5222
5536
|
// src/url-run.ts
|
|
5223
5537
|
var CONVERTER_VERSION = "url-evidence-v7";
|
|
5224
|
-
var parser2 =
|
|
5538
|
+
var parser2 = unified5().use(remarkParse5).use(remarkMdx4);
|
|
5225
5539
|
var ACCEPT = "text/html,application/xhtml+xml";
|
|
5226
5540
|
var MAX_RESPONSE_BYTES = 8e6;
|
|
5227
5541
|
var MAX_ASSET_BYTES = 1e7;
|
|
5228
5542
|
var MAX_RECORDS = 1e5;
|
|
5229
5543
|
var LOCALES = /* @__PURE__ */ new Set(["ar", "cs", "da", "de", "el", "en", "es", "fi", "fr", "he", "hi", "hu", "id", "it", "ja", "ko", "ms", "nl", "no", "pl", "pt", "pt-br", "ro", "ru", "sk", "sv", "th", "tr", "uk", "vi", "zh", "zh-cn", "zh-hans", "zh-hant"]);
|
|
5230
5544
|
function hash(value) {
|
|
5231
|
-
return
|
|
5545
|
+
return createHash5("sha256").update(value).digest("hex");
|
|
5232
5546
|
}
|
|
5233
5547
|
function canonicalJson(value) {
|
|
5234
5548
|
const canonical2 = (value2) => Array.isArray(value2) ? value2.map(canonical2) : value2 !== null && typeof value2 === "object" ? Object.fromEntries(Object.entries(value2).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, field]) => [key, canonical2(field)])) : value2;
|
|
@@ -5749,7 +6063,7 @@ async function runUrlMigration(options) {
|
|
|
5749
6063
|
} catch {
|
|
5750
6064
|
}
|
|
5751
6065
|
}
|
|
5752
|
-
const capture = (
|
|
6066
|
+
const capture = (request2) => initial && canonical(request2.url.href, sourceUrl) === sourceUrl ? initial : acquire(request2);
|
|
5753
6067
|
const requestedScope = options.scopePath ?? options.checkpoint?.scopePath ?? inferredScope ?? (source.pathname.endsWith("/") ? source.pathname : source.pathname.slice(0, source.pathname.lastIndexOf("/")) || "/");
|
|
5754
6068
|
let scopeEnd = requestedScope.length;
|
|
5755
6069
|
while (scopeEnd > 0 && requestedScope.charCodeAt(scopeEnd - 1) === 47) scopeEnd--;
|
|
@@ -6493,16 +6807,16 @@ function rewriteMarkdownDestinations(body, rewrite) {
|
|
|
6493
6807
|
}
|
|
6494
6808
|
|
|
6495
6809
|
// src/components.ts
|
|
6496
|
-
import { createHash as
|
|
6810
|
+
import { createHash as createHash6 } from "crypto";
|
|
6497
6811
|
import { existsSync as existsSync2, lstatSync as lstatSync2, readFileSync as readFileSync2 } from "fs";
|
|
6498
6812
|
import { basename, dirname as dirname2, extname as extname3, posix as posix2, relative as relative3, resolve as resolve3 } from "path";
|
|
6499
|
-
import
|
|
6500
|
-
import
|
|
6813
|
+
import postcss2 from "postcss";
|
|
6814
|
+
import selectorParser2 from "postcss-selector-parser";
|
|
6501
6815
|
import remarkMdx5 from "remark-mdx";
|
|
6502
|
-
import
|
|
6503
|
-
import
|
|
6504
|
-
import { unified as
|
|
6505
|
-
var parser3 =
|
|
6816
|
+
import remarkParse6 from "remark-parse";
|
|
6817
|
+
import ts3 from "typescript";
|
|
6818
|
+
import { unified as unified6 } from "unified";
|
|
6819
|
+
var parser3 = unified6().use(remarkParse6).use(remarkMdx5);
|
|
6506
6820
|
var DOCUSAURUS_THEME_SHIMS = {
|
|
6507
6821
|
"@theme/CodeBlock": {
|
|
6508
6822
|
filename: "docusaurus-code-block.tsx",
|
|
@@ -6542,32 +6856,32 @@ function applyReplacements(source, replacements) {
|
|
|
6542
6856
|
);
|
|
6543
6857
|
}
|
|
6544
6858
|
function hash2(value) {
|
|
6545
|
-
return
|
|
6859
|
+
return createHash6("sha256").update(value).digest("hex").slice(0, 12);
|
|
6546
6860
|
}
|
|
6547
6861
|
function sourceFile(source, filename) {
|
|
6548
|
-
return
|
|
6862
|
+
return ts3.createSourceFile(filename, source, ts3.ScriptTarget.Latest, true, scriptKindFor(filename));
|
|
6549
6863
|
}
|
|
6550
6864
|
function mergeComponentRegistry(existing, incoming) {
|
|
6551
6865
|
const fingerprint = hash2(incoming);
|
|
6552
6866
|
const name = `MigratedRegistry${fingerprint}`;
|
|
6553
6867
|
const registryPath = `./migrated-components-${fingerprint}`;
|
|
6554
6868
|
const source = sourceFile(existing, "custom-components.tsx");
|
|
6555
|
-
const alreadyImported = source.statements.some((statement) =>
|
|
6869
|
+
const alreadyImported = source.statements.some((statement) => ts3.isImportDeclaration(statement) && ts3.isStringLiteral(statement.moduleSpecifier) && statement.moduleSpecifier.text === registryPath);
|
|
6556
6870
|
let initializer;
|
|
6557
6871
|
for (const statement of source.statements) {
|
|
6558
|
-
if (!
|
|
6872
|
+
if (!ts3.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts3.SyntaxKind.ExportKeyword)) continue;
|
|
6559
6873
|
for (const declaration of statement.declarationList.declarations) {
|
|
6560
|
-
if (
|
|
6874
|
+
if (ts3.isIdentifier(declaration.name) && declaration.name.text === "customComponents") initializer = declaration.initializer;
|
|
6561
6875
|
}
|
|
6562
6876
|
}
|
|
6563
|
-
while (initializer && (
|
|
6564
|
-
if (!initializer || !
|
|
6877
|
+
while (initializer && (ts3.isAsExpression(initializer) || ts3.isSatisfiesExpression(initializer) || ts3.isParenthesizedExpression(initializer))) initializer = initializer.expression;
|
|
6878
|
+
if (!initializer || !ts3.isObjectLiteralExpression(initializer)) {
|
|
6565
6879
|
throw new Error("Cannot safely merge src/mdx/custom-components.tsx: export customComponents as an object literal before importing components. The existing registry was preserved.");
|
|
6566
6880
|
}
|
|
6567
6881
|
const content = alreadyImported ? existing : applyReplacements(existing, [
|
|
6568
6882
|
{
|
|
6569
|
-
start: source.statements.filter((statement) =>
|
|
6570
|
-
end: source.statements.filter((statement) =>
|
|
6883
|
+
start: source.statements.filter((statement) => ts3.isExpressionStatement(statement) && ts3.isStringLiteral(statement.expression)).at(-1)?.end ?? 0,
|
|
6884
|
+
end: source.statements.filter((statement) => ts3.isExpressionStatement(statement) && ts3.isStringLiteral(statement.expression)).at(-1)?.end ?? 0,
|
|
6571
6885
|
value: `
|
|
6572
6886
|
import { customComponents as ${name} } from ${JSON.stringify(registryPath)}
|
|
6573
6887
|
`
|
|
@@ -6619,6 +6933,32 @@ function renderPage(bundle, page) {
|
|
|
6619
6933
|
function isIntegrationsObject(value) {
|
|
6620
6934
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
6621
6935
|
}
|
|
6936
|
+
function mergeRedirects(existing = [], incoming = []) {
|
|
6937
|
+
const redirects = [...existing];
|
|
6938
|
+
const key = (source) => literalRoute(source) ?? trimTrailingSlashes(source).toLowerCase();
|
|
6939
|
+
const destinationKey = (destination) => literalRoute(destinationRoute(destination) ?? "");
|
|
6940
|
+
const sources = new Set(existing.map((redirect) => key(redirect.source)));
|
|
6941
|
+
for (const redirect of incoming) {
|
|
6942
|
+
const source = key(redirect.source);
|
|
6943
|
+
if (sources.has(source)) continue;
|
|
6944
|
+
const visited = /* @__PURE__ */ new Set([source]);
|
|
6945
|
+
let destination = destinationKey(redirect.destination);
|
|
6946
|
+
let cycle = false;
|
|
6947
|
+
while (destination) {
|
|
6948
|
+
if (visited.has(destination)) {
|
|
6949
|
+
cycle = true;
|
|
6950
|
+
break;
|
|
6951
|
+
}
|
|
6952
|
+
visited.add(destination);
|
|
6953
|
+
const next = redirects.find((candidate) => literalRoute(candidate.source) === destination);
|
|
6954
|
+
destination = next ? destinationKey(next.destination) : null;
|
|
6955
|
+
}
|
|
6956
|
+
if (cycle) continue;
|
|
6957
|
+
redirects.push(redirect);
|
|
6958
|
+
sources.add(source);
|
|
6959
|
+
}
|
|
6960
|
+
return redirects;
|
|
6961
|
+
}
|
|
6622
6962
|
function mergeMigrationConfig(existing, incoming) {
|
|
6623
6963
|
const tabs = existing.tabs.filter((tab) => tab.tab.toLowerCase() !== "changelog");
|
|
6624
6964
|
const names = new Set(tabs.map((tab) => tab.tab.toLowerCase()));
|
|
@@ -6686,6 +7026,10 @@ function mergeMigrationConfig(existing, incoming) {
|
|
|
6686
7026
|
...incoming,
|
|
6687
7027
|
...existing,
|
|
6688
7028
|
tabs,
|
|
7029
|
+
...existing.redirects || incoming.redirects ? { redirects: mergeRedirects(existing.redirects, incoming.redirects) } : {},
|
|
7030
|
+
// A starter's primary action must not discard a newly imported logo.
|
|
7031
|
+
// Owner-authored fields, including an explicit null logo, remain authoritative.
|
|
7032
|
+
...incoming.navbar || existing.navbar ? { navbar: { ...incoming.navbar, ...existing.navbar } } : {},
|
|
6689
7033
|
// Collection presentation belongs to the imported information
|
|
6690
7034
|
// architecture; starter defaults must not coerce source dropdowns to tabs.
|
|
6691
7035
|
navigation: incoming.navigation ?? existing.navigation,
|