@changerawr/markdown 1.1.7 → 1.1.9

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.d.mts CHANGED
@@ -523,6 +523,7 @@ declare class MarkdownRenderer {
523
523
  addRule(rule: RenderRule): void;
524
524
  hasRule(type: string): boolean;
525
525
  render(tokens: MarkdownToken[]): string;
526
+ private groupListItems;
526
527
  private renderToken;
527
528
  private createErrorBlock;
528
529
  private createDebugBlock;
@@ -564,7 +565,7 @@ declare const ParagraphExtension: Extension;
564
565
 
565
566
  declare const TextExtension: Extension;
566
567
 
567
- declare const CoreExtensions: readonly [Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension];
568
+ declare const CoreExtensions: readonly [Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension];
568
569
 
569
570
  /**
570
571
  * @changerawr/markdown - Main package exports
@@ -623,7 +624,7 @@ declare const markdown: {
623
624
  readonly parseCum: typeof parseCum;
624
625
  readonly ChangerawrMarkdown: typeof ChangerawrMarkdown;
625
626
  readonly extensions: {
626
- readonly core: readonly [Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension];
627
+ readonly core: readonly [Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension];
627
628
  readonly Text: Extension;
628
629
  readonly Heading: Extension;
629
630
  readonly Bold: Extension;
package/dist/index.d.ts CHANGED
@@ -523,6 +523,7 @@ declare class MarkdownRenderer {
523
523
  addRule(rule: RenderRule): void;
524
524
  hasRule(type: string): boolean;
525
525
  render(tokens: MarkdownToken[]): string;
526
+ private groupListItems;
526
527
  private renderToken;
527
528
  private createErrorBlock;
528
529
  private createDebugBlock;
@@ -564,7 +565,7 @@ declare const ParagraphExtension: Extension;
564
565
 
565
566
  declare const TextExtension: Extension;
566
567
 
567
- declare const CoreExtensions: readonly [Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension];
568
+ declare const CoreExtensions: readonly [Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension];
568
569
 
569
570
  /**
570
571
  * @changerawr/markdown - Main package exports
@@ -623,7 +624,7 @@ declare const markdown: {
623
624
  readonly parseCum: typeof parseCum;
624
625
  readonly ChangerawrMarkdown: typeof ChangerawrMarkdown;
625
626
  readonly extensions: {
626
- readonly core: readonly [Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension];
627
+ readonly core: readonly [Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension, Extension];
627
628
  readonly Text: Extension;
628
629
  readonly Heading: Extension;
629
630
  readonly Bold: Extension;
package/dist/index.js CHANGED
@@ -676,20 +676,59 @@ var MarkdownRenderer = class {
676
676
  format: this.config.format
677
677
  }
678
678
  }));
679
- const htmlParts = tokensWithFormat.map((token) => this.renderToken(token));
679
+ const groupedTokens = this.groupListItems(tokensWithFormat);
680
+ const htmlParts = groupedTokens.map((token) => this.renderToken(token));
680
681
  const combinedHtml = htmlParts.join("");
681
682
  if (this.config.sanitize && !this.config.allowUnsafeHtml) {
682
683
  return sanitizeHtml(combinedHtml);
683
684
  }
684
685
  return combinedHtml;
685
686
  }
687
+ groupListItems(tokens) {
688
+ const result = [];
689
+ let i = 0;
690
+ while (i < tokens.length) {
691
+ const token = tokens[i];
692
+ const isListItem = token?.type === "list-item" || token?.type === "ordered-list-item" || token?.type === "task-item";
693
+ if (isListItem) {
694
+ const listItems = [];
695
+ const firstItemType = token.type;
696
+ const isOrdered = firstItemType === "ordered-list-item";
697
+ while (i < tokens.length) {
698
+ const item = tokens[i];
699
+ if (!item) break;
700
+ const itemType = item.type;
701
+ const isSameListType = isOrdered && itemType === "ordered-list-item" || !isOrdered && (itemType === "list-item" || itemType === "task-item");
702
+ if (isSameListType) {
703
+ listItems.push(item);
704
+ i++;
705
+ } else {
706
+ break;
707
+ }
708
+ }
709
+ const wrappedList = {
710
+ type: isOrdered ? "ol" : "ul",
711
+ content: "",
712
+ raw: "",
713
+ children: listItems,
714
+ attributes: { format: this.config.format }
715
+ };
716
+ wrappedList._isWrapped = true;
717
+ result.push(wrappedList);
718
+ } else {
719
+ result.push(token);
720
+ i++;
721
+ }
722
+ }
723
+ return result;
724
+ }
686
725
  renderToken(token) {
687
726
  const rule = this.rules.get(token.type);
688
727
  if (rule) {
689
728
  try {
690
729
  let tokenToRender = token;
691
730
  if (token.children && token.children.length > 0) {
692
- const renderedChildren = this.render(token.children);
731
+ const renderedChildren = token.type === "ul" || token.type === "ol" ? token.children.map((child) => this.renderToken(child)).join("") : this.render(token.children);
693
732
  tokenToRender = {
694
733
  ...token,
695
734
  attributes: {
@@ -1207,7 +1246,8 @@ var ImageExtension = {
1207
1246
  attributes: {
1208
1247
  alt: match[1] || "",
1209
1248
  src: match[2] || "",
1210
- title: match[3] || ""
1249
+ caption: match[3] || ""
1250
+ // Renamed from 'title' to 'caption' for clarity
1211
1251
  }
1212
1252
  })
1213
1253
  }
@@ -1218,13 +1258,24 @@ var ImageExtension = {
1218
1258
  render: (token) => {
1219
1259
  const src = token.attributes?.src || "";
1220
1260
  const alt = token.attributes?.alt || "";
1221
- const title = token.attributes?.title || "";
1222
- const titleAttr = title ? ` title="${escapeHtml(title)}"` : "";
1261
+ const caption = token.attributes?.caption || "";
1223
1262
  const format = token.attributes?.format || "html";
1263
+ if (caption) {
1264
+ if (format === "html") {
1265
+ return `<figure style="margin: 16px 0; text-align: center;">
1266
+ <img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}" style="max-width: 100%; height: auto; border-radius: 8px;" loading="lazy" />
1267
+ <figcaption style="margin-top: 8px; font-size: 14px; color: #6b7280; font-style: italic;">${escapeHtml(caption)}</figcaption>
1268
+ </figure>`;
1269
+ }
1270
+ return `<figure class="my-4 text-center">
1271
+ <img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}" class="max-w-full h-auto rounded-lg" loading="lazy" />
1272
+ <figcaption class="mt-2 text-sm text-gray-500 italic">${escapeHtml(caption)}</figcaption>
1273
+ </figure>`;
1274
+ }
1224
1275
  if (format === "html") {
1225
- return `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}"${titleAttr} style="max-width: 100%; height: auto; border-radius: 8px; margin: 16px 0;" loading="lazy" />`;
1276
+ return `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}" style="max-width: 100%; height: auto; border-radius: 8px; margin: 16px 0;" loading="lazy" />`;
1226
1277
  }
1227
- return `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}"${titleAttr} class="max-w-full h-auto rounded-lg my-4" loading="lazy" />`;
1278
+ return `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}" class="max-w-full h-auto rounded-lg my-4" loading="lazy" />`;
1228
1279
  }
1229
1280
  }
1230
1281
  ]
@@ -1276,16 +1327,57 @@ var ListExtension = {
1276
1327
  name: "list",
1277
1328
  parseRules: [
1278
1329
  {
1279
- name: "list-item",
1330
+ name: "unordered-list-item",
1280
1331
  pattern: /^(\s*)[-*+]\s+(.+)$/m,
1281
1332
  render: (match) => ({
1282
1333
  type: "list-item",
1283
1334
  content: match[2] || "",
1284
- raw: match[0] || ""
1335
+ raw: match[0] || "",
1336
+ attributes: {
1337
+ indent: match[1]?.length || 0,
1338
+ ordered: false,
1339
+ marker: match[1] ? match[0].match(/[-*+]/)?.[0] : "-"
1340
+ }
1341
+ })
1342
+ },
1343
+ {
1344
+ name: "ordered-list-item",
1345
+ pattern: /^(\s*)(\d+)\.\s+(.+)$/m,
1346
+ render: (match) => ({
1347
+ type: "ordered-list-item",
1348
+ content: match[3] || "",
1349
+ raw: match[0] || "",
1350
+ attributes: {
1351
+ indent: match[1]?.length || 0,
1352
+ ordered: true,
1353
+ number: parseInt(match[2] || "1")
1354
+ }
1285
1355
  })
1286
1356
  }
1287
1357
  ],
1288
1358
  renderRules: [
1359
+ {
1360
+ type: "ul",
1361
+ render: (token) => {
1362
+ const format = token.attributes?.format || "tailwind";
1363
+ const content = token.attributes?.renderedChildren || "";
1364
+ if (format === "html") {
1365
+ return `<ul style="margin: 8px 0; padding-left: 24px; list-style: disc;">${content}</ul>`;
1366
+ }
1367
+ return `<ul class="my-2 pl-6 list-disc">${content}</ul>`;
1368
+ }
1369
+ },
1370
+ {
1371
+ type: "ol",
1372
+ render: (token) => {
1373
+ const format = token.attributes?.format || "tailwind";
1374
+ const content = token.attributes?.renderedChildren || "";
1375
+ if (format === "html") {
1376
+ return `<ol style="margin: 8px 0; padding-left: 24px; list-style: decimal;">${content}</ol>`;
1377
+ }
1378
+ return `<ol class="my-2 pl-6 list-decimal">${content}</ol>`;
1379
+ }
1380
+ },
1289
1381
  {
1290
1382
  type: "list-item",
1291
1383
  render: (token) => {
@@ -1296,6 +1388,17 @@ var ListExtension = {
1296
1388
  }
1297
1389
  return `<li>${content}</li>`;
1298
1390
  }
1391
+ },
1392
+ {
1393
+ type: "ordered-list-item",
1394
+ render: (token) => {
1395
+ const format = token.attributes?.format || "tailwind";
1396
+ const content = token.attributes?.renderedChildren || escapeHtml(token.content);
1397
+ if (format === "html") {
1398
+ return `<li>${content}</li>`;
1399
+ }
1400
+ return `<li>${content}</li>`;
1401
+ }
1299
1402
  }
1300
1403
  ]
1301
1404
  };
@@ -1310,6 +1413,7 @@ var TaskListExtension = {
1310
1413
  content: match[3] || "",
1311
1414
  raw: match[0] || "",
1312
1415
  attributes: {
1416
+ indent: match[1]?.length || 0,
1313
1417
  checked: String((match[2] || "").toLowerCase() === "x")
1314
1418
  }
1315
1419
  })
@@ -1322,15 +1426,20 @@ var TaskListExtension = {
1322
1426
  const isChecked = token.attributes?.checked === "true";
1323
1427
  const content = token.attributes?.renderedChildren || escapeHtml(token.content);
1324
1428
  const format = token.attributes?.format || "html";
1429
+ const checkmark = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink: 0; margin-top: 2px;"><polyline points="20 6 9 17 4 12"></polyline></svg>`;
1430
+ const checkbox = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink: 0; margin-top: 2px;"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect></svg>`;
1325
1431
  if (format === "html") {
1326
- return `<div style="display: flex; align-items: center; gap: 8px; margin: 8px 0;">
1327
- <input type="checkbox" ${isChecked ? "checked" : ""} disabled style="margin: 0;" />
1432
+ return `<div style="display: flex; align-items: flex-start; gap: 8px; margin: 8px 0;">
1433
+ <div style="color: ${isChecked ? "#10b981" : "#9ca3af"}; margin-top: 2px;">
1434
+ ${isChecked ? checkmark : checkbox}
1435
+ </div>
1328
1436
  <span${isChecked ? ' style="text-decoration: line-through; color: #6b7280;"' : ""}>${content}</span>
1329
1437
  </div>`;
1330
1438
  }
1331
- return `<div class="flex items-center gap-2 my-2 task-list-item">
1332
- <input type="checkbox" ${isChecked ? "checked" : ""} disabled
1333
- class="form-checkbox h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary" />
1439
+ return `<div class="flex items-start gap-2 my-2 task-list-item">
1440
+ <div class="${isChecked ? "text-green-600" : "text-gray-400"} flex-shrink-0 mt-0.5">
1441
+ ${isChecked ? checkmark : checkbox}
1442
+ </div>
1334
1443
  <span${isChecked ? ' class="line-through text-muted-foreground"' : ""}>${content}</span>
1335
1444
  </div>`;
1336
1445
  }
@@ -1375,6 +1484,35 @@ var TextExtension = {
1375
1484
  ]
1376
1485
  };
1377
1486
 
1487
+ // src/extensions/core/strikethrough.ts
1488
+ var StrikethroughExtension = {
1489
+ name: "strikethrough",
1490
+ parseRules: [
1491
+ {
1492
+ name: "strikethrough",
1493
+ pattern: /~~((?:(?!~~).)+)~~/,
1494
+ render: (match) => ({
1495
+ type: "strikethrough",
1496
+ content: match[1] || "",
1497
+ raw: match[0] || ""
1498
+ })
1499
+ }
1500
+ ],
1501
+ renderRules: [
1502
+ {
1503
+ type: "strikethrough",
1504
+ render: (token) => {
1505
+ const content = escapeHtml(token.content);
1506
+ const format = token.attributes?.format;
1507
+ if (format === "html") {
1508
+ return `<del style="text-decoration: line-through; color: #6b7280;">${content}</del>`;
1509
+ }
1510
+ return `<del class="line-through text-gray-500">${content}</del>`;
1511
+ }
1512
+ }
1513
+ ]
1514
+ };
1515
+
1378
1516
  // src/extensions/core/index.ts
1379
1517
  var CoreExtensions = [
1380
1518
  TextExtension,
@@ -1389,6 +1527,7 @@ var CoreExtensions = [
1389
1527
  TaskListExtension,
1390
1528
  BlockquoteExtension,
1391
1529
  HorizontalRuleExtension,
1530
+ StrikethroughExtension,
1392
1531
  ParagraphExtension,
1393
1532
  LineBreakExtension
1394
1533
  ];