@thallylabs/migrate 0.2.11 → 0.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  import { createRequire } from "module";
17
17
  import { basename as basename3, dirname as dirname4, extname as extname5, isAbsolute as isAbsolute2, relative as relative5, resolve as resolvePath, sep as sep2 } from "path";
18
18
  import { parse as parseYaml4 } from "yaml";
19
- import * as ts2 from "typescript";
19
+ import * as ts3 from "typescript";
20
20
 
21
21
  // src/components.ts
22
22
  import { createHash } from "crypto";
@@ -26,7 +26,7 @@ import postcss from "postcss";
26
26
  import selectorParser from "postcss-selector-parser";
27
27
  import remarkMdx2 from "remark-mdx";
28
28
  import remarkParse2 from "remark-parse";
29
- import ts from "typescript";
29
+ import ts2 from "typescript";
30
30
  import { unified as unified2 } from "unified";
31
31
 
32
32
  // src/frontmatter.ts
@@ -142,7 +142,15 @@ var THALLY_BUILTIN_COMPONENTS = /* @__PURE__ */ new Set([
142
142
  "Visibility",
143
143
  "Human",
144
144
  "Agent",
145
- "BannerPreview"
145
+ "BannerPreview",
146
+ "Banner",
147
+ "CodeBlock",
148
+ "Column",
149
+ "FileTree",
150
+ "LiteYouTubeEmbed",
151
+ "MDX",
152
+ "Video",
153
+ "YouTube"
146
154
  ]);
147
155
  function isThallyBuiltinComponent(name) {
148
156
  return THALLY_BUILTIN_COMPONENTS.has(name) || THALLY_BUILTIN_COMPONENTS.has(name.split(".")[0]);
@@ -1094,12 +1102,117 @@ function normalizeMintlifyParameterAnchors(body) {
1094
1102
  (match, _tag, _before, doubleQuoted, singleQuoted) => `${anchorFor(doubleQuoted ?? singleQuoted)}${match}`
1095
1103
  ));
1096
1104
  }
1105
+ function matchFenceLine(line) {
1106
+ const match = line.match(/^(\s*)(`{3,}|~{3,})(.*)$/);
1107
+ if (!match) return null;
1108
+ return { index: -1, indent: match[1], char: match[2][0], length: match[2].length, info: match[3].trim(), rest: match[3] };
1109
+ }
1110
+ function normalizeNestedCodeFences(body) {
1111
+ const lines = body.split("\n");
1112
+ const fences = lines.map((line, index) => {
1113
+ const fence = matchFenceLine(line);
1114
+ return fence ? { ...fence, index } : null;
1115
+ }).filter((fence) => fence !== null);
1116
+ if (fences.length === 0) return body;
1117
+ const stack = [];
1118
+ const roots = [];
1119
+ for (const fence of fences) {
1120
+ const top = stack.at(-1);
1121
+ if (top && fence.info === "" && fence.char === top.open.char && fence.length >= top.open.length) {
1122
+ stack.pop();
1123
+ const block = { open: top.open, close: fence, children: top.children };
1124
+ const parent = stack.at(-1);
1125
+ if (parent) parent.children.push(block);
1126
+ else roots.push(block);
1127
+ } else {
1128
+ stack.push({ open: fence, children: [] });
1129
+ }
1130
+ }
1131
+ if (stack.length > 0) return body;
1132
+ const widenedLengths = /* @__PURE__ */ new Map();
1133
+ function requiredLength(block) {
1134
+ const deepestChild = Math.max(0, ...block.children.map(requiredLength));
1135
+ const length = Math.max(block.open.length, deepestChild > 0 ? deepestChild + 1 : 0);
1136
+ widenedLengths.set(block.open.index, length);
1137
+ widenedLengths.set(block.close.index, length);
1138
+ return length;
1139
+ }
1140
+ roots.forEach(requiredLength);
1141
+ return lines.map((line, index) => {
1142
+ const targetLength = widenedLengths.get(index);
1143
+ const fence = targetLength ? matchFenceLine(line) : null;
1144
+ if (!targetLength || !fence || targetLength <= fence.length) return line;
1145
+ return `${fence.indent}${fence.char.repeat(targetLength)}${fence.rest}`;
1146
+ }).join("\n");
1147
+ }
1148
+ function maskCodeRegions(body) {
1149
+ let inFence = false;
1150
+ return body.split("\n").map((line) => {
1151
+ if (/^\s*(`{3,}|~{3,})/.test(line)) {
1152
+ inFence = !inFence;
1153
+ return " ".repeat(line.length);
1154
+ }
1155
+ if (inFence) return " ".repeat(line.length);
1156
+ return line.replace(/`[^`]*`/g, (span) => " ".repeat(span.length));
1157
+ }).join("\n");
1158
+ }
1159
+ function isKnownComponentName(name, body) {
1160
+ if (isThallyBuiltinComponent(name)) return true;
1161
+ if (new RegExp(`^\\s*export\\s+(?:const|function|default\\s+function)\\s+${name}\\b`, "m").test(body)) return true;
1162
+ if (new RegExp(`^\\s*import\\s+(?:\\{[^}]*\\b${name}\\b[^}]*\\}|${name})\\s+from\\s+['"][^'"]+['"]`, "m").test(body)) return true;
1163
+ return false;
1164
+ }
1165
+ function escapeOrphanCapitalizedTags(body) {
1166
+ const masked = maskCodeRegions(body);
1167
+ const tagPattern = /<(\/?)([A-Z][A-Za-z0-9]*)(?:\s+[^<>]*?)?(\/?)>/g;
1168
+ const opens = /* @__PURE__ */ new Map();
1169
+ const closedOrSelfClosed = /* @__PURE__ */ new Set();
1170
+ for (const match of masked.matchAll(tagPattern)) {
1171
+ const [full, closing, name, selfClosing] = match;
1172
+ if (closing || selfClosing) {
1173
+ closedOrSelfClosed.add(name);
1174
+ continue;
1175
+ }
1176
+ const start = match.index;
1177
+ const list = opens.get(name) ?? [];
1178
+ list.push({ start, end: start + full.length });
1179
+ opens.set(name, list);
1180
+ }
1181
+ const edits = [];
1182
+ for (const [name, ranges] of opens) {
1183
+ if (closedOrSelfClosed.has(name) || isKnownComponentName(name, body)) continue;
1184
+ edits.push(...ranges);
1185
+ }
1186
+ if (edits.length === 0) return body;
1187
+ try {
1188
+ compileSync(body, { outputFormat: "program" });
1189
+ return body;
1190
+ } catch {
1191
+ }
1192
+ edits.sort((a, b) => a.start - b.start);
1193
+ let result = "";
1194
+ let cursor = 0;
1195
+ for (const edit of edits) {
1196
+ result += body.slice(cursor, edit.start);
1197
+ result += body.slice(edit.start, edit.end).replace(/^</, "&lt;").replace(/>$/, "&gt;");
1198
+ cursor = edit.end;
1199
+ }
1200
+ return result + body.slice(cursor);
1201
+ }
1202
+ var REACT_HOOK_NAMES = ["useState", "useEffect", "useRef", "useCallback", "useMemo", "useContext", "useReducer"];
1203
+ function injectReactHookImports(body) {
1204
+ const masked = maskCodeRegions(body);
1205
+ const used = REACT_HOOK_NAMES.filter((hook) => new RegExp(`\\b${hook}\\s*\\(`).test(masked) && !new RegExp(`import\\s*\\{[^}]*\\b${hook}\\b[^}]*\\}\\s*from\\s*['"]react['"]`).test(body));
1206
+ return used.length > 0 ? `import { ${used.join(", ")} } from 'react'
1207
+
1208
+ ${body}` : body;
1209
+ }
1097
1210
  function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
1098
1211
  const runFern = platform === "fern";
1099
1212
  const runMintlify = platform === "mintlify";
1100
1213
  const runDocusaurus = platform === "docusaurus";
1101
1214
  const sourceBody = runDocusaurus && unwrapMdxCodeBlocks ? unwrapDocusaurusMdxCodeBlocks(body) : body;
1102
- let rewritten = normalizeDocusaurusAdmonitions(normalizeExplicitHeadingIds(runFern ? normalizeFernFileTrees(normalizeFernCallouts(sourceBody)) : sourceBody));
1215
+ let rewritten = normalizeDocusaurusAdmonitions(normalizeExplicitHeadingIds(runFern ? normalizeFernFileTrees(normalizeFernCallouts(normalizeNestedCodeFences(sourceBody))) : normalizeNestedCodeFences(sourceBody)));
1103
1216
  if (runDocusaurus) {
1104
1217
  rewritten = replaceOutsideCode(rewritten, (segment) => segment.replace(
1105
1218
  /:([+\w-]+):/g,
@@ -1133,7 +1246,7 @@ function normalizeMdx(body, platform, unwrapMdxCodeBlocks = true) {
1133
1246
  return result;
1134
1247
  });
1135
1248
  if (runFern) rewritten = unwrapFernCodeBlockTabs(rewritten);
1136
- const normalized = provideScopedGlobalReferences(rewritten);
1249
+ const normalized = escapeOrphanCapitalizedTags(provideScopedGlobalReferences(rewritten));
1137
1250
  if (runDocusaurus && sourceBody !== body) {
1138
1251
  try {
1139
1252
  compileSync(normalized, { outputFormat: "program" });
@@ -1151,7 +1264,7 @@ function parseMarkdownPage(input) {
1151
1264
  ...input.locale ? { locale: input.locale } : {}
1152
1265
  };
1153
1266
  const identity = input.resolveIdentity?.(parsed.data, fallbackIdentity) ?? fallbackIdentity;
1154
- let body = normalizeMdx(parsed.content, input.platform).trim();
1267
+ let body = injectReactHookImports(normalizeMdx(parsed.content, input.platform)).trim();
1155
1268
  const keywords = Array.isArray(parsed.data.keywords) ? parsed.data.keywords.filter((value) => typeof value === "string") : [];
1156
1269
  const heading = leadingPageHeading(body);
1157
1270
  const title = typeof parsed.data.title === "string" && parsed.data.title.trim() ? parsed.data.title.trim() : heading?.title ?? titleFromId(identity.navigationId);
@@ -1261,6 +1374,543 @@ function normalizeAssetPath(value) {
1261
1374
  return segments.join("/");
1262
1375
  }
1263
1376
 
1377
+ // src/inline-extraction.ts
1378
+ import ts from "typescript";
1379
+ var SERVER_ONLY_IDENTIFIERS = /* @__PURE__ */ new Set(["process", "require", "module", "exports", "__dirname", "__filename", "Buffer"]);
1380
+ var BROWSER_IDENTIFIERS = /* @__PURE__ */ new Set([
1381
+ "window",
1382
+ "document",
1383
+ "localStorage",
1384
+ "sessionStorage",
1385
+ "navigator",
1386
+ "location",
1387
+ "history",
1388
+ "IntersectionObserver",
1389
+ "ResizeObserver",
1390
+ "MutationObserver",
1391
+ "matchMedia",
1392
+ "requestAnimationFrame",
1393
+ "cancelAnimationFrame",
1394
+ "alert",
1395
+ "confirm",
1396
+ "prompt",
1397
+ "HTMLElement",
1398
+ "Element",
1399
+ "Node",
1400
+ "Event",
1401
+ "KeyboardEvent",
1402
+ "MouseEvent",
1403
+ "CustomEvent",
1404
+ "FormData",
1405
+ "File",
1406
+ "FileReader",
1407
+ "Image",
1408
+ "Audio",
1409
+ "XMLHttpRequest",
1410
+ "WebSocket",
1411
+ "getComputedStyle",
1412
+ "innerWidth",
1413
+ "innerHeight",
1414
+ "scrollTo"
1415
+ ]);
1416
+ var JS_GLOBALS = /* @__PURE__ */ new Set([
1417
+ "undefined",
1418
+ "NaN",
1419
+ "Infinity",
1420
+ "globalThis",
1421
+ "arguments",
1422
+ "Object",
1423
+ "Function",
1424
+ "Array",
1425
+ "Number",
1426
+ "Boolean",
1427
+ "String",
1428
+ "Symbol",
1429
+ "BigInt",
1430
+ "Date",
1431
+ "RegExp",
1432
+ "Error",
1433
+ "AggregateError",
1434
+ "EvalError",
1435
+ "RangeError",
1436
+ "ReferenceError",
1437
+ "SyntaxError",
1438
+ "TypeError",
1439
+ "URIError",
1440
+ "JSON",
1441
+ "Math",
1442
+ "Intl",
1443
+ "Reflect",
1444
+ "Proxy",
1445
+ "Promise",
1446
+ "Map",
1447
+ "Set",
1448
+ "WeakMap",
1449
+ "WeakSet",
1450
+ "WeakRef",
1451
+ "ArrayBuffer",
1452
+ "SharedArrayBuffer",
1453
+ "DataView",
1454
+ "Atomics",
1455
+ "Int8Array",
1456
+ "Uint8Array",
1457
+ "Uint8ClampedArray",
1458
+ "Int16Array",
1459
+ "Uint16Array",
1460
+ "Int32Array",
1461
+ "Uint32Array",
1462
+ "Float32Array",
1463
+ "Float64Array",
1464
+ "BigInt64Array",
1465
+ "BigUint64Array",
1466
+ "parseInt",
1467
+ "parseFloat",
1468
+ "isNaN",
1469
+ "isFinite",
1470
+ "encodeURI",
1471
+ "encodeURIComponent",
1472
+ "decodeURI",
1473
+ "decodeURIComponent",
1474
+ "console",
1475
+ "fetch",
1476
+ "URL",
1477
+ "URLSearchParams",
1478
+ "Headers",
1479
+ "Request",
1480
+ "Response",
1481
+ "AbortController",
1482
+ "AbortSignal",
1483
+ "TextEncoder",
1484
+ "TextDecoder",
1485
+ "atob",
1486
+ "btoa",
1487
+ "structuredClone",
1488
+ "queueMicrotask",
1489
+ "performance",
1490
+ "setTimeout",
1491
+ "clearTimeout",
1492
+ "setInterval",
1493
+ "clearInterval"
1494
+ ]);
1495
+ var IMPLICIT_MODULE_NAMES = /* @__PURE__ */ new Set(["React", "MintlifyComponents"]);
1496
+ function parse(source) {
1497
+ return ts.createSourceFile("inline.tsx", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
1498
+ }
1499
+ function bindingNames(name, into) {
1500
+ if (ts.isIdentifier(name)) into.add(name.text);
1501
+ else for (const element of name.elements) if (ts.isBindingElement(element)) bindingNames(element.name, into);
1502
+ }
1503
+ function isFunctionLike(node) {
1504
+ return ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) || ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node);
1505
+ }
1506
+ function functionScope(fn) {
1507
+ const scope = /* @__PURE__ */ new Set();
1508
+ if ((ts.isFunctionExpression(fn) || ts.isFunctionDeclaration(fn)) && fn.name) scope.add(fn.name.text);
1509
+ for (const parameter of fn.parameters) bindingNames(parameter.name, scope);
1510
+ function collect(node) {
1511
+ if (ts.isVariableDeclaration(node)) bindingNames(node.name, scope);
1512
+ if ((ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node)) && node.name) scope.add(node.name.text);
1513
+ if (isFunctionLike(node)) return;
1514
+ ts.forEachChild(node, collect);
1515
+ }
1516
+ if (fn.body) ts.forEachChild(fn.body, collect);
1517
+ if (fn.body && !ts.isBlock(fn.body)) collect(fn.body);
1518
+ return scope;
1519
+ }
1520
+ function collectRefs(root) {
1521
+ const refs = [];
1522
+ const assigned = [];
1523
+ let awaitOutsideAsync = false;
1524
+ let dynamicImport = false;
1525
+ function bound(name, scopes) {
1526
+ return scopes.some((scope) => scope.has(name));
1527
+ }
1528
+ function push(name, kind, scopes) {
1529
+ if (!bound(name, scopes)) refs.push({ name, kind });
1530
+ }
1531
+ function walkNode(node, scopes, inAsync) {
1532
+ if (ts.isTypeNode(node)) return;
1533
+ if (isFunctionLike(node)) {
1534
+ const nextScopes = [...scopes, functionScope(node)];
1535
+ const async = !!node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword);
1536
+ for (const parameter of node.parameters) {
1537
+ if (!ts.isIdentifier(parameter.name)) walkNode(parameter.name, nextScopes, async);
1538
+ if (parameter.initializer) walkNode(parameter.initializer, nextScopes, async);
1539
+ }
1540
+ if (node.body) walkNode(node.body, nextScopes, async);
1541
+ return;
1542
+ }
1543
+ if (ts.isAwaitExpression(node) && !inAsync) awaitOutsideAsync = true;
1544
+ const target = ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment ? node.left : (ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) && (node.operator === ts.SyntaxKind.PlusPlusToken || node.operator === ts.SyntaxKind.MinusMinusToken) ? node.operand : void 0;
1545
+ if (target) {
1546
+ let base = target;
1547
+ while (ts.isPropertyAccessExpression(base) || ts.isElementAccessExpression(base)) base = base.expression;
1548
+ if (ts.isIdentifier(base) && !bound(base.text, scopes)) assigned.push(base.text);
1549
+ }
1550
+ if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) dynamicImport = true;
1551
+ if (ts.isIdentifier(node)) {
1552
+ const parent = node.parent;
1553
+ const kind = ts.isJsxExpression(parent) && parent.parent && ts.isJsxAttribute(parent.parent) ? "prop" : "other";
1554
+ push(node.text, kind, scopes);
1555
+ return;
1556
+ }
1557
+ if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
1558
+ let tag = node.tagName;
1559
+ while (ts.isPropertyAccessExpression(tag)) tag = tag.expression;
1560
+ if (ts.isIdentifier(tag)) {
1561
+ if (node.tagName !== tag || /^[A-Z]/.test(tag.text)) push(tag.text, node.tagName === tag ? "tag" : "member", scopes);
1562
+ }
1563
+ walkNode(node.attributes, scopes, inAsync);
1564
+ return;
1565
+ }
1566
+ if (ts.isJsxClosingElement(node)) return;
1567
+ if (ts.isJsxAttribute(node)) {
1568
+ if (node.initializer) walkNode(node.initializer, scopes, inAsync);
1569
+ return;
1570
+ }
1571
+ if (ts.isPropertyAccessExpression(node)) {
1572
+ walkNode(node.expression, scopes, inAsync);
1573
+ return;
1574
+ }
1575
+ if (ts.isQualifiedName(node)) return;
1576
+ if (ts.isPropertyAssignment(node)) {
1577
+ if (ts.isComputedPropertyName(node.name)) walkNode(node.name.expression, scopes, inAsync);
1578
+ walkNode(node.initializer, scopes, inAsync);
1579
+ return;
1580
+ }
1581
+ if (ts.isShorthandPropertyAssignment(node)) {
1582
+ push(node.name.text, "other", scopes);
1583
+ if (node.objectAssignmentInitializer) walkNode(node.objectAssignmentInitializer, scopes, inAsync);
1584
+ return;
1585
+ }
1586
+ if (ts.isBindingElement(node)) {
1587
+ if (node.propertyName && ts.isComputedPropertyName(node.propertyName)) walkNode(node.propertyName.expression, scopes, inAsync);
1588
+ if (node.initializer) walkNode(node.initializer, scopes, inAsync);
1589
+ if (!ts.isIdentifier(node.name)) walkNode(node.name, scopes, inAsync);
1590
+ return;
1591
+ }
1592
+ if (ts.isVariableDeclaration(node)) {
1593
+ if (!ts.isIdentifier(node.name)) walkNode(node.name, scopes, inAsync);
1594
+ if (node.initializer) walkNode(node.initializer, scopes, inAsync);
1595
+ return;
1596
+ }
1597
+ if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {
1598
+ node.members.forEach((member) => walkNode(member, scopes, inAsync));
1599
+ for (const clause of node.heritageClauses ?? []) for (const type of clause.types) walkNode(type.expression, scopes, inAsync);
1600
+ return;
1601
+ }
1602
+ if (ts.isPropertyDeclaration(node)) {
1603
+ if (node.initializer) walkNode(node.initializer, scopes, inAsync);
1604
+ return;
1605
+ }
1606
+ if (ts.isLabeledStatement(node)) {
1607
+ walkNode(node.statement, scopes, inAsync);
1608
+ return;
1609
+ }
1610
+ if (ts.isBreakOrContinueStatement(node)) return;
1611
+ ts.forEachChild(node, (child) => walkNode(child, scopes, inAsync));
1612
+ }
1613
+ walkNode(root, [], false);
1614
+ return { refs, assigned, awaitOutsideAsync, dynamicImport };
1615
+ }
1616
+ function declaredNames(statement) {
1617
+ const isDefault = !!(ts.canHaveModifiers(statement) ? ts.getModifiers(statement) : void 0)?.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword) || ts.isExportAssignment(statement);
1618
+ const names = /* @__PURE__ */ new Set();
1619
+ let componentLike = false;
1620
+ if (ts.isVariableStatement(statement)) {
1621
+ for (const declaration of statement.declarationList.declarations) {
1622
+ bindingNames(declaration.name, names);
1623
+ const initializer = declaration.initializer && unwrap(declaration.initializer);
1624
+ if (ts.isIdentifier(declaration.name) && /^[A-Z]/.test(declaration.name.text) && initializer && (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer) || ts.isClassExpression(initializer))) {
1625
+ componentLike = true;
1626
+ }
1627
+ }
1628
+ } else if ((ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name) {
1629
+ names.add(statement.name.text);
1630
+ componentLike = /^[A-Z]/.test(statement.name.text);
1631
+ }
1632
+ return { names: [...names], componentLike, defaultExport: isDefault };
1633
+ }
1634
+ function unwrap(expression) {
1635
+ let current = expression;
1636
+ while (ts.isParenthesizedExpression(current) || ts.isAsExpression(current) || ts.isSatisfiesExpression(current)) current = current.expression;
1637
+ return current;
1638
+ }
1639
+ function analyzeUnit(index, source, reactGlobals) {
1640
+ const sf = parse(source);
1641
+ const statement = sf.statements[0];
1642
+ const blockers = [];
1643
+ if (!statement || sf.statements.length !== 1) {
1644
+ return { index, source, names: [], refs: [], assigned: [], hooks: false, clientOnly: false, componentLike: false, blockers: ["is not a single declaration"] };
1645
+ }
1646
+ const { names, componentLike, defaultExport } = declaredNames(statement);
1647
+ if (defaultExport) blockers.push("is a default export");
1648
+ const { refs, assigned, awaitOutsideAsync, dynamicImport } = collectRefs(statement);
1649
+ if (awaitOutsideAsync) blockers.push("uses await outside an async function");
1650
+ if (dynamicImport) blockers.push("uses a dynamic import()");
1651
+ const initializer = ts.isVariableStatement(statement) && statement.declarationList.declarations.length === 1 ? statement.declarationList.declarations[0].initializer && unwrap(statement.declarationList.declarations[0].initializer) : statement;
1652
+ if (initializer && isFunctionLike(initializer) && initializer.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword)) {
1653
+ blockers.push("is an async (server) component");
1654
+ }
1655
+ for (const { name } of refs) {
1656
+ if (SERVER_ONLY_IDENTIFIERS.has(name)) blockers.push(`uses the server-only \`${name}\``);
1657
+ }
1658
+ let handlers = false;
1659
+ function scanHandlers(node) {
1660
+ if (ts.isJsxAttribute(node) && ts.isIdentifier(node.name) && /^on[A-Z]/.test(node.name.text)) handlers = true;
1661
+ ts.forEachChild(node, scanHandlers);
1662
+ }
1663
+ scanHandlers(statement);
1664
+ return {
1665
+ index,
1666
+ source,
1667
+ names,
1668
+ refs,
1669
+ assigned,
1670
+ hooks: refs.some(({ name }) => reactGlobals.has(name)) || /\bReact\.(?:use[A-Z]\w*|createContext|forwardRef|memo)\b/.test(source),
1671
+ clientOnly: handlers || refs.some(({ name }) => BROWSER_IDENTIFIERS.has(name)),
1672
+ componentLike,
1673
+ blockers: [...new Set(blockers)]
1674
+ };
1675
+ }
1676
+ function helperNames(source) {
1677
+ const statement = parse(source).statements[0];
1678
+ return statement ? declaredNames(statement).names : [];
1679
+ }
1680
+ function importLocals(statementText) {
1681
+ const sf = parse(statementText);
1682
+ const locals = [];
1683
+ for (const statement of sf.statements) {
1684
+ if (!ts.isImportDeclaration(statement) || !statement.importClause) continue;
1685
+ const clause = statement.importClause;
1686
+ if (clause.name) locals.push(clause.name.text);
1687
+ const named = clause.namedBindings;
1688
+ if (named && ts.isNamespaceImport(named)) locals.push(named.name.text);
1689
+ if (named && ts.isNamedImports(named)) for (const element of named.elements) locals.push(element.name.text);
1690
+ }
1691
+ return locals;
1692
+ }
1693
+ function expressionRefs(expression) {
1694
+ const sf = parse(`const __expression = (${expression})`);
1695
+ const statement = sf.statements[0];
1696
+ return statement ? collectRefs(statement).refs : [];
1697
+ }
1698
+ function bodyReferences(tree) {
1699
+ const mdastTags = /* @__PURE__ */ new Set();
1700
+ const refs = [];
1701
+ function visit(node) {
1702
+ if (node.type === "mdxjsEsm") return;
1703
+ if (["mdxJsxFlowElement", "mdxJsxTextElement"].includes(node.type) && node.name) {
1704
+ const root = node.name.split(".")[0];
1705
+ if (node.name.includes(".")) refs.push({ name: root, kind: "member" });
1706
+ else mdastTags.add(root);
1707
+ }
1708
+ if (["mdxFlowExpression", "mdxTextExpression"].includes(node.type) && node.value) refs.push(...expressionRefs(node.value));
1709
+ for (const attribute of node.attributes ?? []) {
1710
+ const value = attribute.value;
1711
+ if (attribute.type === "mdxJsxExpressionAttribute" && typeof value === "string") {
1712
+ refs.push(...expressionRefs(`{${value}}`));
1713
+ } else if (value && typeof value === "object" && typeof value.value === "string") {
1714
+ refs.push(...expressionRefs(value.value).map((ref, _index, all) => all.length === 1 && value.value.trim() === ref.name ? { name: ref.name, kind: "prop" } : ref));
1715
+ }
1716
+ }
1717
+ for (const child of node.children ?? []) visit(child);
1718
+ }
1719
+ visit(tree);
1720
+ return { mdastTags, refs };
1721
+ }
1722
+ function planInlineExtraction(input) {
1723
+ const units = input.declarations.map((declaration, index) => analyzeUnit(index, declaration.source, input.reactGlobals));
1724
+ const owner = /* @__PURE__ */ new Map();
1725
+ for (const unit of units) for (const name of unit.names) owner.set(name, unit.index);
1726
+ for (let changed = true; changed; ) {
1727
+ changed = false;
1728
+ for (const unit of units) {
1729
+ if (unit.hooks) continue;
1730
+ if (unit.refs.some(({ name }) => /^use[A-Z]/.test(name) && units[owner.get(name) ?? -1]?.hooks)) {
1731
+ unit.hooks = true;
1732
+ changed = true;
1733
+ }
1734
+ }
1735
+ }
1736
+ const importByLocal = /* @__PURE__ */ new Map();
1737
+ for (const statement of input.copyableImports) for (const local of importLocals(statement)) importByLocal.set(local, statement);
1738
+ const helperByName = /* @__PURE__ */ new Map();
1739
+ for (const helper of input.helperDeclarations) {
1740
+ for (const name of helperNames(helper)) helperByName.set(name, helper);
1741
+ }
1742
+ const body = bodyReferences(input.tree);
1743
+ const dependencies = (unit) => {
1744
+ const found = /* @__PURE__ */ new Set();
1745
+ for (const { name } of unit.refs) {
1746
+ const target = owner.get(name);
1747
+ if (target !== void 0 && target !== unit.index) found.add(target);
1748
+ }
1749
+ return found;
1750
+ };
1751
+ const closureOf = (rootIndex) => {
1752
+ const seen = /* @__PURE__ */ new Set([rootIndex]);
1753
+ const queue = [rootIndex];
1754
+ while (queue.length) for (const next of dependencies(units[queue.pop()])) {
1755
+ if (!seen.has(next)) {
1756
+ seen.add(next);
1757
+ queue.push(next);
1758
+ }
1759
+ }
1760
+ return seen;
1761
+ };
1762
+ const intrinsicBlocker = (unit) => {
1763
+ if (unit.blockers.length > 0) return `\`${unit.names[0] ?? "a dependency"}\` ${unit.blockers[0]}`;
1764
+ for (const { name, kind } of unit.refs) {
1765
+ if (owner.has(name) || importByLocal.has(name) || helperByName.has(name)) continue;
1766
+ if (input.unavailableImports.has(name)) {
1767
+ return `\`${unit.names[0]}\` uses \`${name}\`, imported from ${input.unavailableImports.get(name)}, which is not available in the migrated project`;
1768
+ }
1769
+ if (input.reactGlobals.has(name) || IMPLICIT_MODULE_NAMES.has(name) || JS_GLOBALS.has(name) || BROWSER_IDENTIFIERS.has(name)) continue;
1770
+ if ((kind === "tag" || kind === "member") && isThallyBuiltinComponent(name)) continue;
1771
+ return `\`${unit.names[0]}\` uses \`${name}\`, which is not declared or imported on the page`;
1772
+ }
1773
+ return void 0;
1774
+ };
1775
+ const roots = units.filter((unit) => unit.hooks && unit.names.some((name) => /^[A-Z]/.test(name))).map((unit) => unit.index);
1776
+ const blocked = [];
1777
+ const active = new Set(roots);
1778
+ const block = (rootIndex, reason) => {
1779
+ active.delete(rootIndex);
1780
+ blocked.push({ name: units[rootIndex].names.find((name) => /^[A-Z]/.test(name)) ?? units[rootIndex].names[0], reason });
1781
+ };
1782
+ for (const rootIndex of roots) {
1783
+ for (const member of closureOf(rootIndex)) {
1784
+ const reason = intrinsicBlocker(units[member]);
1785
+ if (reason) {
1786
+ block(rootIndex, reason);
1787
+ break;
1788
+ }
1789
+ }
1790
+ }
1791
+ for (let round = 0; round <= units.length + 1; round += 1) {
1792
+ const inModule = /* @__PURE__ */ new Set();
1793
+ for (const rootIndex of active) for (const member of closureOf(rootIndex)) inModule.add(member);
1794
+ const clientSide = /* @__PURE__ */ new Set();
1795
+ for (const index of inModule) if (units[index].hooks || units[index].clientOnly) clientSide.add(index);
1796
+ for (let changed = true; changed; ) {
1797
+ changed = false;
1798
+ for (const index of inModule) {
1799
+ if (clientSide.has(index)) continue;
1800
+ const unit = units[index];
1801
+ const callsClient = unit.refs.some(({ name, kind }) => {
1802
+ const target = owner.get(name);
1803
+ return target !== void 0 && clientSide.has(target) && kind !== "tag" && kind !== "prop";
1804
+ });
1805
+ if (callsClient) {
1806
+ clientSide.add(index);
1807
+ changed = true;
1808
+ }
1809
+ }
1810
+ }
1811
+ for (const rootIndex of active) clientSide.add(rootIndex);
1812
+ const nonModuleRefs = [...body.refs];
1813
+ for (const unit of units) if (!inModule.has(unit.index)) nonModuleRefs.push(...unit.refs);
1814
+ const referencedByPage = (index) => units[index].names.some((name) => body.mdastTags.has(name) || nonModuleRefs.some((ref) => ref.name === name));
1815
+ const kept = /* @__PURE__ */ new Set();
1816
+ for (const index of inModule) {
1817
+ if (clientSide.has(index)) continue;
1818
+ if (!units[index].componentLike || referencedByPage(index)) kept.add(index);
1819
+ }
1820
+ for (let changed = true; changed; ) {
1821
+ changed = false;
1822
+ for (const index of kept) for (const dependency of dependencies(units[index])) {
1823
+ if (inModule.has(dependency) && !clientSide.has(dependency) && !kept.has(dependency)) {
1824
+ kept.add(dependency);
1825
+ changed = true;
1826
+ }
1827
+ }
1828
+ }
1829
+ const moved = new Set([...inModule].filter((index) => !kept.has(index)));
1830
+ const pageRefs = [...nonModuleRefs];
1831
+ for (const index of kept) pageRefs.push(...units[index].refs);
1832
+ const violation = [...moved].find((index) => clientSide.has(index) && units[index].names.some((name) => pageRefs.some((ref) => ref.name === name && ref.kind !== "tag" && ref.kind !== "prop")));
1833
+ if (violation !== void 0) {
1834
+ const names = units[violation].names;
1835
+ const readsIt = (ref) => names.includes(ref.name) && ref.kind !== "tag" && ref.kind !== "prop";
1836
+ const readers = units.filter((unit) => !moved.has(unit.index) && unit.refs.some(readsIt));
1837
+ const promotable = !body.refs.some(readsIt) && readers.every((unit) => unit.componentLike && !active.has(unit.index) && [...closureOf(unit.index)].every((member) => !intrinsicBlocker(units[member])));
1838
+ if (promotable && readers.length > 0) {
1839
+ for (const unit of readers) active.add(unit.index);
1840
+ continue;
1841
+ }
1842
+ for (const rootIndex of [...active]) {
1843
+ if (closureOf(rootIndex).has(violation)) {
1844
+ block(rootIndex, `\`${names[0]}\` is also read or called by page code that stays on the server`);
1845
+ }
1846
+ }
1847
+ continue;
1848
+ }
1849
+ const reachable = new Set([...kept].filter(referencedByPage));
1850
+ for (let changed = true; changed; ) {
1851
+ changed = false;
1852
+ for (const index of [...reachable]) for (const dependency of dependencies(units[index])) {
1853
+ if (kept.has(dependency) && !reachable.has(dependency)) {
1854
+ reachable.add(dependency);
1855
+ changed = true;
1856
+ }
1857
+ }
1858
+ }
1859
+ const mutated = [...reachable].find((index) => units.some((unit) => unit.assigned.some((name) => units[index].names.includes(name))));
1860
+ if (mutated !== void 0) {
1861
+ for (const rootIndex of [...active]) {
1862
+ if (closureOf(rootIndex).has(mutated)) {
1863
+ block(rootIndex, `\`${units[mutated].names[0]}\` is mutable state that page code also uses, so a copy in the client module would diverge`);
1864
+ }
1865
+ }
1866
+ continue;
1867
+ }
1868
+ const movedNames = [...moved].flatMap((index) => units[index].names);
1869
+ const registryNames = movedNames.filter((name) => body.mdastTags.has(name));
1870
+ const importNames = movedNames.filter((name) => pageRefs.some((ref) => ref.name === name));
1871
+ const moduleMembers = [...inModule].sort((a, b) => a - b);
1872
+ const moduleNames = new Set(moduleMembers.flatMap((index) => units[index].names));
1873
+ const usedImports = [];
1874
+ const usedHelpers = [];
1875
+ for (const index of moduleMembers) {
1876
+ for (const { name } of units[index].refs) {
1877
+ const statement = importByLocal.get(name);
1878
+ if (statement && !usedImports.includes(statement)) usedImports.push(statement);
1879
+ const helper = helperByName.get(name);
1880
+ if (helper && !usedHelpers.includes(helper)) usedHelpers.push(helper);
1881
+ }
1882
+ }
1883
+ for (const statement of usedImports) for (const local of importLocals(statement)) moduleNames.add(local);
1884
+ for (const helper of usedHelpers) for (const name of helperNames(helper)) moduleNames.add(name);
1885
+ const pageReferences = new Set(pageRefs.map((ref) => ref.name));
1886
+ for (const tag of body.mdastTags) pageReferences.add(tag);
1887
+ return {
1888
+ blocked,
1889
+ moved: [...moved].sort((a, b) => a - b),
1890
+ copied: [...kept].sort((a, b) => a - b),
1891
+ movedNames,
1892
+ moduleImports: usedImports,
1893
+ moduleHelpers: usedHelpers,
1894
+ registryNames: [...new Set(registryNames)],
1895
+ pageImportNames: [...new Set(importNames)],
1896
+ moduleNames,
1897
+ pageReferences
1898
+ };
1899
+ }
1900
+ return { blocked, moved: [], copied: [], movedNames: [], moduleImports: [], moduleHelpers: [], registryNames: [], pageImportNames: [], moduleNames: /* @__PURE__ */ new Set(), pageReferences: /* @__PURE__ */ new Set() };
1901
+ }
1902
+ function unboundTags(moduleSource, boundNames) {
1903
+ const sf = parse(moduleSource);
1904
+ const tags = /* @__PURE__ */ new Set();
1905
+ for (const statement of sf.statements) {
1906
+ if (ts.isImportDeclaration(statement)) continue;
1907
+ for (const ref of collectRefs(statement).refs) {
1908
+ if ((ref.kind === "tag" || ref.kind === "member") && /^[A-Z]/.test(ref.name) && !boundNames.has(ref.name)) tags.add(ref.name);
1909
+ }
1910
+ }
1911
+ return [...tags].sort();
1912
+ }
1913
+
1264
1914
  // src/components.ts
1265
1915
  function normalizeIndentedFences(content) {
1266
1916
  const lines = content.split("\n");
@@ -1307,23 +1957,23 @@ function normalizeIndentedFences(content) {
1307
1957
  }
1308
1958
  function staticServerHelper(path, imported, local) {
1309
1959
  if (imported === "default") return null;
1310
- const parsed = ts.createSourceFile(path, readFileSync(path, "utf8"), ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
1960
+ const parsed = ts2.createSourceFile(path, readFileSync(path, "utf8"), ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
1311
1961
  const isLiteral = (node) => {
1312
- if (ts.isParenthesizedExpression(node)) return isLiteral(node.expression);
1313
- if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node) || ts.isNumericLiteral(node)) return true;
1314
- if ([ts.SyntaxKind.TrueKeyword, ts.SyntaxKind.FalseKeyword, ts.SyntaxKind.NullKeyword].includes(node.kind)) return true;
1315
- if (ts.isPrefixUnaryExpression(node)) return [ts.SyntaxKind.PlusToken, ts.SyntaxKind.MinusToken].includes(node.operator) && ts.isNumericLiteral(node.operand);
1316
- if (ts.isArrayLiteralExpression(node)) return node.elements.every((element) => ts.isExpression(element) && isLiteral(element));
1317
- if (ts.isObjectLiteralExpression(node)) return node.properties.every((property) => ts.isPropertyAssignment(property) && (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name) || ts.isNumericLiteral(property.name)) && isLiteral(property.initializer));
1962
+ if (ts2.isParenthesizedExpression(node)) return isLiteral(node.expression);
1963
+ if (ts2.isStringLiteral(node) || ts2.isNoSubstitutionTemplateLiteral(node) || ts2.isNumericLiteral(node)) return true;
1964
+ if ([ts2.SyntaxKind.TrueKeyword, ts2.SyntaxKind.FalseKeyword, ts2.SyntaxKind.NullKeyword].includes(node.kind)) return true;
1965
+ if (ts2.isPrefixUnaryExpression(node)) return [ts2.SyntaxKind.PlusToken, ts2.SyntaxKind.MinusToken].includes(node.operator) && ts2.isNumericLiteral(node.operand);
1966
+ if (ts2.isArrayLiteralExpression(node)) return node.elements.every((element) => ts2.isExpression(element) && isLiteral(element));
1967
+ if (ts2.isObjectLiteralExpression(node)) return node.properties.every((property) => ts2.isPropertyAssignment(property) && (ts2.isIdentifier(property.name) || ts2.isStringLiteral(property.name) || ts2.isNumericLiteral(property.name)) && isLiteral(property.initializer));
1318
1968
  return false;
1319
1969
  };
1320
1970
  for (const statement of parsed.statements) {
1321
- if (!ts.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) continue;
1971
+ if (!ts2.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts2.SyntaxKind.ExportKeyword)) continue;
1322
1972
  for (const declaration of statement.declarationList.declarations) {
1323
- if (!ts.isIdentifier(declaration.name) || declaration.name.text !== imported || !declaration.initializer || !ts.isArrowFunction(declaration.initializer)) continue;
1973
+ if (!ts2.isIdentifier(declaration.name) || declaration.name.text !== imported || !declaration.initializer || !ts2.isArrowFunction(declaration.initializer)) continue;
1324
1974
  const arrow = declaration.initializer;
1325
1975
  if (arrow.parameters.length > 0) continue;
1326
- const result = ts.isBlock(arrow.body) ? arrow.body.statements.length === 1 && ts.isReturnStatement(arrow.body.statements[0]) ? arrow.body.statements[0].expression : void 0 : arrow.body;
1976
+ const result = ts2.isBlock(arrow.body) ? arrow.body.statements.length === 1 && ts2.isReturnStatement(arrow.body.statements[0]) ? arrow.body.statements[0].expression : void 0 : arrow.body;
1327
1977
  if (result && isLiteral(result)) return `export const ${local} = () => (${result.getText(parsed)});`;
1328
1978
  }
1329
1979
  }
@@ -1547,12 +2197,12 @@ function wrapImpureCssModuleSelectors(css) {
1547
2197
  return root.toString();
1548
2198
  }
1549
2199
  function sourceFile(source, filename) {
1550
- return ts.createSourceFile(
2200
+ return ts2.createSourceFile(
1551
2201
  filename,
1552
2202
  source,
1553
- ts.ScriptTarget.Latest,
2203
+ ts2.ScriptTarget.Latest,
1554
2204
  true,
1555
- /\.[cm]?ts$/.test(filename) ? ts.ScriptKind.TS : ts.ScriptKind.TSX
2205
+ /\.[cm]?ts$/.test(filename) ? ts2.ScriptKind.TS : ts2.ScriptKind.TSX
1556
2206
  );
1557
2207
  }
1558
2208
  function walk(node, visitor) {
@@ -1563,24 +2213,24 @@ function implicitReactImports(source) {
1563
2213
  const bindings = /* @__PURE__ */ new Set();
1564
2214
  const references = /* @__PURE__ */ new Set();
1565
2215
  function bind(name) {
1566
- if (ts.isIdentifier(name)) bindings.add(name.text);
1567
- else for (const element of name.elements) if (ts.isBindingElement(element)) bind(element.name);
2216
+ if (ts2.isIdentifier(name)) bindings.add(name.text);
2217
+ else for (const element of name.elements) if (ts2.isBindingElement(element)) bind(element.name);
1568
2218
  }
1569
2219
  for (const statement of source.statements) {
1570
- if (ts.isImportDeclaration(statement) && statement.importClause) {
2220
+ if (ts2.isImportDeclaration(statement) && statement.importClause) {
1571
2221
  const clause = statement.importClause;
1572
2222
  if (clause.name) bindings.add(clause.name.text);
1573
2223
  if (clause.namedBindings) {
1574
- if (ts.isNamespaceImport(clause.namedBindings)) bindings.add(clause.namedBindings.name.text);
2224
+ if (ts2.isNamespaceImport(clause.namedBindings)) bindings.add(clause.namedBindings.name.text);
1575
2225
  else for (const element of clause.namedBindings.elements) bindings.add(element.name.text);
1576
2226
  }
1577
2227
  }
1578
- if (ts.isVariableStatement(statement)) for (const declaration of statement.declarationList.declarations) bind(declaration.name);
1579
- if ((ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name) bindings.add(statement.name.text);
2228
+ if (ts2.isVariableStatement(statement)) for (const declaration of statement.declarationList.declarations) bind(declaration.name);
2229
+ if ((ts2.isFunctionDeclaration(statement) || ts2.isClassDeclaration(statement)) && statement.name) bindings.add(statement.name.text);
1580
2230
  }
1581
2231
  function visit(node) {
1582
- if (ts.isIdentifier(node) && !(ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) && !(ts.isPropertyAssignment(node.parent) && node.parent.name === node)) references.add(node.text);
1583
- ts.forEachChild(node, visit);
2232
+ if (ts2.isIdentifier(node) && !(ts2.isPropertyAccessExpression(node.parent) && node.parent.name === node) && !(ts2.isPropertyAssignment(node.parent) && node.parent.name === node)) references.add(node.text);
2233
+ ts2.forEachChild(node, visit);
1584
2234
  }
1585
2235
  visit(source);
1586
2236
  const hooks = [...REACT_GLOBALS].filter((name) => references.has(name) && !bindings.has(name)).sort();
@@ -1596,13 +2246,22 @@ function implicitReactImports(source) {
1596
2246
  usesMintlifyComponents ? mintlifyComponentsShim() : ""
1597
2247
  ].filter(Boolean).join("\n");
1598
2248
  }
2249
+ function resolveInlineBuiltinReferences(source, moduleNames) {
2250
+ const unresolved = unboundTags(source, moduleNames);
2251
+ if (unresolved.length === 0) return source;
2252
+ return [
2253
+ "import { builtinMdxComponents } from '@/components/mdx/builtin-components';",
2254
+ `const { ${unresolved.join(", ")} } = builtinMdxComponents;`,
2255
+ source
2256
+ ].join("\n");
2257
+ }
1599
2258
  function imports(statement) {
1600
- if (!ts.isStringLiteral(statement.moduleSpecifier) || !statement.importClause) return [];
2259
+ if (!ts2.isStringLiteral(statement.moduleSpecifier) || !statement.importClause) return [];
1601
2260
  const clause = statement.importClause;
1602
2261
  if (clause.isTypeOnly) return [];
1603
2262
  const source = statement.moduleSpecifier.text;
1604
2263
  const bindings = clause.name ? [{ local: clause.name.text, imported: "default", source }] : [];
1605
- if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {
2264
+ if (clause.namedBindings && ts2.isNamedImports(clause.namedBindings)) {
1606
2265
  for (const element of clause.namedBindings.elements) {
1607
2266
  if (!element.isTypeOnly) bindings.push({ local: element.name.text, imported: element.propertyName?.text ?? element.name.text, source });
1608
2267
  }
@@ -1618,6 +2277,7 @@ var CLIENT_BUILTIN_COMPONENT_TAGS = /* @__PURE__ */ new Set([
1618
2277
  "ParamField",
1619
2278
  "Expandable",
1620
2279
  "CodeGroup",
2280
+ "CodeBlock",
1621
2281
  "Badge",
1622
2282
  "Tooltip",
1623
2283
  "Tabs",
@@ -1627,6 +2287,7 @@ var CLIENT_BUILTIN_COMPONENT_TAGS = /* @__PURE__ */ new Set([
1627
2287
  "InlineRequestExample",
1628
2288
  "InlineResponseExample",
1629
2289
  "Tree",
2290
+ "FileTree",
1630
2291
  "Folder",
1631
2292
  "File",
1632
2293
  "Mermaid",
@@ -1648,8 +2309,8 @@ var CLIENT_BUILTIN_COMPONENT_TAGS = /* @__PURE__ */ new Set([
1648
2309
  function isConfirmedClientBoundaryTag(name) {
1649
2310
  return EXTRACTED_CLIENT_COMPONENT_TAG.test(name) || CLIENT_BUILTIN_COMPONENT_TAGS.has(name);
1650
2311
  }
1651
- function functionValuedAttribute(node, declaredNames) {
1652
- const isFunctionValue = (value) => declaredNames.has(value.trim()) || isFunctionInitializer(value.trim(), 0);
2312
+ function functionValuedAttribute(node, declaredNames2) {
2313
+ const isFunctionValue = (value) => declaredNames2.has(value.trim()) || isFunctionInitializer(value.trim(), 0);
1653
2314
  for (const attribute of node.attributes ?? []) {
1654
2315
  const raw = attribute.value;
1655
2316
  const value = raw && typeof raw === "object" ? raw.value : void 0;
@@ -1662,21 +2323,21 @@ function functionValuedAttribute(node, declaredNames) {
1662
2323
  }
1663
2324
  return void 0;
1664
2325
  }
1665
- function propsTargetExtractedClientComponent(body, declaredNames) {
2326
+ function propsTargetExtractedClientComponent(body, declaredNames2) {
1666
2327
  const tree = parser.parse(body);
1667
2328
  let found = false;
1668
2329
  walk(tree, (node) => {
1669
2330
  if (found || !node.name || !isConfirmedClientBoundaryTag(node.name)) return;
1670
- if (functionValuedAttribute(node, declaredNames) !== void 0) found = true;
2331
+ if (functionValuedAttribute(node, declaredNames2) !== void 0) found = true;
1671
2332
  });
1672
2333
  return found;
1673
2334
  }
1674
- function hasAnyFunctionValuedProp(body, declaredNames) {
2335
+ function hasAnyFunctionValuedProp(body, declaredNames2) {
1675
2336
  const tree = parser.parse(body);
1676
2337
  let found = false;
1677
2338
  walk(tree, (node) => {
1678
2339
  if (found || !node.name) return;
1679
- if (functionValuedAttribute(node, declaredNames) !== void 0) found = true;
2340
+ if (functionValuedAttribute(node, declaredNames2) !== void 0) found = true;
1680
2341
  });
1681
2342
  return found;
1682
2343
  }
@@ -1684,13 +2345,13 @@ function declarationsReferenceBrowserGlobal(body) {
1684
2345
  const tree = parser.parse(body);
1685
2346
  let found = false;
1686
2347
  function inspect(node) {
1687
- if (ts.isIdentifier(node) && (node.text === "document" || node.text === "window")) found = true;
1688
- ts.forEachChild(node, inspect);
2348
+ if (ts2.isIdentifier(node) && (node.text === "document" || node.text === "window")) found = true;
2349
+ ts2.forEachChild(node, inspect);
1689
2350
  }
1690
2351
  for (const node of tree.children ?? []) {
1691
2352
  if (found || node.type !== "mdxjsEsm" || node.value === void 0) continue;
1692
2353
  for (const statement of sourceFile(node.value, "inline.tsx").statements) {
1693
- if (ts.isVariableStatement(statement) || ts.isFunctionDeclaration(statement)) inspect(statement);
2354
+ if (ts2.isVariableStatement(statement) || ts2.isFunctionDeclaration(statement)) inspect(statement);
1694
2355
  }
1695
2356
  }
1696
2357
  return found;
@@ -1794,14 +2455,14 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
1794
2455
  return;
1795
2456
  }
1796
2457
  const text = content.toString("utf8");
1797
- const syntax = ts.transpileModule(text, {
2458
+ const syntax = ts2.transpileModule(text, {
1798
2459
  fileName: path,
1799
2460
  reportDiagnostics: true,
1800
- compilerOptions: { jsx: ts.JsxEmit.Preserve, target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.ESNext }
2461
+ compilerOptions: { jsx: ts2.JsxEmit.Preserve, target: ts2.ScriptTarget.ESNext, module: ts2.ModuleKind.ESNext }
1801
2462
  });
1802
- if (syntax.diagnostics?.some((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error)) throw new Error("component source contains unsupported JavaScript or TypeScript syntax");
2463
+ if (syntax.diagnostics?.some((diagnostic) => diagnostic.category === ts2.DiagnosticCategory.Error)) throw new Error("component source contains unsupported JavaScript or TypeScript syntax");
1803
2464
  const ast = sourceFile(text, path);
1804
- if (ast.statements.some((statement) => ts.isExpressionStatement(statement) && ts.isStringLiteral(statement.expression) && statement.expression.text === "use server")) throw new Error("server-only component modules require manual migration");
2465
+ 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");
1805
2466
  const edits = [];
1806
2467
  function dependency(literal, importDeclaration) {
1807
2468
  const specifier = literal.text;
@@ -1811,10 +2472,10 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
1811
2472
  const localName = importDeclaration?.importClause?.name?.text;
1812
2473
  if (localName) {
1813
2474
  let renameToProp2 = function(node) {
1814
- if (ts.isJsxAttribute(node) && node.name.getText(ast) === "to" && ts.isJsxOpeningLikeElement(node.parent.parent) && node.parent.parent.tagName.getText(ast) === localName) {
2475
+ if (ts2.isJsxAttribute(node) && node.name.getText(ast) === "to" && ts2.isJsxOpeningLikeElement(node.parent.parent) && node.parent.parent.tagName.getText(ast) === localName) {
1815
2476
  edits.push({ start: node.name.getStart(ast), end: node.name.end, value: "href" });
1816
2477
  }
1817
- ts.forEachChild(node, renameToProp2);
2478
+ ts2.forEachChild(node, renameToProp2);
1818
2479
  };
1819
2480
  var renameToProp = renameToProp2;
1820
2481
  renameToProp2(ast);
@@ -1837,15 +2498,15 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
1837
2498
  edits.push({ start: literal.getStart(ast), end: literal.end, value: JSON.stringify(portableSpecifier(nextPath.startsWith(".") ? nextPath : `./${nextPath}`)) });
1838
2499
  }
1839
2500
  function inspect(node) {
1840
- if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
1841
- dependency(node.moduleSpecifier, ts.isImportDeclaration(node) ? node : void 0);
2501
+ if ((ts2.isImportDeclaration(node) || ts2.isExportDeclaration(node)) && node.moduleSpecifier && ts2.isStringLiteral(node.moduleSpecifier)) {
2502
+ dependency(node.moduleSpecifier, ts2.isImportDeclaration(node) ? node : void 0);
1842
2503
  }
1843
- if (ts.isCallExpression(node) && (node.expression.kind === ts.SyntaxKind.ImportKeyword || ts.isIdentifier(node.expression) && node.expression.text === "require")) {
2504
+ if (ts2.isCallExpression(node) && (node.expression.kind === ts2.SyntaxKind.ImportKeyword || ts2.isIdentifier(node.expression) && node.expression.text === "require")) {
1844
2505
  const argument = node.arguments[0];
1845
- if (node.arguments.length !== 1 || !argument || !ts.isStringLiteralLike(argument)) throw new Error("computed component imports require manual migration");
2506
+ if (node.arguments.length !== 1 || !argument || !ts2.isStringLiteralLike(argument)) throw new Error("computed component imports require manual migration");
1846
2507
  dependency(argument);
1847
2508
  }
1848
- ts.forEachChild(node, inspect);
2509
+ ts2.forEachChild(node, inspect);
1849
2510
  }
1850
2511
  inspect(ast);
1851
2512
  const replaced = applyReplacements(text, edits);
@@ -1923,15 +2584,15 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
1923
2584
  function hasExpressionReference(names, options = {}) {
1924
2585
  let found = false;
1925
2586
  function inspect2(node) {
1926
- if (ts.isIdentifier(node) && names.has(node.text)) found = true;
1927
- ts.forEachChild(node, inspect2);
2587
+ if (ts2.isIdentifier(node) && names.has(node.text)) found = true;
2588
+ ts2.forEachChild(node, inspect2);
1928
2589
  }
1929
2590
  walk(tree, (node) => {
1930
2591
  if (options.excludedNodes?.some((excluded) => node.position?.start.offset !== void 0 && node.position.end.offset !== void 0 && node.position.start.offset >= excluded.position.start.offset && node.position.end.offset <= excluded.position.end.offset)) return;
1931
2592
  if (node.name && [...names].some((name) => node.name.startsWith(`${name}.`) || options.includeDirectTags && node.name === name)) found = true;
1932
2593
  if (options.includeDeclarations !== false && node.type === "mdxjsEsm" && node.value) {
1933
2594
  for (const statement of sourceFile(node.value, "expression.tsx").statements) {
1934
- if (!ts.isImportDeclaration(statement)) inspect2(statement);
2595
+ if (!ts2.isImportDeclaration(statement)) inspect2(statement);
1935
2596
  }
1936
2597
  }
1937
2598
  const expressions = [
@@ -1960,13 +2621,13 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
1960
2621
  if (node.value === void 0 || node.position?.start.offset === void 0) continue;
1961
2622
  const ast = sourceFile(node.value, "inline.tsx");
1962
2623
  for (const statement of ast.statements) {
1963
- if (!ts.isImportDeclaration(statement)) {
2624
+ if (!ts2.isImportDeclaration(statement)) {
1964
2625
  let inspect2 = function(node2) {
1965
- if (ts.isCallExpression(node2) && (node2.expression.kind === ts.SyntaxKind.ImportKeyword || ts.isIdentifier(node2.expression) && node2.expression.text === "require")) unsupportedDependency = true;
1966
- ts.forEachChild(node2, inspect2);
2626
+ if (ts2.isCallExpression(node2) && (node2.expression.kind === ts2.SyntaxKind.ImportKeyword || ts2.isIdentifier(node2.expression) && node2.expression.text === "require")) unsupportedDependency = true;
2627
+ ts2.forEachChild(node2, inspect2);
1967
2628
  };
1968
2629
  var inspect = inspect2;
1969
- let unsupportedDependency = ts.isExportDeclaration(statement) && !!statement.moduleSpecifier;
2630
+ let unsupportedDependency = ts2.isExportDeclaration(statement) && !!statement.moduleSpecifier;
1970
2631
  inspect2(statement);
1971
2632
  if (unsupportedDependency) {
1972
2633
  hasUnsupportedImports = true;
@@ -1980,7 +2641,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
1980
2641
  continue;
1981
2642
  }
1982
2643
  const bindings = imports(statement);
1983
- const rawSpecifier = ts.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : "";
2644
+ const rawSpecifier = ts2.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : "";
1984
2645
  const specifier = rawSpecifier.startsWith("@site/") ? `/${rawSpecifier.slice("@site/".length)}` : rawSpecifier;
1985
2646
  if (isScaffoldProvidedImport(specifier)) {
1986
2647
  if (specifier === "react" && bindings.length > 0 && bindings.every((binding) => REACT_GLOBALS.has(binding.imported)) && !hasExpressionReference(new Set(bindings.map((binding) => binding.local)))) {
@@ -2043,7 +2704,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
2043
2704
  } catch {
2044
2705
  }
2045
2706
  }
2046
- if (!bindings.length || statement.importClause?.namedBindings && ts.isNamespaceImport(statement.importClause.namedBindings)) {
2707
+ if (!bindings.length || statement.importClause?.namedBindings && ts2.isNamespaceImport(statement.importClause.namedBindings)) {
2047
2708
  warn("Namespace or side-effect MDX imports require manual registration; the import was preserved.", currentFile);
2048
2709
  hasUnsupportedImports = true;
2049
2710
  continue;
@@ -2116,10 +2777,60 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
2116
2777
  }
2117
2778
  }
2118
2779
  }
2780
+ const refusedInlineComponents = /* @__PURE__ */ new Set();
2781
+ {
2782
+ const plan = planInlineExtraction({
2783
+ declarations,
2784
+ tree,
2785
+ copyableImports: [...moduleImports, ...realPageImports],
2786
+ helperDeclarations: serverPageDeclarations,
2787
+ unavailableImports: unsupportedImports,
2788
+ reactGlobals: REACT_GLOBALS
2789
+ });
2790
+ for (const { name, reason } of plan.blocked) {
2791
+ refusedInlineComponents.add(name);
2792
+ warn(`Inline component "${name}" calls a React hook but was left in the page: ${reason}. Move it and everything it uses into a client component manually.`, currentFile);
2793
+ }
2794
+ const moduleSource = plan.moved.length === 0 ? "" : [
2795
+ ...plan.moduleImports,
2796
+ ...plan.moduleHelpers,
2797
+ ...[...plan.moved, ...plan.copied].sort((a, b) => a - b).map((index) => declarations[index].source)
2798
+ ].join("\n\n");
2799
+ if (plan.moved.length > 0 && (copied.size >= MAX_COMPONENT_FILES || Buffer.byteLength(moduleSource) > MAX_FILE_BYTES || copiedBytes + Buffer.byteLength(moduleSource) > MAX_COMPONENT_BYTES)) {
2800
+ warn(`Inline component "${plan.movedNames[0]}" exceeded the component migration budget; source was preserved.`, currentFile);
2801
+ } else if (plan.moved.length > 0) {
2802
+ const path = `${destinationRoot}/inline-${hash(`${relative2(root, currentFile)}:components`)}.jsx`;
2803
+ const inlineSource = `${resolveInlineBuiltinReferences(moduleSource, plan.moduleNames)}
2804
+ `;
2805
+ copied.set(path, { path, content: `'use client';
2806
+ ${implicitReactImports(sourceFile(inlineSource, "inline.jsx"))}
2807
+ ${inlineSource}` });
2808
+ copiedBytes += Buffer.byteLength(inlineSource);
2809
+ const movedIndexes = new Set(plan.moved);
2810
+ for (const index of plan.moved) edits.push({ start: declarations[index].start, end: declarations[index].end, value: "" });
2811
+ for (const name of plan.registryNames) {
2812
+ const registered = register(path, name);
2813
+ aliases.set(name, registered);
2814
+ moduleImports.push(`import { ${name} } from ${JSON.stringify(portableSpecifier(`./${relative2(destinationRoot, path).replace(/\\/g, "/")}`))};`);
2815
+ }
2816
+ if (plan.pageImportNames.length > 0) {
2817
+ realPageImports.push(`import { ${plan.pageImportNames.join(", ")} } from ${JSON.stringify(portableSpecifier(`@/${path.replace(/^src\//, "").replace(/\\/g, "/")}`))};`);
2818
+ }
2819
+ for (const entry of [...sharedImportEdits]) {
2820
+ const locals = [...sourceFile(content.slice(entry.start, entry.end), "shared.tsx").statements].flatMap((statement) => ts2.isImportDeclaration(statement) ? imports(statement).map((binding) => binding.local) : []);
2821
+ if (locals.length === 0 || locals.some((local) => plan.pageReferences.has(local))) continue;
2822
+ edits.push(entry);
2823
+ sharedImportEdits.splice(sharedImportEdits.indexOf(entry), 1);
2824
+ }
2825
+ for (let index = declarations.length - 1; index >= 0; index -= 1) {
2826
+ if (movedIndexes.has(index)) declarations.splice(index, 1);
2827
+ }
2828
+ }
2829
+ }
2119
2830
  if (droppedMdxDataBindings.size > 0) {
2120
2831
  for (const node of esmNodes) {
2121
2832
  let stripDroppedSpreads2 = function(inner) {
2122
- if (ts.isSpreadElement(inner) && ts.isIdentifier(inner.expression) && droppedMdxDataBindings.has(inner.expression.text)) {
2833
+ if (ts2.isSpreadElement(inner) && ts2.isIdentifier(inner.expression) && droppedMdxDataBindings.has(inner.expression.text)) {
2123
2834
  const start = nodeStart + inner.getStart(ast);
2124
2835
  let end = nodeStart + inner.end;
2125
2836
  const following = nodeText.slice(inner.end).match(/^\s*,/);
@@ -2127,7 +2838,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
2127
2838
  edits.push({ start, end, value: "" });
2128
2839
  return;
2129
2840
  }
2130
- ts.forEachChild(inner, stripDroppedSpreads2);
2841
+ ts2.forEachChild(inner, stripDroppedSpreads2);
2131
2842
  };
2132
2843
  var stripDroppedSpreads = stripDroppedSpreads2;
2133
2844
  if (node.value === void 0 || node.position?.start.offset === void 0) continue;
@@ -2161,7 +2872,7 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
2161
2872
  }
2162
2873
  });
2163
2874
  const statefulDeclarationNames = new Set(
2164
- declarations.filter(({ source }) => /\bon[A-Z]\w*\s*=|\buse[A-Z]\w*\s*\(/.test(source)).map(({ source }) => source.match(/^export const (\w+)/)?.[1]).filter((name) => !!name)
2875
+ declarations.filter(({ source }) => /\bon[A-Z]\w*\s*=|\buse[A-Z]\w*\s*\(/.test(source)).map(({ source }) => source.match(/^export const (\w+)/)?.[1]).filter((name) => !!name && !refusedInlineComponents.has(name))
2165
2876
  );
2166
2877
  const extracted = [];
2167
2878
  for (const candidate of tree.children ?? []) {
@@ -2180,12 +2891,12 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
2180
2891
  continue;
2181
2892
  }
2182
2893
  const jsx = content.slice(node.position.start.offset, node.position.end.offset);
2183
- const result = ts.transpileModule(`export default function Inline() { return (${jsx}); }`, {
2894
+ const result = ts2.transpileModule(`export default function Inline() { return (${jsx}); }`, {
2184
2895
  fileName: "inline.jsx",
2185
- compilerOptions: { jsx: ts.JsxEmit.Preserve },
2896
+ compilerOptions: { jsx: ts2.JsxEmit.Preserve },
2186
2897
  reportDiagnostics: true
2187
2898
  });
2188
- if (result.diagnostics?.some((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error)) {
2899
+ if (result.diagnostics?.some((diagnostic) => diagnostic.category === ts2.DiagnosticCategory.Error)) {
2189
2900
  warn("Interactive MDX could not be safely extracted as JSX; source was preserved.", currentFile);
2190
2901
  continue;
2191
2902
  }
@@ -2193,15 +2904,15 @@ function createComponentMigrator(siteRoot, confinementRoot, warnings, sourceIden
2193
2904
  }
2194
2905
  if (extracted.length && declarations.length) {
2195
2906
  let bind2 = function(name) {
2196
- if (ts.isIdentifier(name)) declared.add(name.text);
2197
- else for (const element of name.elements) if (ts.isBindingElement(element)) bind2(element.name);
2907
+ if (ts2.isIdentifier(name)) declared.add(name.text);
2908
+ else for (const element of name.elements) if (ts2.isBindingElement(element)) bind2(element.name);
2198
2909
  };
2199
2910
  var bind = bind2;
2200
2911
  const declared = /* @__PURE__ */ new Set();
2201
2912
  for (const declaration of declarations) {
2202
2913
  for (const statement of sourceFile(declaration.source, "declaration.tsx").statements) {
2203
- if ((ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name) declared.add(statement.name.text);
2204
- if (ts.isVariableStatement(statement)) for (const variable of statement.declarationList.declarations) bind2(variable.name);
2914
+ if ((ts2.isFunctionDeclaration(statement) || ts2.isClassDeclaration(statement)) && statement.name) declared.add(statement.name.text);
2915
+ if (ts2.isVariableStatement(statement)) for (const variable of statement.declarationList.declarations) bind2(variable.name);
2205
2916
  }
2206
2917
  }
2207
2918
  const hasSharedDeclarations = hasExpressionReference(declared, {
@@ -2362,22 +3073,22 @@ function mergeComponentRegistry(existing, incoming) {
2362
3073
  const name = `MigratedRegistry${fingerprint}`;
2363
3074
  const registryPath = `./migrated-components-${fingerprint}`;
2364
3075
  const source = sourceFile(existing, "custom-components.tsx");
2365
- const alreadyImported = source.statements.some((statement) => ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier) && statement.moduleSpecifier.text === registryPath);
3076
+ const alreadyImported = source.statements.some((statement) => ts2.isImportDeclaration(statement) && ts2.isStringLiteral(statement.moduleSpecifier) && statement.moduleSpecifier.text === registryPath);
2366
3077
  let initializer;
2367
3078
  for (const statement of source.statements) {
2368
- if (!ts.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) continue;
3079
+ if (!ts2.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts2.SyntaxKind.ExportKeyword)) continue;
2369
3080
  for (const declaration of statement.declarationList.declarations) {
2370
- if (ts.isIdentifier(declaration.name) && declaration.name.text === "customComponents") initializer = declaration.initializer;
3081
+ if (ts2.isIdentifier(declaration.name) && declaration.name.text === "customComponents") initializer = declaration.initializer;
2371
3082
  }
2372
3083
  }
2373
- while (initializer && (ts.isAsExpression(initializer) || ts.isSatisfiesExpression(initializer) || ts.isParenthesizedExpression(initializer))) initializer = initializer.expression;
2374
- if (!initializer || !ts.isObjectLiteralExpression(initializer)) {
3084
+ while (initializer && (ts2.isAsExpression(initializer) || ts2.isSatisfiesExpression(initializer) || ts2.isParenthesizedExpression(initializer))) initializer = initializer.expression;
3085
+ if (!initializer || !ts2.isObjectLiteralExpression(initializer)) {
2375
3086
  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.");
2376
3087
  }
2377
3088
  const content = alreadyImported ? existing : applyReplacements(existing, [
2378
3089
  {
2379
- start: source.statements.filter((statement) => ts.isExpressionStatement(statement) && ts.isStringLiteral(statement.expression)).at(-1)?.end ?? 0,
2380
- end: source.statements.filter((statement) => ts.isExpressionStatement(statement) && ts.isStringLiteral(statement.expression)).at(-1)?.end ?? 0,
3090
+ start: source.statements.filter((statement) => ts2.isExpressionStatement(statement) && ts2.isStringLiteral(statement.expression)).at(-1)?.end ?? 0,
3091
+ end: source.statements.filter((statement) => ts2.isExpressionStatement(statement) && ts2.isStringLiteral(statement.expression)).at(-1)?.end ?? 0,
2381
3092
  value: `
2382
3093
  import { customComponents as ${name} } from ${JSON.stringify(registryPath)}
2383
3094
  `
@@ -5773,18 +6484,18 @@ function interpolateSnippet(snippet, attributes, children) {
5773
6484
  }).join("\n");
5774
6485
  }
5775
6486
  function snippetComponentBody(source, componentName) {
5776
- const parsed = ts2.createSourceFile("snippet.tsx", source, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
6487
+ const parsed = ts3.createSourceFile("snippet.tsx", source, ts3.ScriptTarget.Latest, true, ts3.ScriptKind.TSX);
5777
6488
  for (const statement of parsed.statements) {
5778
- if (!ts2.isVariableStatement(statement)) continue;
6489
+ if (!ts3.isVariableStatement(statement)) continue;
5779
6490
  for (const declaration of statement.declarationList.declarations) {
5780
- if (!ts2.isIdentifier(declaration.name) || declaration.name.text !== componentName) continue;
6491
+ if (!ts3.isIdentifier(declaration.name) || declaration.name.text !== componentName) continue;
5781
6492
  const initializer = declaration.initializer;
5782
- if (!initializer || !ts2.isArrowFunction(initializer)) continue;
5783
- const returned = ts2.isBlock(initializer.body) ? initializer.body.statements.find(ts2.isReturnStatement)?.expression : initializer.body;
6493
+ if (!initializer || !ts3.isArrowFunction(initializer)) continue;
6494
+ const returned = ts3.isBlock(initializer.body) ? initializer.body.statements.find(ts3.isReturnStatement)?.expression : initializer.body;
5784
6495
  if (!returned) continue;
5785
6496
  let expression = returned;
5786
- while (ts2.isParenthesizedExpression(expression)) expression = expression.expression;
5787
- if (ts2.isJsxElement(expression) || ts2.isJsxSelfClosingElement(expression) || ts2.isJsxFragment(expression)) {
6497
+ while (ts3.isParenthesizedExpression(expression)) expression = expression.expression;
6498
+ if (ts3.isJsxElement(expression) || ts3.isJsxSelfClosingElement(expression) || ts3.isJsxFragment(expression)) {
5788
6499
  return expression.getText(parsed);
5789
6500
  }
5790
6501
  }
@@ -5792,30 +6503,31 @@ function snippetComponentBody(source, componentName) {
5792
6503
  return source;
5793
6504
  }
5794
6505
  function statefulSnippetDeclaration(source, componentName) {
5795
- const parsed = ts2.createSourceFile("snippet.tsx", source, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
5796
- if (parsed.statements.length !== 1) return null;
5797
- const statement = parsed.statements[0];
5798
- if (!ts2.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts2.SyntaxKind.ExportKeyword) || statement.declarationList.declarations.length !== 1) return null;
6506
+ const parsed = ts3.createSourceFile("snippet.tsx", source, ts3.ScriptTarget.Latest, true, ts3.ScriptKind.TSX);
6507
+ const isEsm = (statement2) => ts3.isImportDeclaration(statement2) || (ts3.isVariableStatement(statement2) || ts3.isFunctionDeclaration(statement2) || ts3.isClassDeclaration(statement2)) && !!ts3.getModifiers(statement2)?.some((modifier) => modifier.kind === ts3.SyntaxKind.ExportKeyword);
6508
+ if (parsed.statements.length === 0 || !parsed.statements.every(isEsm)) return null;
6509
+ const statement = parsed.statements.find((candidate) => ts3.isVariableStatement(candidate) && candidate.declarationList.declarations.length === 1 && ts3.isIdentifier(candidate.declarationList.declarations[0].name) && candidate.declarationList.declarations[0].name.text === componentName);
6510
+ if (!statement || !ts3.isVariableStatement(statement)) return null;
5799
6511
  const declaration = statement.declarationList.declarations[0];
5800
- if (!ts2.isIdentifier(declaration.name) || declaration.name.text !== componentName || !declaration.initializer || !ts2.isArrowFunction(declaration.initializer) || !ts2.isBlock(declaration.initializer.body)) return null;
6512
+ if (!declaration.initializer || !ts3.isArrowFunction(declaration.initializer) || !ts3.isBlock(declaration.initializer.body)) return null;
5801
6513
  const body = declaration.initializer.body.statements;
5802
- if (body.length < 2 || !body.some(ts2.isReturnStatement)) return null;
6514
+ if (body.length < 2 || !body.some(ts3.isReturnStatement)) return null;
5803
6515
  return source.trim();
5804
6516
  }
5805
6517
  function staticNamedSnippetValues(source) {
5806
6518
  const values = /* @__PURE__ */ new Map();
5807
- const parsed = ts2.createSourceFile("snippet.tsx", source, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
6519
+ const parsed = ts3.createSourceFile("snippet.tsx", source, ts3.ScriptTarget.Latest, true, ts3.ScriptKind.TSX);
5808
6520
  for (const statement of parsed.statements) {
5809
- if (!ts2.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts2.SyntaxKind.ExportKeyword)) continue;
6521
+ if (!ts3.isVariableStatement(statement) || !statement.modifiers?.some((modifier) => modifier.kind === ts3.SyntaxKind.ExportKeyword)) continue;
5810
6522
  for (const declaration of statement.declarationList.declarations) {
5811
- if (!ts2.isIdentifier(declaration.name) || !declaration.initializer) continue;
6523
+ if (!ts3.isIdentifier(declaration.name) || !declaration.initializer) continue;
5812
6524
  const expression = declaration.initializer;
5813
- if (ts2.isStringLiteral(expression) || ts2.isNoSubstitutionTemplateLiteral(expression)) {
6525
+ if (ts3.isStringLiteral(expression) || ts3.isNoSubstitutionTemplateLiteral(expression)) {
5814
6526
  values.set(declaration.name.text, JSON.stringify(expression.text));
5815
- } else if (ts2.isNumericLiteral(expression)) {
6527
+ } else if (ts3.isNumericLiteral(expression)) {
5816
6528
  values.set(declaration.name.text, expression.text);
5817
- } else if (expression.kind === ts2.SyntaxKind.TrueKeyword || expression.kind === ts2.SyntaxKind.FalseKeyword) {
5818
- values.set(declaration.name.text, expression.kind === ts2.SyntaxKind.TrueKeyword ? "true" : "false");
6529
+ } else if (expression.kind === ts3.SyntaxKind.TrueKeyword || expression.kind === ts3.SyntaxKind.FalseKeyword) {
6530
+ values.set(declaration.name.text, expression.kind === ts3.SyntaxKind.TrueKeyword ? "true" : "false");
5819
6531
  }
5820
6532
  }
5821
6533
  }
@@ -6231,8 +6943,17 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
6231
6943
  result = result.replace(SNIPPET_TAG_PATTERN, (_tag, doubleQuoted, singleQuoted) => {
6232
6944
  const filePath = doubleQuoted ?? singleQuoted;
6233
6945
  try {
6234
- const candidate = resolveWithin(siteRoot, `snippets/${filePath}`);
6235
- if (!existsSync5(candidate) || !lstatSync5(candidate).isFile()) throw new Error("file not found");
6946
+ const candidate = [
6947
+ () => resolveWithin(siteRoot, `snippets/${filePath}`),
6948
+ () => resolveSnippetPath(filePath, currentFile, repositoryRoot, siteRoot)
6949
+ ].map((resolveCandidate) => {
6950
+ try {
6951
+ return resolveCandidate();
6952
+ } catch {
6953
+ return void 0;
6954
+ }
6955
+ }).find((path) => path !== void 0 && existsSync5(path) && lstatSync5(path).isFile());
6956
+ if (!candidate) throw new Error("file not found");
6236
6957
  return inlineMdxSnippets(
6237
6958
  withoutFrontmatter(readFileSync5(candidate, "utf8")),
6238
6959
  candidate,
@@ -6254,7 +6975,7 @@ function inlineMdxSnippets(raw, currentFile, repositoryRoot, warnings, depth = 0
6254
6975
  if (preservedDeclarations.size > 0) {
6255
6976
  const frontmatter = result.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/);
6256
6977
  const prefix = frontmatter?.[0] ?? "";
6257
- result = `${prefix}${[...preservedDeclarations.values()].join("\n\n")}
6978
+ result = `${prefix}${[...new Set(preservedDeclarations.values())].join("\n\n")}
6258
6979
 
6259
6980
  ${result.slice(prefix.length)}`;
6260
6981
  }
@@ -6658,9 +7379,9 @@ function migrateRepository(options) {
6658
7379
  });
6659
7380
  continue;
6660
7381
  }
6661
- const declaredNames = functionDeclaredNames(page.body);
6662
- if (hasAnyFunctionValuedProp(page.body, declaredNames)) {
6663
- if (propsTargetExtractedClientComponent(page.body, declaredNames)) {
7382
+ const declaredNames2 = functionDeclaredNames(page.body);
7383
+ if (hasAnyFunctionValuedProp(page.body, declaredNames2)) {
7384
+ if (propsTargetExtractedClientComponent(page.body, declaredNames2)) {
6664
7385
  skipped++;
6665
7386
  warnings.push({
6666
7387
  code: "skipped-file",
@@ -7463,6 +8184,7 @@ var PORTABLE_MDX_COMPONENTS = /* @__PURE__ */ new Set([
7463
8184
  "Card",
7464
8185
  "CardGroup",
7465
8186
  "Check",
8187
+ "CodeBlock",
7466
8188
  "CodeGroup",
7467
8189
  "Color",
7468
8190
  "Column",
@@ -7473,6 +8195,7 @@ var PORTABLE_MDX_COMPONENTS = /* @__PURE__ */ new Set([
7473
8195
  "Expandable",
7474
8196
  "Agent",
7475
8197
  "AgentPrompt",
8198
+ "Banner",
7476
8199
  "BannerPreview",
7477
8200
  "Embed",
7478
8201
  "File",
@@ -7489,6 +8212,8 @@ var PORTABLE_MDX_COMPONENTS = /* @__PURE__ */ new Set([
7489
8212
  "InlineResponseExample",
7490
8213
  "Latex",
7491
8214
  "LegacyView",
8215
+ "LiteYouTubeEmbed",
8216
+ "MDX",
7492
8217
  "Mermaid",
7493
8218
  "Note",
7494
8219
  "Panel",
@@ -7512,9 +8237,11 @@ var PORTABLE_MDX_COMPONENTS = /* @__PURE__ */ new Set([
7512
8237
  "Tooltip",
7513
8238
  "Tree",
7514
8239
  "Update",
8240
+ "Video",
7515
8241
  "View",
7516
8242
  "Visibility",
7517
- "Warning"
8243
+ "Warning",
8244
+ "YouTube"
7518
8245
  ]);
7519
8246
  var LOCALE_CODES = /* @__PURE__ */ new Set([
7520
8247
  "ar",