@changerawr/markdown 1.0.5 → 1.1.0

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.
@@ -1046,40 +1046,56 @@ var ChangerawrMarkdown = (() => {
1046
1046
  constructor(config) {
1047
1047
  this.rules = [];
1048
1048
  this.warnings = [];
1049
- this.config = config || {};
1049
+ this.config = __spreadValues({
1050
+ debugMode: false,
1051
+ maxIterations: 1e4,
1052
+ validateMarkdown: false
1053
+ }, config);
1050
1054
  }
1051
1055
  addRule(rule) {
1052
1056
  this.rules.push(rule);
1053
1057
  this.rules.sort((a, b) => {
1054
- if (a.name.includes("alert") || a.name.includes("embed") || a.name.includes("button")) return -1;
1055
- if (b.name.includes("alert") || b.name.includes("embed") || b.name.includes("button")) return 1;
1056
- if (a.name === "task-list") return -1;
1057
- if (b.name === "task-list") return 1;
1058
- if (a.name === "list" && b.name === "task-list") return 1;
1059
- if (b.name === "list" && a.name === "task-list") return -1;
1058
+ const aFeatureExtension = ["alert", "button", "embed"].includes(a.name);
1059
+ const bFeatureExtension = ["alert", "button", "embed"].includes(b.name);
1060
+ if (aFeatureExtension && !bFeatureExtension) return -1;
1061
+ if (!aFeatureExtension && bFeatureExtension) return 1;
1062
+ const aCoreExtension = ["text", "heading", "bold", "italic", "code", "codeblock", "link", "image", "list", "task-list", "blockquote", "hr", "paragraph", "line-break"].includes(a.name);
1063
+ const bCoreExtension = ["text", "heading", "bold", "italic", "code", "codeblock", "link", "image", "list", "task-list", "blockquote", "hr", "paragraph", "line-break"].includes(b.name);
1064
+ if (aCoreExtension && !bCoreExtension) return -1;
1065
+ if (!aCoreExtension && bCoreExtension) return 1;
1066
+ if (a.name === "image" && b.name === "link") return -1;
1067
+ if (a.name === "link" && b.name === "image") return 1;
1068
+ if (a.name === "task-item" && b.name === "list-item") return -1;
1069
+ if (a.name === "list-item" && b.name === "task-item") return 1;
1070
+ if (a.name === "codeblock" && b.name === "code") return -1;
1071
+ if (a.name === "code" && b.name === "codeblock") return 1;
1072
+ if (a.name === "bold" && b.name === "italic") return -1;
1073
+ if (a.name === "italic" && b.name === "bold") return 1;
1060
1074
  return a.name.localeCompare(b.name);
1061
1075
  });
1062
1076
  }
1063
- setupDefaultRulesIfEmpty() {
1064
- const hasDefaultRules = this.rules.some(
1065
- (rule) => !["alert", "button", "embed"].includes(rule.name)
1066
- );
1067
- if (!hasDefaultRules) {
1068
- this.setupDefaultRules();
1069
- }
1070
- }
1071
1077
  hasRule(name) {
1072
1078
  return this.rules.some((rule) => rule.name === name);
1073
1079
  }
1074
1080
  parse(markdown2) {
1075
1081
  var _a;
1076
1082
  this.warnings = [];
1077
- this.setupDefaultRulesIfEmpty();
1083
+ if (!markdown2.trim()) {
1084
+ return [];
1085
+ }
1086
+ if (this.rules.length === 0) {
1087
+ this.warnings.push("No parse rules registered - consider using CoreExtensions");
1088
+ return [{
1089
+ type: "text",
1090
+ content: markdown2,
1091
+ raw: markdown2
1092
+ }];
1093
+ }
1078
1094
  const processedMarkdown = this.preprocessMarkdown(markdown2);
1079
1095
  const tokens = [];
1080
1096
  let remaining = processedMarkdown;
1081
1097
  let iterationCount = 0;
1082
- const maxIterations = this.config.maxIterations || markdown2.length * 2;
1098
+ const maxIterations = this.config.maxIterations || 1e4;
1083
1099
  while (remaining.length > 0 && iterationCount < maxIterations) {
1084
1100
  iterationCount++;
1085
1101
  let matched = false;
@@ -1167,9 +1183,6 @@ var ChangerawrMarkdown = (() => {
1167
1183
  clearWarnings() {
1168
1184
  this.warnings = [];
1169
1185
  }
1170
- getIterationCount() {
1171
- return 0;
1172
- }
1173
1186
  preprocessMarkdown(markdown2) {
1174
1187
  if (this.config.validateMarkdown) {
1175
1188
  this.validateMarkdown(markdown2);
@@ -1224,164 +1237,6 @@ var ChangerawrMarkdown = (() => {
1224
1237
  }
1225
1238
  return processed;
1226
1239
  }
1227
- setupDefaultRules() {
1228
- this.addRule({
1229
- name: "heading",
1230
- pattern: /^(#{1,6})\s+(.+)$/m,
1231
- render: (match) => {
1232
- var _a, _b;
1233
- return {
1234
- type: "heading",
1235
- content: ((_a = match[2]) == null ? void 0 : _a.trim()) || "",
1236
- raw: match[0] || "",
1237
- attributes: {
1238
- level: String(((_b = match[1]) == null ? void 0 : _b.length) || 1)
1239
- }
1240
- };
1241
- }
1242
- });
1243
- this.addRule({
1244
- name: "codeblock",
1245
- pattern: /```(\w+)?\s*\n([\s\S]*?)\n```/,
1246
- render: (match) => ({
1247
- type: "codeblock",
1248
- content: match[2] || "",
1249
- raw: match[0] || "",
1250
- attributes: {
1251
- language: match[1] || "text"
1252
- }
1253
- })
1254
- });
1255
- this.addRule({
1256
- name: "hard-break-backslash",
1257
- pattern: /\\\s*\n/,
1258
- render: (match) => ({
1259
- type: "line-break",
1260
- content: "",
1261
- raw: match[0] || ""
1262
- })
1263
- });
1264
- this.addRule({
1265
- name: "hard-break-spaces",
1266
- pattern: / +\n/,
1267
- render: (match) => ({
1268
- type: "line-break",
1269
- content: "",
1270
- raw: match[0] || ""
1271
- })
1272
- });
1273
- this.addRule({
1274
- name: "paragraph-break",
1275
- pattern: /\n\s*\n/,
1276
- render: (match) => ({
1277
- type: "paragraph-break",
1278
- content: "",
1279
- raw: match[0] || ""
1280
- })
1281
- });
1282
- this.addRule({
1283
- name: "bold",
1284
- pattern: /\*\*((?:(?!\*\*).)+)\*\*/,
1285
- render: (match) => ({
1286
- type: "bold",
1287
- content: match[1] || "",
1288
- raw: match[0] || ""
1289
- })
1290
- });
1291
- this.addRule({
1292
- name: "italic",
1293
- pattern: /\*((?:(?!\*).)+)\*/,
1294
- render: (match) => ({
1295
- type: "italic",
1296
- content: match[1] || "",
1297
- raw: match[0] || ""
1298
- })
1299
- });
1300
- this.addRule({
1301
- name: "code",
1302
- pattern: /`([^`]+)`/,
1303
- render: (match) => ({
1304
- type: "code",
1305
- content: match[1] || "",
1306
- raw: match[0] || ""
1307
- })
1308
- });
1309
- this.addRule({
1310
- name: "image",
1311
- pattern: /!\[([^\]]*)\]\(([^)]+?)(?:\s+"([^"]+)")?\)/,
1312
- render: (match) => ({
1313
- type: "image",
1314
- content: match[1] || "",
1315
- raw: match[0] || "",
1316
- attributes: {
1317
- alt: match[1] || "",
1318
- src: match[2] || "",
1319
- title: match[3] || ""
1320
- }
1321
- })
1322
- });
1323
- this.addRule({
1324
- name: "link",
1325
- pattern: /\[([^\]]+)\]\(([^)]+)\)/,
1326
- render: (match) => ({
1327
- type: "link",
1328
- content: match[1] || "",
1329
- raw: match[0] || "",
1330
- attributes: {
1331
- href: match[2] || ""
1332
- }
1333
- })
1334
- });
1335
- this.addRule({
1336
- name: "task-list",
1337
- pattern: /^(\s*)-\s*\[([ xX])\]\s*(.+)$/m,
1338
- render: (match) => ({
1339
- type: "task-item",
1340
- content: match[3] || "",
1341
- raw: match[0] || "",
1342
- attributes: {
1343
- checked: String((match[2] || "").toLowerCase() === "x")
1344
- }
1345
- })
1346
- });
1347
- this.addRule({
1348
- name: "list",
1349
- pattern: /^(\s*)[-*+]\s+(.+)$/m,
1350
- render: (match) => ({
1351
- type: "list-item",
1352
- content: match[2] || "",
1353
- raw: match[0] || ""
1354
- })
1355
- });
1356
- this.addRule({
1357
- name: "blockquote",
1358
- pattern: /^>\s+(.+)$/m,
1359
- render: (match) => ({
1360
- type: "blockquote",
1361
- content: match[1] || "",
1362
- raw: match[0] || ""
1363
- })
1364
- });
1365
- this.addRule({
1366
- name: "hr",
1367
- pattern: /^---$/m,
1368
- render: (match) => ({
1369
- type: "hr",
1370
- content: "",
1371
- raw: match[0] || ""
1372
- })
1373
- });
1374
- this.addRule({
1375
- name: "soft-break",
1376
- pattern: /\n/,
1377
- render: (match) => ({
1378
- type: "soft-break",
1379
- content: " ",
1380
- // Convert to space for inline text
1381
- raw: match[0] || ""
1382
- })
1383
- });
1384
- }
1385
1240
  };
1386
1241
 
1387
1242
  // src/utils.ts
@@ -1619,7 +1474,6 @@ var ChangerawrMarkdown = (() => {
1619
1474
  allowUnsafeHtml: false,
1620
1475
  debugMode: false
1621
1476
  }, config);
1622
- this.setupDefaultRules();
1623
1477
  }
1624
1478
  addRule(rule) {
1625
1479
  this.rules.set(rule.type, rule);
@@ -1629,28 +1483,18 @@ var ChangerawrMarkdown = (() => {
1629
1483
  }
1630
1484
  render(tokens) {
1631
1485
  this.warnings = [];
1632
- const htmlParts = tokens.map((token) => this.renderToken(token));
1486
+ const tokensWithFormat = tokens.map((token) => __spreadProps(__spreadValues({}, token), {
1487
+ attributes: __spreadProps(__spreadValues({}, token.attributes), {
1488
+ format: this.config.format
1489
+ })
1490
+ }));
1491
+ const htmlParts = tokensWithFormat.map((token) => this.renderToken(token));
1633
1492
  const combinedHtml = htmlParts.join("");
1634
1493
  if (this.config.sanitize && !this.config.allowUnsafeHtml) {
1635
1494
  return sanitizeHtml(combinedHtml);
1636
1495
  }
1637
1496
  return combinedHtml;
1638
1497
  }
1639
- getWarnings() {
1640
- return [...this.warnings];
1641
- }
1642
- getConfig() {
1643
- return __spreadValues({}, this.config);
1644
- }
1645
- updateConfig(config) {
1646
- this.config = __spreadValues(__spreadValues({}, this.config), config);
1647
- }
1648
- setDebugMode(enabled) {
1649
- this.config.debugMode = enabled;
1650
- }
1651
- clearWarnings() {
1652
- this.warnings = [];
1653
- }
1654
1498
  renderToken(token) {
1655
1499
  const rule = this.rules.get(token.type);
1656
1500
  if (rule) {
@@ -1662,9 +1506,6 @@ var ChangerawrMarkdown = (() => {
1662
1506
  return this.createErrorBlock(`Render error for ${token.type}: ${errorMessage}`);
1663
1507
  }
1664
1508
  }
1665
- if (token.type === "text") {
1666
- return escapeHtml(token.content || token.raw || "");
1667
- }
1668
1509
  if (this.config.debugMode) {
1669
1510
  return this.createDebugBlock(token);
1670
1511
  }
@@ -1692,16 +1533,243 @@ var ChangerawrMarkdown = (() => {
1692
1533
  <strong>Content:</strong> ${escapeHtml(token.content || token.raw || "")}
1693
1534
  </div>`;
1694
1535
  }
1695
- setupDefaultRules() {
1696
- this.addRule({
1536
+ getWarnings() {
1537
+ return [...this.warnings];
1538
+ }
1539
+ getConfig() {
1540
+ return __spreadValues({}, this.config);
1541
+ }
1542
+ updateConfig(config) {
1543
+ this.config = __spreadValues(__spreadValues({}, this.config), config);
1544
+ }
1545
+ setDebugMode(enabled) {
1546
+ this.config.debugMode = enabled;
1547
+ }
1548
+ clearWarnings() {
1549
+ this.warnings = [];
1550
+ }
1551
+ };
1552
+
1553
+ // src/extensions/core/blockquote.ts
1554
+ var BlockquoteExtension = {
1555
+ name: "blockquote",
1556
+ parseRules: [
1557
+ {
1558
+ name: "blockquote",
1559
+ pattern: /^>\s+(.+)$/m,
1560
+ render: (match) => ({
1561
+ type: "blockquote",
1562
+ content: match[1] || "",
1563
+ raw: match[0] || ""
1564
+ })
1565
+ }
1566
+ ],
1567
+ renderRules: [
1568
+ {
1569
+ type: "blockquote",
1570
+ render: (token) => {
1571
+ var _a;
1572
+ const content = escapeHtml(token.content);
1573
+ const format = ((_a = token.attributes) == null ? void 0 : _a.format) || "html";
1574
+ if (format === "html") {
1575
+ return `<blockquote style="border-left: 2px solid #d1d5db; padding: 8px 0 8px 16px; margin: 16px 0; font-style: italic; color: #6b7280;">${content}</blockquote>`;
1576
+ }
1577
+ return `<blockquote class="pl-4 py-2 border-l-2 border-border italic text-muted-foreground my-4">${content}</blockquote>`;
1578
+ }
1579
+ }
1580
+ ]
1581
+ };
1582
+
1583
+ // src/extensions/core/breaks.ts
1584
+ var LineBreakExtension = {
1585
+ name: "line-break",
1586
+ parseRules: [
1587
+ {
1588
+ name: "hard-break-backslash",
1589
+ pattern: /\\\s*\n/,
1590
+ render: (match) => ({
1591
+ type: "line-break",
1592
+ content: "",
1593
+ raw: match[0] || ""
1594
+ })
1595
+ },
1596
+ {
1597
+ name: "hard-break-spaces",
1598
+ pattern: / +\n/,
1599
+ render: (match) => ({
1600
+ type: "line-break",
1601
+ content: "",
1602
+ raw: match[0] || ""
1603
+ })
1604
+ }
1605
+ ],
1606
+ renderRules: [
1607
+ {
1608
+ type: "line-break",
1609
+ render: () => "<br>"
1610
+ },
1611
+ {
1612
+ type: "paragraph-break",
1613
+ render: () => "</p><p>"
1614
+ },
1615
+ {
1616
+ type: "soft-break",
1617
+ render: (token) => token.content || " "
1618
+ }
1619
+ ]
1620
+ };
1621
+
1622
+ // src/extensions/core/code.ts
1623
+ var InlineCodeExtension = {
1624
+ name: "inline-code",
1625
+ parseRules: [
1626
+ {
1627
+ name: "code",
1628
+ pattern: /`([^`]+)`/,
1629
+ render: (match) => ({
1630
+ type: "code",
1631
+ content: match[1] || "",
1632
+ raw: match[0] || ""
1633
+ })
1634
+ }
1635
+ ],
1636
+ renderRules: [
1637
+ {
1638
+ type: "code",
1639
+ render: (token) => {
1640
+ var _a;
1641
+ const content = escapeHtml(token.content);
1642
+ const format = (_a = token.attributes) == null ? void 0 : _a.format;
1643
+ if (format === "html") {
1644
+ return `<code style="background-color: #f3f4f6; padding: 2px 6px; border-radius: 4px; font-family: monospace; font-size: 0.875rem;">${content}</code>`;
1645
+ }
1646
+ return `<code class="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">${content}</code>`;
1647
+ }
1648
+ }
1649
+ ]
1650
+ };
1651
+ var CodeBlockExtension = {
1652
+ name: "codeblock",
1653
+ parseRules: [
1654
+ {
1655
+ name: "codeblock",
1656
+ pattern: /```(\w+)?\s*\n([\s\S]*?)\n```/,
1657
+ render: (match) => ({
1658
+ type: "codeblock",
1659
+ content: match[2] || "",
1660
+ raw: match[0] || "",
1661
+ attributes: {
1662
+ language: match[1] || "text"
1663
+ }
1664
+ })
1665
+ }
1666
+ ],
1667
+ renderRules: [
1668
+ {
1669
+ type: "codeblock",
1670
+ render: (token) => {
1671
+ var _a, _b;
1672
+ const language = ((_a = token.attributes) == null ? void 0 : _a.language) || "text";
1673
+ const escapedCode = escapeHtml(token.content);
1674
+ const format = ((_b = token.attributes) == null ? void 0 : _b.format) || "html";
1675
+ if (format === "html") {
1676
+ return `<pre style="background-color: #f3f4f6; padding: 16px; border-radius: 6px; overflow-x: auto; margin: 16px 0;"><code class="language-${escapeHtml(language)}">${escapedCode}</code></pre>`;
1677
+ }
1678
+ return `<pre class="bg-muted p-4 rounded-md overflow-x-auto my-4"><code class="language-${escapeHtml(language)}">${escapedCode}</code></pre>`;
1679
+ }
1680
+ }
1681
+ ]
1682
+ };
1683
+
1684
+ // src/extensions/core/emphasis.ts
1685
+ var BoldExtension = {
1686
+ name: "bold",
1687
+ parseRules: [
1688
+ {
1689
+ name: "bold",
1690
+ pattern: /\*\*((?:(?!\*\*).)+)\*\*/,
1691
+ render: (match) => ({
1692
+ type: "bold",
1693
+ content: match[1] || "",
1694
+ raw: match[0] || ""
1695
+ })
1696
+ }
1697
+ ],
1698
+ renderRules: [
1699
+ {
1700
+ type: "bold",
1701
+ render: (token) => {
1702
+ var _a;
1703
+ const content = escapeHtml(token.content);
1704
+ const format = (_a = token.attributes) == null ? void 0 : _a.format;
1705
+ if (format === "html") {
1706
+ return `<strong>${content}</strong>`;
1707
+ }
1708
+ return `<strong class="font-bold">${content}</strong>`;
1709
+ }
1710
+ }
1711
+ ]
1712
+ };
1713
+ var ItalicExtension = {
1714
+ name: "italic",
1715
+ parseRules: [
1716
+ {
1717
+ name: "italic",
1718
+ pattern: /\*((?:(?!\*).)+)\*/,
1719
+ render: (match) => ({
1720
+ type: "italic",
1721
+ content: match[1] || "",
1722
+ raw: match[0] || ""
1723
+ })
1724
+ }
1725
+ ],
1726
+ renderRules: [
1727
+ {
1728
+ type: "italic",
1729
+ render: (token) => {
1730
+ var _a;
1731
+ const content = escapeHtml(token.content);
1732
+ const format = (_a = token.attributes) == null ? void 0 : _a.format;
1733
+ if (format === "html") {
1734
+ return `<em>${content}</em>`;
1735
+ }
1736
+ return `<em class="italic">${content}</em>`;
1737
+ }
1738
+ }
1739
+ ]
1740
+ };
1741
+
1742
+ // src/extensions/core/heading.ts
1743
+ var HeadingExtension = {
1744
+ name: "heading",
1745
+ parseRules: [
1746
+ {
1747
+ name: "heading",
1748
+ pattern: /^(#{1,6})\s+(.+)$/m,
1749
+ render: (match) => {
1750
+ var _a, _b;
1751
+ return {
1752
+ type: "heading",
1753
+ content: ((_a = match[2]) == null ? void 0 : _a.trim()) || "",
1754
+ raw: match[0] || "",
1755
+ attributes: {
1756
+ level: String(((_b = match[1]) == null ? void 0 : _b.length) || 1)
1757
+ }
1758
+ };
1759
+ }
1760
+ }
1761
+ ],
1762
+ renderRules: [
1763
+ {
1697
1764
  type: "heading",
1698
1765
  render: (token) => {
1699
- var _a;
1766
+ var _a, _b;
1700
1767
  const level = parseInt(((_a = token.attributes) == null ? void 0 : _a.level) || "1");
1701
1768
  const text2 = token.content;
1702
1769
  const id = generateId(text2);
1703
1770
  const escapedContent = escapeHtml(text2);
1704
- if (this.config.format === "html") {
1771
+ const format = ((_b = token.attributes) == null ? void 0 : _b.format) || "html";
1772
+ if (format === "html") {
1705
1773
  return `<h${level} id="${id}">${escapedContent}</h${level}>`;
1706
1774
  }
1707
1775
  let headingClasses = "group relative flex items-center gap-2";
@@ -1728,63 +1796,111 @@ var ChangerawrMarkdown = (() => {
1728
1796
  return `<h${level} id="${id}" class="${headingClasses}">
1729
1797
  ${escapedContent}
1730
1798
  <a href="#${id}" class="opacity-0 group-hover:opacity-100 text-muted-foreground transition-opacity">
1731
- <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
1732
- <path d="M7.5 4H5.75A3.75 3.75 0 002 7.75v.5a3.75 3.75 0 003.75 3.75h1.5m-1.5-4h3m1.5-4h1.75A3.75 3.75 0 0114 7.75v.5a3.75 3.75 0 01-3.75 3.75H8.5"/>
1733
- </svg>
1799
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1800
+ <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
1801
+ <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
1802
+ </svg>
1734
1803
  </a>
1735
1804
  </h${level}>`;
1736
1805
  }
1737
- });
1738
- this.addRule({
1739
- type: "bold",
1806
+ }
1807
+ ]
1808
+ };
1809
+
1810
+ // src/extensions/core/hr.ts
1811
+ var HorizontalRuleExtension = {
1812
+ name: "hr",
1813
+ parseRules: [
1814
+ {
1815
+ name: "hr",
1816
+ pattern: /^---$/m,
1817
+ render: (match) => ({
1818
+ type: "hr",
1819
+ content: "",
1820
+ raw: match[0] || ""
1821
+ })
1822
+ }
1823
+ ],
1824
+ renderRules: [
1825
+ {
1826
+ type: "hr",
1740
1827
  render: (token) => {
1741
- const content = escapeHtml(token.content);
1742
- if (this.config.format === "html") {
1743
- return `<strong>${content}</strong>`;
1828
+ var _a;
1829
+ const format = (_a = token.attributes) == null ? void 0 : _a.format;
1830
+ if (format === "html") {
1831
+ return '<hr style="margin: 24px 0; border: none; border-top: 1px solid #d1d5db;">';
1744
1832
  }
1745
- return `<strong class="font-bold">${content}</strong>`;
1833
+ return '<hr class="my-6 border-t border-border">';
1746
1834
  }
1747
- });
1748
- this.addRule({
1749
- type: "italic",
1750
- render: (token) => {
1751
- const content = escapeHtml(token.content);
1752
- if (this.config.format === "html") {
1753
- return `<em>${content}</em>`;
1835
+ }
1836
+ ]
1837
+ };
1838
+
1839
+ // src/extensions/core/image.ts
1840
+ var ImageExtension = {
1841
+ name: "image",
1842
+ parseRules: [
1843
+ {
1844
+ name: "image",
1845
+ pattern: /!\[([^\]]*)\]\(([^)]+?)(?:\s+"([^"]+)")?\)/,
1846
+ render: (match) => ({
1847
+ type: "image",
1848
+ content: match[1] || "",
1849
+ raw: match[0] || "",
1850
+ attributes: {
1851
+ alt: match[1] || "",
1852
+ src: match[2] || "",
1853
+ title: match[3] || ""
1754
1854
  }
1755
- return `<em class="italic">${content}</em>`;
1756
- }
1757
- });
1758
- this.addRule({
1759
- type: "code",
1855
+ })
1856
+ }
1857
+ ],
1858
+ renderRules: [
1859
+ {
1860
+ type: "image",
1760
1861
  render: (token) => {
1761
- const content = escapeHtml(token.content);
1762
- if (this.config.format === "html") {
1763
- return `<code style="background-color: #f3f4f6; padding: 2px 6px; border-radius: 4px; font-family: monospace; font-size: 0.875rem;">${content}</code>`;
1862
+ var _a, _b, _c, _d;
1863
+ const src = ((_a = token.attributes) == null ? void 0 : _a.src) || "";
1864
+ const alt = ((_b = token.attributes) == null ? void 0 : _b.alt) || "";
1865
+ const title = ((_c = token.attributes) == null ? void 0 : _c.title) || "";
1866
+ const titleAttr = title ? ` title="${escapeHtml(title)}"` : "";
1867
+ const format = ((_d = token.attributes) == null ? void 0 : _d.format) || "html";
1868
+ if (format === "html") {
1869
+ return `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}"${titleAttr} style="max-width: 100%; height: auto; border-radius: 8px; margin: 16px 0;" loading="lazy" />`;
1764
1870
  }
1765
- return `<code class="bg-muted px-1.5 py-0.5 rounded text-sm font-mono">${content}</code>`;
1871
+ return `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}"${titleAttr} class="max-w-full h-auto rounded-lg my-4" loading="lazy" />`;
1766
1872
  }
1767
- });
1768
- this.addRule({
1769
- type: "codeblock",
1770
- render: (token) => {
1771
- var _a;
1772
- const language = ((_a = token.attributes) == null ? void 0 : _a.language) || "text";
1773
- const escapedCode = escapeHtml(token.content);
1774
- if (this.config.format === "html") {
1775
- return `<pre style="background-color: #f3f4f6; padding: 16px; border-radius: 6px; overflow-x: auto; margin: 16px 0;"><code class="language-${escapeHtml(language)}">${escapedCode}</code></pre>`;
1873
+ }
1874
+ ]
1875
+ };
1876
+
1877
+ // src/extensions/core/links.ts
1878
+ var LinkExtension = {
1879
+ name: "link",
1880
+ parseRules: [
1881
+ {
1882
+ name: "link",
1883
+ pattern: /\[(?!(?:button|embed):)([^\]]+)\]\(([^)]+)\)/,
1884
+ render: (match) => ({
1885
+ type: "link",
1886
+ content: match[1] || "",
1887
+ raw: match[0] || "",
1888
+ attributes: {
1889
+ href: match[2] || ""
1776
1890
  }
1777
- return `<pre class="bg-muted p-4 rounded-md overflow-x-auto my-4"><code class="language-${escapeHtml(language)}">${escapedCode}</code></pre>`;
1778
- }
1779
- });
1780
- this.addRule({
1891
+ })
1892
+ }
1893
+ ],
1894
+ renderRules: [
1895
+ {
1781
1896
  type: "link",
1782
1897
  render: (token) => {
1783
- var _a;
1898
+ var _a, _b;
1784
1899
  const href = ((_a = token.attributes) == null ? void 0 : _a.href) || "#";
1785
1900
  const escapedHref = escapeHtml(href);
1786
1901
  const escapedText = escapeHtml(token.content);
1787
- if (this.config.format === "html") {
1902
+ const format = ((_b = token.attributes) == null ? void 0 : _b.format) || "html";
1903
+ if (format === "html") {
1788
1904
  return `<a href="${escapedHref}" target="_blank" rel="noopener noreferrer">${escapedText}</a>`;
1789
1905
  }
1790
1906
  return `<a href="${escapedHref}" class="text-primary hover:underline inline-flex items-center gap-1" target="_blank" rel="noopener noreferrer">
@@ -1796,48 +1912,56 @@ var ChangerawrMarkdown = (() => {
1796
1912
  </svg>
1797
1913
  </a>`;
1798
1914
  }
1799
- });
1800
- this.addRule({
1915
+ }
1916
+ ]
1917
+ };
1918
+
1919
+ // src/extensions/core/lists.ts
1920
+ var ListExtension = {
1921
+ name: "list",
1922
+ parseRules: [
1923
+ {
1924
+ name: "list-item",
1925
+ pattern: /^(\s*)[-*+]\s+(.+)$/m,
1926
+ render: (match) => ({
1927
+ type: "list-item",
1928
+ content: match[2] || "",
1929
+ raw: match[0] || ""
1930
+ })
1931
+ }
1932
+ ],
1933
+ renderRules: [
1934
+ {
1801
1935
  type: "list-item",
1802
1936
  render: (token) => `<li>${escapeHtml(token.content)}</li>`
1803
- });
1804
- this.addRule({
1805
- type: "blockquote",
1806
- render: (token) => {
1807
- const content = escapeHtml(token.content);
1808
- if (this.config.format === "html") {
1809
- return `<blockquote style="border-left: 2px solid #d1d5db; padding: 8px 0 8px 16px; margin: 16px 0; font-style: italic; color: #6b7280;">${content}</blockquote>`;
1810
- }
1811
- return `<blockquote class="pl-4 py-2 border-l-2 border-border italic text-muted-foreground my-4">${content}</blockquote>`;
1812
- }
1813
- });
1814
- this.addRule({
1815
- type: "text",
1816
- render: (token) => {
1817
- if (!token.content) return "";
1818
- return escapeHtml(token.content);
1819
- }
1820
- });
1821
- this.addRule({
1822
- type: "paragraph",
1823
- render: (token) => {
1824
- if (!token.content) return "";
1825
- const content = token.content.trim();
1826
- if (!content) return "";
1827
- const processedContent = content.includes("<br>") ? content : escapeHtml(content);
1828
- if (this.config.format === "html") {
1829
- return `<p style="line-height: 1.75; margin-bottom: 16px;">${processedContent}</p>`;
1937
+ }
1938
+ ]
1939
+ };
1940
+ var TaskListExtension = {
1941
+ name: "task-list",
1942
+ parseRules: [
1943
+ {
1944
+ name: "task-item",
1945
+ pattern: /^(\s*)-\s*\[([ xX])\]\s*(.+)$/m,
1946
+ render: (match) => ({
1947
+ type: "task-item",
1948
+ content: match[3] || "",
1949
+ raw: match[0] || "",
1950
+ attributes: {
1951
+ checked: String((match[2] || "").toLowerCase() === "x")
1830
1952
  }
1831
- return `<p class="leading-7 mb-4">${processedContent}</p>`;
1832
- }
1833
- });
1834
- this.addRule({
1953
+ })
1954
+ }
1955
+ ],
1956
+ renderRules: [
1957
+ {
1835
1958
  type: "task-item",
1836
1959
  render: (token) => {
1837
- var _a;
1960
+ var _a, _b;
1838
1961
  const isChecked = ((_a = token.attributes) == null ? void 0 : _a.checked) === "true";
1839
1962
  const escapedContent = escapeHtml(token.content);
1840
- if (this.config.format === "html") {
1963
+ const format = ((_b = token.attributes) == null ? void 0 : _b.format) || "html";
1964
+ if (format === "html") {
1841
1965
  return `<div style="display: flex; align-items: center; gap: 8px; margin: 8px 0;">
1842
1966
  <input type="checkbox" ${isChecked ? "checked" : ""} disabled style="margin: 0;" />
1843
1967
  <span${isChecked ? ' style="text-decoration: line-through; color: #6b7280;"' : ""}>${escapedContent}</span>
@@ -1849,45 +1973,66 @@ var ChangerawrMarkdown = (() => {
1849
1973
  <span${isChecked ? ' class="line-through text-muted-foreground"' : ""}>${escapedContent}</span>
1850
1974
  </div>`;
1851
1975
  }
1852
- });
1853
- this.addRule({
1854
- type: "image",
1976
+ }
1977
+ ]
1978
+ };
1979
+
1980
+ // src/extensions/core/paragraph.ts
1981
+ var ParagraphExtension = {
1982
+ name: "paragraph",
1983
+ parseRules: [],
1984
+ renderRules: [
1985
+ {
1986
+ type: "paragraph",
1855
1987
  render: (token) => {
1856
- var _a, _b, _c;
1857
- const src = ((_a = token.attributes) == null ? void 0 : _a.src) || "";
1858
- const alt = ((_b = token.attributes) == null ? void 0 : _b.alt) || "";
1859
- const title = ((_c = token.attributes) == null ? void 0 : _c.title) || "";
1860
- const titleAttr = title ? ` title="${escapeHtml(title)}"` : "";
1861
- if (this.config.format === "html") {
1862
- return `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}"${titleAttr} style="max-width: 100%; height: auto; border-radius: 8px; margin: 16px 0;" loading="lazy" />`;
1988
+ var _a;
1989
+ if (!token.content) return "";
1990
+ const content = token.content.trim();
1991
+ if (!content) return "";
1992
+ const processedContent = content.includes("<br>") ? content : escapeHtml(content);
1993
+ const format = ((_a = token.attributes) == null ? void 0 : _a.format) || "html";
1994
+ if (format === "html") {
1995
+ return `<p style="line-height: 1.75; margin-bottom: 16px;">${processedContent}</p>`;
1863
1996
  }
1864
- return `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}"${titleAttr} class="max-w-full h-auto rounded-lg my-4" loading="lazy" />`;
1997
+ return `<p class="leading-7 mb-4">${processedContent}</p>`;
1865
1998
  }
1866
- });
1867
- this.addRule({
1868
- type: "hr",
1869
- render: () => {
1870
- if (this.config.format === "html") {
1871
- return '<hr style="margin: 24px 0; border: none; border-top: 1px solid #d1d5db;">';
1872
- }
1873
- return '<hr class="my-6 border-t border-border">';
1999
+ }
2000
+ ]
2001
+ };
2002
+
2003
+ // src/extensions/core/text.ts
2004
+ var TextExtension = {
2005
+ name: "text",
2006
+ parseRules: [],
2007
+ renderRules: [
2008
+ {
2009
+ type: "text",
2010
+ render: (token) => {
2011
+ if (!token.content) return "";
2012
+ return escapeHtml(token.content);
1874
2013
  }
1875
- });
1876
- this.addRule({
1877
- type: "line-break",
1878
- render: () => "<br>"
1879
- });
1880
- this.addRule({
1881
- type: "paragraph-break",
1882
- render: () => "</p><p>"
1883
- });
1884
- this.addRule({
1885
- type: "soft-break",
1886
- render: (token) => token.content || " "
1887
- });
1888
- }
2014
+ }
2015
+ ]
1889
2016
  };
1890
2017
 
2018
+ // src/extensions/core/index.ts
2019
+ var CoreExtensions = [
2020
+ TextExtension,
2021
+ HeadingExtension,
2022
+ BoldExtension,
2023
+ ItalicExtension,
2024
+ InlineCodeExtension,
2025
+ CodeBlockExtension,
2026
+ LinkExtension,
2027
+ ImageExtension,
2028
+ ListExtension,
2029
+ TaskListExtension,
2030
+ BlockquoteExtension,
2031
+ HorizontalRuleExtension,
2032
+ ParagraphExtension,
2033
+ LineBreakExtension
2034
+ ];
2035
+
1891
2036
  // src/extensions/alert.ts
1892
2037
  var AlertExtension = {
1893
2038
  name: "alert",
@@ -1969,26 +2114,19 @@ var ChangerawrMarkdown = (() => {
1969
2114
  name: "button",
1970
2115
  pattern: /\[button:([^\]]+)\]\(([^)]+)\)(?:\{([^}]+)\})?/,
1971
2116
  render: (match) => {
1972
- const text2 = match[1] || "";
1973
- const href = match[2] || "";
1974
- const optionsString = match[3] || "";
1975
- const options = optionsString.split(",").map((opt) => opt.trim()).filter(Boolean);
1976
- const styleOptions = ["default", "primary", "secondary", "success", "danger", "outline", "ghost"];
1977
- const style = options.find((opt) => styleOptions.includes(opt)) || "primary";
1978
- const sizeOptions = ["sm", "md", "lg"];
1979
- const size = options.find((opt) => sizeOptions.includes(opt)) || "md";
1980
- const disabled = options.includes("disabled");
1981
- const target = options.includes("self") ? "_self" : "_blank";
2117
+ const options = match[3] ? match[3].split(",").map((opt) => opt.trim()) : [];
1982
2118
  return {
1983
2119
  type: "button",
1984
- content: text2,
2120
+ content: match[1] || "",
1985
2121
  raw: match[0] || "",
1986
2122
  attributes: {
1987
- href,
1988
- style,
1989
- size,
1990
- disabled: disabled.toString(),
1991
- target
2123
+ href: match[2] || "",
2124
+ style: options.find(
2125
+ (opt) => ["default", "primary", "secondary", "success", "danger", "outline", "ghost"].includes(opt)
2126
+ ) || "primary",
2127
+ size: options.find((opt) => ["sm", "md", "lg"].includes(opt)) || "md",
2128
+ disabled: String(options.includes("disabled")),
2129
+ target: options.includes("self") ? "_self" : "_blank"
1992
2130
  }
1993
2131
  };
1994
2132
  }
@@ -2004,54 +2142,92 @@ var ChangerawrMarkdown = (() => {
2004
2142
  const size = ((_c = token.attributes) == null ? void 0 : _c.size) || "md";
2005
2143
  const disabled = ((_d = token.attributes) == null ? void 0 : _d.disabled) === "true";
2006
2144
  const target = ((_e = token.attributes) == null ? void 0 : _e.target) || "_blank";
2007
- const text2 = token.content;
2008
- const classes = buildButtonClasses(style, size);
2145
+ const baseClasses = `
2146
+ inline-flex items-center justify-center font-medium rounded-lg
2147
+ transition-all duration-200 ease-out
2148
+ focus:outline-none focus:ring-2 focus:ring-offset-2
2149
+ disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none
2150
+ transform hover:scale-[1.02] active:scale-[0.98]
2151
+ shadow-sm hover:shadow-md active:shadow-sm
2152
+ border border-transparent
2153
+ relative overflow-hidden
2154
+ before:absolute before:inset-0 before:rounded-lg
2155
+ before:bg-gradient-to-br before:from-white/20 before:to-transparent
2156
+ before:opacity-0 hover:before:opacity-100 before:transition-opacity before:duration-200
2157
+ `.replace(/\s+/g, " ").trim();
2158
+ const sizeClasses = {
2159
+ sm: "px-3 py-1.5 text-sm gap-1.5",
2160
+ md: "px-4 py-2 text-base gap-2",
2161
+ lg: "px-6 py-3 text-lg gap-2.5"
2162
+ };
2163
+ const styleClasses = {
2164
+ default: `
2165
+ bg-slate-600 text-white border-slate-500
2166
+ hover:bg-slate-700 hover:border-slate-400
2167
+ focus:ring-slate-500
2168
+ shadow-[0_1px_0_0_rgba(255,255,255,0.1)_inset,0_1px_2px_0_rgba(0,0,0,0.1)]
2169
+ hover:shadow-[0_1px_0_0_rgba(255,255,255,0.15)_inset,0_2px_4px_0_rgba(0,0,0,0.15)]
2170
+ `,
2171
+ primary: `
2172
+ bg-blue-600 text-white border-blue-500
2173
+ hover:bg-blue-700 hover:border-blue-400
2174
+ focus:ring-blue-500
2175
+ shadow-[0_1px_0_0_rgba(255,255,255,0.1)_inset,0_1px_2px_0_rgba(0,0,0,0.1)]
2176
+ hover:shadow-[0_1px_0_0_rgba(255,255,255,0.15)_inset,0_2px_4px_0_rgba(0,0,0,0.15)]
2177
+ `,
2178
+ secondary: `
2179
+ bg-gray-600 text-white border-gray-500
2180
+ hover:bg-gray-700 hover:border-gray-400
2181
+ focus:ring-gray-500
2182
+ shadow-[0_1px_0_0_rgba(255,255,255,0.1)_inset,0_1px_2px_0_rgba(0,0,0,0.1)]
2183
+ hover:shadow-[0_1px_0_0_rgba(255,255,255,0.15)_inset,0_2px_4px_0_rgba(0,0,0,0.15)]
2184
+ `,
2185
+ success: `
2186
+ bg-green-600 text-white border-green-500
2187
+ hover:bg-green-700 hover:border-green-400
2188
+ focus:ring-green-500
2189
+ shadow-[0_1px_0_0_rgba(255,255,255,0.1)_inset,0_1px_2px_0_rgba(0,0,0,0.1)]
2190
+ hover:shadow-[0_1px_0_0_rgba(255,255,255,0.15)_inset,0_2px_4px_0_rgba(0,0,0,0.15)]
2191
+ `,
2192
+ danger: `
2193
+ bg-red-600 text-white border-red-500
2194
+ hover:bg-red-700 hover:border-red-400
2195
+ focus:ring-red-500
2196
+ shadow-[0_1px_0_0_rgba(255,255,255,0.1)_inset,0_1px_2px_0_rgba(0,0,0,0.1)]
2197
+ hover:shadow-[0_1px_0_0_rgba(255,255,255,0.15)_inset,0_2px_4px_0_rgba(0,0,0,0.15)]
2198
+ `,
2199
+ outline: `
2200
+ bg-transparent text-blue-600 border-blue-600
2201
+ hover:bg-blue-50 hover:border-blue-700 hover:text-blue-700
2202
+ focus:ring-blue-500
2203
+ shadow-[0_0_0_1px_rgba(59,130,246,0.5)_inset]
2204
+ hover:shadow-[0_0_0_1px_rgba(29,78,216,0.6)_inset,0_1px_2px_0_rgba(0,0,0,0.05)]
2205
+ `,
2206
+ ghost: `
2207
+ bg-transparent text-gray-700 border-transparent
2208
+ hover:bg-gray-100 hover:text-gray-900
2209
+ focus:ring-gray-500
2210
+ shadow-none
2211
+ hover:shadow-[0_1px_2px_0_rgba(0,0,0,0.05)]
2212
+ `
2213
+ };
2214
+ const classes = `
2215
+ ${baseClasses}
2216
+ ${sizeClasses[size] || sizeClasses.md}
2217
+ ${styleClasses[style] || styleClasses.primary}
2218
+ `.replace(/\s+/g, " ").trim();
2009
2219
  const targetAttr = target === "_blank" ? ' target="_blank" rel="noopener noreferrer"' : target === "_self" ? ' target="_self"' : "";
2010
2220
  const disabledAttr = disabled ? ' aria-disabled="true" tabindex="-1"' : "";
2011
- const externalIcon = target === "_blank" && !disabled ? '<svg class="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/></svg>' : "";
2221
+ const externalIcon = target === "_blank" && !disabled ? `<svg class="w-4 h-4 ml-1 opacity-75" fill="none" stroke="currentColor" viewBox="0 0 24 24">
2222
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/>
2223
+ </svg>` : "";
2012
2224
  return `<a href="${href}" class="${classes}"${targetAttr}${disabledAttr}>
2013
- ${text2}${externalIcon}
2014
- </a>`;
2225
+ <span class="relative z-10">${token.content}</span>${externalIcon}
2226
+ </a>`;
2015
2227
  }
2016
2228
  }
2017
2229
  ]
2018
2230
  };
2019
- function buildButtonClasses(style, size) {
2020
- var _a, _b, _c, _d;
2021
- const base = [
2022
- "inline-flex",
2023
- "items-center",
2024
- "justify-center",
2025
- "font-medium",
2026
- "rounded-lg",
2027
- "transition-colors",
2028
- "focus:outline-none",
2029
- "focus:ring-2",
2030
- "focus:ring-offset-2",
2031
- "disabled:opacity-50",
2032
- "disabled:cursor-not-allowed"
2033
- ];
2034
- const sizes = {
2035
- sm: ["px-3", "py-1.5", "text-sm"],
2036
- md: ["px-4", "py-2", "text-base"],
2037
- lg: ["px-6", "py-3", "text-lg"]
2038
- };
2039
- const styles = {
2040
- default: ["bg-slate-600", "text-white", "hover:bg-slate-700", "focus:ring-slate-500"],
2041
- primary: ["bg-blue-600", "text-white", "hover:bg-blue-700", "focus:ring-blue-500"],
2042
- secondary: ["bg-gray-600", "text-white", "hover:bg-gray-700", "focus:ring-gray-500"],
2043
- success: ["bg-green-600", "text-white", "hover:bg-green-700", "focus:ring-green-500"],
2044
- danger: ["bg-red-600", "text-white", "hover:bg-red-700", "focus:ring-red-500"],
2045
- outline: ["border", "border-blue-600", "text-blue-600", "hover:bg-blue-50", "focus:ring-blue-500"],
2046
- ghost: ["text-gray-700", "hover:bg-gray-100", "focus:ring-gray-500"]
2047
- };
2048
- const allClasses = [
2049
- ...base,
2050
- ...(_b = (_a = sizes[size]) != null ? _a : sizes.md) != null ? _b : [],
2051
- ...(_d = (_c = styles[style]) != null ? _c : styles.primary) != null ? _d : []
2052
- ];
2053
- return allClasses.join(" ");
2054
- }
2055
2231
 
2056
2232
  // src/extensions/embed.ts
2057
2233
  var EmbedExtension = {
@@ -2130,8 +2306,7 @@ var ChangerawrMarkdown = (() => {
2130
2306
  params.set("rel", "0");
2131
2307
  params.set("modestbranding", "1");
2132
2308
  const embedUrl = `https://www.youtube.com/embed/${videoId}?${params.toString()}`;
2133
- return `
2134
- <div class="${classes}">
2309
+ return `<div class="${classes}">
2135
2310
  <div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
2136
2311
  <iframe
2137
2312
  style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;"
@@ -2159,8 +2334,7 @@ var ChangerawrMarkdown = (() => {
2159
2334
  "editable": "true"
2160
2335
  });
2161
2336
  const embedUrl = `https://codepen.io/${user}/embed/${penId}?${embedParams.toString()}`;
2162
- return `
2163
- <div class="${classes}">
2337
+ return `<div class="${classes}">
2164
2338
  <iframe
2165
2339
  height="${height}"
2166
2340
  style="width: 100%; border: 0;"
@@ -2184,8 +2358,7 @@ var ChangerawrMarkdown = (() => {
2184
2358
  if (options.mute === "1") params.set("muted", "1");
2185
2359
  if (options.loop === "1") params.set("loop", "1");
2186
2360
  const embedUrl = `https://player.vimeo.com/video/${videoId}?${params.toString()}`;
2187
- return `
2188
- <div class="${classes}">
2361
+ return `<div class="${classes}">
2189
2362
  <div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
2190
2363
  <iframe
2191
2364
  style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;"
@@ -2201,8 +2374,7 @@ var ChangerawrMarkdown = (() => {
2201
2374
  function renderSpotifyEmbed(url, options, classes) {
2202
2375
  const embedUrl = url.replace("open.spotify.com", "open.spotify.com/embed");
2203
2376
  const height = options.height || "380";
2204
- return `
2205
- <div class="${classes}">
2377
+ return `<div class="${classes}">
2206
2378
  <iframe
2207
2379
  style="border-radius: 12px;"
2208
2380
  src="${embedUrl}"
@@ -2225,8 +2397,7 @@ var ChangerawrMarkdown = (() => {
2225
2397
  if (!embedUrl.includes("?")) {
2226
2398
  embedUrl += `?view=${view}`;
2227
2399
  }
2228
- return `
2229
- <div class="${classes}">
2400
+ return `<div class="${classes}">
2230
2401
  <iframe
2231
2402
  src="${embedUrl}"
2232
2403
  style="width: 100%; height: ${height}px; border: 0; border-radius: 4px; overflow: hidden;"
@@ -2239,8 +2410,7 @@ var ChangerawrMarkdown = (() => {
2239
2410
  function renderFigmaEmbed(url, options, classes) {
2240
2411
  const embedUrl = `https://www.figma.com/embed?embed_host=share&url=${encodeURIComponent(url)}`;
2241
2412
  const height = options.height || "450";
2242
- return `
2243
- <div class="${classes}">
2413
+ return `<div class="${classes}">
2244
2414
  <iframe
2245
2415
  style="border: none;"
2246
2416
  width="100%"
@@ -2251,8 +2421,7 @@ var ChangerawrMarkdown = (() => {
2251
2421
  </div>`;
2252
2422
  }
2253
2423
  function renderTwitterEmbed(url, _options, classes) {
2254
- return `
2255
- <div class="${classes}">
2424
+ return `<div class="${classes}">
2256
2425
  <div class="p-4">
2257
2426
  <div class="flex items-center gap-3 mb-3">
2258
2427
  <svg class="w-6 h-6 fill-current text-blue-500" viewBox="0 0 24 24">
@@ -2280,8 +2449,7 @@ var ChangerawrMarkdown = (() => {
2280
2449
  if (!owner || !repo) {
2281
2450
  return createErrorEmbed("Invalid GitHub URL", url, classes);
2282
2451
  }
2283
- return `
2284
- <div class="${classes}">
2452
+ return `<div class="${classes}">
2285
2453
  <div class="p-4">
2286
2454
  <div class="flex items-center gap-3 mb-3">
2287
2455
  <svg class="w-6 h-6 fill-current" viewBox="0 0 24 24">
@@ -2304,8 +2472,7 @@ var ChangerawrMarkdown = (() => {
2304
2472
  }
2305
2473
  function renderGenericEmbed(url, _options, classes) {
2306
2474
  const domain = extractDomain(url);
2307
- return `
2308
- <div class="${classes}">
2475
+ return `<div class="${classes}">
2309
2476
  <div class="p-4">
2310
2477
  <div class="flex items-center gap-3 mb-3">
2311
2478
  <div class="w-10 h-10 rounded-lg bg-muted flex items-center justify-center">
@@ -2329,8 +2496,7 @@ var ChangerawrMarkdown = (() => {
2329
2496
  </div>`;
2330
2497
  }
2331
2498
  function createErrorEmbed(error, url, classes) {
2332
- return `
2333
- <div class="${classes}">
2499
+ return `<div class="${classes}">
2334
2500
  <div class="p-4 text-destructive">
2335
2501
  <div class="font-medium flex items-center gap-2">
2336
2502
  <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -2365,19 +2531,54 @@ var ChangerawrMarkdown = (() => {
2365
2531
  this.extensions = /* @__PURE__ */ new Map();
2366
2532
  this.parser = new MarkdownParser(config == null ? void 0 : config.parser);
2367
2533
  this.renderer = new MarkdownRenderer(config == null ? void 0 : config.renderer);
2368
- this.registerBuiltInExtensions();
2534
+ this.registerCoreExtensions();
2535
+ this.registerFeatureExtensions();
2369
2536
  if (config == null ? void 0 : config.extensions) {
2370
2537
  config.extensions.forEach((extension) => {
2371
2538
  this.registerExtension(extension);
2372
2539
  });
2373
2540
  }
2374
- this.parser.setupDefaultRulesIfEmpty();
2375
2541
  }
2376
- /**
2377
- * Register a custom extension
2378
- */
2542
+ registerFeatureExtensions() {
2543
+ this.registerExtension(AlertExtension);
2544
+ this.registerExtension(ButtonExtension);
2545
+ this.registerExtension(EmbedExtension);
2546
+ }
2547
+ registerCoreExtensions() {
2548
+ CoreExtensions.forEach((extension) => {
2549
+ this.registerExtension(extension);
2550
+ });
2551
+ }
2379
2552
  registerExtension(extension) {
2380
2553
  try {
2554
+ if (!extension.name || typeof extension.name !== "string") {
2555
+ throw new Error("Extension must have a valid name");
2556
+ }
2557
+ if (!Array.isArray(extension.parseRules)) {
2558
+ throw new Error("Extension must have parseRules array");
2559
+ }
2560
+ if (!Array.isArray(extension.renderRules)) {
2561
+ throw new Error("Extension must have renderRules array");
2562
+ }
2563
+ extension.parseRules.forEach((rule, index) => {
2564
+ if (!rule.name || typeof rule.name !== "string") {
2565
+ throw new Error(`Parse rule ${index} must have a valid name`);
2566
+ }
2567
+ if (!rule.pattern || !(rule.pattern instanceof RegExp)) {
2568
+ throw new Error(`Parse rule ${index} must have a valid RegExp pattern`);
2569
+ }
2570
+ if (!rule.render || typeof rule.render !== "function") {
2571
+ throw new Error(`Parse rule ${index} must have a valid render function`);
2572
+ }
2573
+ });
2574
+ extension.renderRules.forEach((rule, index) => {
2575
+ if (!rule.type || typeof rule.type !== "string") {
2576
+ throw new Error(`Render rule ${index} must have a valid type`);
2577
+ }
2578
+ if (!rule.render || typeof rule.render !== "function") {
2579
+ throw new Error(`Render rule ${index} must have a valid render function`);
2580
+ }
2581
+ });
2381
2582
  this.extensions.set(extension.name, extension);
2382
2583
  extension.parseRules.forEach((rule) => {
2383
2584
  this.parser.addRule(rule);
@@ -2398,9 +2599,6 @@ var ChangerawrMarkdown = (() => {
2398
2599
  };
2399
2600
  }
2400
2601
  }
2401
- /**
2402
- * Unregister an extension
2403
- */
2404
2602
  unregisterExtension(name) {
2405
2603
  const extension = this.extensions.get(name);
2406
2604
  if (!extension) {
@@ -2414,46 +2612,25 @@ var ChangerawrMarkdown = (() => {
2414
2612
  return false;
2415
2613
  }
2416
2614
  }
2417
- /**
2418
- * Parse markdown content into tokens
2419
- */
2420
2615
  parse(markdown2) {
2421
2616
  return this.parser.parse(markdown2);
2422
2617
  }
2423
- /**
2424
- * Render tokens to HTML
2425
- */
2426
2618
  render(tokens) {
2427
2619
  return this.renderer.render(tokens);
2428
2620
  }
2429
- /**
2430
- * Parse and render markdown to HTML in one step
2431
- */
2432
2621
  toHtml(markdown2) {
2433
2622
  const tokens = this.parse(markdown2);
2434
2623
  return this.render(tokens);
2435
2624
  }
2436
- /**
2437
- * Get list of registered extensions
2438
- */
2439
2625
  getExtensions() {
2440
2626
  return Array.from(this.extensions.keys());
2441
2627
  }
2442
- /**
2443
- * Check if extension is registered
2444
- */
2445
2628
  hasExtension(name) {
2446
2629
  return this.extensions.has(name);
2447
2630
  }
2448
- /**
2449
- * Get parser warnings
2450
- */
2451
2631
  getWarnings() {
2452
2632
  return [...this.parser.getWarnings(), ...this.renderer.getWarnings()];
2453
2633
  }
2454
- /**
2455
- * Get debug information from last render
2456
- */
2457
2634
  getDebugInfo() {
2458
2635
  return {
2459
2636
  warnings: this.getWarnings(),
@@ -2463,9 +2640,6 @@ var ChangerawrMarkdown = (() => {
2463
2640
  iterationCount: 0
2464
2641
  };
2465
2642
  }
2466
- /**
2467
- * Get performance metrics for the last operation
2468
- */
2469
2643
  getPerformanceMetrics() {
2470
2644
  return {
2471
2645
  parseTime: 0,
@@ -2474,28 +2648,29 @@ var ChangerawrMarkdown = (() => {
2474
2648
  tokenCount: 0
2475
2649
  };
2476
2650
  }
2477
- /**
2478
- * Register built-in extensions
2479
- */
2480
- registerBuiltInExtensions() {
2481
- this.registerExtension(AlertExtension);
2482
- this.registerExtension(ButtonExtension);
2483
- this.registerExtension(EmbedExtension);
2484
- }
2485
- /**
2486
- * Rebuild parser and renderer with current extensions
2487
- */
2488
2651
  rebuildParserAndRenderer() {
2489
2652
  const parserConfig = this.parser.getConfig();
2490
2653
  const rendererConfig = this.renderer.getConfig();
2491
2654
  this.parser = new MarkdownParser(parserConfig);
2492
2655
  this.renderer = new MarkdownRenderer(rendererConfig);
2493
2656
  const extensionsToRegister = Array.from(this.extensions.values());
2494
- this.extensions.clear();
2495
- extensionsToRegister.forEach((extension) => {
2496
- this.registerExtension(extension);
2657
+ const featureExtensions = extensionsToRegister.filter(
2658
+ (ext) => ["alert", "button", "embed"].includes(ext.name)
2659
+ );
2660
+ const coreExtensions = extensionsToRegister.filter(
2661
+ (ext) => ["text", "heading", "bold", "italic", "code", "codeblock", "link", "image", "list", "task-list", "blockquote", "hr", "paragraph", "line-break"].includes(ext.name)
2662
+ );
2663
+ const customExtensions = extensionsToRegister.filter(
2664
+ (ext) => !["alert", "button", "embed", "text", "heading", "bold", "italic", "code", "codeblock", "link", "image", "list", "task-list", "blockquote", "hr", "paragraph", "line-break"].includes(ext.name)
2665
+ );
2666
+ [...featureExtensions, ...coreExtensions, ...customExtensions].forEach((extension) => {
2667
+ extension.parseRules.forEach((rule) => {
2668
+ this.parser.addRule(rule);
2669
+ });
2670
+ extension.renderRules.forEach((rule) => {
2671
+ this.renderer.addRule(rule);
2672
+ });
2497
2673
  });
2498
- this.parser.setupDefaultRulesIfEmpty();
2499
2674
  }
2500
2675
  };
2501
2676
  var markdown = new ChangerawrMarkdown();