@owomark/processor 0.1.5 → 0.1.6

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
@@ -1,15 +1,15 @@
1
1
  // src/processor/index.ts
2
- import { unified } from "unified";
3
- import remarkParse from "remark-parse";
4
- import remarkGfm from "remark-gfm";
5
- import remarkMath from "remark-math";
6
- import remarkMdx from "remark-mdx";
2
+ import { unified as unified2 } from "unified";
3
+ import remarkParse2 from "remark-parse";
4
+ import remarkGfm2 from "remark-gfm";
5
+ import remarkMath2 from "remark-math";
6
+ import remarkMdx2 from "remark-mdx";
7
7
  import remarkRehype from "remark-rehype";
8
8
  import rehypeKatex from "rehype-katex";
9
9
  import rehypeSlug from "rehype-slug";
10
10
  import rehypePrettyCode from "rehype-pretty-code";
11
11
  import rehypeStringify from "rehype-stringify";
12
- import remarkDirective from "remark-directive";
12
+ import remarkDirective2 from "remark-directive";
13
13
 
14
14
  // src/processor/rehype-math-display-fix.ts
15
15
  function rehypeMathDisplayFix() {
@@ -1343,72 +1343,276 @@ function markdownSandboxHandler(_state, node) {
1343
1343
  };
1344
1344
  }
1345
1345
 
1346
+ // src/processor/remark-mdx-source-lines.ts
1347
+ function setMdxAttribute(node, name, value) {
1348
+ const attributes = Array.isArray(node.attributes) ? node.attributes : [];
1349
+ const existing = attributes.findIndex(
1350
+ (attribute) => attribute?.type === "mdxJsxAttribute" && attribute.name === name
1351
+ );
1352
+ const nextAttribute = {
1353
+ type: "mdxJsxAttribute",
1354
+ name,
1355
+ value
1356
+ };
1357
+ if (existing >= 0) {
1358
+ attributes[existing] = nextAttribute;
1359
+ } else {
1360
+ attributes.push(nextAttribute);
1361
+ }
1362
+ node.attributes = attributes;
1363
+ }
1364
+ function remapLine(line, sourceMap) {
1365
+ if (typeof line !== "number" || !sourceMap?.segments.length) return line;
1366
+ let delta = 0;
1367
+ for (const segment of sourceMap.segments) {
1368
+ if (line < segment.normalizedStartLine) {
1369
+ break;
1370
+ }
1371
+ if (line <= segment.normalizedEndLine) {
1372
+ if (line === segment.normalizedStartLine) return segment.sourceStartLine;
1373
+ if (line === segment.normalizedEndLine) return segment.sourceEndLine;
1374
+ return segment.sourceStartLine + (line - segment.normalizedStartLine - 1);
1375
+ }
1376
+ delta += segment.normalizedEndLine - segment.normalizedStartLine + 1 - (segment.sourceEndLine - segment.sourceStartLine + 1);
1377
+ }
1378
+ return line - delta;
1379
+ }
1380
+ function stampMdxJsxNode(node, sourceMap) {
1381
+ const startLine = remapLine(node.position?.start?.line, sourceMap);
1382
+ if (!startLine) return;
1383
+ const endLine = remapLine(node.position?.end?.line, sourceMap) ?? startLine;
1384
+ setMdxAttribute(node, "data-source-line-start", String(startLine));
1385
+ setMdxAttribute(node, "data-source-line-end", String(endLine));
1386
+ setMdxAttribute(node, "data-block-id", `L${startLine}-${endLine}`);
1387
+ }
1388
+ function walk3(node, sourceMap) {
1389
+ if (!node || typeof node !== "object") return;
1390
+ if (node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") {
1391
+ stampMdxJsxNode(node, sourceMap);
1392
+ }
1393
+ if (Array.isArray(node.children)) {
1394
+ for (const child of node.children) walk3(child, sourceMap);
1395
+ }
1396
+ }
1397
+ function remarkMdxSourceLines(options) {
1398
+ return (tree) => {
1399
+ walk3(tree, options?.sourceMap);
1400
+ };
1401
+ }
1402
+
1403
+ // src/processor/rehype-source-lines.ts
1404
+ var LEAF_TAGS = /* @__PURE__ */ new Set([
1405
+ "p",
1406
+ "h1",
1407
+ "h2",
1408
+ "h3",
1409
+ "h4",
1410
+ "h5",
1411
+ "h6",
1412
+ "pre",
1413
+ "table",
1414
+ "hr",
1415
+ "img"
1416
+ ]);
1417
+ var CONTAINER_TAGS = /* @__PURE__ */ new Set([
1418
+ "ul",
1419
+ "ol",
1420
+ "li",
1421
+ "blockquote",
1422
+ "div",
1423
+ "section",
1424
+ "details",
1425
+ "summary"
1426
+ ]);
1427
+ function liHasAnchorDescendant(node) {
1428
+ if (!Array.isArray(node.children)) return false;
1429
+ for (const child of node.children) {
1430
+ if (child.type !== "element") continue;
1431
+ if (LEAF_TAGS.has(child.tagName)) return true;
1432
+ if (child.tagName === "ul" || child.tagName === "ol") return true;
1433
+ if (CONTAINER_TAGS.has(child.tagName) && liHasAnchorDescendant(child)) return true;
1434
+ }
1435
+ return false;
1436
+ }
1437
+ function stampAnchorAttributes(node) {
1438
+ const sl = node.position.start.line;
1439
+ const el2 = node.position.end?.line ?? sl;
1440
+ node.properties = node.properties || {};
1441
+ node.properties["data-source-line-start"] = sl;
1442
+ node.properties["data-source-line-end"] = el2;
1443
+ node.properties["data-block-id"] = `L${sl}-${el2}`;
1444
+ }
1445
+ function walk4(node) {
1446
+ if (!node) return;
1447
+ if (node.type === "element" && node.position?.start?.line) {
1448
+ const tag = node.tagName;
1449
+ if (LEAF_TAGS.has(tag)) {
1450
+ stampAnchorAttributes(node);
1451
+ } else if (tag === "li" && !liHasAnchorDescendant(node)) {
1452
+ stampAnchorAttributes(node);
1453
+ } else if (tag === "div") {
1454
+ const classes = node.properties?.className || [];
1455
+ if (classes.includes("katex-display") || classes.includes("math-display")) {
1456
+ stampAnchorAttributes(node);
1457
+ return;
1458
+ }
1459
+ }
1460
+ }
1461
+ if (Array.isArray(node.children)) {
1462
+ for (const child of node.children) walk4(child);
1463
+ }
1464
+ }
1465
+ function rehypeSourceLines() {
1466
+ return (tree) => {
1467
+ walk4(tree);
1468
+ };
1469
+ }
1470
+
1471
+ // src/processor/plugin-registry.ts
1472
+ var BUILTIN_PLUGINS = /* @__PURE__ */ new Map([
1473
+ ["rehype-source-lines", rehypeSourceLines]
1474
+ ]);
1475
+ var GLOBAL_KEY = "__owomark_custom_plugins__";
1476
+ function getCustomPlugins() {
1477
+ const g = globalThis;
1478
+ if (!g[GLOBAL_KEY]) g[GLOBAL_KEY] = /* @__PURE__ */ new Map();
1479
+ return g[GLOBAL_KEY];
1480
+ }
1481
+ function registerPlugin(name, plugin) {
1482
+ getCustomPlugins().set(name, plugin);
1483
+ }
1484
+ function allBuiltinDescriptors(descriptors) {
1485
+ return descriptors.every((d) => BUILTIN_PLUGINS.has(d.name));
1486
+ }
1487
+ function resolveDescriptors(descriptors) {
1488
+ return descriptors.map((d) => {
1489
+ const plugin = BUILTIN_PLUGINS.get(d.name) ?? getCustomPlugins().get(d.name);
1490
+ if (!plugin) {
1491
+ throw new Error(`[owomark] Unknown plugin descriptor: "${d.name}". Register it first via registerPlugin().`);
1492
+ }
1493
+ if (d.options) return [plugin, d.options];
1494
+ return plugin;
1495
+ });
1496
+ }
1497
+
1346
1498
  // src/mdx-components/callout.ts
1347
1499
  import { createElement } from "react";
1500
+
1501
+ // src/mdx-components/dom-props.ts
1502
+ function mergeClassName(...values) {
1503
+ const merged = values.filter(Boolean).join(" ").trim();
1504
+ return merged || void 0;
1505
+ }
1506
+
1507
+ // src/mdx-components/callout.ts
1348
1508
  var ICONS = { info: "i", warn: "!", error: "\xD7" };
1349
- function Callout({ type = "info", children }) {
1509
+ function Callout({
1510
+ type = "info",
1511
+ children,
1512
+ className,
1513
+ ...domProps
1514
+ }) {
1350
1515
  return createElement(
1351
1516
  "div",
1352
- { className: `mdx-callout mdx-callout-${type}`, "data-callout-type": type },
1517
+ {
1518
+ ...domProps,
1519
+ className: mergeClassName("mdx-callout", `mdx-callout-${type}`, className),
1520
+ "data-callout-type": type
1521
+ },
1353
1522
  createElement("span", { className: "mdx-callout-icon" }, ICONS[type] || ICONS.info),
1354
1523
  createElement("div", { className: "mdx-callout-content" }, children)
1355
1524
  );
1356
1525
  }
1357
1526
 
1358
- // src/mdx-components/code-demo.ts
1527
+ // src/mdx-components/note.ts
1359
1528
  import { createElement as createElement2 } from "react";
1360
- function CodeDemo({ title, language = "text", code }) {
1529
+ function Note({
1530
+ title,
1531
+ children,
1532
+ className,
1533
+ ...domProps
1534
+ }) {
1361
1535
  return createElement2(
1536
+ "aside",
1537
+ {
1538
+ ...domProps,
1539
+ className: mergeClassName("mdx-note", className)
1540
+ },
1541
+ title ? createElement2("div", { className: "mdx-note-title" }, title) : null,
1542
+ createElement2("div", { className: "mdx-note-body" }, children)
1543
+ );
1544
+ }
1545
+
1546
+ // src/mdx-components/code-demo.ts
1547
+ import { createElement as createElement3 } from "react";
1548
+ function CodeDemo({
1549
+ title,
1550
+ language = "text",
1551
+ code,
1552
+ className,
1553
+ ...domProps
1554
+ }) {
1555
+ return createElement3(
1362
1556
  "figure",
1363
- { className: "mdx-code-demo", "data-code-demo": "" },
1364
- title && createElement2("figcaption", null, title),
1365
- createElement2(
1557
+ {
1558
+ ...domProps,
1559
+ className: mergeClassName("mdx-code-demo", className),
1560
+ "data-code-demo": ""
1561
+ },
1562
+ title && createElement3("figcaption", null, title),
1563
+ createElement3(
1366
1564
  "pre",
1367
1565
  { "data-language": language },
1368
- createElement2("code", null, code)
1566
+ createElement3("code", null, code)
1369
1567
  )
1370
1568
  );
1371
1569
  }
1372
1570
 
1373
1571
  // src/mdx-components/steps.ts
1374
- import { createElement as createElement3, Children } from "react";
1375
- function Steps({ children }) {
1572
+ import { createElement as createElement4, Children } from "react";
1573
+ function Steps({ children, className, ...domProps }) {
1376
1574
  const items = [];
1377
1575
  Children.forEach(children, (child) => {
1378
1576
  if (child && typeof child === "object" && "props" in child) {
1379
1577
  items.push(child);
1380
1578
  }
1381
1579
  });
1382
- return createElement3(
1580
+ return createElement4(
1383
1581
  "div",
1384
- { className: "mdx-steps" },
1582
+ {
1583
+ ...domProps,
1584
+ className: mergeClassName("mdx-steps", className)
1585
+ },
1385
1586
  items.map(
1386
- (item, i) => createElement3(
1587
+ (item, i) => createElement4(
1387
1588
  "div",
1388
1589
  { className: "mdx-steps-item", key: i },
1389
- createElement3(
1590
+ createElement4(
1390
1591
  "div",
1391
1592
  { className: "mdx-steps-indicator" },
1392
- createElement3("span", { className: "mdx-steps-number" }, String(i + 1)),
1393
- i < items.length - 1 && createElement3("div", { className: "mdx-steps-line" })
1593
+ createElement4("span", { className: "mdx-steps-number" }, String(i + 1)),
1594
+ i < items.length - 1 && createElement4("div", { className: "mdx-steps-line" })
1394
1595
  ),
1395
- createElement3("div", { className: "mdx-steps-content" }, item)
1596
+ createElement4("div", { className: "mdx-steps-content" }, item)
1396
1597
  )
1397
1598
  )
1398
1599
  );
1399
1600
  }
1400
- function Step({ title, children }) {
1401
- return createElement3(
1601
+ function Step({ title, children, className, ...domProps }) {
1602
+ return createElement4(
1402
1603
  "div",
1403
- { className: "mdx-step" },
1404
- title && createElement3("h4", { className: "mdx-step-title" }, title),
1405
- children && createElement3("div", { className: "mdx-step-body" }, children)
1604
+ {
1605
+ ...domProps,
1606
+ className: mergeClassName("mdx-step", className)
1607
+ },
1608
+ title && createElement4("h4", { className: "mdx-step-title" }, title),
1609
+ children && createElement4("div", { className: "mdx-step-body" }, children)
1406
1610
  );
1407
1611
  }
1408
1612
 
1409
1613
  // src/mdx-components/tabs.ts
1410
- import { createElement as createElement4, Children as Children2 } from "react";
1411
- function Tabs({ children }) {
1614
+ import { createElement as createElement5, Children as Children2 } from "react";
1615
+ function Tabs({ children, className, ...domProps }) {
1412
1616
  const tabs = [];
1413
1617
  Children2.forEach(children, (child) => {
1414
1618
  if (child && typeof child === "object" && "props" in child) {
@@ -1416,37 +1620,47 @@ function Tabs({ children }) {
1416
1620
  }
1417
1621
  });
1418
1622
  const groupId = `mdx-tabs-${Math.random().toString(36).slice(2, 8)}`;
1419
- return createElement4(
1623
+ return createElement5(
1420
1624
  "div",
1421
- { className: "mdx-tabs" },
1422
- createElement4(
1625
+ {
1626
+ ...domProps,
1627
+ className: mergeClassName("mdx-tabs", className)
1628
+ },
1629
+ createElement5(
1423
1630
  "div",
1424
1631
  { className: "mdx-tabs-list", role: "tablist" },
1425
1632
  tabs.map(
1426
- (tab, i) => createElement4(
1633
+ (tab, i) => createElement5(
1427
1634
  "label",
1428
1635
  { className: "mdx-tabs-trigger", key: i },
1429
- createElement4("input", {
1636
+ createElement5("input", {
1430
1637
  type: "radio",
1431
1638
  name: groupId,
1432
1639
  className: "mdx-tabs-radio",
1433
1640
  defaultChecked: i === 0
1434
1641
  }),
1435
- createElement4("span", null, tab.label)
1642
+ createElement5("span", null, tab.label)
1436
1643
  )
1437
1644
  )
1438
1645
  ),
1439
1646
  tabs.map(
1440
- (tab, i) => createElement4("div", { className: "mdx-tabs-panel", key: i }, tab.content)
1647
+ (tab, i) => createElement5("div", { className: "mdx-tabs-panel", key: i }, tab.content)
1441
1648
  )
1442
1649
  );
1443
1650
  }
1444
- function Tab({ label: _label, children }) {
1445
- return createElement4("div", null, children);
1651
+ function Tab({ label: _label, children, className, ...domProps }) {
1652
+ return createElement5(
1653
+ "div",
1654
+ {
1655
+ ...domProps,
1656
+ className
1657
+ },
1658
+ children
1659
+ );
1446
1660
  }
1447
1661
 
1448
1662
  // src/mdx-components/file-tree.ts
1449
- import { createElement as createElement5 } from "react";
1663
+ import { createElement as createElement6 } from "react";
1450
1664
  function parseFileTree(text) {
1451
1665
  const entries = [];
1452
1666
  for (const line of text.split("\n")) {
@@ -1460,22 +1674,25 @@ function parseFileTree(text) {
1460
1674
  }
1461
1675
  return entries;
1462
1676
  }
1463
- function FileTree({ children }) {
1677
+ function FileTree({ children, className, ...domProps }) {
1464
1678
  const text = extractText(children);
1465
1679
  const entries = parseFileTree(text);
1466
- return createElement5(
1680
+ return createElement6(
1467
1681
  "div",
1468
- { className: "mdx-file-tree" },
1682
+ {
1683
+ ...domProps,
1684
+ className: mergeClassName("mdx-file-tree", className)
1685
+ },
1469
1686
  entries.map(
1470
- (entry, i) => createElement5(
1687
+ (entry, i) => createElement6(
1471
1688
  "div",
1472
1689
  {
1473
1690
  className: `mdx-file-tree-entry ${entry.isDir ? "mdx-file-tree-dir" : "mdx-file-tree-file"}`,
1474
1691
  style: { paddingLeft: `${entry.depth * 1.25 + 0.5}rem` },
1475
1692
  key: i
1476
1693
  },
1477
- createElement5("span", { className: "mdx-file-tree-icon" }, entry.isDir ? "\u{1F4C1}" : "\u{1F4C4}"),
1478
- createElement5("span", { className: "mdx-file-tree-name" }, entry.name)
1694
+ createElement6("span", { className: "mdx-file-tree-icon" }, entry.isDir ? "\u{1F4C1}" : "\u{1F4C4}"),
1695
+ createElement6("span", { className: "mdx-file-tree-name" }, entry.name)
1479
1696
  )
1480
1697
  )
1481
1698
  );
@@ -1491,14 +1708,22 @@ function extractText(node) {
1491
1708
  }
1492
1709
 
1493
1710
  // src/mdx-components/kbd.ts
1494
- import { createElement as createElement6 } from "react";
1495
- function Kbd({ children }) {
1496
- return createElement6("kbd", { className: "mdx-kbd" }, children);
1711
+ import { createElement as createElement7 } from "react";
1712
+ function Kbd({ children, className, ...domProps }) {
1713
+ return createElement7(
1714
+ "kbd",
1715
+ {
1716
+ ...domProps,
1717
+ className: mergeClassName("mdx-kbd", className)
1718
+ },
1719
+ children
1720
+ );
1497
1721
  }
1498
1722
 
1499
1723
  // src/mdx-components/index.ts
1500
1724
  var DEFAULT_MDX_COMPONENTS = {
1501
1725
  Callout,
1726
+ Note,
1502
1727
  CodeDemo,
1503
1728
  Steps,
1504
1729
  Step,
@@ -1508,6 +1733,324 @@ var DEFAULT_MDX_COMPONENTS = {
1508
1733
  Kbd
1509
1734
  };
1510
1735
 
1736
+ // src/processor/mdx-syntax-analysis.ts
1737
+ import { unified } from "unified";
1738
+ import remarkParse from "remark-parse";
1739
+ import remarkGfm from "remark-gfm";
1740
+ import remarkMath from "remark-math";
1741
+ import remarkMdx from "remark-mdx";
1742
+ import remarkDirective from "remark-directive";
1743
+ var MDX_NODE_REASONS = /* @__PURE__ */ new Map([
1744
+ ["mdxjsEsm", "mdxjs-esm"],
1745
+ ["mdxJsxFlowElement", "mdx-jsx-flow"],
1746
+ ["mdxJsxTextElement", "mdx-jsx-text"],
1747
+ ["mdxFlowExpression", "mdx-flow-expression"],
1748
+ ["mdxTextExpression", "mdx-text-expression"]
1749
+ ]);
1750
+ var MASKED_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set([
1751
+ "code",
1752
+ "inlineCode",
1753
+ "math",
1754
+ "inlineMath"
1755
+ ]);
1756
+ function applyPlugin(proc, entry) {
1757
+ if (Array.isArray(entry)) {
1758
+ const [plugin, ...args] = entry;
1759
+ return proc.use(plugin, ...args);
1760
+ }
1761
+ return proc.use(entry);
1762
+ }
1763
+ function createParser(mode, options) {
1764
+ const enableMath = options?.enableMath !== false;
1765
+ const enableSideAnnotation = options?.enableSideAnnotation !== false;
1766
+ const remarkPlugins = [remarkGfm];
1767
+ if (enableMath) {
1768
+ remarkPlugins.push(remarkMath, remarkNormalizeStandaloneMath);
1769
+ }
1770
+ remarkPlugins.push(remarkDirective);
1771
+ if (mode === "production") {
1772
+ if (enableSideAnnotation) {
1773
+ remarkPlugins.push(remarkMicromarkSideAnnotation);
1774
+ }
1775
+ remarkPlugins.push(remarkMdx);
1776
+ }
1777
+ if (enableSideAnnotation) {
1778
+ remarkPlugins.push(remarkSideAnnotation);
1779
+ }
1780
+ if (options?.extraRemarkDescriptors?.length) {
1781
+ remarkPlugins.push(...resolveDescriptors(options.extraRemarkDescriptors));
1782
+ }
1783
+ if (options?.extraRemarkPlugins) {
1784
+ remarkPlugins.push(...options.extraRemarkPlugins);
1785
+ }
1786
+ let parser = unified().use(remarkParse);
1787
+ for (const plugin of remarkPlugins) {
1788
+ parser = applyPlugin(parser, plugin);
1789
+ }
1790
+ return parser;
1791
+ }
1792
+ function collectRangesByNodeTypes(root, nodeTypes) {
1793
+ const stack = [root];
1794
+ const ranges = [];
1795
+ while (stack.length > 0) {
1796
+ const node = stack.pop();
1797
+ if (!node) continue;
1798
+ const nodeType = typeof node.type === "string" ? node.type : null;
1799
+ if (nodeType && nodeTypes.has(nodeType)) {
1800
+ const start = node.position?.start?.offset;
1801
+ const end = node.position?.end?.offset;
1802
+ if (typeof start === "number" && typeof end === "number" && start >= 0 && end >= start) {
1803
+ ranges.push({ start, end });
1804
+ }
1805
+ }
1806
+ const children = Array.isArray(node.children) ? node.children : [];
1807
+ for (let index = children.length - 1; index >= 0; index -= 1) {
1808
+ stack.push(children[index]);
1809
+ }
1810
+ }
1811
+ ranges.sort((left, right) => left.start - right.start);
1812
+ return ranges;
1813
+ }
1814
+ function buildMaskedSource(source, root) {
1815
+ const ranges = collectRangesByNodeTypes(root, MASKED_LITERAL_NODE_TYPES);
1816
+ let cursor = 0;
1817
+ let result = "";
1818
+ for (const range of ranges) {
1819
+ if (range.start < cursor) continue;
1820
+ result += source.slice(cursor, range.start);
1821
+ result += source.slice(range.start, range.end).replace(/[^\s]/g, "x");
1822
+ cursor = range.end;
1823
+ }
1824
+ result += source.slice(cursor);
1825
+ return result;
1826
+ }
1827
+ function hasIndentedCodeIndent(line) {
1828
+ return line.startsWith(" ") || line.startsWith(" ");
1829
+ }
1830
+ function stripIndentedCodeIndent(line) {
1831
+ if (line.startsWith(" ")) return line.slice(4);
1832
+ if (line.startsWith(" ")) return line.slice(1);
1833
+ return line;
1834
+ }
1835
+ function parseMarkdownTree(source, options) {
1836
+ return createParser("preview", options).parse(source);
1837
+ }
1838
+ function getFence(lines) {
1839
+ const tildeRuns = lines.flatMap((line) => line.match(/~+/g) ?? []);
1840
+ let longestRun = 2;
1841
+ for (const run of tildeRuns) {
1842
+ if (run.length > longestRun) {
1843
+ longestRun = run.length;
1844
+ }
1845
+ }
1846
+ return "~".repeat(longestRun + 1);
1847
+ }
1848
+ function collectIndentedCodeRewrites(source, root) {
1849
+ const sourceLines = source.split("\n");
1850
+ const stack = [root];
1851
+ const rewrites = [];
1852
+ while (stack.length > 0) {
1853
+ const node = stack.pop();
1854
+ if (!node) continue;
1855
+ if (node.type === "code") {
1856
+ const startLine = node.position?.start?.line;
1857
+ const endLine = node.position?.end?.line;
1858
+ const startColumn = node.position?.start?.column;
1859
+ if (typeof startLine === "number" && typeof endLine === "number" && typeof startColumn === "number" && startLine >= 1 && endLine >= startLine) {
1860
+ const firstLine = sourceLines[startLine - 1] ?? "";
1861
+ const preservedPrefixColumns = Math.max(0, startColumn - 1);
1862
+ const prefix = firstLine.slice(0, preservedPrefixColumns);
1863
+ const firstContentLine = firstLine.slice(prefix.length);
1864
+ if (hasIndentedCodeIndent(firstContentLine)) {
1865
+ const originalLines = sourceLines.slice(startLine - 1, endLine);
1866
+ const normalizedLines = originalLines.map((line) => {
1867
+ const withoutPrefix = line.startsWith(prefix) ? line.slice(prefix.length) : line;
1868
+ return stripIndentedCodeIndent(withoutPrefix);
1869
+ });
1870
+ const fence = getFence(normalizedLines);
1871
+ rewrites.push({
1872
+ startLine,
1873
+ endLine,
1874
+ replacementLines: [
1875
+ `${prefix}${fence}`,
1876
+ ...normalizedLines.map((line) => `${prefix}${line}`),
1877
+ `${prefix}${fence}`
1878
+ ],
1879
+ preservedPrefixColumns,
1880
+ removedIndentColumns: 4
1881
+ });
1882
+ }
1883
+ }
1884
+ }
1885
+ const children = Array.isArray(node.children) ? node.children : [];
1886
+ for (let index = children.length - 1; index >= 0; index -= 1) {
1887
+ stack.push(children[index]);
1888
+ }
1889
+ }
1890
+ rewrites.sort((left, right) => left.startLine - right.startLine);
1891
+ return rewrites;
1892
+ }
1893
+ function buildCompilePlan(source, rewrites) {
1894
+ if (rewrites.length === 0) {
1895
+ return {
1896
+ compileSource: source,
1897
+ sourceMap: { segments: [] }
1898
+ };
1899
+ }
1900
+ const sourceLines = source.split("\n");
1901
+ const outputLines = [];
1902
+ const segments = [];
1903
+ let lineNumber = 1;
1904
+ let rewriteIndex = 0;
1905
+ while (lineNumber <= sourceLines.length) {
1906
+ const rewrite = rewrites[rewriteIndex];
1907
+ if (rewrite && rewrite.startLine === lineNumber) {
1908
+ const normalizedStartLine = outputLines.length + 1;
1909
+ outputLines.push(...rewrite.replacementLines);
1910
+ const normalizedEndLine = outputLines.length;
1911
+ segments.push({
1912
+ kind: "indented-code",
1913
+ normalizedStartLine,
1914
+ normalizedEndLine,
1915
+ sourceStartLine: rewrite.startLine,
1916
+ sourceEndLine: rewrite.endLine,
1917
+ preservedPrefixColumns: rewrite.preservedPrefixColumns,
1918
+ removedIndentColumns: rewrite.removedIndentColumns
1919
+ });
1920
+ lineNumber = rewrite.endLine + 1;
1921
+ rewriteIndex += 1;
1922
+ continue;
1923
+ }
1924
+ outputLines.push(sourceLines[lineNumber - 1]);
1925
+ lineNumber += 1;
1926
+ }
1927
+ const normalizedSource = outputLines.join("\n");
1928
+ return {
1929
+ compileSource: source.endsWith("\n") ? `${normalizedSource}
1930
+ ` : normalizedSource,
1931
+ sourceMap: { segments }
1932
+ };
1933
+ }
1934
+ function collectMdxSyntaxMetadata(root) {
1935
+ const componentNames = /* @__PURE__ */ new Set();
1936
+ const stack = [root];
1937
+ let reason;
1938
+ while (stack.length > 0) {
1939
+ const node = stack.pop();
1940
+ if (!node) continue;
1941
+ const nodeType = typeof node.type === "string" ? node.type : null;
1942
+ if (!reason && nodeType) {
1943
+ reason = MDX_NODE_REASONS.get(nodeType);
1944
+ }
1945
+ if ((nodeType === "mdxJsxFlowElement" || nodeType === "mdxJsxTextElement") && typeof node.name === "string" && /^[A-Z]/.test(node.name)) {
1946
+ componentNames.add(node.name);
1947
+ }
1948
+ const children = Array.isArray(node.children) ? node.children : [];
1949
+ for (let index = children.length - 1; index >= 0; index -= 1) {
1950
+ stack.push(children[index]);
1951
+ }
1952
+ }
1953
+ return {
1954
+ reason,
1955
+ componentNames: Array.from(componentNames)
1956
+ };
1957
+ }
1958
+ function inspectMdxSource(source, options) {
1959
+ try {
1960
+ const markdownTree = parseMarkdownTree(source, options);
1961
+ const rewrites = collectIndentedCodeRewrites(source, markdownTree);
1962
+ const { compileSource, sourceMap } = buildCompilePlan(source, rewrites);
1963
+ const mdxProbeSource = buildMaskedSource(compileSource, parseMarkdownTree(compileSource, options));
1964
+ const mdxTree = createParser("production", options).use(remarkMdx).parse(mdxProbeSource);
1965
+ const { reason, componentNames } = collectMdxSyntaxMetadata(mdxTree);
1966
+ return {
1967
+ hasMdxSyntax: reason !== void 0,
1968
+ reason,
1969
+ componentNames,
1970
+ compileSource,
1971
+ sourceMap
1972
+ };
1973
+ } catch {
1974
+ return {
1975
+ hasMdxSyntax: true,
1976
+ reason: "parse-failed-fallback",
1977
+ componentNames: [],
1978
+ compileSource: source,
1979
+ sourceMap: { segments: [] }
1980
+ };
1981
+ }
1982
+ }
1983
+ function analyzeMdxSyntax(source, options) {
1984
+ const inspection = inspectMdxSource(source, options);
1985
+ return {
1986
+ hasMdxSyntax: inspection.hasMdxSyntax,
1987
+ reason: inspection.reason,
1988
+ componentNames: inspection.componentNames
1989
+ };
1990
+ }
1991
+ function detectMdxSyntax(source, options) {
1992
+ const { hasMdxSyntax, reason } = analyzeMdxSyntax(source, options);
1993
+ return { hasMdxSyntax, reason };
1994
+ }
1995
+ function remapMdxLineNumber(line, sourceMap) {
1996
+ if (typeof line !== "number" || !sourceMap?.segments.length) return line;
1997
+ let delta = 0;
1998
+ for (const segment of sourceMap.segments) {
1999
+ if (line < segment.normalizedStartLine) {
2000
+ break;
2001
+ }
2002
+ if (line <= segment.normalizedEndLine) {
2003
+ if (line === segment.normalizedStartLine) return segment.sourceStartLine;
2004
+ if (line === segment.normalizedEndLine) return segment.sourceEndLine;
2005
+ return segment.sourceStartLine + (line - segment.normalizedStartLine - 1);
2006
+ }
2007
+ delta += segment.normalizedEndLine - segment.normalizedStartLine + 1 - (segment.sourceEndLine - segment.sourceStartLine + 1);
2008
+ }
2009
+ return line - delta;
2010
+ }
2011
+ function remapMdxColumnNumber(line, column, sourceMap) {
2012
+ if (typeof line !== "number" || typeof column !== "number" || !sourceMap?.segments.length) {
2013
+ return column;
2014
+ }
2015
+ for (const segment of sourceMap.segments) {
2016
+ if (line < segment.normalizedStartLine) break;
2017
+ if (line > segment.normalizedEndLine) continue;
2018
+ if (line === segment.normalizedStartLine || line === segment.normalizedEndLine) {
2019
+ return segment.preservedPrefixColumns + 1;
2020
+ }
2021
+ if (column <= segment.preservedPrefixColumns) {
2022
+ return column;
2023
+ }
2024
+ return column + segment.removedIndentColumns;
2025
+ }
2026
+ return column;
2027
+ }
2028
+ function remapMdxErrorDetails(error, sourceMap) {
2029
+ if (error && typeof error === "object") {
2030
+ const value = error;
2031
+ if (typeof value.line === "number") {
2032
+ return {
2033
+ message: value.message ?? String(error),
2034
+ line: remapMdxLineNumber(value.line, sourceMap),
2035
+ column: remapMdxColumnNumber(value.line, value.column, sourceMap)
2036
+ };
2037
+ }
2038
+ const text = value.message ?? String(error);
2039
+ const match = text.match(/\((\d+):(\d+)/);
2040
+ if (match) {
2041
+ const line = Number(match[1]);
2042
+ const column = Number(match[2]);
2043
+ return {
2044
+ message: text,
2045
+ line: remapMdxLineNumber(line, sourceMap),
2046
+ column: remapMdxColumnNumber(line, column, sourceMap)
2047
+ };
2048
+ }
2049
+ return { message: text };
2050
+ }
2051
+ return { message: String(error) };
2052
+ }
2053
+
1511
2054
  // src/processor/index.ts
1512
2055
  var DEFAULT_CODE_THEME = "vitesse-light";
1513
2056
  function buildRemarkPlugins(options) {
@@ -1515,19 +2058,19 @@ function buildRemarkPlugins(options) {
1515
2058
  const enableSideAnnotation = options.enableSideAnnotation !== false;
1516
2059
  const enableMarkdownSandbox = options.enableMarkdownSandbox !== false;
1517
2060
  const plugins = [
1518
- remarkParse,
1519
- remarkGfm
2061
+ remarkParse2,
2062
+ remarkGfm2
1520
2063
  ];
1521
2064
  if (enableMath) {
1522
- plugins.push(remarkMath);
2065
+ plugins.push(remarkMath2);
1523
2066
  plugins.push(remarkNormalizeStandaloneMath);
1524
2067
  }
1525
- plugins.push(remarkDirective);
2068
+ plugins.push(remarkDirective2);
1526
2069
  if (options.mode !== "preview") {
1527
2070
  if (enableSideAnnotation) {
1528
2071
  plugins.push(remarkMicromarkSideAnnotation);
1529
2072
  }
1530
- plugins.push(remarkMdx);
2073
+ plugins.push(remarkMdx2);
1531
2074
  }
1532
2075
  if (!options.preserveSoftLineBreaks) {
1533
2076
  plugins.push(remarkConvertSoftBreaksToHardBreaks);
@@ -1541,6 +2084,14 @@ function buildRemarkPlugins(options) {
1541
2084
  createProcessor: createOwoMarkProcessor
1542
2085
  }]);
1543
2086
  }
2087
+ if (options.sourceAnchors) {
2088
+ plugins.push([remarkMdxSourceLines, {
2089
+ sourceMap: options.mdxSourceMap
2090
+ }]);
2091
+ }
2092
+ if (options.extraRemarkDescriptors?.length) {
2093
+ plugins.push(...resolveDescriptors(options.extraRemarkDescriptors));
2094
+ }
1544
2095
  if (options.extraRemarkPlugins) {
1545
2096
  plugins.push(...options.extraRemarkPlugins);
1546
2097
  }
@@ -1554,10 +2105,19 @@ function buildRehypePlugins(options) {
1554
2105
  if (enableMath) {
1555
2106
  plugins.push(rehypeKatex, rehypeMathDisplayFix);
1556
2107
  }
1557
- plugins.push(rehypeSlug, [rehypePrettyCode, { theme }]);
2108
+ plugins.push(rehypeSlug);
2109
+ if (options.enableCodeHighlight !== false) {
2110
+ plugins.push([rehypePrettyCode, { theme }]);
2111
+ }
1558
2112
  if (enableSideAnnotation) {
1559
2113
  plugins.push(rehypeSideAnnotation);
1560
2114
  }
2115
+ if (options.sourceAnchors) {
2116
+ plugins.push(rehypeSourceLines);
2117
+ }
2118
+ if (options.extraRehypeDescriptors?.length) {
2119
+ plugins.push(...resolveDescriptors(options.extraRehypeDescriptors));
2120
+ }
1561
2121
  if (options.extraRehypePlugins) {
1562
2122
  plugins.push(...options.extraRehypePlugins);
1563
2123
  }
@@ -1577,9 +2137,9 @@ function createOwoMarkProcessor(options) {
1577
2137
  function createUnifiedProcessor(opts) {
1578
2138
  const remarkPlugins = buildRemarkPlugins(opts);
1579
2139
  const rehypePlugins = buildRehypePlugins(opts);
1580
- let proc = unified();
2140
+ let proc = unified2();
1581
2141
  for (const plugin of remarkPlugins) {
1582
- proc = applyPlugin(proc, plugin);
2142
+ proc = applyPlugin2(proc, plugin);
1583
2143
  }
1584
2144
  proc = proc.use(remarkRehype, {
1585
2145
  handlers: {
@@ -1587,7 +2147,7 @@ function createUnifiedProcessor(opts) {
1587
2147
  }
1588
2148
  });
1589
2149
  for (const plugin of rehypePlugins) {
1590
- proc = applyPlugin(proc, plugin);
2150
+ proc = applyPlugin2(proc, plugin);
1591
2151
  }
1592
2152
  proc = proc.use(rehypeStringify, { allowDangerousHtml: true });
1593
2153
  return {
@@ -1597,21 +2157,40 @@ function createUnifiedProcessor(opts) {
1597
2157
  }
1598
2158
  };
1599
2159
  }
1600
- var FENCED_CODE_RE = /^```[\s\S]*?^```/gm;
1601
- var INLINE_CODE_RE = /`[^`]+`/g;
1602
- var JSX_TAG_RE = /<([A-Z][A-Za-z0-9]*)/g;
1603
- function extractComponentNames(source) {
1604
- const stripped = source.replace(FENCED_CODE_RE, "").replace(INLINE_CODE_RE, "");
1605
- const names = /* @__PURE__ */ new Set();
1606
- let match;
1607
- while ((match = JSX_TAG_RE.exec(stripped)) !== null) {
1608
- names.add(match[1]);
1609
- }
1610
- return names;
1611
- }
1612
2160
  function createMdxProcessor(opts) {
1613
- const { remarkPlugins, rehypePlugins } = getOwoMarkPlugins({ ...opts, mode: "production" });
1614
2161
  const registeredComponents = { ...DEFAULT_MDX_COMPONENTS, ...opts.mdxComponents };
2162
+ const createMissingComponent = (componentName) => (props) => {
2163
+ const { children, ...restProps } = props;
2164
+ return _react.createElement("div", { "data-mdx-missing": componentName, ...restProps }, children);
2165
+ };
2166
+ function registerMissingComponentPath(componentMap, componentName) {
2167
+ const parts = componentName.split(".");
2168
+ let cursor = componentMap;
2169
+ let inserted = false;
2170
+ for (let index = 0; index < parts.length; index += 1) {
2171
+ const part = parts[index];
2172
+ const isLeaf = index === parts.length - 1;
2173
+ const existing = cursor[part];
2174
+ if (isLeaf) {
2175
+ if (existing === void 0) {
2176
+ cursor[part] = createMissingComponent(componentName);
2177
+ inserted = true;
2178
+ }
2179
+ return inserted;
2180
+ }
2181
+ if (existing == null) {
2182
+ cursor[part] = {};
2183
+ inserted = true;
2184
+ cursor = cursor[part];
2185
+ continue;
2186
+ }
2187
+ if (typeof existing === "function") {
2188
+ return inserted;
2189
+ }
2190
+ cursor = existing;
2191
+ }
2192
+ return inserted;
2193
+ }
1615
2194
  let _evaluate;
1616
2195
  let _renderToStaticMarkup;
1617
2196
  let _jsxRuntime;
@@ -1633,19 +2212,33 @@ function createMdxProcessor(opts) {
1633
2212
  return {
1634
2213
  async process(source) {
1635
2214
  await ensureImports();
1636
- const usedNames = extractComponentNames(source);
2215
+ const inspection = inspectMdxSource(source, {
2216
+ enableMath: opts.enableMath,
2217
+ enableSideAnnotation: opts.enableSideAnnotation,
2218
+ extraRemarkDescriptors: opts.extraRemarkDescriptors,
2219
+ extraRemarkPlugins: opts.extraRemarkPlugins
2220
+ });
2221
+ const { remarkPlugins, rehypePlugins } = getOwoMarkPlugins({
2222
+ ...opts,
2223
+ mode: "production",
2224
+ mdxSourceMap: inspection.sourceMap
2225
+ });
1637
2226
  const componentMap = { ...registeredComponents };
1638
- for (const name of usedNames) {
1639
- if (!(name in componentMap)) {
2227
+ for (const name of inspection.componentNames) {
2228
+ if (registerMissingComponentPath(componentMap, name)) {
1640
2229
  console.warn(`[owomark-mdx] Unregistered MDX component: <${name}>`);
1641
- componentMap[name] = (props) => _react.createElement("div", { "data-mdx-missing": name }, props.children);
1642
2230
  }
1643
2231
  }
1644
- const { default: Content } = await _evaluate(source, {
1645
- ..._jsxRuntime,
1646
- remarkPlugins,
1647
- rehypePlugins
1648
- });
2232
+ let Content;
2233
+ try {
2234
+ ({ default: Content } = await _evaluate(inspection.compileSource, {
2235
+ ..._jsxRuntime,
2236
+ remarkPlugins,
2237
+ rehypePlugins
2238
+ }));
2239
+ } catch (error) {
2240
+ throw remapMdxErrorDetails(error, inspection.sourceMap);
2241
+ }
1649
2242
  const html = _renderToStaticMarkup(
1650
2243
  _react.createElement(Content, { components: componentMap })
1651
2244
  );
@@ -1653,14 +2246,14 @@ function createMdxProcessor(opts) {
1653
2246
  }
1654
2247
  };
1655
2248
  }
1656
- function applyPlugin(proc, entry) {
2249
+ function applyPlugin2(proc, entry) {
1657
2250
  if (Array.isArray(entry)) {
1658
2251
  const [plugin, ...args] = entry;
1659
2252
  return proc.use(plugin, ...args);
1660
2253
  }
1661
2254
  return proc.use(entry);
1662
2255
  }
1663
- var MDX_MANAGED_REMARK_PLUGINS = /* @__PURE__ */ new Set([remarkParse, remarkMdx]);
2256
+ var MDX_MANAGED_REMARK_PLUGINS = /* @__PURE__ */ new Set([remarkParse2, remarkMdx2]);
1664
2257
  function getOwoMarkPlugins(options) {
1665
2258
  const opts = {
1666
2259
  mode: "production",
@@ -1679,15 +2272,24 @@ export {
1679
2272
  DEFAULT_MDX_COMPONENTS,
1680
2273
  FileTree,
1681
2274
  Kbd,
2275
+ Note,
1682
2276
  Step,
1683
2277
  Steps,
1684
2278
  Tab,
1685
2279
  Tabs,
2280
+ allBuiltinDescriptors,
2281
+ analyzeMdxSyntax,
1686
2282
  createOwoMarkProcessor,
2283
+ detectMdxSyntax,
1687
2284
  getOwoMarkPlugins,
2285
+ inspectMdxSource,
2286
+ registerPlugin,
1688
2287
  rehypeMathDisplayFix,
1689
2288
  rehypeSideAnnotation,
2289
+ rehypeSourceLines,
2290
+ remapMdxErrorDetails,
1690
2291
  remarkConvertSoftBreaksToHardBreaks,
1691
2292
  remarkMicromarkSideAnnotation,
1692
- remarkSideAnnotation
2293
+ remarkSideAnnotation,
2294
+ resolveDescriptors
1693
2295
  };