@owomark/processor 0.1.5 → 0.1.7

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() {
@@ -30,7 +30,8 @@ function walk(node) {
30
30
  type: "element",
31
31
  tagName: "div",
32
32
  properties: { className: ["math-display-block"] },
33
- children: codeEl.children
33
+ children: codeEl.children,
34
+ position: child.position ?? codeEl.position
34
35
  };
35
36
  }
36
37
  }
@@ -140,43 +141,15 @@ function pushSplitTextNodes(target, textNode) {
140
141
  }
141
142
 
142
143
  // src/processor/remark-side-annotation.ts
143
- var STRUCTURAL_TYPES = {
144
- ":": "plain",
145
- "}": "brace",
146
- "{": "left-brace",
147
- "]": "bracket",
148
- "[": "left-bracket",
149
- "|": "line",
150
- "-": "dash",
151
- "->": "arrow",
152
- "=>": "fat-arrow",
153
- "~>": "wave-arrow"
154
- };
155
- var SEMANTIC_TYPES = {
156
- "!": "warning",
157
- "?": "question"
158
- };
159
- var COMPOUND_TYPES = {
160
- "}->": "brace-arrow",
161
- "}=>": "brace-fat-arrow",
162
- "]->": "bracket-arrow",
163
- "]=>": "bracket-fat-arrow",
164
- "|->": "line-arrow",
165
- "|=>": "line-fat-arrow",
166
- "}!": "brace-warning",
167
- "}?": "brace-question"
168
- };
169
- var TYPE_TABLE = {
170
- ...STRUCTURAL_TYPES,
171
- ...SEMANTIC_TYPES,
172
- ...COMPOUND_TYPES
173
- };
174
- var TYPE_SYMBOLS_SORTED = Object.keys(TYPE_TABLE).sort(
175
- (a, b) => b.length - a.length
176
- );
177
- var TYPE_BY_KEYWORD = Object.fromEntries(
178
- Object.entries(TYPE_TABLE).map(([symbol, keyword]) => [keyword, symbol])
179
- );
144
+ import {
145
+ SIDE_ANNOTATION_SYMBOL_BY_KEYWORD,
146
+ SIDE_ANNOTATION_TYPE_SYMBOLS_SORTED as TYPE_SYMBOLS_SORTED,
147
+ SIDE_ANNOTATION_TYPE_TABLE as TYPE_TABLE,
148
+ SIDE_NOTE_DEFINITION_RE as NOTE_DEF_RE,
149
+ SIDE_NOTE_REF_RE as NOTE_REF_RE
150
+ } from "@owomark/core/semantic/syntax";
151
+ var TYPE_BY_KEYWORD = SIDE_ANNOTATION_SYMBOL_BY_KEYWORD;
152
+ var TYPE_TABLE_LOOKUP = TYPE_TABLE;
180
153
  function makeSideAnnotationNode(opts) {
181
154
  const classNames = ["side-annotation", `side-type-${opts.sideType}`];
182
155
  if (opts.orphan) classNames.push("side-orphan");
@@ -205,8 +178,6 @@ var INLINE_ANNOTATION_RE = /(?:^|(?<=\s))\(>((?:[^ ()\\]|\\.)+?) ((?:[^)\\]|\\.)
205
178
  var CONTINUATION_RE = /(?:^|(?<=\s))\(>\+\)\s*$/m;
206
179
  var CONTINUATION_RE_GLOBAL = /(?:^|(?<=\s))\(>\+\)\s*$/gm;
207
180
  var ESCAPE_RE = /\(\\>/;
208
- var NOTE_DEF_RE = /^\[>([\w-]+)\]:\s*(?:\{type=([^}"]+|"[^"]*")\}\s*)?/;
209
- var NOTE_REF_RE = /^\[>([\w-]+)\]$/;
210
181
  function remarkSideAnnotation() {
211
182
  return (tree) => {
212
183
  const noteDefinitions = collectNoteDefinitions(tree);
@@ -228,7 +199,7 @@ function collectNoteDefinitions(tree) {
228
199
  let typeSymbol = ":";
229
200
  if (match[2]) {
230
201
  const raw = match[2].replace(/^"|"$/g, "");
231
- if (TYPE_TABLE[raw]) {
202
+ if (TYPE_TABLE_LOOKUP[raw]) {
232
203
  typeSymbol = raw;
233
204
  } else if (TYPE_BY_KEYWORD[raw]) {
234
205
  typeSymbol = TYPE_BY_KEYWORD[raw];
@@ -263,7 +234,7 @@ function collectNoteDefinitions(tree) {
263
234
  type: "sideNoteDefinition",
264
235
  identifier: id,
265
236
  sideTypeSymbol: typeSymbol,
266
- sideType: TYPE_TABLE[typeSymbol] || "plain",
237
+ sideType: TYPE_TABLE_LOOKUP[typeSymbol] || "plain",
267
238
  children: contentChildren
268
239
  });
269
240
  toRemove.push(i);
@@ -287,7 +258,7 @@ function processDirectiveContainers(tree, noteDefinitions) {
287
258
  const refMatch = NOTE_REF_RE.exec(label.trim());
288
259
  if (refMatch) {
289
260
  noteRef = refMatch[1];
290
- const def = noteDefinitions.get(noteRef);
261
+ const def = noteDefinitions.get(refMatch[1]);
291
262
  if (def) {
292
263
  sideType = def.sideType;
293
264
  sideTypeSymbol = def.sideTypeSymbol;
@@ -567,7 +538,7 @@ function parseInlineAnnotationText(inner) {
567
538
  if (spaceIdx < 0) return null;
568
539
  const typeCandidate = inner.slice(0, spaceIdx);
569
540
  if (!typeCandidate) return null;
570
- const sideType = TYPE_TABLE[typeCandidate];
541
+ const sideType = TYPE_TABLE_LOOKUP[typeCandidate];
571
542
  if (sideType) {
572
543
  const content2 = inner.slice(spaceIdx + 1).replace(/\\([)])/g, "$1").trim();
573
544
  if (!content2) return null;
@@ -699,6 +670,7 @@ function splitDirectiveLabelParagraph(paragraph) {
699
670
  }
700
671
 
701
672
  // src/processor/rehype-side-annotation.ts
673
+ import { SIDE_ANNOTATION_RENDERER_KEY_BY_TYPE } from "@owomark/core/semantic/syntax";
702
674
  var STROKE_WIDTH = "1.5";
703
675
  function el(tagName, properties, children = []) {
704
676
  return { type: "element", tagName, properties, children };
@@ -952,6 +924,7 @@ function visit(node) {
952
924
  function transform(node) {
953
925
  const properties = node.properties ?? {};
954
926
  const sideType = String(properties["data-side-type"] || "plain");
927
+ const rendererKey = SIDE_ANNOTATION_RENDERER_KEY_BY_TYPE[sideType] ?? sideType;
955
928
  const sideText = properties["data-side-text"] ? String(properties["data-side-text"]) : null;
956
929
  const isOrphan = properties["data-side-orphan"] != null;
957
930
  const mainContent = el("div", { class: "side-annotation-main" }, node.children);
@@ -959,7 +932,7 @@ function transform(node) {
959
932
  if (isOrphan) {
960
933
  asideChildren.push(SVG_GENERATORS["line"]());
961
934
  } else {
962
- const svgGen = SVG_GENERATORS[sideType];
935
+ const svgGen = SVG_GENERATORS[rendererKey];
963
936
  if (svgGen) {
964
937
  asideChildren.push(svgGen());
965
938
  }
@@ -997,7 +970,7 @@ function sideAnnotationSyntax() {
997
970
  }
998
971
  };
999
972
  }
1000
- function tokenizeSideAnnotation(effects, ok, nok) {
973
+ function tokenizeSideAnnotation(effects, ok2, nok) {
1001
974
  return start;
1002
975
  function start(code) {
1003
976
  if (code !== CODE_OPEN_PAREN) return nok(code);
@@ -1021,7 +994,7 @@ function tokenizeSideAnnotation(effects, ok, nok) {
1021
994
  if (code === CODE_CLOSE_PAREN) {
1022
995
  effects.consume(code);
1023
996
  effects.exit("sideAnnotationMarker");
1024
- return ok;
997
+ return ok2;
1025
998
  }
1026
999
  effects.consume(code);
1027
1000
  return content;
@@ -1060,6 +1033,37 @@ function remarkMicromarkSideAnnotation() {
1060
1033
  fromMarkdownExtensions.push(sideAnnotationFromMarkdown());
1061
1034
  }
1062
1035
 
1036
+ // src/processor/remark-code-block-metadata.ts
1037
+ function visit2(node, visitor) {
1038
+ visitor(node);
1039
+ if (!Array.isArray(node.children)) {
1040
+ return;
1041
+ }
1042
+ for (const child of node.children) {
1043
+ visit2(child, visitor);
1044
+ }
1045
+ }
1046
+ function remarkCodeBlockMetadata() {
1047
+ return (tree) => {
1048
+ visit2(tree, (node) => {
1049
+ if (node.type !== "code") {
1050
+ return;
1051
+ }
1052
+ const hProperties = node.data?.hProperties ?? {};
1053
+ const language = typeof node.lang === "string" && node.lang.trim() ? node.lang.trim() : null;
1054
+ const meta = typeof node.meta === "string" && node.meta.trim() ? node.meta.trim() : null;
1055
+ node.data = {
1056
+ ...node.data,
1057
+ hProperties: {
1058
+ ...hProperties,
1059
+ ...language ? { "data-language": language } : {},
1060
+ ...meta ? { "data-meta": meta } : {}
1061
+ }
1062
+ };
1063
+ });
1064
+ };
1065
+ }
1066
+
1063
1067
  // src/processor/remark-markdown-sandbox.ts
1064
1068
  var DEFAULT_OUTER_FENCE_TICKS = 4;
1065
1069
  var SANDBOX_ROOT_CLASS = "owo-markdown-sandbox";
@@ -1295,6 +1299,7 @@ async function transformChildren(node, sourceLines, options, sandboxCount) {
1295
1299
  const sandboxId = createSandboxId(codeNode.position?.start?.line, sandboxCount.value - 1);
1296
1300
  const nestedProcessor = options.createProcessor({
1297
1301
  ...options.processorOptions,
1302
+ canonicalDocument: void 0,
1298
1303
  enableMarkdownSandbox: false,
1299
1304
  enableSideAnnotation: meta.options.sideAnnotation ?? options.processorOptions.enableSideAnnotation,
1300
1305
  enableMath: meta.options.math ?? options.processorOptions.enableMath,
@@ -1343,72 +1348,1107 @@ function markdownSandboxHandler(_state, node) {
1343
1348
  };
1344
1349
  }
1345
1350
 
1351
+ // ../../node_modules/unist-util-visit/node_modules/unist-util-is/lib/index.js
1352
+ var convert = (
1353
+ /**
1354
+ * @type {(
1355
+ * (<Kind extends Node>(test: PredicateTest<Kind>) => AssertPredicate<Kind>) &
1356
+ * ((test?: Test) => AssertAnything)
1357
+ * )}
1358
+ */
1359
+ /**
1360
+ * @param {Test} [test]
1361
+ * @returns {AssertAnything}
1362
+ */
1363
+ (function(test) {
1364
+ if (test === void 0 || test === null) {
1365
+ return ok;
1366
+ }
1367
+ if (typeof test === "string") {
1368
+ return typeFactory(test);
1369
+ }
1370
+ if (typeof test === "object") {
1371
+ return Array.isArray(test) ? anyFactory(test) : propsFactory(test);
1372
+ }
1373
+ if (typeof test === "function") {
1374
+ return castFactory(test);
1375
+ }
1376
+ throw new Error("Expected function, string, or object as test");
1377
+ })
1378
+ );
1379
+ function anyFactory(tests) {
1380
+ const checks = [];
1381
+ let index = -1;
1382
+ while (++index < tests.length) {
1383
+ checks[index] = convert(tests[index]);
1384
+ }
1385
+ return castFactory(any);
1386
+ function any(...parameters) {
1387
+ let index2 = -1;
1388
+ while (++index2 < checks.length) {
1389
+ if (checks[index2].call(this, ...parameters)) return true;
1390
+ }
1391
+ return false;
1392
+ }
1393
+ }
1394
+ function propsFactory(check) {
1395
+ return castFactory(all);
1396
+ function all(node) {
1397
+ let key;
1398
+ for (key in check) {
1399
+ if (node[key] !== check[key]) return false;
1400
+ }
1401
+ return true;
1402
+ }
1403
+ }
1404
+ function typeFactory(check) {
1405
+ return castFactory(type);
1406
+ function type(node) {
1407
+ return node && node.type === check;
1408
+ }
1409
+ }
1410
+ function castFactory(check) {
1411
+ return assertion;
1412
+ function assertion(node, ...parameters) {
1413
+ return Boolean(
1414
+ node && typeof node === "object" && "type" in node && // @ts-expect-error: fine.
1415
+ Boolean(check.call(this, node, ...parameters))
1416
+ );
1417
+ }
1418
+ }
1419
+ function ok() {
1420
+ return true;
1421
+ }
1422
+
1423
+ // ../../node_modules/unist-util-visit/node_modules/unist-util-visit-parents/lib/color.js
1424
+ function color(d) {
1425
+ return "\x1B[33m" + d + "\x1B[39m";
1426
+ }
1427
+
1428
+ // ../../node_modules/unist-util-visit/node_modules/unist-util-visit-parents/lib/index.js
1429
+ var CONTINUE = true;
1430
+ var EXIT = false;
1431
+ var SKIP = "skip";
1432
+ var visitParents = (
1433
+ /**
1434
+ * @type {(
1435
+ * (<Tree extends Node, Check extends Test>(tree: Tree, test: Check, visitor: BuildVisitor<Tree, Check>, reverse?: boolean | null | undefined) => void) &
1436
+ * (<Tree extends Node>(tree: Tree, visitor: BuildVisitor<Tree>, reverse?: boolean | null | undefined) => void)
1437
+ * )}
1438
+ */
1439
+ /**
1440
+ * @param {Node} tree
1441
+ * @param {Test} test
1442
+ * @param {Visitor<Node>} visitor
1443
+ * @param {boolean | null | undefined} [reverse]
1444
+ * @returns {void}
1445
+ */
1446
+ (function(tree, test, visitor, reverse) {
1447
+ if (typeof test === "function" && typeof visitor !== "function") {
1448
+ reverse = visitor;
1449
+ visitor = test;
1450
+ test = null;
1451
+ }
1452
+ const is2 = convert(test);
1453
+ const step = reverse ? -1 : 1;
1454
+ factory(tree, void 0, [])();
1455
+ function factory(node, index, parents) {
1456
+ const value = node && typeof node === "object" ? node : {};
1457
+ if (typeof value.type === "string") {
1458
+ const name = (
1459
+ // `hast`
1460
+ typeof value.tagName === "string" ? value.tagName : (
1461
+ // `xast`
1462
+ typeof value.name === "string" ? value.name : void 0
1463
+ )
1464
+ );
1465
+ Object.defineProperty(visit4, "name", {
1466
+ value: "node (" + color(node.type + (name ? "<" + name + ">" : "")) + ")"
1467
+ });
1468
+ }
1469
+ return visit4;
1470
+ function visit4() {
1471
+ let result = [];
1472
+ let subresult;
1473
+ let offset;
1474
+ let grandparents;
1475
+ if (!test || is2(node, index, parents[parents.length - 1] || null)) {
1476
+ result = toResult(visitor(node, parents));
1477
+ if (result[0] === EXIT) {
1478
+ return result;
1479
+ }
1480
+ }
1481
+ if (node.children && result[0] !== SKIP) {
1482
+ offset = (reverse ? node.children.length : -1) + step;
1483
+ grandparents = parents.concat(node);
1484
+ while (offset > -1 && offset < node.children.length) {
1485
+ subresult = factory(node.children[offset], offset, grandparents)();
1486
+ if (subresult[0] === EXIT) {
1487
+ return subresult;
1488
+ }
1489
+ offset = typeof subresult[1] === "number" ? subresult[1] : offset + step;
1490
+ }
1491
+ }
1492
+ return result;
1493
+ }
1494
+ }
1495
+ })
1496
+ );
1497
+ function toResult(value) {
1498
+ if (Array.isArray(value)) {
1499
+ return value;
1500
+ }
1501
+ if (typeof value === "number") {
1502
+ return [CONTINUE, value];
1503
+ }
1504
+ return [value];
1505
+ }
1506
+
1507
+ // ../../node_modules/unist-util-visit/lib/index.js
1508
+ var visit3 = (
1509
+ /**
1510
+ * @type {(
1511
+ * (<Tree extends Node, Check extends Test>(tree: Tree, test: Check, visitor: BuildVisitor<Tree, Check>, reverse?: boolean | null | undefined) => void) &
1512
+ * (<Tree extends Node>(tree: Tree, visitor: BuildVisitor<Tree>, reverse?: boolean | null | undefined) => void)
1513
+ * )}
1514
+ */
1515
+ /**
1516
+ * @param {Node} tree
1517
+ * @param {Test} test
1518
+ * @param {Visitor} visitor
1519
+ * @param {boolean | null | undefined} [reverse]
1520
+ * @returns {void}
1521
+ */
1522
+ (function(tree, test, visitor, reverse) {
1523
+ if (typeof test === "function" && typeof visitor !== "function") {
1524
+ reverse = visitor;
1525
+ visitor = test;
1526
+ test = null;
1527
+ }
1528
+ visitParents(tree, test, overload, reverse);
1529
+ function overload(node, parents) {
1530
+ const parent = parents[parents.length - 1];
1531
+ return visitor(
1532
+ node,
1533
+ parent ? parent.children.indexOf(node) : null,
1534
+ parent
1535
+ );
1536
+ }
1537
+ })
1538
+ );
1539
+
1540
+ // src/processor/owo-component-registry.ts
1541
+ import {
1542
+ componentRegistry,
1543
+ getComponentDescriptorByDirective
1544
+ } from "@owomark/core/semantic/components";
1545
+ function toComponentRegistryEntry(descriptor) {
1546
+ return {
1547
+ directiveName: descriptor.directiveName,
1548
+ componentName: descriptor.componentName,
1549
+ kind: descriptor.componentKind,
1550
+ allowedAttrs: descriptor.allowedAttrs,
1551
+ requiredAttrs: descriptor.requiredAttrs,
1552
+ requiredParent: descriptor.requiredParent,
1553
+ allowedChildDirective: descriptor.allowedChildDirectives[0] ?? null,
1554
+ payloadStrategy: descriptor.payloadStrategy
1555
+ };
1556
+ }
1557
+ var entries = componentRegistry.list().map(toComponentRegistryEntry);
1558
+ var COMPONENT_REGISTRY = new Map(
1559
+ entries.map((e) => [e.directiveName, e])
1560
+ );
1561
+ function isKnownDirective(name) {
1562
+ return COMPONENT_REGISTRY.has(name);
1563
+ }
1564
+ function getComponentEntry(name) {
1565
+ const entry = COMPONENT_REGISTRY.get(name);
1566
+ if (entry) return entry;
1567
+ const descriptor = getComponentDescriptorByDirective(name);
1568
+ return descriptor ? toComponentRegistryEntry(descriptor) : void 0;
1569
+ }
1570
+
1571
+ // src/processor/owo-components-diagnostics.ts
1572
+ var SOURCE = "owo-components";
1573
+ function reportDisabledFlag(file, name, position) {
1574
+ file.message(
1575
+ `Component directive ":::${name}" requires enableComponents to be enabled`,
1576
+ { place: position, source: SOURCE }
1577
+ );
1578
+ }
1579
+ function reportUnknownComponent(file, name, position) {
1580
+ file.message(
1581
+ `Unknown component directive ":::${name}"`,
1582
+ { place: position, source: SOURCE }
1583
+ );
1584
+ }
1585
+ function reportInvalidAttr(file, name, attr, position) {
1586
+ file.message(
1587
+ `Attribute "${attr}" is not allowed on ":::${name}"`,
1588
+ { place: position, source: SOURCE }
1589
+ );
1590
+ }
1591
+ function reportMissingAttr(file, name, attr, position) {
1592
+ file.message(
1593
+ `":::${name}" requires attribute "${attr}"`,
1594
+ { place: position, source: SOURCE }
1595
+ );
1596
+ }
1597
+ function reportInvalidNesting(file, name, expectedParent, position) {
1598
+ file.message(
1599
+ `":::${name}" must be inside ":::${expectedParent}"`,
1600
+ { place: position, source: SOURCE }
1601
+ );
1602
+ }
1603
+ function reportInvalidChildren(file, parentName, expectedChild, position) {
1604
+ file.message(
1605
+ `":::${parentName}" children must all be ":::${expectedChild}"`,
1606
+ { place: position, source: SOURCE }
1607
+ );
1608
+ }
1609
+ function reportMissingPayload(file, name, what, position) {
1610
+ file.message(
1611
+ `":::${name}" requires ${what}`,
1612
+ { place: position, source: SOURCE }
1613
+ );
1614
+ }
1615
+ function reportConflictingPayload(file, name, what, position) {
1616
+ file.message(
1617
+ `":::${name}" ${what}`,
1618
+ { place: position, source: SOURCE }
1619
+ );
1620
+ }
1621
+
1622
+ // src/processor/remark-owo-components.ts
1623
+ function escapeHtml2(text) {
1624
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1625
+ }
1626
+ function findCodeBlock(children) {
1627
+ for (const child of children) {
1628
+ if (child.type === "code") return child;
1629
+ }
1630
+ return null;
1631
+ }
1632
+ function countCodeBlocks(children) {
1633
+ return children.filter((c) => c.type === "code").length;
1634
+ }
1635
+ function hasContainerDirectiveChildren(children, name) {
1636
+ return children.some(
1637
+ (c) => c.type === "containerDirective" && c.name === name
1638
+ );
1639
+ }
1640
+ function allChildrenAreDirective(children, name) {
1641
+ const meaningful = children.filter(
1642
+ (c) => c.type !== "paragraph" || !isBlankParagraph(c)
1643
+ );
1644
+ return meaningful.length > 0 && meaningful.every(
1645
+ (c) => c.type === "containerDirective" && c.name === name
1646
+ );
1647
+ }
1648
+ function isBlankParagraph(node) {
1649
+ if (node.type !== "paragraph") return false;
1650
+ const children = node.children;
1651
+ if (!children || children.length === 0) return true;
1652
+ return children.every((c) => c.type === "text" && !c.value?.trim());
1653
+ }
1654
+ function getDirectiveChildren(children, name) {
1655
+ return children.filter(
1656
+ (c) => c.type === "containerDirective" && c.name === name
1657
+ );
1658
+ }
1659
+ function extractTextContent(children) {
1660
+ let text = "";
1661
+ for (const child of children) {
1662
+ if (child.type === "text") {
1663
+ text += child.value ?? "";
1664
+ } else if (child.children) {
1665
+ text += extractTextContent(child.children);
1666
+ }
1667
+ }
1668
+ return text;
1669
+ }
1670
+ function getPosition(node) {
1671
+ return node.position?.start;
1672
+ }
1673
+ function validateAttrs(file, node, entry) {
1674
+ const attrs = node.attributes ?? {};
1675
+ let valid = true;
1676
+ for (const key of Object.keys(attrs)) {
1677
+ if (!entry.allowedAttrs.includes(key)) {
1678
+ reportInvalidAttr(file, entry.directiveName, key, getPosition(node));
1679
+ }
1680
+ }
1681
+ for (const key of entry.requiredAttrs) {
1682
+ if (!attrs[key]?.trim()) {
1683
+ reportMissingAttr(file, entry.directiveName, key, getPosition(node));
1684
+ valid = false;
1685
+ }
1686
+ }
1687
+ return valid;
1688
+ }
1689
+ function mdastHtmlNode(html) {
1690
+ return { type: "html", value: html };
1691
+ }
1692
+ function mdastWrapper(hName, className, children) {
1693
+ const cls = Array.isArray(className) ? className : [className];
1694
+ return {
1695
+ type: "paragraph",
1696
+ data: { hName, hProperties: { className: cls } },
1697
+ children
1698
+ };
1699
+ }
1700
+ function transformNote(node) {
1701
+ const title = node.attributes?.title;
1702
+ node.data = {
1703
+ hName: "aside",
1704
+ hProperties: { className: ["mdx-note"] }
1705
+ };
1706
+ if (title && node.children) {
1707
+ node.children.unshift(mdastHtmlNode(
1708
+ `<div class="mdx-note-title">${escapeHtml2(title)}</div>`
1709
+ ));
1710
+ }
1711
+ if (node.children) {
1712
+ const wrapper = mdastWrapper(
1713
+ "div",
1714
+ "mdx-note-body",
1715
+ title ? node.children.slice(1) : [...node.children]
1716
+ );
1717
+ node.children = title ? [node.children[0], wrapper] : [wrapper];
1718
+ }
1719
+ }
1720
+ function transformCallout(node) {
1721
+ const type = node.attributes?.type ?? "info";
1722
+ const ICONS2 = { info: "i", warn: "!", error: "\xD7", success: "\u2713" };
1723
+ const icon = ICONS2[type] ?? ICONS2.info;
1724
+ node.data = {
1725
+ hName: "div",
1726
+ hProperties: {
1727
+ className: ["mdx-callout", `mdx-callout-${type}`],
1728
+ "data-callout-type": type
1729
+ }
1730
+ };
1731
+ if (node.children) {
1732
+ node.children.unshift(mdastHtmlNode(
1733
+ `<span class="mdx-callout-icon">${escapeHtml2(icon)}</span>`
1734
+ ));
1735
+ const contentChildren = node.children.slice(1);
1736
+ const wrapper = mdastWrapper("div", "mdx-callout-content", contentChildren);
1737
+ node.children = [node.children[0], wrapper];
1738
+ }
1739
+ }
1740
+ function transformDetails(node) {
1741
+ const summary = node.attributes?.summary ?? "";
1742
+ const open = node.attributes?.open;
1743
+ node.data = {
1744
+ hName: "details",
1745
+ hProperties: {
1746
+ className: ["mdx-details"],
1747
+ ...open === "true" ? { open: true } : {}
1748
+ }
1749
+ };
1750
+ if (node.children) {
1751
+ node.children.unshift(mdastHtmlNode(
1752
+ `<summary class="mdx-details-summary">${escapeHtml2(summary)}</summary>`
1753
+ ));
1754
+ const bodyChildren = node.children.slice(1);
1755
+ const wrapper = mdastWrapper("div", "mdx-details-body", bodyChildren);
1756
+ node.children = [node.children[0], wrapper];
1757
+ }
1758
+ }
1759
+ function transformKbd(node) {
1760
+ node.data = {
1761
+ hName: "kbd",
1762
+ hProperties: { className: ["mdx-kbd"] }
1763
+ };
1764
+ }
1765
+ function makeRenderedNode(node, html) {
1766
+ node.type = "owoComponentRendered";
1767
+ node.children = [];
1768
+ node.data = { html };
1769
+ }
1770
+ function renderCodeDemoSingle(attrs, code, fenceLang) {
1771
+ const title = attrs.title ?? "";
1772
+ const language = attrs.language ?? (fenceLang || "text");
1773
+ const titleHtml = title ? `<figcaption>${escapeHtml2(title)}</figcaption>` : "";
1774
+ return `<figure class="mdx-code-demo" data-code-demo>${titleHtml}<pre data-language="${escapeHtml2(language)}"><code>${escapeHtml2(code)}</code></pre></figure>`;
1775
+ }
1776
+ function renderCodeDemoMultiTab(attrs, tabs) {
1777
+ const title = attrs.title ?? "";
1778
+ const titleHtml = title ? `<figcaption>${escapeHtml2(title)}</figcaption>` : "";
1779
+ const groupId = `mdx-code-tabs-${Math.random().toString(36).slice(2, 8)}`;
1780
+ const tabListItems = tabs.map(
1781
+ (tab, i) => `<label class="mdx-tabs-trigger"><input type="radio" name="${groupId}" class="mdx-tabs-radio"${i === 0 ? " checked" : ""}><span>${escapeHtml2(tab.label)}</span></label>`
1782
+ ).join("");
1783
+ const panels = tabs.map(
1784
+ (tab) => `<div class="mdx-tabs-panel"><pre data-language="${escapeHtml2(tab.language)}"><code>${escapeHtml2(tab.code)}</code></pre></div>`
1785
+ ).join("");
1786
+ return `<figure class="mdx-code-demo" data-code-demo>${titleHtml}<div class="mdx-tabs"><div class="mdx-tabs-list" role="tablist">${tabListItems}</div>${panels}</div></figure>`;
1787
+ }
1788
+ function renderFileTree(text) {
1789
+ const entries2 = [];
1790
+ for (const line of text.split("\n")) {
1791
+ const trimmed = line.replace(/^[\s\-*]*/, "");
1792
+ if (!trimmed) continue;
1793
+ const leadingSpaces = line.match(/^(\s*)/)?.[1].length ?? 0;
1794
+ const depth = Math.floor(leadingSpaces / 2);
1795
+ const isDir = trimmed.endsWith("/");
1796
+ const name = isDir ? trimmed.slice(0, -1) : trimmed;
1797
+ entries2.push({ name, isDir, depth });
1798
+ }
1799
+ const items = entries2.map((entry) => {
1800
+ const icon = entry.isDir ? "\u{1F4C1}" : "\u{1F4C4}";
1801
+ const cls = entry.isDir ? "mdx-file-tree-dir" : "mdx-file-tree-file";
1802
+ return `<div class="mdx-file-tree-entry ${cls}" style="padding-left: ${entry.depth * 1.25 + 0.5}rem"><span class="mdx-file-tree-icon">${icon}</span><span class="mdx-file-tree-name">${escapeHtml2(entry.name)}</span></div>`;
1803
+ }).join("");
1804
+ return `<div class="mdx-file-tree">${items}</div>`;
1805
+ }
1806
+ function renderLinkCard(attrs, summaryText) {
1807
+ const href = attrs.href ?? "";
1808
+ const title = attrs.title ?? "";
1809
+ const description = attrs.description ?? summaryText;
1810
+ const domain = attrs.domain;
1811
+ const titleHtml = `<div class="mdx-link-card-title">${escapeHtml2(title)}</div>`;
1812
+ const descHtml = description ? `<div class="mdx-link-card-desc">${escapeHtml2(description)}</div>` : "";
1813
+ const domainHtml = domain ? `<div class="mdx-link-card-domain">${escapeHtml2(domain)}</div>` : "";
1814
+ return `<a class="mdx-link-card" href="${escapeHtml2(href)}">${titleHtml}${descHtml}${domainHtml}</a>`;
1815
+ }
1816
+ function transformSteps(node) {
1817
+ const stepNodes = getDirectiveChildren(node.children ?? [], "step");
1818
+ node.data = {
1819
+ hName: "div",
1820
+ hProperties: { className: ["mdx-steps"] }
1821
+ };
1822
+ const items = [];
1823
+ for (let i = 0; i < stepNodes.length; i++) {
1824
+ const step = stepNodes[i];
1825
+ const title = step.attributes?.title;
1826
+ const titleNode = title ? mdastHtmlNode(`<h4 class="mdx-step-title">${escapeHtml2(title)}</h4>`) : null;
1827
+ const bodyChildren = step.children ?? [];
1828
+ const bodyNode = bodyChildren.length > 0 ? mdastWrapper("div", "mdx-step-body", bodyChildren) : null;
1829
+ const line = i < stepNodes.length - 1 ? mdastHtmlNode('<div class="mdx-steps-line"></div>') : null;
1830
+ const indicatorChildren = [
1831
+ mdastHtmlNode(`<span class="mdx-steps-number">${i + 1}</span>`)
1832
+ ];
1833
+ if (line) indicatorChildren.push(line);
1834
+ const stepContentChildren = [];
1835
+ if (titleNode) stepContentChildren.push(titleNode);
1836
+ if (bodyNode) stepContentChildren.push(bodyNode);
1837
+ const stepInner = mdastWrapper("div", "mdx-step", stepContentChildren);
1838
+ const indicatorWrapper = mdastWrapper("div", "mdx-steps-indicator", indicatorChildren);
1839
+ const contentWrapper = mdastWrapper("div", "mdx-steps-content", [stepInner]);
1840
+ items.push(mdastWrapper("div", "mdx-steps-item", [indicatorWrapper, contentWrapper]));
1841
+ }
1842
+ node.children = items;
1843
+ }
1844
+ function transformTabs(node) {
1845
+ const tabNodes = getDirectiveChildren(node.children ?? [], "tab");
1846
+ const groupId = `mdx-tabs-${Math.random().toString(36).slice(2, 8)}`;
1847
+ node.data = {
1848
+ hName: "div",
1849
+ hProperties: { className: ["mdx-tabs"] }
1850
+ };
1851
+ const triggers = [];
1852
+ const panels = [];
1853
+ for (let i = 0; i < tabNodes.length; i++) {
1854
+ const tab = tabNodes[i];
1855
+ const label = tab.attributes?.label ?? `Tab ${i + 1}`;
1856
+ triggers.push(mdastHtmlNode(
1857
+ `<label class="mdx-tabs-trigger"><input type="radio" name="${groupId}" class="mdx-tabs-radio"${i === 0 ? " checked" : ""}><span>${escapeHtml2(label)}</span></label>`
1858
+ ));
1859
+ panels.push(mdastWrapper("div", "mdx-tabs-panel", tab.children ?? []));
1860
+ }
1861
+ const tabList = mdastWrapper("div", "mdx-tabs-list", triggers);
1862
+ tabList.data.hProperties.role = "tablist";
1863
+ node.children = [tabList, ...panels];
1864
+ }
1865
+ function remarkOwoComponents(options) {
1866
+ const { enabled } = options;
1867
+ return function transform2(tree, file) {
1868
+ visit3(tree, (node, _index, parent) => {
1869
+ const directive = node;
1870
+ if (directive.type === "textDirective") {
1871
+ return handleTextDirective(directive, parent ?? void 0, file, enabled);
1872
+ }
1873
+ if (directive.type !== "containerDirective") return;
1874
+ const { name } = directive;
1875
+ if (name === "side") return;
1876
+ const entry = COMPONENT_REGISTRY.get(name);
1877
+ if (!entry) {
1878
+ reportUnknownComponent(file, name, getPosition(directive));
1879
+ return;
1880
+ }
1881
+ if (!enabled) {
1882
+ reportDisabledFlag(file, name, getPosition(directive));
1883
+ return;
1884
+ }
1885
+ validateAttrs(file, directive, entry);
1886
+ if (entry.requiredParent) {
1887
+ const parentDirective = parent;
1888
+ if (!parentDirective || parentDirective.type !== "containerDirective" || parentDirective.name !== entry.requiredParent) {
1889
+ reportInvalidNesting(file, name, entry.requiredParent, getPosition(directive));
1890
+ return;
1891
+ }
1892
+ }
1893
+ if (entry.allowedChildDirective && directive.children) {
1894
+ const childName = entry.allowedChildDirective;
1895
+ const hasChildDirectives = hasContainerDirectiveChildren(directive.children, childName);
1896
+ if (entry.kind === "block-parent") {
1897
+ if (!allChildrenAreDirective(directive.children, childName)) {
1898
+ if (directive.children.some((c) => !isBlankParagraph(c))) {
1899
+ reportInvalidChildren(file, name, childName, getPosition(directive));
1900
+ }
1901
+ }
1902
+ }
1903
+ if (name === "code-demo" && hasChildDirectives) {
1904
+ const hasTopLevelCode = countCodeBlocks(directive.children) > 0;
1905
+ if (hasTopLevelCode) {
1906
+ reportConflictingPayload(file, name, "cannot mix top-level code blocks with :::code-tab children", getPosition(directive));
1907
+ return;
1908
+ }
1909
+ if (!allChildrenAreDirective(directive.children, "code-tab")) {
1910
+ reportInvalidChildren(file, name, "code-tab", getPosition(directive));
1911
+ }
1912
+ const codeTabNodes = getDirectiveChildren(directive.children, "code-tab");
1913
+ for (const ct of codeTabNodes) {
1914
+ validateAttrs(file, ct, COMPONENT_REGISTRY.get("code-tab"));
1915
+ const codeCount = countCodeBlocks(ct.children ?? []);
1916
+ if (codeCount === 0) {
1917
+ reportMissingPayload(file, "code-tab", "a fenced code block", getPosition(ct));
1918
+ } else if (codeCount > 1) {
1919
+ reportConflictingPayload(file, "code-tab", "must contain exactly one fenced code block", getPosition(ct));
1920
+ }
1921
+ }
1922
+ const tabs = codeTabNodes.map((ct) => {
1923
+ const code = findCodeBlock(ct.children ?? []);
1924
+ return {
1925
+ label: ct.attributes?.label ?? "",
1926
+ language: ct.attributes?.language ?? code?.lang ?? "text",
1927
+ code: code?.value ?? ""
1928
+ };
1929
+ });
1930
+ makeRenderedNode(directive, renderCodeDemoMultiTab(directive.attributes ?? {}, tabs));
1931
+ return SKIP;
1932
+ }
1933
+ }
1934
+ switch (name) {
1935
+ case "note":
1936
+ transformNote(directive);
1937
+ return SKIP;
1938
+ case "callout":
1939
+ transformCallout(directive);
1940
+ return SKIP;
1941
+ case "details":
1942
+ transformDetails(directive);
1943
+ return SKIP;
1944
+ case "kbd":
1945
+ transformKbd(directive);
1946
+ return SKIP;
1947
+ case "code-demo": {
1948
+ const codeBlock = findCodeBlock(directive.children ?? []);
1949
+ if (!codeBlock) {
1950
+ reportMissingPayload(file, name, "a fenced code block", getPosition(directive));
1951
+ return;
1952
+ }
1953
+ if (countCodeBlocks(directive.children ?? []) > 1) {
1954
+ reportConflictingPayload(file, name, "must contain exactly one fenced code block (or use :::code-tab)", getPosition(directive));
1955
+ return;
1956
+ }
1957
+ makeRenderedNode(
1958
+ directive,
1959
+ renderCodeDemoSingle(directive.attributes ?? {}, codeBlock.value, codeBlock.lang ?? "")
1960
+ );
1961
+ return SKIP;
1962
+ }
1963
+ case "file-tree": {
1964
+ const codeBlock = findCodeBlock(directive.children ?? []);
1965
+ if (!codeBlock) {
1966
+ reportMissingPayload(file, name, "a fenced code block", getPosition(directive));
1967
+ return;
1968
+ }
1969
+ makeRenderedNode(directive, renderFileTree(codeBlock.value));
1970
+ return SKIP;
1971
+ }
1972
+ case "link-card": {
1973
+ const attrs = directive.attributes ?? {};
1974
+ const hasDesc = Boolean(attrs.description);
1975
+ const bodyText = extractTextContent(directive.children ?? []).trim();
1976
+ if (hasDesc && bodyText) {
1977
+ reportConflictingPayload(file, name, 'cannot have both "description" attribute and body text', getPosition(directive));
1978
+ }
1979
+ makeRenderedNode(directive, renderLinkCard(attrs, bodyText));
1980
+ return SKIP;
1981
+ }
1982
+ case "steps":
1983
+ transformSteps(directive);
1984
+ return SKIP;
1985
+ case "tabs":
1986
+ transformTabs(directive);
1987
+ return SKIP;
1988
+ case "step":
1989
+ case "tab":
1990
+ case "code-tab":
1991
+ break;
1992
+ }
1993
+ });
1994
+ };
1995
+ }
1996
+ function handleTextDirective(node, _parent, file, enabled) {
1997
+ if (node.name === "kbd") {
1998
+ if (!enabled) {
1999
+ reportDisabledFlag(file, node.name, getPosition(node));
2000
+ return;
2001
+ }
2002
+ transformKbd(node);
2003
+ return SKIP;
2004
+ }
2005
+ const entry = COMPONENT_REGISTRY.get(node.name);
2006
+ if (entry && entry.kind !== "inline-text") {
2007
+ reportInvalidNesting(file, node.name, "block context (use ::: syntax)", getPosition(node));
2008
+ }
2009
+ }
2010
+ function owoComponentRenderedHandler(_state, node) {
2011
+ return {
2012
+ type: "raw",
2013
+ value: node.data?.html ?? ""
2014
+ };
2015
+ }
2016
+
2017
+ // src/processor/source-normalization.ts
2018
+ import {
2019
+ collectMathFenceNormalizationRewrites
2020
+ } from "@owomark/core/semantic/syntax";
2021
+ function splitLogicalLines(source) {
2022
+ const lines = source.split("\n");
2023
+ if (source.endsWith("\n")) {
2024
+ lines.pop();
2025
+ }
2026
+ return lines;
2027
+ }
2028
+ function createIdentitySourceMap(source) {
2029
+ const lineCount = splitLogicalLines(source).length;
2030
+ return {
2031
+ normalizedToSourceLine: Array.from({ length: lineCount }, (_, index) => index + 1),
2032
+ normalizedToSourceColumn: Array.from({ length: lineCount }, () => 1),
2033
+ segments: []
2034
+ };
2035
+ }
2036
+ function applySourceRewrites(source, sourceMap, rewrites) {
2037
+ if (rewrites.length === 0) {
2038
+ return { source, sourceMap };
2039
+ }
2040
+ const inputLines = splitLogicalLines(source);
2041
+ const outputLines = [];
2042
+ const normalizedToSourceLine = [];
2043
+ const normalizedToSourceColumn = [];
2044
+ const segments = [...sourceMap.segments];
2045
+ let lineNumber = 1;
2046
+ let rewriteIndex = 0;
2047
+ while (lineNumber <= inputLines.length) {
2048
+ const rewrite = rewrites[rewriteIndex];
2049
+ if (rewrite && rewrite.startLine === lineNumber) {
2050
+ const normalizedStartLine = outputLines.length + 1;
2051
+ outputLines.push(...rewrite.replacementLines);
2052
+ for (const mapping of rewrite.lineMappings) {
2053
+ const sourceLine = sourceMap.normalizedToSourceLine[mapping.sourceLine - 1] ?? mapping.sourceLine;
2054
+ const sourceColumnBase = sourceMap.normalizedToSourceColumn[mapping.sourceLine - 1] ?? 1;
2055
+ normalizedToSourceLine.push(sourceLine);
2056
+ normalizedToSourceColumn.push(sourceColumnBase + mapping.sourceColumn - 1);
2057
+ }
2058
+ segments.push({
2059
+ kind: rewrite.kind,
2060
+ normalizedStartLine,
2061
+ normalizedEndLine: outputLines.length,
2062
+ sourceStartLine: sourceMap.normalizedToSourceLine[rewrite.startLine - 1] ?? rewrite.startLine,
2063
+ sourceEndLine: sourceMap.normalizedToSourceLine[rewrite.endLine - 1] ?? rewrite.endLine
2064
+ });
2065
+ lineNumber = rewrite.endLine + 1;
2066
+ rewriteIndex += 1;
2067
+ continue;
2068
+ }
2069
+ outputLines.push(inputLines[lineNumber - 1]);
2070
+ normalizedToSourceLine.push(sourceMap.normalizedToSourceLine[lineNumber - 1] ?? lineNumber);
2071
+ normalizedToSourceColumn.push(sourceMap.normalizedToSourceColumn[lineNumber - 1] ?? 1);
2072
+ lineNumber += 1;
2073
+ }
2074
+ const normalizedSource = outputLines.join("\n");
2075
+ return {
2076
+ source: source.endsWith("\n") ? `${normalizedSource}
2077
+ ` : normalizedSource,
2078
+ sourceMap: {
2079
+ normalizedToSourceLine,
2080
+ normalizedToSourceColumn,
2081
+ segments
2082
+ }
2083
+ };
2084
+ }
2085
+ function normalizeOwoMarkSource(source, options) {
2086
+ const baseMap = createIdentitySourceMap(source);
2087
+ if (options?.enableMath === false) {
2088
+ return { source, sourceMap: baseMap };
2089
+ }
2090
+ const rewrites = collectMathFenceNormalizationRewrites(source).map((rewrite) => ({
2091
+ kind: rewrite.kind,
2092
+ startLine: rewrite.startLine,
2093
+ endLine: rewrite.endLine,
2094
+ replacementLines: rewrite.replacementLines,
2095
+ lineMappings: rewrite.lineMappings
2096
+ }));
2097
+ return applySourceRewrites(source, baseMap, rewrites);
2098
+ }
2099
+ function remapNormalizedLine(line, sourceMap) {
2100
+ if (typeof line !== "number" || line < 1) return line;
2101
+ return sourceMap?.normalizedToSourceLine[line - 1] ?? line;
2102
+ }
2103
+ function remapNormalizedColumn(line, column, sourceMap) {
2104
+ if (typeof line !== "number" || typeof column !== "number" || line < 1 || column < 1) {
2105
+ return column;
2106
+ }
2107
+ const baseColumn = sourceMap?.normalizedToSourceColumn[line - 1];
2108
+ if (typeof baseColumn !== "number") {
2109
+ return column;
2110
+ }
2111
+ return baseColumn + column - 1;
2112
+ }
2113
+
2114
+ // src/processor/remark-mdx-source-lines.ts
2115
+ function setMdxAttribute(node, name, value) {
2116
+ const attributes = Array.isArray(node.attributes) ? node.attributes : [];
2117
+ const existing = attributes.findIndex(
2118
+ (attribute) => attribute?.type === "mdxJsxAttribute" && attribute.name === name
2119
+ );
2120
+ const nextAttribute = {
2121
+ type: "mdxJsxAttribute",
2122
+ name,
2123
+ value
2124
+ };
2125
+ if (existing >= 0) {
2126
+ attributes[existing] = nextAttribute;
2127
+ } else {
2128
+ attributes.push(nextAttribute);
2129
+ }
2130
+ node.attributes = attributes;
2131
+ }
2132
+ function remapLine(line, sourceMap) {
2133
+ return remapNormalizedLine(line, sourceMap);
2134
+ }
2135
+ function stampMdxJsxNode(node, sourceMap) {
2136
+ const startLine = remapLine(node.position?.start?.line, sourceMap);
2137
+ if (!startLine) return;
2138
+ const endLine = remapLine(node.position?.end?.line, sourceMap) ?? startLine;
2139
+ setMdxAttribute(node, "data-source-line-start", String(startLine));
2140
+ setMdxAttribute(node, "data-source-line-end", String(endLine));
2141
+ setMdxAttribute(node, "data-block-id", `L${startLine}-${endLine}`);
2142
+ }
2143
+ function walk3(node, sourceMap) {
2144
+ if (!node || typeof node !== "object") return;
2145
+ if (node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") {
2146
+ stampMdxJsxNode(node, sourceMap);
2147
+ }
2148
+ if (Array.isArray(node.children)) {
2149
+ for (const child of node.children) walk3(child, sourceMap);
2150
+ }
2151
+ }
2152
+ function remarkMdxSourceLines(options) {
2153
+ return (tree) => {
2154
+ walk3(tree, options?.sourceMap);
2155
+ };
2156
+ }
2157
+
2158
+ // src/processor/rehype-source-lines.ts
2159
+ var LEAF_TAGS = /* @__PURE__ */ new Set([
2160
+ "p",
2161
+ "h1",
2162
+ "h2",
2163
+ "h3",
2164
+ "h4",
2165
+ "h5",
2166
+ "h6",
2167
+ "pre",
2168
+ "table",
2169
+ "hr",
2170
+ "img"
2171
+ ]);
2172
+ var CONTAINER_TAGS = /* @__PURE__ */ new Set([
2173
+ "ul",
2174
+ "ol",
2175
+ "li",
2176
+ "blockquote",
2177
+ "div",
2178
+ "section",
2179
+ "details",
2180
+ "summary"
2181
+ ]);
2182
+ var MATH_LEAF_CLASSES = /* @__PURE__ */ new Set([
2183
+ "katex-display",
2184
+ "math-display",
2185
+ "math-display-block"
2186
+ ]);
2187
+ function liHasAnchorDescendant(node) {
2188
+ if (!Array.isArray(node.children)) return false;
2189
+ for (const child of node.children) {
2190
+ if (child.type !== "element") continue;
2191
+ if (LEAF_TAGS.has(child.tagName)) return true;
2192
+ if (child.tagName === "ul" || child.tagName === "ol") return true;
2193
+ if (CONTAINER_TAGS.has(child.tagName) && liHasAnchorDescendant(child)) return true;
2194
+ }
2195
+ return false;
2196
+ }
2197
+ function stampAnchorAttributes(node) {
2198
+ const sl = node.position.start.line;
2199
+ const el2 = node.position.end?.line ?? sl;
2200
+ node.properties = node.properties || {};
2201
+ node.properties["data-source-line-start"] = sl;
2202
+ node.properties["data-source-line-end"] = el2;
2203
+ node.properties["data-block-id"] = `L${sl}-${el2}`;
2204
+ }
2205
+ function walk4(node) {
2206
+ if (!node) return;
2207
+ if (node.type === "element" && node.position?.start?.line) {
2208
+ const tag = node.tagName;
2209
+ if (LEAF_TAGS.has(tag)) {
2210
+ stampAnchorAttributes(node);
2211
+ } else if (tag === "li" && !liHasAnchorDescendant(node)) {
2212
+ stampAnchorAttributes(node);
2213
+ } else if (tag === "div") {
2214
+ const classes = node.properties?.className || [];
2215
+ if (classes.some((className) => MATH_LEAF_CLASSES.has(className))) {
2216
+ stampAnchorAttributes(node);
2217
+ return;
2218
+ }
2219
+ }
2220
+ }
2221
+ if (Array.isArray(node.children)) {
2222
+ for (const child of node.children) walk4(child);
2223
+ }
2224
+ }
2225
+ function rehypeSourceLines() {
2226
+ return (tree) => {
2227
+ walk4(tree);
2228
+ };
2229
+ }
2230
+
2231
+ // src/processor/plugin-registry.ts
2232
+ var BUILTIN_PLUGINS = /* @__PURE__ */ new Map([
2233
+ ["rehype-source-lines", {
2234
+ plugin: rehypeSourceLines,
2235
+ workerSafe: true
2236
+ }]
2237
+ ]);
2238
+ var GLOBAL_KEY = "__owomark_custom_plugins__";
2239
+ function getCustomPlugins() {
2240
+ const g = globalThis;
2241
+ if (!g[GLOBAL_KEY]) g[GLOBAL_KEY] = /* @__PURE__ */ new Map();
2242
+ return g[GLOBAL_KEY];
2243
+ }
2244
+ function registerPlugin(name, plugin) {
2245
+ getCustomPlugins().set(name, plugin);
2246
+ }
2247
+ function allBuiltinDescriptors(descriptors) {
2248
+ return descriptors.every((d) => BUILTIN_PLUGINS.has(d.name));
2249
+ }
2250
+ function isWorkerSafeBuiltinDescriptor(descriptor) {
2251
+ return BUILTIN_PLUGINS.get(descriptor.name)?.workerSafe === true;
2252
+ }
2253
+ function allWorkerSafeBuiltinDescriptors(descriptors) {
2254
+ return descriptors.every((d) => BUILTIN_PLUGINS.get(d.name)?.workerSafe === true);
2255
+ }
2256
+ function resolveDescriptors(descriptors) {
2257
+ return descriptors.map((d) => {
2258
+ const plugin = BUILTIN_PLUGINS.get(d.name)?.plugin ?? getCustomPlugins().get(d.name);
2259
+ if (!plugin) {
2260
+ throw new Error(`[owomark] Unknown plugin descriptor: "${d.name}". Register it first via registerPlugin().`);
2261
+ }
2262
+ if (d.options) return [plugin, d.options];
2263
+ return plugin;
2264
+ });
2265
+ }
2266
+
1346
2267
  // src/mdx-components/callout.ts
1347
2268
  import { createElement } from "react";
2269
+
2270
+ // src/mdx-components/dom-props.ts
2271
+ function mergeClassName(...values) {
2272
+ const merged = values.filter(Boolean).join(" ").trim();
2273
+ return merged || void 0;
2274
+ }
2275
+
2276
+ // src/mdx-components/callout.ts
1348
2277
  var ICONS = { info: "i", warn: "!", error: "\xD7" };
1349
- function Callout({ type = "info", children }) {
2278
+ function Callout({
2279
+ type = "info",
2280
+ children,
2281
+ className,
2282
+ ...domProps
2283
+ }) {
1350
2284
  return createElement(
1351
2285
  "div",
1352
- { className: `mdx-callout mdx-callout-${type}`, "data-callout-type": type },
2286
+ {
2287
+ ...domProps,
2288
+ className: mergeClassName("mdx-callout", `mdx-callout-${type}`, className),
2289
+ "data-callout-type": type
2290
+ },
1353
2291
  createElement("span", { className: "mdx-callout-icon" }, ICONS[type] || ICONS.info),
1354
2292
  createElement("div", { className: "mdx-callout-content" }, children)
1355
2293
  );
1356
2294
  }
1357
2295
 
1358
- // src/mdx-components/code-demo.ts
2296
+ // src/mdx-components/note.ts
1359
2297
  import { createElement as createElement2 } from "react";
1360
- function CodeDemo({ title, language = "text", code }) {
2298
+ function Note({
2299
+ title,
2300
+ children,
2301
+ className,
2302
+ ...domProps
2303
+ }) {
1361
2304
  return createElement2(
2305
+ "aside",
2306
+ {
2307
+ ...domProps,
2308
+ className: mergeClassName("mdx-note", className)
2309
+ },
2310
+ title ? createElement2("div", { className: "mdx-note-title" }, title) : null,
2311
+ createElement2("div", { className: "mdx-note-body" }, children)
2312
+ );
2313
+ }
2314
+
2315
+ // src/mdx-components/code-demo.ts
2316
+ import { createElement as createElement3 } from "react";
2317
+ function CodeDemo({
2318
+ title,
2319
+ language = "text",
2320
+ code,
2321
+ className,
2322
+ ...domProps
2323
+ }) {
2324
+ return createElement3(
1362
2325
  "figure",
1363
- { className: "mdx-code-demo", "data-code-demo": "" },
1364
- title && createElement2("figcaption", null, title),
1365
- createElement2(
2326
+ {
2327
+ ...domProps,
2328
+ className: mergeClassName("mdx-code-demo", className),
2329
+ "data-code-demo": ""
2330
+ },
2331
+ title && createElement3("figcaption", null, title),
2332
+ createElement3(
1366
2333
  "pre",
1367
2334
  { "data-language": language },
1368
- createElement2("code", null, code)
2335
+ createElement3("code", null, code)
1369
2336
  )
1370
2337
  );
1371
2338
  }
1372
2339
 
2340
+ // src/mdx-components/code-tab.ts
2341
+ import { createElement as createElement4 } from "react";
2342
+ function CodeTab({
2343
+ label,
2344
+ language,
2345
+ children,
2346
+ className,
2347
+ ...domProps
2348
+ }) {
2349
+ return createElement4(
2350
+ "div",
2351
+ {
2352
+ ...domProps,
2353
+ className: mergeClassName("mdx-code-tab", className),
2354
+ "data-label": label,
2355
+ "data-language": language
2356
+ },
2357
+ children
2358
+ );
2359
+ }
2360
+
2361
+ // src/mdx-components/details.ts
2362
+ import { createElement as createElement5 } from "react";
2363
+ function Details({
2364
+ summary,
2365
+ open,
2366
+ children,
2367
+ className,
2368
+ ...domProps
2369
+ }) {
2370
+ return createElement5(
2371
+ "details",
2372
+ {
2373
+ ...domProps,
2374
+ className: mergeClassName("mdx-details", className),
2375
+ open: open === "true" || void 0
2376
+ },
2377
+ createElement5("summary", { className: "mdx-details-summary" }, summary),
2378
+ createElement5("div", { className: "mdx-details-body" }, children)
2379
+ );
2380
+ }
2381
+
2382
+ // src/mdx-components/link-card.ts
2383
+ import { createElement as createElement6 } from "react";
2384
+ function LinkCard({
2385
+ href,
2386
+ title,
2387
+ description,
2388
+ domain,
2389
+ children,
2390
+ className,
2391
+ ...domProps
2392
+ }) {
2393
+ const desc = description || (children ? children : null);
2394
+ return createElement6(
2395
+ "a",
2396
+ {
2397
+ ...domProps,
2398
+ className: mergeClassName("mdx-link-card", className),
2399
+ href
2400
+ },
2401
+ createElement6("div", { className: "mdx-link-card-title" }, title),
2402
+ desc ? createElement6("div", { className: "mdx-link-card-desc" }, desc) : null,
2403
+ domain ? createElement6("div", { className: "mdx-link-card-domain" }, domain) : null
2404
+ );
2405
+ }
2406
+
1373
2407
  // src/mdx-components/steps.ts
1374
- import { createElement as createElement3, Children } from "react";
1375
- function Steps({ children }) {
2408
+ import { createElement as createElement7, Children } from "react";
2409
+ function Steps({ children, className, ...domProps }) {
1376
2410
  const items = [];
1377
2411
  Children.forEach(children, (child) => {
1378
2412
  if (child && typeof child === "object" && "props" in child) {
1379
2413
  items.push(child);
1380
2414
  }
1381
2415
  });
1382
- return createElement3(
2416
+ return createElement7(
1383
2417
  "div",
1384
- { className: "mdx-steps" },
2418
+ {
2419
+ ...domProps,
2420
+ className: mergeClassName("mdx-steps", className)
2421
+ },
1385
2422
  items.map(
1386
- (item, i) => createElement3(
2423
+ (item, i) => createElement7(
1387
2424
  "div",
1388
2425
  { className: "mdx-steps-item", key: i },
1389
- createElement3(
2426
+ createElement7(
1390
2427
  "div",
1391
2428
  { 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" })
2429
+ createElement7("span", { className: "mdx-steps-number" }, String(i + 1)),
2430
+ i < items.length - 1 && createElement7("div", { className: "mdx-steps-line" })
1394
2431
  ),
1395
- createElement3("div", { className: "mdx-steps-content" }, item)
2432
+ createElement7("div", { className: "mdx-steps-content" }, item)
1396
2433
  )
1397
2434
  )
1398
2435
  );
1399
2436
  }
1400
- function Step({ title, children }) {
1401
- return createElement3(
2437
+ function Step({ title, children, className, ...domProps }) {
2438
+ return createElement7(
1402
2439
  "div",
1403
- { className: "mdx-step" },
1404
- title && createElement3("h4", { className: "mdx-step-title" }, title),
1405
- children && createElement3("div", { className: "mdx-step-body" }, children)
2440
+ {
2441
+ ...domProps,
2442
+ className: mergeClassName("mdx-step", className)
2443
+ },
2444
+ title && createElement7("h4", { className: "mdx-step-title" }, title),
2445
+ children && createElement7("div", { className: "mdx-step-body" }, children)
1406
2446
  );
1407
2447
  }
1408
2448
 
1409
2449
  // src/mdx-components/tabs.ts
1410
- import { createElement as createElement4, Children as Children2 } from "react";
1411
- function Tabs({ children }) {
2450
+ import { createElement as createElement8, Children as Children2 } from "react";
2451
+ function Tabs({ children, className, ...domProps }) {
1412
2452
  const tabs = [];
1413
2453
  Children2.forEach(children, (child) => {
1414
2454
  if (child && typeof child === "object" && "props" in child) {
@@ -1416,39 +2456,49 @@ function Tabs({ children }) {
1416
2456
  }
1417
2457
  });
1418
2458
  const groupId = `mdx-tabs-${Math.random().toString(36).slice(2, 8)}`;
1419
- return createElement4(
2459
+ return createElement8(
1420
2460
  "div",
1421
- { className: "mdx-tabs" },
1422
- createElement4(
2461
+ {
2462
+ ...domProps,
2463
+ className: mergeClassName("mdx-tabs", className)
2464
+ },
2465
+ createElement8(
1423
2466
  "div",
1424
2467
  { className: "mdx-tabs-list", role: "tablist" },
1425
2468
  tabs.map(
1426
- (tab, i) => createElement4(
2469
+ (tab, i) => createElement8(
1427
2470
  "label",
1428
2471
  { className: "mdx-tabs-trigger", key: i },
1429
- createElement4("input", {
2472
+ createElement8("input", {
1430
2473
  type: "radio",
1431
2474
  name: groupId,
1432
2475
  className: "mdx-tabs-radio",
1433
2476
  defaultChecked: i === 0
1434
2477
  }),
1435
- createElement4("span", null, tab.label)
2478
+ createElement8("span", null, tab.label)
1436
2479
  )
1437
2480
  )
1438
2481
  ),
1439
2482
  tabs.map(
1440
- (tab, i) => createElement4("div", { className: "mdx-tabs-panel", key: i }, tab.content)
2483
+ (tab, i) => createElement8("div", { className: "mdx-tabs-panel", key: i }, tab.content)
1441
2484
  )
1442
2485
  );
1443
2486
  }
1444
- function Tab({ label: _label, children }) {
1445
- return createElement4("div", null, children);
2487
+ function Tab({ label: _label, children, className, ...domProps }) {
2488
+ return createElement8(
2489
+ "div",
2490
+ {
2491
+ ...domProps,
2492
+ className
2493
+ },
2494
+ children
2495
+ );
1446
2496
  }
1447
2497
 
1448
2498
  // src/mdx-components/file-tree.ts
1449
- import { createElement as createElement5 } from "react";
2499
+ import { createElement as createElement9 } from "react";
1450
2500
  function parseFileTree(text) {
1451
- const entries = [];
2501
+ const entries2 = [];
1452
2502
  for (const line of text.split("\n")) {
1453
2503
  const trimmed = line.replace(/^[\s\-\*]*/, "");
1454
2504
  if (!trimmed) continue;
@@ -1456,26 +2506,29 @@ function parseFileTree(text) {
1456
2506
  const depth = Math.floor(leadingSpaces / 2);
1457
2507
  const isDir = trimmed.endsWith("/");
1458
2508
  const name = isDir ? trimmed.slice(0, -1) : trimmed;
1459
- entries.push({ name, isDir, depth });
2509
+ entries2.push({ name, isDir, depth });
1460
2510
  }
1461
- return entries;
2511
+ return entries2;
1462
2512
  }
1463
- function FileTree({ children }) {
2513
+ function FileTree({ children, className, ...domProps }) {
1464
2514
  const text = extractText(children);
1465
- const entries = parseFileTree(text);
1466
- return createElement5(
2515
+ const entries2 = parseFileTree(text);
2516
+ return createElement9(
1467
2517
  "div",
1468
- { className: "mdx-file-tree" },
1469
- entries.map(
1470
- (entry, i) => createElement5(
2518
+ {
2519
+ ...domProps,
2520
+ className: mergeClassName("mdx-file-tree", className)
2521
+ },
2522
+ entries2.map(
2523
+ (entry, i) => createElement9(
1471
2524
  "div",
1472
2525
  {
1473
2526
  className: `mdx-file-tree-entry ${entry.isDir ? "mdx-file-tree-dir" : "mdx-file-tree-file"}`,
1474
2527
  style: { paddingLeft: `${entry.depth * 1.25 + 0.5}rem` },
1475
2528
  key: i
1476
2529
  },
1477
- createElement5("span", { className: "mdx-file-tree-icon" }, entry.isDir ? "\u{1F4C1}" : "\u{1F4C4}"),
1478
- createElement5("span", { className: "mdx-file-tree-name" }, entry.name)
2530
+ createElement9("span", { className: "mdx-file-tree-icon" }, entry.isDir ? "\u{1F4C1}" : "\u{1F4C4}"),
2531
+ createElement9("span", { className: "mdx-file-tree-name" }, entry.name)
1479
2532
  )
1480
2533
  )
1481
2534
  );
@@ -1491,15 +2544,26 @@ function extractText(node) {
1491
2544
  }
1492
2545
 
1493
2546
  // src/mdx-components/kbd.ts
1494
- import { createElement as createElement6 } from "react";
1495
- function Kbd({ children }) {
1496
- return createElement6("kbd", { className: "mdx-kbd" }, children);
2547
+ import { createElement as createElement10 } from "react";
2548
+ function Kbd({ children, className, ...domProps }) {
2549
+ return createElement10(
2550
+ "kbd",
2551
+ {
2552
+ ...domProps,
2553
+ className: mergeClassName("mdx-kbd", className)
2554
+ },
2555
+ children
2556
+ );
1497
2557
  }
1498
2558
 
1499
2559
  // src/mdx-components/index.ts
1500
2560
  var DEFAULT_MDX_COMPONENTS = {
1501
2561
  Callout,
2562
+ Note,
1502
2563
  CodeDemo,
2564
+ CodeTab,
2565
+ Details,
2566
+ LinkCard,
1503
2567
  Steps,
1504
2568
  Step,
1505
2569
  Tabs,
@@ -1508,6 +2572,810 @@ var DEFAULT_MDX_COMPONENTS = {
1508
2572
  Kbd
1509
2573
  };
1510
2574
 
2575
+ // src/processor/mdx-syntax-analysis.ts
2576
+ import { unified } from "unified";
2577
+ import remarkParse from "remark-parse";
2578
+ import remarkGfm from "remark-gfm";
2579
+ import remarkMath from "remark-math";
2580
+ import remarkMdx from "remark-mdx";
2581
+ import remarkDirective from "remark-directive";
2582
+ var MDX_NODE_REASONS = /* @__PURE__ */ new Map([
2583
+ ["mdxjsEsm", "mdxjs-esm"],
2584
+ ["mdxJsxFlowElement", "mdx-jsx-flow"],
2585
+ ["mdxJsxTextElement", "mdx-jsx-text"],
2586
+ ["mdxFlowExpression", "mdx-flow-expression"],
2587
+ ["mdxTextExpression", "mdx-text-expression"]
2588
+ ]);
2589
+ var MASKED_LITERAL_NODE_TYPES = /* @__PURE__ */ new Set([
2590
+ "code",
2591
+ "inlineCode",
2592
+ "math",
2593
+ "inlineMath"
2594
+ ]);
2595
+ function applyPlugin(proc, entry) {
2596
+ if (Array.isArray(entry)) {
2597
+ const [plugin, ...args] = entry;
2598
+ return proc.use(plugin, ...args);
2599
+ }
2600
+ return proc.use(entry);
2601
+ }
2602
+ function createParser(mode, options) {
2603
+ const enableMath = options?.enableMath !== false;
2604
+ const enableSideAnnotation = options?.enableSideAnnotation !== false;
2605
+ const remarkPlugins = [remarkGfm];
2606
+ if (enableMath) {
2607
+ remarkPlugins.push(remarkMath, remarkNormalizeStandaloneMath);
2608
+ }
2609
+ remarkPlugins.push(remarkDirective);
2610
+ if (mode === "production") {
2611
+ if (enableSideAnnotation) {
2612
+ remarkPlugins.push(remarkMicromarkSideAnnotation);
2613
+ }
2614
+ remarkPlugins.push(remarkMdx);
2615
+ }
2616
+ if (enableSideAnnotation) {
2617
+ remarkPlugins.push(remarkSideAnnotation);
2618
+ }
2619
+ if (options?.extraRemarkDescriptors?.length) {
2620
+ remarkPlugins.push(...resolveDescriptors(options.extraRemarkDescriptors));
2621
+ }
2622
+ if (options?.extraRemarkPlugins) {
2623
+ remarkPlugins.push(...options.extraRemarkPlugins);
2624
+ }
2625
+ let parser = unified().use(remarkParse);
2626
+ for (const plugin of remarkPlugins) {
2627
+ parser = applyPlugin(parser, plugin);
2628
+ }
2629
+ return parser;
2630
+ }
2631
+ function collectRangesByNodeTypes(root, nodeTypes) {
2632
+ const stack = [root];
2633
+ const ranges = [];
2634
+ while (stack.length > 0) {
2635
+ const node = stack.pop();
2636
+ if (!node) continue;
2637
+ const nodeType = typeof node.type === "string" ? node.type : null;
2638
+ if (nodeType && nodeTypes.has(nodeType)) {
2639
+ const start = node.position?.start?.offset;
2640
+ const end = node.position?.end?.offset;
2641
+ if (typeof start === "number" && typeof end === "number" && start >= 0 && end >= start) {
2642
+ ranges.push({ start, end });
2643
+ }
2644
+ }
2645
+ const children = Array.isArray(node.children) ? node.children : [];
2646
+ for (let index = children.length - 1; index >= 0; index -= 1) {
2647
+ stack.push(children[index]);
2648
+ }
2649
+ }
2650
+ ranges.sort((left, right) => left.start - right.start);
2651
+ return ranges;
2652
+ }
2653
+ function buildMaskedSource(source, root) {
2654
+ const ranges = collectRangesByNodeTypes(root, MASKED_LITERAL_NODE_TYPES);
2655
+ let cursor = 0;
2656
+ let result = "";
2657
+ for (const range of ranges) {
2658
+ if (range.start < cursor) continue;
2659
+ result += source.slice(cursor, range.start);
2660
+ result += source.slice(range.start, range.end).replace(/[^\s]/g, "x");
2661
+ cursor = range.end;
2662
+ }
2663
+ result += source.slice(cursor);
2664
+ return result;
2665
+ }
2666
+ function hasIndentedCodeIndent(line) {
2667
+ return line.startsWith(" ") || line.startsWith(" ");
2668
+ }
2669
+ function stripIndentedCodeIndent(line) {
2670
+ if (line.startsWith(" ")) return line.slice(4);
2671
+ if (line.startsWith(" ")) return line.slice(1);
2672
+ return line;
2673
+ }
2674
+ function parseMarkdownTree(source, options) {
2675
+ return createParser("preview", options).parse(source);
2676
+ }
2677
+ function getFence(lines) {
2678
+ const tildeRuns = lines.flatMap((line) => line.match(/~+/g) ?? []);
2679
+ let longestRun = 2;
2680
+ for (const run of tildeRuns) {
2681
+ if (run.length > longestRun) {
2682
+ longestRun = run.length;
2683
+ }
2684
+ }
2685
+ return "~".repeat(longestRun + 1);
2686
+ }
2687
+ function collectIndentedCodeRewrites(source, root) {
2688
+ const sourceLines = source.split("\n");
2689
+ const stack = [root];
2690
+ const rewrites = [];
2691
+ while (stack.length > 0) {
2692
+ const node = stack.pop();
2693
+ if (!node) continue;
2694
+ if (node.type === "code") {
2695
+ const startLine = node.position?.start?.line;
2696
+ const endLine = node.position?.end?.line;
2697
+ const startColumn = node.position?.start?.column;
2698
+ if (typeof startLine === "number" && typeof endLine === "number" && typeof startColumn === "number" && startLine >= 1 && endLine >= startLine) {
2699
+ const firstLine = sourceLines[startLine - 1] ?? "";
2700
+ const preservedPrefixColumns = Math.max(0, startColumn - 1);
2701
+ const prefix = firstLine.slice(0, preservedPrefixColumns);
2702
+ const firstContentLine = firstLine.slice(prefix.length);
2703
+ if (hasIndentedCodeIndent(firstContentLine)) {
2704
+ const originalLines = sourceLines.slice(startLine - 1, endLine);
2705
+ const normalizedLines = originalLines.map((line) => {
2706
+ const withoutPrefix = line.startsWith(prefix) ? line.slice(prefix.length) : line;
2707
+ return stripIndentedCodeIndent(withoutPrefix);
2708
+ });
2709
+ const fence = getFence(normalizedLines);
2710
+ const lineMappings = [
2711
+ { sourceLine: startLine, sourceColumn: preservedPrefixColumns + 1 },
2712
+ ...normalizedLines.map((_, offset) => ({
2713
+ sourceLine: startLine + offset,
2714
+ sourceColumn: preservedPrefixColumns + 5
2715
+ })),
2716
+ { sourceLine: endLine, sourceColumn: preservedPrefixColumns + 1 }
2717
+ ];
2718
+ rewrites.push({
2719
+ kind: "indented-code",
2720
+ startLine,
2721
+ endLine,
2722
+ replacementLines: [
2723
+ `${prefix}${fence}`,
2724
+ ...normalizedLines.map((line) => `${prefix}${line}`),
2725
+ `${prefix}${fence}`
2726
+ ],
2727
+ lineMappings
2728
+ });
2729
+ }
2730
+ }
2731
+ }
2732
+ const children = Array.isArray(node.children) ? node.children : [];
2733
+ for (let index = children.length - 1; index >= 0; index -= 1) {
2734
+ stack.push(children[index]);
2735
+ }
2736
+ }
2737
+ rewrites.sort((left, right) => left.startLine - right.startLine);
2738
+ return rewrites;
2739
+ }
2740
+ function collectMdxSyntaxMetadata(root) {
2741
+ const componentNames = /* @__PURE__ */ new Set();
2742
+ const stack = [root];
2743
+ let reason;
2744
+ while (stack.length > 0) {
2745
+ const node = stack.pop();
2746
+ if (!node) continue;
2747
+ const nodeType = typeof node.type === "string" ? node.type : null;
2748
+ if (!reason && nodeType) {
2749
+ reason = MDX_NODE_REASONS.get(nodeType);
2750
+ }
2751
+ if ((nodeType === "mdxJsxFlowElement" || nodeType === "mdxJsxTextElement") && typeof node.name === "string" && /^[A-Z]/.test(node.name)) {
2752
+ componentNames.add(node.name);
2753
+ }
2754
+ const children = Array.isArray(node.children) ? node.children : [];
2755
+ for (let index = children.length - 1; index >= 0; index -= 1) {
2756
+ stack.push(children[index]);
2757
+ }
2758
+ }
2759
+ return {
2760
+ reason,
2761
+ componentNames: Array.from(componentNames)
2762
+ };
2763
+ }
2764
+ function inspectMdxSource(source, options) {
2765
+ try {
2766
+ const normalized = normalizeOwoMarkSource(source, { enableMath: options?.enableMath });
2767
+ const markdownTree = parseMarkdownTree(normalized.source, options);
2768
+ const rewrites = collectIndentedCodeRewrites(normalized.source, markdownTree);
2769
+ const compilePlan = applySourceRewrites(normalized.source, normalized.sourceMap, rewrites);
2770
+ const mdxProbeSource = buildMaskedSource(
2771
+ compilePlan.source,
2772
+ parseMarkdownTree(compilePlan.source, options)
2773
+ );
2774
+ const mdxTree = createParser("production", options).use(remarkMdx).parse(mdxProbeSource);
2775
+ const { reason, componentNames } = collectMdxSyntaxMetadata(mdxTree);
2776
+ return {
2777
+ hasMdxSyntax: reason !== void 0,
2778
+ reason,
2779
+ componentNames,
2780
+ compileSource: compilePlan.source,
2781
+ sourceMap: compilePlan.sourceMap
2782
+ };
2783
+ } catch {
2784
+ const fallback = normalizeOwoMarkSource(source, { enableMath: options?.enableMath });
2785
+ return {
2786
+ hasMdxSyntax: true,
2787
+ reason: "parse-failed-fallback",
2788
+ componentNames: [],
2789
+ compileSource: fallback.source,
2790
+ sourceMap: fallback.sourceMap
2791
+ };
2792
+ }
2793
+ }
2794
+ function analyzeMdxSyntax(source, options) {
2795
+ const inspection = inspectMdxSource(source, options);
2796
+ return {
2797
+ hasMdxSyntax: inspection.hasMdxSyntax,
2798
+ reason: inspection.reason,
2799
+ componentNames: inspection.componentNames
2800
+ };
2801
+ }
2802
+ function detectMdxSyntax(source, options) {
2803
+ const { hasMdxSyntax, reason } = analyzeMdxSyntax(source, options);
2804
+ return { hasMdxSyntax, reason };
2805
+ }
2806
+ function remapMdxLineNumber(line, sourceMap) {
2807
+ return remapNormalizedLine(line, sourceMap);
2808
+ }
2809
+ function remapMdxColumnNumber(line, column, sourceMap) {
2810
+ return remapNormalizedColumn(line, column, sourceMap);
2811
+ }
2812
+ function remapMdxErrorDetails(error, sourceMap) {
2813
+ if (error && typeof error === "object") {
2814
+ const value = error;
2815
+ if (typeof value.line === "number") {
2816
+ return {
2817
+ message: value.message ?? String(error),
2818
+ line: remapMdxLineNumber(value.line, sourceMap),
2819
+ column: remapMdxColumnNumber(value.line, value.column, sourceMap)
2820
+ };
2821
+ }
2822
+ const text = value.message ?? String(error);
2823
+ const match = text.match(/\((\d+):(\d+)/);
2824
+ if (match) {
2825
+ const line = Number(match[1]);
2826
+ const column = Number(match[2]);
2827
+ return {
2828
+ message: text,
2829
+ line: remapMdxLineNumber(line, sourceMap),
2830
+ column: remapMdxColumnNumber(line, column, sourceMap)
2831
+ };
2832
+ }
2833
+ return { message: text };
2834
+ }
2835
+ return { message: String(error) };
2836
+ }
2837
+
2838
+ // src/processor/index.ts
2839
+ import { parseMarkdownToDocument as parseMarkdownToDocument2 } from "@owomark/core";
2840
+
2841
+ // src/processor/canonical-mdast.ts
2842
+ import {
2843
+ CARDS_FAMILY_CUSTOM_BLOCK_KEY,
2844
+ isCardsFamilyAttributes,
2845
+ parseInlineSideAnnotationFromText,
2846
+ parseMarkdownToDocument,
2847
+ stripInlineSideAnnotationTail,
2848
+ stripSideContinuationTail
2849
+ } from "@owomark/core";
2850
+ function createInlineMathNode(value) {
2851
+ return {
2852
+ type: "inlineMath",
2853
+ value,
2854
+ data: {
2855
+ hName: "code",
2856
+ hProperties: { className: ["language-math", "math-inline"] },
2857
+ hChildren: [{ type: "text", value }]
2858
+ }
2859
+ };
2860
+ }
2861
+ function splitMixedDoubleDollarText(value) {
2862
+ const nodes = [];
2863
+ let cursor = 0;
2864
+ const re = /\$\$([^$\n]+)\$\$/g;
2865
+ let match;
2866
+ while ((match = re.exec(value)) != null) {
2867
+ if (match.index > cursor) {
2868
+ nodes.push({ type: "text", value: value.slice(cursor, match.index) });
2869
+ }
2870
+ nodes.push(createInlineMathNode(match[1]));
2871
+ cursor = match.index + match[0].length;
2872
+ }
2873
+ if (cursor < value.length) {
2874
+ nodes.push({ type: "text", value: value.slice(cursor) });
2875
+ }
2876
+ return nodes.length > 0 ? nodes : [{ type: "text", value }];
2877
+ }
2878
+ function countLines(raw) {
2879
+ return raw === "" ? 1 : raw.split("\n").length;
2880
+ }
2881
+ function createPosition(startLine, endLine, offset, raw, sourceMap) {
2882
+ const normalizedEndColumn = raw.length === 0 ? 1 : (raw.split("\n").at(-1)?.length ?? 0) + 1;
2883
+ const remappedStartLine = remapNormalizedLine(startLine, sourceMap) ?? startLine;
2884
+ const remappedEndLine = remapNormalizedLine(endLine, sourceMap) ?? endLine;
2885
+ const remappedStartColumn = remapNormalizedColumn(startLine, 1, sourceMap) ?? 1;
2886
+ const remappedEndColumn = remapNormalizedColumn(endLine, normalizedEndColumn, sourceMap) ?? normalizedEndColumn;
2887
+ return {
2888
+ start: {
2889
+ line: remappedStartLine,
2890
+ column: remappedStartColumn,
2891
+ offset
2892
+ },
2893
+ end: {
2894
+ line: remappedEndLine,
2895
+ column: remappedEndColumn,
2896
+ offset: offset + raw.length
2897
+ }
2898
+ };
2899
+ }
2900
+ function advanceState(state, raw, sourceMap) {
2901
+ const startLine = state.line;
2902
+ const endLine = startLine + countLines(raw) - 1;
2903
+ const position = createPosition(startLine, endLine, state.offset, raw, sourceMap);
2904
+ state.line = endLine + 1;
2905
+ state.offset += raw.length + 1;
2906
+ return position;
2907
+ }
2908
+ function updateContainerPosition(node, child) {
2909
+ if (!child.position) {
2910
+ return;
2911
+ }
2912
+ if (!node.position) {
2913
+ node.position = {
2914
+ start: { ...child.position.start },
2915
+ end: { ...child.position.end }
2916
+ };
2917
+ return;
2918
+ }
2919
+ node.position.end = { ...child.position.end };
2920
+ }
2921
+ function appendChild(parent, child) {
2922
+ parent.children ??= [];
2923
+ parent.children.push(child);
2924
+ updateContainerPosition(parent, child);
2925
+ }
2926
+ function frameKey(frame) {
2927
+ return `${frame.kind}:${frame.depth}`;
2928
+ }
2929
+ function ancestryKey(frames) {
2930
+ return frames.map(frameKey).join("/");
2931
+ }
2932
+ function parseDirectiveAttributes(raw) {
2933
+ const attributes = {};
2934
+ const match = raw.match(/\{([^}]*)\}\s*$/);
2935
+ if (!match) {
2936
+ return attributes;
2937
+ }
2938
+ const content = match[1].trim();
2939
+ if (!content) {
2940
+ return attributes;
2941
+ }
2942
+ const attrRe = /([A-Za-z0-9_-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s]+))/g;
2943
+ let attrMatch;
2944
+ while ((attrMatch = attrRe.exec(content)) != null) {
2945
+ attributes[attrMatch[1]] = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? "";
2946
+ }
2947
+ return attributes;
2948
+ }
2949
+ function parseFenceMeta(block) {
2950
+ const opener = block.syntaxRaw.split("\n")[0] ?? "";
2951
+ const match = opener.match(/^[`~]{3,}([^\s]*)\s*(.*)$/);
2952
+ if (!match) {
2953
+ return null;
2954
+ }
2955
+ const meta = match[2]?.trim() ?? "";
2956
+ return meta.length > 0 ? meta : null;
2957
+ }
2958
+ function inlineToMdast(nodes, options) {
2959
+ return nodes.flatMap((node) => {
2960
+ switch (node.kind) {
2961
+ case "text":
2962
+ return options.enableMath === false ? [{ type: "text", value: node.text }] : splitMixedDoubleDollarText(node.text);
2963
+ case "strong":
2964
+ return [{ type: "strong", children: inlineToMdast(node.children, options) }];
2965
+ case "emphasis":
2966
+ return [{ type: "emphasis", children: inlineToMdast(node.children, options) }];
2967
+ case "delete":
2968
+ return [{ type: "delete", children: inlineToMdast(node.children, options) }];
2969
+ case "inlineCode":
2970
+ return [{ type: "inlineCode", value: node.text }];
2971
+ case "inlineMath":
2972
+ return options.enableMath === false ? [{ type: "text", value: `$${node.text}$` }] : [createInlineMathNode(node.text)];
2973
+ case "html":
2974
+ return [{ type: "html", value: node.text }];
2975
+ case "link":
2976
+ return [{ type: "link", url: node.url, children: inlineToMdast(node.children, options) }];
2977
+ case "image":
2978
+ return [{
2979
+ type: "image",
2980
+ url: node.url,
2981
+ alt: node.alt.map((child) => child.kind === "text" ? child.text : "").join("")
2982
+ }];
2983
+ }
2984
+ });
2985
+ }
2986
+ function inlineFromParagraphSource(source, options) {
2987
+ const document = parseMarkdownToDocument(source);
2988
+ const paragraph = document.conformance.blocks.find((block) => block.kind === "paragraph");
2989
+ return paragraph?.kind === "paragraph" ? inlineToMdast(paragraph.inline, options) : [{ type: "text", value: source }];
2990
+ }
2991
+ function attachBlockToParent(parent, blockNode) {
2992
+ appendChild(parent, blockNode);
2993
+ }
2994
+ function createSideAnnotationNode(block, position, options) {
2995
+ const strippedInlineMarkdown = block.raw.split("\n").map((line) => {
2996
+ if (parseInlineSideAnnotationFromText(line)) {
2997
+ return stripInlineSideAnnotationTail(line);
2998
+ }
2999
+ if (line.includes("(>+)")) {
3000
+ return stripSideContinuationTail(line);
3001
+ }
3002
+ return line;
3003
+ }).join("\n");
3004
+ const memberMarkdown = block.sideAnnotationKind === "inline" || block.sideAnnotationKind === "continuation-chain" ? strippedInlineMarkdown : block.members.map((member) => member.syntaxRaw).join("\n\n");
3005
+ const children = block.sideAnnotationKind === "continuation-chain" ? [{
3006
+ type: "paragraph",
3007
+ children: strippedInlineMarkdown.split("\n").flatMap((line, index, lines) => {
3008
+ const lineChildren = inlineFromParagraphSource(line, options);
3009
+ if (index === lines.length - 1) {
3010
+ return lineChildren;
3011
+ }
3012
+ return [...lineChildren, { type: "break" }];
3013
+ })
3014
+ }] : block.sideAnnotationKind !== "container" && block.sideAnnotationKind !== "reference-container" && !strippedInlineMarkdown.includes("\n\n") ? [{
3015
+ type: "paragraph",
3016
+ children: strippedInlineMarkdown.split("\n").flatMap((line, index, lines) => {
3017
+ const lineChildren = inlineFromParagraphSource(line, options);
3018
+ if (index === lines.length - 1) {
3019
+ return lineChildren;
3020
+ }
3021
+ return [...lineChildren, { type: "break" }];
3022
+ })
3023
+ }] : buildRootFromDocument(parseMarkdownToDocument(memberMarkdown), options).children ?? [];
3024
+ return {
3025
+ type: "sideAnnotation",
3026
+ data: {
3027
+ hName: "div",
3028
+ hProperties: {
3029
+ className: [
3030
+ "side-annotation",
3031
+ `side-type-${block.sideType}`,
3032
+ ...block.orphan ? ["side-orphan"] : []
3033
+ ],
3034
+ "data-side-type": block.sideType,
3035
+ ...block.annotationText ? { "data-side-text": block.annotationText } : {},
3036
+ ...block.orphan ? { "data-side-orphan": "true" } : {}
3037
+ }
3038
+ },
3039
+ sideType: block.sideType,
3040
+ sideTypeSymbol: block.sideTypeSymbol,
3041
+ noteRef: block.noteRef ?? null,
3042
+ inlineText: block.annotationText ?? null,
3043
+ orphan: block.orphan ?? false,
3044
+ position,
3045
+ children
3046
+ };
3047
+ }
3048
+ function createDirectiveContainerNode(block, position, options) {
3049
+ const lines = block.syntaxRaw.split("\n");
3050
+ const opener = lines[0] ?? "";
3051
+ const innerMarkdown = lines.slice(1, -1).join("\n");
3052
+ return {
3053
+ type: "containerDirective",
3054
+ name: block.directiveName,
3055
+ attributes: parseDirectiveAttributes(opener),
3056
+ position,
3057
+ children: buildRootFromDocument(parseMarkdownToDocument(innerMarkdown), options).children ?? []
3058
+ };
3059
+ }
3060
+ function createCustomBlockNodes(block, position, options) {
3061
+ const cardsAttributes = isCardsFamilyAttributes(block.customBlockAttributes) ? block.customBlockAttributes : null;
3062
+ if (block.customBlockKey === CARDS_FAMILY_CUSTOM_BLOCK_KEY && cardsAttributes) {
3063
+ return [{
3064
+ type: "cardsContainer",
3065
+ position,
3066
+ data: {
3067
+ hName: "section",
3068
+ hProperties: {
3069
+ className: ["owo-cards"],
3070
+ "data-owo-cards": "",
3071
+ "data-owo-cards-cols": String(cardsAttributes.layout.cols)
3072
+ }
3073
+ },
3074
+ children: cardsAttributes.cards.map((card) => {
3075
+ const bodyRoot = buildRootFromDocument(parseMarkdownToDocument(card.bodyMarkdown), options);
3076
+ const children = [];
3077
+ if (card.title) {
3078
+ children.push({
3079
+ type: "cardsTitle",
3080
+ position,
3081
+ data: {
3082
+ hName: "header",
3083
+ hProperties: {
3084
+ className: ["owo-card-title"]
3085
+ }
3086
+ },
3087
+ children: [{ type: "text", value: card.title }]
3088
+ });
3089
+ }
3090
+ children.push({
3091
+ type: "cardsBody",
3092
+ position,
3093
+ data: {
3094
+ hName: "div",
3095
+ hProperties: {
3096
+ className: ["owo-card-body"]
3097
+ }
3098
+ },
3099
+ children: bodyRoot.children ?? []
3100
+ });
3101
+ return {
3102
+ type: "cardsItem",
3103
+ position,
3104
+ data: {
3105
+ hName: "article",
3106
+ hProperties: {
3107
+ className: ["owo-card", ...card.tone ? [`owo-card-tone-${card.tone}`] : []],
3108
+ "data-owo-card": "",
3109
+ ...card.tone ? { "data-owo-card-tone": card.tone } : {}
3110
+ }
3111
+ },
3112
+ children
3113
+ };
3114
+ })
3115
+ }];
3116
+ }
3117
+ switch (block.customBlockRuntime.processorFallback) {
3118
+ case "skip-block":
3119
+ return [];
3120
+ case "unwrap-children": {
3121
+ const innerMarkdown = block.syntaxRaw.split("\n").slice(1, -1).join("\n");
3122
+ if (!innerMarkdown.trim()) {
3123
+ return [];
3124
+ }
3125
+ return (buildRootFromDocument(parseMarkdownToDocument(innerMarkdown), options).children ?? []).map((child) => ({
3126
+ ...child,
3127
+ position: child.position ?? position
3128
+ }));
3129
+ }
3130
+ case "render-raw":
3131
+ default:
3132
+ return [{
3133
+ type: "paragraph",
3134
+ position,
3135
+ children: [{ type: "text", value: block.raw }]
3136
+ }];
3137
+ }
3138
+ }
3139
+ function buildLeafNode(block, position, options) {
3140
+ switch (block.type) {
3141
+ case "paragraph":
3142
+ return [{
3143
+ type: "paragraph",
3144
+ children: inlineToMdast(block.conformanceInline ?? [], options),
3145
+ position
3146
+ }];
3147
+ case "heading":
3148
+ return [{
3149
+ type: "heading",
3150
+ depth: block.headingLevel,
3151
+ children: inlineToMdast(block.conformanceInline ?? [], options),
3152
+ position
3153
+ }];
3154
+ case "code-fence":
3155
+ return [{
3156
+ type: "code",
3157
+ lang: block.language || null,
3158
+ meta: parseFenceMeta(block),
3159
+ value: block.syntaxRaw.split("\n").slice(1, -1).join("\n"),
3160
+ position
3161
+ }];
3162
+ case "math-block":
3163
+ if (options.enableMath === false) {
3164
+ return [{
3165
+ type: "paragraph",
3166
+ children: [{ type: "text", value: block.raw }],
3167
+ position
3168
+ }];
3169
+ }
3170
+ return [{
3171
+ type: "math",
3172
+ meta: null,
3173
+ value: block.syntaxRaw.includes("\n") ? block.syntaxRaw.split("\n").slice(1, -1).join("\n") : block.syntaxRaw.slice(2, -2),
3174
+ data: {
3175
+ hName: "pre",
3176
+ hChildren: [{
3177
+ type: "element",
3178
+ tagName: "code",
3179
+ properties: { className: ["language-math", "math-display"] },
3180
+ children: [{
3181
+ type: "text",
3182
+ value: block.syntaxRaw.includes("\n") ? block.syntaxRaw.split("\n").slice(1, -1).join("\n") : block.syntaxRaw.slice(2, -2)
3183
+ }]
3184
+ }]
3185
+ },
3186
+ position
3187
+ }];
3188
+ case "table":
3189
+ return block.conformanceTableNode != null ? [block.conformanceTableNode(position)] : [];
3190
+ case "html-block":
3191
+ return [{ type: "html", value: block.syntaxRaw, position }];
3192
+ case "thematic-break":
3193
+ return [{ type: "thematicBreak", position }];
3194
+ case "side-annotation":
3195
+ if (options.enableSideAnnotation === false) {
3196
+ return [{
3197
+ type: "paragraph",
3198
+ children: [{ type: "text", value: block.raw }],
3199
+ position
3200
+ }];
3201
+ }
3202
+ return [createSideAnnotationNode(block, position, options)];
3203
+ case "directive-container":
3204
+ if (options.enableComponents === false && block.directiveName !== "side") {
3205
+ return [{
3206
+ type: "paragraph",
3207
+ children: [{ type: "text", value: block.raw }],
3208
+ position
3209
+ }];
3210
+ }
3211
+ return [createDirectiveContainerNode(block, position, options)];
3212
+ case "custom-block":
3213
+ return createCustomBlockNodes(block, position, options);
3214
+ case "blockquote":
3215
+ return [{
3216
+ type: "paragraph",
3217
+ children: inlineToMdast(block.conformanceInline ?? [], options),
3218
+ position
3219
+ }];
3220
+ default:
3221
+ return [];
3222
+ }
3223
+ }
3224
+ function ensureListContext(stack, parent, kind, depth, ancestry) {
3225
+ const key = ancestryKey(ancestry);
3226
+ const existing = stack.find((entry) => entry.kind === kind && entry.depth === depth && entry.ancestryKey === key);
3227
+ if (existing) {
3228
+ return existing;
3229
+ }
3230
+ const node = {
3231
+ type: "list",
3232
+ ordered: kind === "ordered-list",
3233
+ children: []
3234
+ };
3235
+ appendChild(parent, node);
3236
+ const created = {
3237
+ kind,
3238
+ depth,
3239
+ ancestryKey: key,
3240
+ node,
3241
+ currentListItem: null
3242
+ };
3243
+ stack.push(created);
3244
+ return created;
3245
+ }
3246
+ function buildRootFromBlocks(blocks, options) {
3247
+ const root = { type: "root", children: [] };
3248
+ const state = { line: 1, offset: 0 };
3249
+ const listStack = [];
3250
+ const containerMap = /* @__PURE__ */ new Map([["", root]]);
3251
+ for (const rawBlock of blocks) {
3252
+ const position = advanceState(state, rawBlock.raw, options.sourceMap);
3253
+ const block = rawBlock;
3254
+ if (rawBlock.type === "paragraph" && rawBlock.raw.trim() === "") {
3255
+ continue;
3256
+ }
3257
+ const effectiveAncestry = rawBlock.type === "blockquote" ? [
3258
+ ...rawBlock.ancestry,
3259
+ ...Array.from({ length: rawBlock.depth }, (_, index) => ({
3260
+ kind: "blockquote",
3261
+ depth: index + 1
3262
+ }))
3263
+ ] : rawBlock.ancestry;
3264
+ let parent = root;
3265
+ let ancestryFrames = [];
3266
+ for (const frame of effectiveAncestry) {
3267
+ ancestryFrames = [...ancestryFrames, { kind: frame.kind, depth: frame.depth }];
3268
+ const key = ancestryKey(ancestryFrames);
3269
+ const cached = containerMap.get(key);
3270
+ if (cached) {
3271
+ parent = cached;
3272
+ continue;
3273
+ }
3274
+ let node;
3275
+ if (frame.kind === "blockquote") {
3276
+ node = { type: "blockquote", children: [] };
3277
+ } else if (frame.kind === "unordered-list" || frame.kind === "ordered-list") {
3278
+ node = { type: "list", ordered: frame.kind === "ordered-list", children: [] };
3279
+ } else {
3280
+ node = { type: "listItem", children: [] };
3281
+ }
3282
+ appendChild(parent, node);
3283
+ containerMap.set(key, node);
3284
+ parent = node;
3285
+ }
3286
+ if (rawBlock.type === "unordered-list" || rawBlock.type === "ordered-list") {
3287
+ const listContext = ensureListContext(listStack, parent, rawBlock.type, rawBlock.depth, rawBlock.ancestry);
3288
+ const listItem = { type: "listItem", children: [], position };
3289
+ appendChild(listContext.node, listItem);
3290
+ listContext.currentListItem = listItem;
3291
+ const paragraph = {
3292
+ type: "paragraph",
3293
+ children: inlineToMdast(block.conformanceInline ?? [], options),
3294
+ position
3295
+ };
3296
+ appendChild(listItem, paragraph);
3297
+ const syntheticFrames = [
3298
+ ...rawBlock.ancestry.map((frame) => ({ kind: frame.kind, depth: frame.depth })),
3299
+ { kind: rawBlock.type, depth: rawBlock.depth },
3300
+ { kind: "list-item", depth: rawBlock.depth }
3301
+ ];
3302
+ containerMap.set(ancestryKey(syntheticFrames), listItem);
3303
+ updateContainerPosition(listContext.node, listItem);
3304
+ continue;
3305
+ }
3306
+ for (const node of buildLeafNode(block, position, options)) {
3307
+ attachBlockToParent(parent, node);
3308
+ }
3309
+ }
3310
+ return root;
3311
+ }
3312
+ function buildRootFromDocument(document, options = {}) {
3313
+ const conformanceBlocks = [...document.conformance.blocks];
3314
+ function shiftConformanceForBlock(block) {
3315
+ if (block.type === "side-annotation" || block.type === "side-note-definition" || block.type === "directive-container" || block.type === "custom-block" || block.type === "reference-definition") {
3316
+ return null;
3317
+ }
3318
+ return conformanceBlocks.shift() ?? null;
3319
+ }
3320
+ const enrichedBlocks = document.blocks.map((block) => {
3321
+ const conformance = shiftConformanceForBlock(block);
3322
+ return {
3323
+ ...block,
3324
+ conformanceInline: conformance?.kind === "paragraph" || conformance?.kind === "heading" || conformance?.kind === "blockquote" || conformance?.kind === "listItem" ? conformance.inline : null,
3325
+ conformanceTableNode: conformance?.kind === "table" ? (position) => ({
3326
+ type: "table",
3327
+ children: conformance.rows.map((row) => ({
3328
+ type: "tableRow",
3329
+ children: row.cells.map((cell) => ({
3330
+ type: "tableCell",
3331
+ children: [{ type: "paragraph", children: inlineToMdast(cell.inline, options) }]
3332
+ }))
3333
+ })),
3334
+ position
3335
+ }) : null
3336
+ };
3337
+ });
3338
+ return buildRootFromBlocks(enrichedBlocks, options);
3339
+ }
3340
+
3341
+ // src/processor/mdx-execution-plan.ts
3342
+ function planMdxCompileExecution(options) {
3343
+ if (options.enableCodeHighlight !== false) {
3344
+ return {
3345
+ target: "main-thread",
3346
+ reason: "code-highlighting-not-worker-safe"
3347
+ };
3348
+ }
3349
+ if (options.extraRemarkPlugins?.length) {
3350
+ return {
3351
+ target: "main-thread",
3352
+ reason: "extra-remark-plugins-not-worker-safe"
3353
+ };
3354
+ }
3355
+ if (options.extraRehypePlugins?.length) {
3356
+ return {
3357
+ target: "main-thread",
3358
+ reason: "extra-rehype-plugins-not-worker-safe"
3359
+ };
3360
+ }
3361
+ if (options.extraRemarkDescriptors?.length && !allWorkerSafeBuiltinDescriptors(options.extraRemarkDescriptors)) {
3362
+ return {
3363
+ target: "main-thread",
3364
+ reason: "extra-remark-descriptors-not-worker-safe"
3365
+ };
3366
+ }
3367
+ if (options.extraRehypeDescriptors?.length && !allWorkerSafeBuiltinDescriptors(options.extraRehypeDescriptors)) {
3368
+ return {
3369
+ target: "main-thread",
3370
+ reason: "extra-rehype-descriptors-not-worker-safe"
3371
+ };
3372
+ }
3373
+ return {
3374
+ target: "worker",
3375
+ reason: "worker-safe"
3376
+ };
3377
+ }
3378
+
1511
3379
  // src/processor/index.ts
1512
3380
  var DEFAULT_CODE_THEME = "vitesse-light";
1513
3381
  function buildRemarkPlugins(options) {
@@ -1515,23 +3383,27 @@ function buildRemarkPlugins(options) {
1515
3383
  const enableSideAnnotation = options.enableSideAnnotation !== false;
1516
3384
  const enableMarkdownSandbox = options.enableMarkdownSandbox !== false;
1517
3385
  const plugins = [
1518
- remarkParse,
1519
- remarkGfm
3386
+ options.canonicalDocument == null ? remarkParse2 : createCanonicalDocumentParser(options.canonicalDocument, options),
3387
+ remarkGfm2
1520
3388
  ];
1521
3389
  if (enableMath) {
1522
- plugins.push(remarkMath);
3390
+ plugins.push(remarkMath2);
1523
3391
  plugins.push(remarkNormalizeStandaloneMath);
1524
3392
  }
1525
- plugins.push(remarkDirective);
3393
+ plugins.push(remarkDirective2);
3394
+ plugins.push([remarkOwoComponents, {
3395
+ enabled: options.enableComponents !== false
3396
+ }]);
1526
3397
  if (options.mode !== "preview") {
1527
3398
  if (enableSideAnnotation) {
1528
3399
  plugins.push(remarkMicromarkSideAnnotation);
1529
3400
  }
1530
- plugins.push(remarkMdx);
3401
+ plugins.push(remarkMdx2);
1531
3402
  }
1532
3403
  if (!options.preserveSoftLineBreaks) {
1533
3404
  plugins.push(remarkConvertSoftBreaksToHardBreaks);
1534
3405
  }
3406
+ plugins.push(remarkCodeBlockMetadata);
1535
3407
  if (enableSideAnnotation) {
1536
3408
  plugins.push(remarkSideAnnotation);
1537
3409
  }
@@ -1541,11 +3413,29 @@ function buildRemarkPlugins(options) {
1541
3413
  createProcessor: createOwoMarkProcessor
1542
3414
  }]);
1543
3415
  }
3416
+ if (options.sourceAnchors) {
3417
+ plugins.push([remarkMdxSourceLines, {
3418
+ sourceMap: options.mdxSourceMap
3419
+ }]);
3420
+ }
3421
+ if (options.extraRemarkDescriptors?.length) {
3422
+ plugins.push(...resolveDescriptors(options.extraRemarkDescriptors));
3423
+ }
1544
3424
  if (options.extraRemarkPlugins) {
1545
3425
  plugins.push(...options.extraRemarkPlugins);
1546
3426
  }
1547
3427
  return plugins;
1548
3428
  }
3429
+ function createCanonicalDocumentParser(document, options) {
3430
+ return function canonicalDocumentParser() {
3431
+ this.parser = () => buildRootFromDocument(document, {
3432
+ enableSideAnnotation: options.enableSideAnnotation,
3433
+ enableMath: options.enableMath,
3434
+ enableComponents: options.enableComponents,
3435
+ sourceMap: options.sourceMap
3436
+ });
3437
+ };
3438
+ }
1549
3439
  function buildRehypePlugins(options) {
1550
3440
  const enableMath = options.enableMath !== false;
1551
3441
  const enableSideAnnotation = options.enableSideAnnotation !== false;
@@ -1554,10 +3444,19 @@ function buildRehypePlugins(options) {
1554
3444
  if (enableMath) {
1555
3445
  plugins.push(rehypeKatex, rehypeMathDisplayFix);
1556
3446
  }
1557
- plugins.push(rehypeSlug, [rehypePrettyCode, { theme }]);
3447
+ plugins.push(rehypeSlug);
3448
+ if (options.enableCodeHighlight !== false) {
3449
+ plugins.push([rehypePrettyCode, { theme }]);
3450
+ }
1558
3451
  if (enableSideAnnotation) {
1559
3452
  plugins.push(rehypeSideAnnotation);
1560
3453
  }
3454
+ if (options.sourceAnchors) {
3455
+ plugins.push(rehypeSourceLines);
3456
+ }
3457
+ if (options.extraRehypeDescriptors?.length) {
3458
+ plugins.push(...resolveDescriptors(options.extraRehypeDescriptors));
3459
+ }
1561
3460
  if (options.extraRehypePlugins) {
1562
3461
  plugins.push(...options.extraRehypePlugins);
1563
3462
  }
@@ -1575,43 +3474,69 @@ function createOwoMarkProcessor(options) {
1575
3474
  return createUnifiedProcessor(opts);
1576
3475
  }
1577
3476
  function createUnifiedProcessor(opts) {
1578
- const remarkPlugins = buildRemarkPlugins(opts);
1579
3477
  const rehypePlugins = buildRehypePlugins(opts);
1580
- let proc = unified();
1581
- for (const plugin of remarkPlugins) {
1582
- proc = applyPlugin(proc, plugin);
1583
- }
1584
- proc = proc.use(remarkRehype, {
1585
- handlers: {
1586
- markdownSandbox: markdownSandboxHandler
1587
- }
1588
- });
1589
- for (const plugin of rehypePlugins) {
1590
- proc = applyPlugin(proc, plugin);
1591
- }
1592
- proc = proc.use(rehypeStringify, { allowDangerousHtml: true });
1593
3478
  return {
1594
3479
  async process(source) {
1595
- const result = await proc.process(source);
3480
+ const normalized = normalizeOwoMarkSource(source, { enableMath: opts.enableMath });
3481
+ const canonicalDocument = opts.canonicalDocument ?? parseMarkdownToDocument2(normalized.source);
3482
+ const remarkPlugins = buildRemarkPlugins({
3483
+ ...opts,
3484
+ canonicalDocument,
3485
+ sourceMap: normalized.sourceMap
3486
+ });
3487
+ let runtimeProc = unified2();
3488
+ for (const plugin of remarkPlugins) {
3489
+ runtimeProc = applyPlugin2(runtimeProc, plugin);
3490
+ }
3491
+ runtimeProc = runtimeProc.use(remarkRehype, {
3492
+ handlers: {
3493
+ markdownSandbox: markdownSandboxHandler,
3494
+ owoComponentRendered: owoComponentRenderedHandler
3495
+ }
3496
+ });
3497
+ for (const plugin of rehypePlugins) {
3498
+ runtimeProc = applyPlugin2(runtimeProc, plugin);
3499
+ }
3500
+ runtimeProc = runtimeProc.use(rehypeStringify, { allowDangerousHtml: true });
3501
+ const result = await runtimeProc.process(normalized.source);
1596
3502
  return { value: String(result), toString: () => String(result) };
1597
3503
  }
1598
3504
  };
1599
3505
  }
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
3506
  function createMdxProcessor(opts) {
1613
- const { remarkPlugins, rehypePlugins } = getOwoMarkPlugins({ ...opts, mode: "production" });
1614
3507
  const registeredComponents = { ...DEFAULT_MDX_COMPONENTS, ...opts.mdxComponents };
3508
+ const createMissingComponent = (componentName) => (props) => {
3509
+ const { children, ...restProps } = props;
3510
+ return _react.createElement("div", { "data-mdx-missing": componentName, ...restProps }, children);
3511
+ };
3512
+ function registerMissingComponentPath(componentMap, componentName) {
3513
+ const parts = componentName.split(".");
3514
+ let cursor = componentMap;
3515
+ let inserted = false;
3516
+ for (let index = 0; index < parts.length; index += 1) {
3517
+ const part = parts[index];
3518
+ const isLeaf = index === parts.length - 1;
3519
+ const existing = cursor[part];
3520
+ if (isLeaf) {
3521
+ if (existing === void 0) {
3522
+ cursor[part] = createMissingComponent(componentName);
3523
+ inserted = true;
3524
+ }
3525
+ return inserted;
3526
+ }
3527
+ if (existing == null) {
3528
+ cursor[part] = {};
3529
+ inserted = true;
3530
+ cursor = cursor[part];
3531
+ continue;
3532
+ }
3533
+ if (typeof existing === "function") {
3534
+ return inserted;
3535
+ }
3536
+ cursor = existing;
3537
+ }
3538
+ return inserted;
3539
+ }
1615
3540
  let _evaluate;
1616
3541
  let _renderToStaticMarkup;
1617
3542
  let _jsxRuntime;
@@ -1633,19 +3558,33 @@ function createMdxProcessor(opts) {
1633
3558
  return {
1634
3559
  async process(source) {
1635
3560
  await ensureImports();
1636
- const usedNames = extractComponentNames(source);
3561
+ const inspection = inspectMdxSource(source, {
3562
+ enableMath: opts.enableMath,
3563
+ enableSideAnnotation: opts.enableSideAnnotation,
3564
+ extraRemarkDescriptors: opts.extraRemarkDescriptors,
3565
+ extraRemarkPlugins: opts.extraRemarkPlugins
3566
+ });
3567
+ const { remarkPlugins, rehypePlugins } = getOwoMarkPlugins({
3568
+ ...opts,
3569
+ mode: "production",
3570
+ mdxSourceMap: inspection.sourceMap
3571
+ });
1637
3572
  const componentMap = { ...registeredComponents };
1638
- for (const name of usedNames) {
1639
- if (!(name in componentMap)) {
3573
+ for (const name of inspection.componentNames) {
3574
+ if (registerMissingComponentPath(componentMap, name)) {
1640
3575
  console.warn(`[owomark-mdx] Unregistered MDX component: <${name}>`);
1641
- componentMap[name] = (props) => _react.createElement("div", { "data-mdx-missing": name }, props.children);
1642
3576
  }
1643
3577
  }
1644
- const { default: Content } = await _evaluate(source, {
1645
- ..._jsxRuntime,
1646
- remarkPlugins,
1647
- rehypePlugins
1648
- });
3578
+ let Content;
3579
+ try {
3580
+ ({ default: Content } = await _evaluate(inspection.compileSource, {
3581
+ ..._jsxRuntime,
3582
+ remarkPlugins,
3583
+ rehypePlugins
3584
+ }));
3585
+ } catch (error) {
3586
+ throw remapMdxErrorDetails(error, inspection.sourceMap);
3587
+ }
1649
3588
  const html = _renderToStaticMarkup(
1650
3589
  _react.createElement(Content, { components: componentMap })
1651
3590
  );
@@ -1653,14 +3592,14 @@ function createMdxProcessor(opts) {
1653
3592
  }
1654
3593
  };
1655
3594
  }
1656
- function applyPlugin(proc, entry) {
3595
+ function applyPlugin2(proc, entry) {
1657
3596
  if (Array.isArray(entry)) {
1658
3597
  const [plugin, ...args] = entry;
1659
3598
  return proc.use(plugin, ...args);
1660
3599
  }
1661
3600
  return proc.use(entry);
1662
3601
  }
1663
- var MDX_MANAGED_REMARK_PLUGINS = /* @__PURE__ */ new Set([remarkParse, remarkMdx]);
3602
+ var MDX_MANAGED_REMARK_PLUGINS = /* @__PURE__ */ new Set([remarkParse2, remarkMdx2]);
1664
3603
  function getOwoMarkPlugins(options) {
1665
3604
  const opts = {
1666
3605
  mode: "production",
@@ -1674,20 +3613,41 @@ function getOwoMarkPlugins(options) {
1674
3613
  return { remarkPlugins, rehypePlugins };
1675
3614
  }
1676
3615
  export {
3616
+ COMPONENT_REGISTRY,
1677
3617
  Callout,
1678
3618
  CodeDemo,
3619
+ CodeTab,
1679
3620
  DEFAULT_MDX_COMPONENTS,
3621
+ Details,
1680
3622
  FileTree,
1681
3623
  Kbd,
3624
+ LinkCard,
3625
+ Note,
1682
3626
  Step,
1683
3627
  Steps,
1684
3628
  Tab,
1685
3629
  Tabs,
3630
+ allBuiltinDescriptors,
3631
+ allWorkerSafeBuiltinDescriptors,
3632
+ analyzeMdxSyntax,
1686
3633
  createOwoMarkProcessor,
3634
+ detectMdxSyntax,
3635
+ getComponentEntry,
1687
3636
  getOwoMarkPlugins,
3637
+ inspectMdxSource,
3638
+ isKnownDirective,
3639
+ isWorkerSafeBuiltinDescriptor,
3640
+ owoComponentRenderedHandler,
3641
+ planMdxCompileExecution,
3642
+ registerPlugin,
1688
3643
  rehypeMathDisplayFix,
1689
3644
  rehypeSideAnnotation,
3645
+ rehypeSourceLines,
3646
+ remapMdxErrorDetails,
3647
+ remarkCodeBlockMetadata,
1690
3648
  remarkConvertSoftBreaksToHardBreaks,
1691
3649
  remarkMicromarkSideAnnotation,
1692
- remarkSideAnnotation
3650
+ remarkOwoComponents,
3651
+ remarkSideAnnotation,
3652
+ resolveDescriptors
1693
3653
  };