@mirrordown/mdit-attrs 0.1.3 → 0.2.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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,23 @@
3
3
 
4
4
 
5
5
 
6
+
7
+ ## 0.2.0
8
+ <sub>2026-10-28</sub>
9
+
10
+ - *(minor)*
11
+ Make `mdit-attrs` and `remd-attrs` render identical HTML, following markdown-it-attrs wherever the two disagreed. An attribute line lazily continuing a list's last item (`- a`, `- b`, `{.list}`) now applies to that list, including nested lists, in both engines; it was silently dropped. An attribute block on the line after a hard break now applies to the paragraph and keeps the `<br>` (`mdit-attrs` dropped the class, `remd-attrs` dropped the break). Text consisting only of an attribute block is no longer ignored by either engine's delimiter check. `remd-attrs` now supports attributes after a fence's language (` ```js {.x} `), on table cells (`td` and `th`), and at the end of loose and ordered list items. On fences, `class` is now always the first attribute in both engines (`mdit-attrs` wrote `id` before the language class).
12
+ - *(minor)*
13
+ An attribute block on a line of its own now goes on the block it's written after, at the level its `>` markers and indentation put it, as kramdown places a block IAL. Written inside a blockquote or list item, it goes on the paragraph (`> para` then `> {.x}` gives `<p class="x">`), or on the item in a tight list (`- a` then ` {.x}` gives `<li class="x">`). Written outside one, as a lazy continuation line, it goes on that blockquote (`> para` then `{.x}`) or on the item's list (`- a` then `{.x}`), the outermost such block when it leaves several. Both plugins used to give the paragraph every line written inside a blockquote, and the list every line in a list item's first paragraph, whatever its indentation. markdown-it-attrs can't see indentation and gives the line to the outermost block ending with the paragraph; the cases where Mirrordown now differs from it are those where the indentation says otherwise. Inside tab panels and step bodies, the panel's own `>` belongs to the tab: a line written in the panel is placed as it would be at the top level.
14
+
15
+ An attribute block right after an inline element now applies when text follows it, as in markdown-it-attrs: `**important**{.warning} text.` gives `<strong class="warning">`, where both plugins kept the block as text unless it ended the text run. Blocks that follow one another merge (`` `npm i`{.cmd}{#install} ``). In `remd-attrs`, inline blocks are also read in headings, table cells and nested elements, and before the heading and list item rules, so `# Title **b**{.x}` gives the `strong` the class, as `mdit-attrs` does. `{.a} {#b}` is no longer read as one block holding `.a} {#b`: only the last block ends the paragraph.
16
+ - *(patch)*
17
+ Fixes for differences between the markdown-it and remark plugins that only show up when plugins are combined:
18
+
19
+ - `mdit-attrs` no longer reads braces in an image's alt text as a trailing attribute block: `![{.cls}](x.png)` gave its paragraph `class="cls"`. Paragraph, heading and list item attributes now only come from literal text, as in `remd-attrs`.
20
+ - `mdit-squeeze-paragraphs` now judges a paragraph empty by what it renders, as `remd-squeeze-paragraphs` does, so a paragraph that was only an attribute block (`{.note}`) is removed instead of kept as an empty `<p class="note">`.
21
+ - `remd-github-alerts` builds its icons as hast elements instead of a `raw` node, so they render in a default unified pipeline instead of appearing as escaped `<svg>` text unless `allowDangerousHtml` was on. Both engines' icons now close their SVG elements explicitly (`<path …></path>`), which is how rehype serializes them by default.
22
+
6
23
  ## 0.1.3
7
24
  <sub>2026-06-28</sub>
8
25
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @mirrordown/mdit-attrs
2
2
 
3
- > Part of [Mirrordown](https://github.com/mirrordown/mirrordown) — a suite of markdown syntax extensions for the unified and markdown-it ecosystems.
3
+ > Part of [Mirrordown](https://github.com/mirrordown/mirrordown) — a suite of markdown syntax extensions for the unified, markdown-it and Sätteri ecosystems.
4
4
 
5
5
  A markdown-it plugin for the `attrs` syntax extension.
6
6
 
@@ -22,9 +22,9 @@ Attributes are written in curly braces using CSS-like shorthand:
22
22
 
23
23
  ### Headings
24
24
 
25
- ```markdown
25
+ ````markdown
26
26
  ## My Section {#my-section .highlight}
27
- ```
27
+ ````
28
28
 
29
29
  ### Code fences
30
30
 
@@ -36,24 +36,42 @@ const x = 1;
36
36
 
37
37
  ### Paragraphs
38
38
 
39
- ```markdown
39
+ ````markdown
40
40
  A paragraph with a custom class.
41
41
  {.note}
42
- ```
42
+ ````
43
43
 
44
44
  ### Inline elements
45
45
 
46
- ```markdown
46
+ ````markdown
47
47
  This is **important**{.warning} text.
48
- ```
48
+ ````
49
49
 
50
50
  ### After lists and tables
51
51
 
52
- ```markdown
52
+ ````markdown
53
53
  - Item one
54
54
  - Item two
55
- {.checklist}
56
- ```
55
+ {.checklist}
56
+ ````
57
+
58
+ ### Inside blockquotes and lists
59
+
60
+ A block on a line of its own goes on the block it's written after, at the level its `>` markers and indentation put it, as kramdown places a block IAL. Written inside a blockquote or list item, it goes on the paragraph, or on the item in a tight list. Written outside one, as a lazy continuation line, it goes on that blockquote, or on the item's list.
61
+
62
+ ````markdown
63
+ > A quoted paragraph.
64
+ > {.note}
65
+
66
+ > A quoted paragraph.
67
+ {.callout}
68
+
69
+ - Item one
70
+ {.first}
71
+ - Item two
72
+ ````
73
+
74
+ markdown-it-attrs can't see a line's indentation, so it gives such a line to the outermost block that ends with the paragraph instead.
57
75
 
58
76
  ## Install
59
77
 
@@ -79,8 +97,8 @@ import { attrs } from "@mirrordown/mdit-attrs";
79
97
 
80
98
  export default defineConfig({
81
99
  markdown: {
82
- config: (md) => md.use(attrs)
83
- }
100
+ config: (md) => md.use(attrs),
101
+ },
84
102
  });
85
103
  ```
86
104
 
package/dist/index.d.mts CHANGED
@@ -1,6 +1,4 @@
1
1
  import { PluginWithOptions } from "markdown-it";
2
-
3
- //#region src/types.d.ts
4
2
  /** A markdown-it rule that attribute lists can be attached to. */
5
3
  type AttrRuleName = "fence" | "inline" | "table" | "list" | "heading" | "hr" | "softbreak" | "block";
6
4
  /** Delimiters and allowed characters for the attribute-list syntax. */
@@ -24,10 +22,7 @@ interface AttrsOptions extends Partial<DelimiterConfig> {
24
22
  type Attr = [key: string, value: string];
25
23
  /** [startIndex, endIndex] within the token content string, exclusive of delimiters */
26
24
  type DelimiterRange = [start: number, end: number];
27
- //#endregion
28
- //#region src/plugin.d.ts
29
25
  /** markdown-it plugin for attribute lists (`{.class #id key=value}`) on elements. */
30
- declare const attrs: PluginWithOptions<AttrsOptions>;
31
- //#endregion
32
- export { type Attr, type AttrRuleName, type AttrsOptions, type DelimiterConfig, type DelimiterRange, attrs };
26
+ export declare const attrs: PluginWithOptions<AttrsOptions>;
27
+ export type { Attr, AttrRuleName, AttrsOptions, DelimiterConfig, DelimiterRange };
33
28
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/plugin.ts"],"mappings":";;;;KACY,YAAA;;UAWK,eAAA;EAXO;EAatB,IAAA;EAbsB;EAetB,KAAA;EAJe;EAMf,OAAA,EAAS,KAAA,UAAe,MAAA;AAAA;;UAIT,YAAA,SAAqB,OAAA,CAAQ,eAAA;EAN5C;;;;EAWA,IAAA,qBAAyB,YAAA;AAAA;AAL3B;AAAA,KASY,IAAA,IAAQ,GAAA,UAAa,KAAA;;KAGrB,cAAA,IAAkB,KAAA,UAAe,GAAA;;;;cC5BhC,KAAA,EAAO,iBAAA,CAAkB,YAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/plugin.ts"],"mappings":";;KACY;;UAWK;;EAEf;;EAEA;;EAEA,SAAS,eAAe;;;UAIT,qBAAqB,QAAQ;;;;;EAK5C,yBAAyB;;;KAIf,QAAQ,aAAa;;KAGrB,kBAAkB,eAAe;;qBC5BhC,OAAO,kBAAkB"}
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
- //#region src/helper/getAttrs.ts
1
+ // src/helper/getAttrs.ts
2
2
  const CLASS_MARKER = 46;
3
3
  const ID_MARKER = 35;
4
4
  const PAIR_SEPARATOR = 32;
5
5
  const KEY_SEPARATOR = 61;
6
6
  const QUOTE_MARKER = 34;
7
- const DISALLOWED_KEY_CHARS = new Set([
7
+ const DISALLOWED_KEY_CHARS = /* @__PURE__ */ new Set([
8
8
  9,
9
9
  10,
10
10
  12,
@@ -59,14 +59,12 @@ const getAttrs = (str, range, allowed) => {
59
59
  if (allowed.length === 0) return attrs;
60
60
  return attrs.filter(([attr]) => allowed.some((item) => item instanceof RegExp ? item.test(attr) : item === attr));
61
61
  };
62
- //#endregion
63
- //#region src/helper/addAttrs.ts
62
+ // src/helper/addAttrs.ts
64
63
  const addAttrs = (token, content, range, allowed) => {
65
64
  for (const [key, value] of getAttrs(content, range, allowed)) if (key === "class" || key === "css-module") token.attrJoin(key, value);
66
65
  else token.attrPush([key, value]);
67
66
  };
68
- //#endregion
69
- //#region src/helper/getDelimiterChecker.ts
67
+ // src/helper/getDelimiterChecker.ts
70
68
  /**
71
69
  * Returns a function that checks whether `str` contains a valid attribute
72
70
  * block at the given position ("start", "end", or "only") and returns the
@@ -95,6 +93,7 @@ const getDelimiterChecker = (left, right) => {
95
93
  if (pos === "only") {
96
94
  const contentEnd = str.length - rl;
97
95
  if (contentEnd <= ll) return null;
96
+ if (str.lastIndexOf(left, contentEnd - 1) !== 0) return null;
98
97
  return [ll, contentEnd];
99
98
  }
100
99
  if (pos === "start") {
@@ -104,12 +103,11 @@ const getDelimiterChecker = (left, right) => {
104
103
  }
105
104
  const start = str.lastIndexOf(left, str.length - rl - 1);
106
105
  if (start === -1) return null;
107
- if (str.startsWith(left, start - ll)) return null;
106
+ if (start >= ll && str.startsWith(left, start - ll)) return null;
108
107
  return [start + ll, str.length - rl];
109
108
  };
110
109
  };
111
- //#endregion
112
- //#region src/helper/testRule.ts
110
+ // src/helper/testRule.ts
113
111
  const matches = (test, actual) => {
114
112
  if (typeof test === "function") return test(actual);
115
113
  return test === actual;
@@ -225,8 +223,7 @@ const testRule = (tokens, index, test) => {
225
223
  range
226
224
  };
227
225
  };
228
- //#endregion
229
- //#region src/helper/getMatchingOpeningToken.ts
226
+ // src/helper/getMatchingOpeningToken.ts
230
227
  /**
231
228
  * Given a closing or self-closing token at `index`, returns its matching
232
229
  * opening token by walking backwards to find the token of the same type at
@@ -249,9 +246,49 @@ const getMatchingOpeningToken = (tokens, index) => {
249
246
  }
250
247
  return null;
251
248
  };
252
- //#endregion
253
- //#region src/rules/block.ts
254
- const SKIP_TYPES = new Set([
249
+ // src/helper/containers.ts
250
+ /**
251
+ * How many of `containers`, outermost first, a line is written in: a line that
252
+ * lazily continues a paragraph has fewer `>` markers, or less indentation,
253
+ * than the blocks around that paragraph. Tabs count as one column.
254
+ */
255
+ const containersKept = (line, containers) => {
256
+ const prefix = /^[ \t>]*/.exec(line)?.[0] ?? "";
257
+ const markers = prefix.split(">").length - 1;
258
+ let kept = 0;
259
+ for (const container of containers) {
260
+ if (container.kind === "quote" ? markers < container.markers : prefix.length < container.column) break;
261
+ kept++;
262
+ }
263
+ return kept;
264
+ };
265
+ /**
266
+ * The columns the content of the list items opened on a line starts at, in
267
+ * the order they open, as CommonMark reads a list marker: up to four spaces
268
+ * after it belong to the marker, more start indented content one column after.
269
+ */
270
+ const itemColumns = (line) => {
271
+ const columns = [];
272
+ let pos = 0;
273
+ for (;;) {
274
+ while (line[pos] === " " || line[pos] === " ") pos++;
275
+ if (line[pos] === ">") {
276
+ pos++;
277
+ continue;
278
+ }
279
+ const marker = /^(?:[-+*]|\d{1,9}[.)])(?=[ \t]|$)/.exec(line.slice(pos));
280
+ if (!marker) return columns;
281
+ const end = pos + marker[0].length;
282
+ let spaces = 0;
283
+ while (line[end + spaces] === " " || line[end + spaces] === " ") spaces++;
284
+ const column = end + spaces === line.length || spaces > 4 ? end + 1 : end + spaces;
285
+ columns.push(column);
286
+ if (spaces > 4) return columns;
287
+ pos = column;
288
+ }
289
+ };
290
+ // src/rules/block.ts
291
+ const SKIP_TYPES = /* @__PURE__ */ new Set([
255
292
  "code_inline",
256
293
  "math_inline",
257
294
  "fence",
@@ -266,7 +303,7 @@ const createBlockRule = (options) => {
266
303
  type: "inline",
267
304
  children: [{
268
305
  index: -1,
269
- type: (t) => !SKIP_TYPES.has(t),
306
+ type: "text",
270
307
  content: (content) => check(content.trim(), "end") !== null
271
308
  }]
272
309
  }],
@@ -288,10 +325,21 @@ const createBlockRule = (options) => {
288
325
  }
289
326
  };
290
327
  };
291
- //#endregion
292
- //#region src/rules/inline.ts
328
+ // src/rules/inline.ts
293
329
  const createInlineRules = (options) => {
294
330
  const check = getDelimiterChecker(options.left, options.right);
331
+ const takeLeadingAttrs = (target, children, i) => {
332
+ const child = children[i];
333
+ let content = child.content;
334
+ let range = check(content, "start");
335
+ while (range) {
336
+ addAttrs(target, content, range, options.allowed);
337
+ content = content.slice(range[1] + options.right.length);
338
+ range = check(content, "start");
339
+ }
340
+ if (content) child.content = content;
341
+ else children.splice(i, 1);
342
+ };
295
343
  return [{
296
344
  name: "inline nesting self-close",
297
345
  tests: [{
@@ -304,12 +352,10 @@ const createInlineRules = (options) => {
304
352
  for (let i = children.length - 1; i >= 0; i--) {
305
353
  const child = children[i];
306
354
  if (child.type !== "text") continue;
307
- const range = check(child.content, "only");
308
- if (!range) continue;
355
+ if (!check(child.content, "start")) continue;
309
356
  const prev = children[i - 1];
310
- if (prev?.nesting !== 0 || prev.type === "softbreak") continue;
311
- addAttrs(prev, child.content, range, options.allowed);
312
- children.splice(i, 1);
357
+ if (prev?.type !== "image" && prev?.type !== "code_inline") continue;
358
+ takeLeadingAttrs(prev, children, i);
313
359
  modified = true;
314
360
  }
315
361
  return modified;
@@ -326,8 +372,7 @@ const createInlineRules = (options) => {
326
372
  for (let i = children.length - 1; i >= 0; i--) {
327
373
  const child = children[i];
328
374
  if (child.type !== "text") continue;
329
- const range = check(child.content, "only");
330
- if (!range) continue;
375
+ if (!check(child.content, "start")) continue;
331
376
  const prev = children[i - 1];
332
377
  if (!prev || prev.nesting !== -1) continue;
333
378
  const openType = prev.type.replace(/_close$/, "_open");
@@ -337,16 +382,14 @@ const createInlineRules = (options) => {
337
382
  break;
338
383
  }
339
384
  if (openIdx === -1) continue;
340
- addAttrs(children[openIdx], child.content, range, options.allowed);
341
- children.splice(i, 1);
385
+ takeLeadingAttrs(children[openIdx], children, i);
342
386
  modified = true;
343
387
  }
344
388
  return modified;
345
389
  }
346
390
  }];
347
391
  };
348
- //#endregion
349
- //#region src/rules/fence.ts
392
+ // src/rules/fence.ts
350
393
  const createFenceRule = (options) => {
351
394
  const check = getDelimiterChecker(options.left, options.right);
352
395
  return {
@@ -362,30 +405,36 @@ const createFenceRule = (options) => {
362
405
  if (!range) return;
363
406
  addAttrs(token, info, range, options.allowed);
364
407
  token.info = info.slice(0, info.lastIndexOf(options.left, range[0] - 1)).trimEnd();
408
+ if (token.info && token.attrIndex("class") < 0) {
409
+ token.attrs = [["class", ""], ...token.attrs ?? []];
410
+ token.meta = {
411
+ ...token.meta,
412
+ attrsReservedClass: true
413
+ };
414
+ }
365
415
  }
366
416
  };
367
417
  };
368
- //#endregion
369
- //#region src/rules/heading.ts
418
+ // src/rules/heading.ts
370
419
  const createHeadingRule = (options) => {
371
420
  const check = getDelimiterChecker(options.left, options.right);
372
421
  return {
373
422
  name: "heading attributes",
374
423
  tests: [{
375
- shift: 0,
424
+ shift: -1,
376
425
  type: "heading_open"
377
426
  }, {
378
- shift: 1,
427
+ shift: 0,
379
428
  type: "inline",
380
429
  children: [{
381
430
  index: -1,
382
- type: (t) => t !== "code_inline" && t !== "math_inline",
431
+ type: "text",
383
432
  content: (content) => check(content.trim(), "end") !== null
384
433
  }]
385
434
  }],
386
435
  transform(tokens, index) {
387
- const openToken = tokens[index];
388
- const children = tokens[index + 1].children;
436
+ const openToken = tokens[index - 1];
437
+ const children = tokens[index].children;
389
438
  const lastChild = children[children.length - 1];
390
439
  const trimmed = lastChild.content.trimEnd();
391
440
  const range = check(trimmed, "end");
@@ -395,8 +444,7 @@ const createHeadingRule = (options) => {
395
444
  }
396
445
  };
397
446
  };
398
- //#endregion
399
- //#region src/rules/hr.ts
447
+ // src/rules/hr.ts
400
448
  const createHrRule = (options) => {
401
449
  const check = getDelimiterChecker(options.left, options.right);
402
450
  return {
@@ -422,8 +470,7 @@ const createHrRule = (options) => {
422
470
  }
423
471
  };
424
472
  };
425
- //#endregion
426
- //#region src/rules/list.ts
473
+ // src/rules/list.ts
427
474
  const createListRules = (options) => {
428
475
  const check = getDelimiterChecker(options.left, options.right);
429
476
  return [
@@ -435,7 +482,7 @@ const createListRules = (options) => {
435
482
  type: "inline",
436
483
  children: [{
437
484
  index: -1,
438
- type: (t) => t !== "code_inline",
485
+ type: "text",
439
486
  content: (content) => check(content.trim(), "end") !== null
440
487
  }]
441
488
  },
@@ -468,7 +515,7 @@ const createListRules = (options) => {
468
515
  type: "inline",
469
516
  children: [{
470
517
  index: -1,
471
- type: (t) => t !== "code_inline",
518
+ type: "text",
472
519
  content: (content) => check(content.trim(), "end") !== null
473
520
  }]
474
521
  },
@@ -500,7 +547,7 @@ const createListRules = (options) => {
500
547
  type: "inline",
501
548
  children: [{
502
549
  index: -1,
503
- type: (t) => t !== "code_inline",
550
+ type: "text",
504
551
  content: (content) => check(content.trim(), "end") !== null
505
552
  }]
506
553
  }, {
@@ -610,8 +657,7 @@ const createListRules = (options) => {
610
657
  }
611
658
  ];
612
659
  };
613
- //#endregion
614
- //#region src/rules/softbreak.ts
660
+ // src/rules/softbreak.ts
615
661
  const createSoftbreakRule = (options) => {
616
662
  const check = getDelimiterChecker(options.left, options.right);
617
663
  return {
@@ -621,32 +667,74 @@ const createSoftbreakRule = (options) => {
621
667
  type: "inline",
622
668
  children: [{
623
669
  index: -2,
624
- type: "softbreak"
670
+ type: (type) => type === "softbreak" || type === "hardbreak"
625
671
  }, {
626
672
  index: -1,
627
673
  type: "text",
628
674
  content: (content) => check(content.trim(), "only") !== null
629
675
  }]
630
676
  }],
631
- transform(tokens, index) {
632
- const children = tokens[index].children;
677
+ transform(tokens, index, _position, _range, src) {
678
+ const inline = tokens[index];
679
+ const children = inline.children;
633
680
  const content = children[children.length - 1].content.trim();
634
681
  const range = check(content, "only");
635
- let target = tokens[index];
636
- for (let i = index - 1; i >= 0; i--) {
637
- const t = tokens[i];
638
- if (t.nesting === 1) {
639
- target = t;
682
+ const ancestors = [];
683
+ let source = src;
684
+ let level = inline.level;
685
+ for (let i = index - 1; i >= 0 && level > 0; i--) {
686
+ const token = tokens[i];
687
+ if (token.nesting !== 1 || token.level >= level) continue;
688
+ level = token.level;
689
+ const meta = token.meta;
690
+ const own = typeof meta === "object" && meta !== null && "attrsSource" in meta ? meta.attrsSource : void 0;
691
+ if (typeof own === "string") {
692
+ source = own;
640
693
  break;
641
694
  }
695
+ ancestors.push(token);
696
+ }
697
+ const block = ancestors.at(0);
698
+ if (!block) return;
699
+ const lines = source.split("\n");
700
+ const containers = [];
701
+ let quotes = 0;
702
+ for (let i = ancestors.length - 1; i >= 1; i--) {
703
+ const open = ancestors[i];
704
+ if (open.type === "blockquote_open") containers.push({
705
+ open,
706
+ target: open,
707
+ line: {
708
+ kind: "quote",
709
+ markers: ++quotes
710
+ }
711
+ });
712
+ else if (open.type === "list_item_open" && open.map) {
713
+ const before = containers.filter((c) => c.open.type === "list_item_open" && c.open.map?.[0] === open.map[0]).length;
714
+ const column = itemColumns(lines[open.map[0]] ?? "").at(before);
715
+ if (column === void 0) return;
716
+ containers.push({
717
+ open,
718
+ target: ancestors.at(i + 1) ?? open,
719
+ line: {
720
+ kind: "item",
721
+ column
722
+ }
723
+ });
724
+ }
642
725
  }
726
+ const line = inline.map ? lines[inline.map[1] - 1] ?? "" : "";
727
+ const kept = inline.map ? containersKept(line, containers.map((c) => c.line)) : containers.length;
728
+ let target = block;
729
+ if (kept < containers.length) target = containers[kept].target;
730
+ else if (block.hidden && ancestors[1]?.type === "list_item_open") target = ancestors[1];
643
731
  addAttrs(target, content, range, options.allowed);
644
- children.splice(children.length - 2, 2);
732
+ const isSoft = children[children.length - 2].type === "softbreak";
733
+ children.splice(children.length - (isSoft ? 2 : 1), isSoft ? 2 : 1);
645
734
  }
646
735
  };
647
736
  };
648
- //#endregion
649
- //#region src/rules/table.ts
737
+ // src/rules/table.ts
650
738
  const createTableRules = (options) => {
651
739
  const check = getDelimiterChecker(options.left, options.right);
652
740
  return [
@@ -814,9 +902,8 @@ const createTableRules = (options) => {
814
902
  }
815
903
  ];
816
904
  };
817
- //#endregion
818
- //#region src/rules/rules.ts
819
- const ALL_RULE_SET = new Set([
905
+ // src/rules/rules.ts
906
+ const ALL_RULE_SET = /* @__PURE__ */ new Set([
820
907
  "fence",
821
908
  "inline",
822
909
  "table",
@@ -835,16 +922,15 @@ const createRules = (options) => {
835
922
  const rules = [];
836
923
  if (enabled.has("fence")) rules.push(createFenceRule(options));
837
924
  if (enabled.has("inline")) rules.push(...createInlineRules(options));
925
+ if (enabled.has("softbreak")) rules.push(createSoftbreakRule(options));
838
926
  if (enabled.has("table")) rules.push(...createTableRules(options));
839
927
  if (enabled.has("list")) rules.push(...createListRules(options));
840
928
  if (enabled.has("heading")) rules.push(createHeadingRule(options));
841
929
  if (enabled.has("hr")) rules.push(createHrRule(options));
842
- if (enabled.has("softbreak")) rules.push(createSoftbreakRule(options));
843
930
  if (enabled.has("block")) rules.push(createBlockRule(options));
844
931
  return rules;
845
932
  };
846
- //#endregion
847
- //#region src/plugin.ts
933
+ // src/plugin.ts
848
934
  /** markdown-it plugin for attribute lists (`{.class #id key=value}`) on elements. */
849
935
  const attrs = (md, { left = "{", right = "}", allowed = [], rule = "all" } = {}) => {
850
936
  const rules = createRules({
@@ -853,6 +939,11 @@ const attrs = (md, { left = "{", right = "}", allowed = [], rule = "all" } = {})
853
939
  allowed,
854
940
  rule
855
941
  });
942
+ const renderFence = md.renderer.rules.fence;
943
+ if (renderFence) md.renderer.rules.fence = (tokens, idx, opts, env, self) => {
944
+ const html = renderFence(tokens, idx, opts, env, self);
945
+ return tokens[idx].meta?.attrsReservedClass ? html.replace(" class=\" ", " class=\"") : html;
946
+ };
856
947
  md.core.ruler.before("linkify", "attrs", (state) => {
857
948
  const { tokens } = state;
858
949
  for (let index = 0; index < tokens.length; index++) for (let ruleIndex = 0; ruleIndex < rules.length; ruleIndex++) {
@@ -865,12 +956,11 @@ const attrs = (md, { left = "{", right = "}", allowed = [], rule = "all" } = {})
865
956
  if (result.range) range = result.range;
866
957
  return result.match;
867
958
  })) {
868
- if (pattern.transform(tokens, index, position, range) !== false && (pattern.name === "inline attributes" || pattern.name === "inline nesting self-close")) ruleIndex--;
959
+ if (pattern.transform(tokens, index, position, range, state.src) !== false && (pattern.name === "inline attributes" || pattern.name === "inline nesting self-close")) ruleIndex--;
869
960
  }
870
961
  }
871
962
  });
872
963
  };
873
- //#endregion
874
964
  export { attrs };
875
965
 
876
966
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/helper/getAttrs.ts","../src/helper/addAttrs.ts","../src/helper/getDelimiterChecker.ts","../src/helper/testRule.ts","../src/helper/getMatchingOpeningToken.ts","../src/rules/block.ts","../src/rules/inline.ts","../src/rules/fence.ts","../src/rules/heading.ts","../src/rules/hr.ts","../src/rules/list.ts","../src/rules/softbreak.ts","../src/rules/table.ts","../src/rules/rules.ts","../src/plugin.ts"],"sourcesContent":["import type { Attr, DelimiterRange } from \"../types.js\";\n\nconst CLASS_MARKER = 46; // '.'\nconst ID_MARKER = 35; // '#'\nconst PAIR_SEPARATOR = 32; // ' '\nconst KEY_SEPARATOR = 61; // '='\nconst QUOTE_MARKER = 34; // '\"'\n\nconst DISALLOWED_KEY_CHARS = new Set([9, 10, 12, 32, 47, 62, 34, 39, 61]);\n\nexport const getAttrs = (\n str: string,\n range: DelimiterRange,\n allowed: Array<string | RegExp>\n): Attr[] => {\n let key = \"\";\n let value = \"\";\n let parsingKey = true;\n let valueInsideQuotes = false;\n const attrs: Attr[] = [];\n\n for (let i = range[0]; i < range[1]; i++) {\n const code = str.charCodeAt(i);\n\n if (code === KEY_SEPARATOR && parsingKey) {\n parsingKey = false;\n continue;\n }\n\n if (code === CLASS_MARKER && key === \"\") {\n key =\n str.charCodeAt(i + 1) === CLASS_MARKER ? (i++, \"css-module\") : \"class\";\n parsingKey = false;\n continue;\n }\n\n if (code === ID_MARKER && key === \"\") {\n key = \"id\";\n parsingKey = false;\n continue;\n }\n\n if (code === QUOTE_MARKER) {\n if (value === \"\" && !valueInsideQuotes) {\n valueInsideQuotes = true;\n } else if (valueInsideQuotes) {\n valueInsideQuotes = false;\n }\n continue;\n }\n\n if (code === PAIR_SEPARATOR && !valueInsideQuotes) {\n if (key !== \"\") {\n attrs.push([key, value]);\n key = \"\";\n value = \"\";\n parsingKey = true;\n }\n continue;\n }\n\n if (parsingKey) {\n if (!DISALLOWED_KEY_CHARS.has(code)) key += str[i];\n } else {\n value += str[i];\n }\n }\n\n if (key !== \"\") attrs.push([key, value]);\n\n if (allowed.length === 0) return attrs;\n return attrs.filter(([attr]) =>\n allowed.some((item) =>\n item instanceof RegExp ? item.test(attr) : item === attr\n )\n );\n};\n","import type Token from \"markdown-it/lib/token.mjs\";\nimport type { DelimiterRange } from \"../types.js\";\nimport { getAttrs } from \"./getAttrs.js\";\n\nexport const addAttrs = (\n token: Token,\n content: string,\n range: DelimiterRange,\n allowed: Array<string | RegExp>\n): void => {\n for (const [key, value] of getAttrs(content, range, allowed)) {\n if (key === \"class\" || key === \"css-module\") {\n token.attrJoin(key, value);\n } else {\n token.attrPush([key, value]);\n }\n }\n};\n","import type { DelimiterRange } from \"../types.js\";\n\ntype DelimiterPosition = \"start\" | \"end\" | \"only\";\n\nexport type DelimiterChecker = (\n str: string,\n pos: DelimiterPosition\n) => DelimiterRange | null;\n\n/**\n * Returns a function that checks whether `str` contains a valid attribute\n * block at the given position (\"start\", \"end\", or \"only\") and returns the\n * [start, end] range of the content inside the delimiters, or null if no\n * match. The returned range is exclusive of the delimiter characters.\n *\n * A valid block must contain at least one character (i.e. `{}` is invalid),\n * and the outer delimiters must not be repeated (i.e. `{{}}` is invalid).\n */\nexport const getDelimiterChecker = (\n left: string,\n right: string\n): DelimiterChecker => {\n const ll = left.length;\n const rl = right.length;\n const minLen = ll + 1 + rl;\n const doubleLeft = left + left;\n const doubleRight = right + right;\n\n return (str, pos): DelimiterRange | null => {\n if (str.length < minLen) return null;\n\n if (pos === \"start\" || pos === \"only\") {\n if (!str.startsWith(left)) return null;\n if (str.startsWith(doubleLeft)) return null;\n }\n\n if (pos === \"end\" || pos === \"only\") {\n if (!str.endsWith(right)) return null;\n if (str.endsWith(doubleRight)) return null;\n }\n\n if (pos === \"only\") {\n const contentEnd = str.length - rl;\n if (contentEnd <= ll) return null;\n return [ll, contentEnd];\n }\n\n if (pos === \"start\") {\n const end = str.indexOf(right, ll + 1);\n if (end === -1) return null;\n return [ll, end];\n }\n\n // pos === \"end\"\n const start = str.lastIndexOf(left, str.length - rl - 1);\n if (start === -1) return null;\n if (str.startsWith(left, start - ll)) return null;\n return [start + ll, str.length - rl];\n };\n};\n","// Token.meta is typed `any` by markdown-it; casts bridge to our richer rule-test predicates.\n/* oxlint-disable typescript/no-unsafe-type-assertion */\nimport type Token from \"markdown-it/lib/token.mjs\";\nimport type { DelimiterRange } from \"../types.js\";\nimport type { DelimiterChecker } from \"./getDelimiterChecker.js\";\n\nexport interface RuleTest {\n /** Offset from the current token index. Mutually exclusive with `position`. */\n shift?: number;\n /** Absolute token index. Mutually exclusive with `shift`. */\n position?: number;\n /** Token type must equal this string. */\n type?: string | ((t: string) => boolean);\n /** Token tag must equal this string. */\n tag?: string;\n /** Token nesting must equal this value. */\n nesting?: number | ((n: number) => boolean);\n /** Inspect token content; called with (content, token, tokens, index). */\n content?: string | ((c: string) => boolean);\n /** Inspect token.meta; predicate receives the meta object (may be null). */\n meta?: (meta: Record<string, unknown> | null) => boolean;\n /** Inspect a child token at the given index (negative = from end). */\n children?: Array<Omit<RuleTest, \"shift\" | \"position\"> & { index?: number }>;\n /** If set, use this delimiter checker to extract a range from token content. */\n attrChecker?: DelimiterChecker;\n /** Which position argument to pass to attrChecker (\"start\"|\"end\"|\"only\"). */\n attrPos?: \"start\" | \"end\" | \"only\";\n}\n\nexport interface TestResult {\n match: boolean;\n position: number | null;\n range: DelimiterRange | null;\n}\n\nconst matches = (test: unknown, actual: unknown): boolean => {\n if (typeof test === \"function\")\n return (test as (v: unknown) => boolean)(actual);\n return test === actual;\n};\n\nconst testChild = (\n child: Token,\n childTest: Omit<RuleTest, \"shift\" | \"position\">\n): { match: boolean; range: DelimiterRange | null } => {\n let range: DelimiterRange | null = null;\n\n if (childTest.type !== undefined && !matches(childTest.type, child.type)) {\n return { match: false, range: null };\n }\n if (\n childTest.nesting !== undefined &&\n !matches(childTest.nesting, child.nesting)\n ) {\n return { match: false, range: null };\n }\n if (childTest.tag !== undefined && child.tag !== childTest.tag) {\n return { match: false, range: null };\n }\n if (childTest.content !== undefined) {\n if (!matches(childTest.content, child.content))\n return { match: false, range: null };\n }\n if (childTest.attrChecker) {\n range = childTest.attrChecker(child.content, childTest.attrPos ?? \"only\");\n if (!range) return { match: false, range: null };\n }\n\n return { match: true, range };\n};\n\nexport const testRule = (\n tokens: Token[],\n index: number,\n test: RuleTest\n): TestResult => {\n let tokenIndex: number;\n if (test.position !== undefined) {\n tokenIndex =\n test.position < 0 ? tokens.length + test.position : test.position;\n } else {\n tokenIndex = index + (test.shift ?? 0);\n }\n\n const token = tokens[tokenIndex];\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (!token) return { match: false, position: null, range: null };\n\n let range: DelimiterRange | null = null;\n\n if (test.type !== undefined && !matches(test.type, token.type)) {\n return { match: false, position: null, range: null };\n }\n if (test.nesting !== undefined && !matches(test.nesting, token.nesting)) {\n return { match: false, position: null, range: null };\n }\n if (test.tag !== undefined && token.tag !== test.tag) {\n return { match: false, position: null, range: null };\n }\n if (test.content !== undefined && !matches(test.content, token.content)) {\n return { match: false, position: null, range: null };\n }\n if (\n test.meta !== undefined &&\n !test.meta((token.meta as Record<string, unknown> | null) ?? null)\n ) {\n return { match: false, position: null, range: null };\n }\n if (test.attrChecker) {\n range = test.attrChecker(token.content, test.attrPos ?? \"only\");\n if (!range) return { match: false, position: null, range: null };\n }\n\n if (test.children) {\n const children = token.children ?? [];\n for (const childTest of test.children) {\n const idx =\n childTest.index !== undefined\n ? childTest.index < 0\n ? children.length + childTest.index\n : childTest.index\n : -1;\n\n if (idx >= 0) {\n const child = children[idx];\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (!child) return { match: false, position: null, range: null };\n const result = testChild(child, childTest);\n if (!result.match) return { match: false, position: null, range: null };\n if (result.range) range = result.range;\n } else {\n // No index: find any matching child\n const found = children.some((child) => {\n const result = testChild(child, childTest);\n if (result.range) range = result.range;\n return result.match;\n });\n if (!found) return { match: false, position: null, range: null };\n }\n }\n }\n\n return { match: true, position: tokenIndex, range };\n};\n","import type Token from \"markdown-it/lib/token.mjs\";\n\n/**\n * Given a closing or self-closing token at `index`, returns its matching\n * opening token by walking backwards to find the token of the same type at\n * the same nesting level. Returns the token itself for nesting === 0.\n */\nexport const getMatchingOpeningToken = (\n tokens: Token[],\n index: number\n): Token | null => {\n const token = tokens[index];\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (!token) return null;\n if (token.type === \"softbreak\") return null;\n if (token.nesting === 0) return token;\n\n const target = token.type.replace(/_close$/, \"_open\");\n let depth = 0;\n\n for (let i = index; i >= 0; i--) {\n const t = tokens[i];\n if (t.type === token.type) depth++;\n else if (t.type === target) {\n depth--;\n if (depth === 0) return t;\n }\n }\n\n return null;\n};\n","import type { DelimiterConfig } from \"../types.js\";\nimport {\n addAttrs,\n getDelimiterChecker,\n getMatchingOpeningToken\n} from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\n// Token types that should not be treated as attr targets\nconst SKIP_TYPES = new Set([\n \"code_inline\",\n \"math_inline\",\n \"fence\",\n \"code_block\"\n]);\n\nexport const createBlockRule = (options: DelimiterConfig): AttrRule => {\n const check = getDelimiterChecker(options.left, options.right);\n\n return {\n name: \"block attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: -1,\n type: (t: string) => !SKIP_TYPES.has(t),\n content: (content: string) => check(content.trim(), \"end\") !== null\n }\n ]\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const lastChild = children[children.length - 1];\n\n const content = lastChild.content.trimEnd();\n const range = check(content, \"end\")!;\n\n // Find the block-level opening token that contains this inline\n // Walk backwards: skip the paragraph_open immediately before, then\n // look for the outermost open that wraps this inline token.\n let openToken = null;\n\n // First: find the _close token that closes the block containing this inline\n // by walking forward from the inline's position\n let closeIdx = index + 1;\n while (closeIdx < tokens.length && tokens[closeIdx].nesting !== -1) {\n closeIdx++;\n }\n\n if (closeIdx < tokens.length) {\n openToken = getMatchingOpeningToken(tokens, closeIdx);\n }\n\n if (!openToken) return;\n if (SKIP_TYPES.has(openToken.type)) return;\n\n addAttrs(openToken, content, range, options.allowed);\n\n // Strip the attr block from the last child's content\n const attrStart = content.lastIndexOf(options.left, range[0] - 1);\n lastChild.content = content.slice(0, attrStart).trimEnd();\n\n // Drop the child if now empty\n if (lastChild.content === \"\" && children.length > 1) {\n children.pop();\n }\n }\n };\n};\n","import type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createInlineRules = (options: DelimiterConfig): AttrRule[] => {\n const check = getDelimiterChecker(options.left, options.right);\n\n // Handles self-closing inline elements: `code`, images (nesting === 0)\n const selfClose: AttrRule = {\n name: \"inline nesting self-close\",\n tests: [{ shift: 0, type: \"inline\" }],\n transform(tokens, index) {\n const token = tokens[index];\n const children = token.children!;\n let modified = false;\n\n for (let i = children.length - 1; i >= 0; i--) {\n const child = children[i];\n if (child.type !== \"text\") continue;\n\n const range = check(child.content, \"only\");\n if (!range) continue;\n\n // The preceding sibling must be nesting === 0 but not a softbreak\n const prev = children[i - 1];\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (prev?.nesting !== 0 || prev.type === \"softbreak\") continue;\n\n addAttrs(prev, child.content, range, options.allowed);\n children.splice(i, 1);\n modified = true;\n }\n\n return modified;\n }\n };\n\n // Handles closing inline elements: em, strong, s, etc. (nesting === -1)\n const closing: AttrRule = {\n name: \"inline attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\"\n }\n ],\n transform(tokens, index) {\n const token = tokens[index];\n const children = token.children!;\n let modified = false;\n\n for (let i = children.length - 1; i >= 0; i--) {\n const child = children[i];\n if (child.type !== \"text\") continue;\n\n const range = check(child.content, \"only\");\n if (!range) continue;\n\n // The preceding sibling must be a closing tag (nesting === -1)\n const prev = children[i - 1];\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (!prev || prev.nesting !== -1) continue;\n\n // Find the matching opening token among children\n const openType = prev.type.replace(/_close$/, \"_open\");\n let openIdx = -1;\n for (let j = i - 2; j >= 0; j--) {\n if (\n children[j].type === openType &&\n children[j].level === prev.level\n ) {\n openIdx = j;\n break;\n }\n }\n if (openIdx === -1) continue;\n\n addAttrs(children[openIdx], child.content, range, options.allowed);\n children.splice(i, 1);\n modified = true;\n }\n\n return modified;\n }\n };\n\n return [selfClose, closing];\n};\n","import type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createFenceRule = (options: DelimiterConfig): AttrRule => {\n const check = getDelimiterChecker(options.left, options.right);\n\n return {\n name: \"fence attributes\",\n tests: [\n {\n shift: 0,\n type: \"fence\"\n }\n ],\n transform(tokens, index) {\n const token = tokens[index];\n const info = token.info.trim();\n const range = check(info, \"end\") ?? check(info, \"only\");\n if (!range) return;\n addAttrs(token, info, range, options.allowed);\n // Strip the attr block from the info string, preserving the language tag\n token.info = info\n .slice(0, info.lastIndexOf(options.left, range[0] - 1))\n .trimEnd();\n }\n };\n};\n","import type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createHeadingRule = (options: DelimiterConfig): AttrRule => {\n const check = getDelimiterChecker(options.left, options.right);\n\n return {\n name: \"heading attributes\",\n tests: [\n {\n shift: 0,\n type: \"heading_open\"\n },\n {\n shift: 1,\n type: \"inline\",\n children: [\n {\n index: -1,\n type: (t: string) => t !== \"code_inline\" && t !== \"math_inline\",\n content: (content: string) => check(content.trim(), \"end\") !== null\n }\n ]\n }\n ],\n transform(tokens, index) {\n const openToken = tokens[index];\n const inline = tokens[index + 1];\n const children = inline.children!;\n const lastChild = children[children.length - 1];\n\n const content = lastChild.content;\n const trimmed = content.trimEnd();\n const range = check(trimmed, \"end\")!;\n\n addAttrs(openToken, trimmed, range, options.allowed);\n\n // Strip the attr block from the last child content\n const before = trimmed.slice(\n 0,\n trimmed.lastIndexOf(options.left, range[0] - 1)\n );\n lastChild.content = before.trimEnd();\n\n // Drop the child entirely if it's now empty\n if (lastChild.content === \"\" && children.length > 1) {\n children.pop();\n }\n }\n };\n};\n","import type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createHrRule = (options: DelimiterConfig): AttrRule => {\n const check = getDelimiterChecker(options.left, options.right);\n\n return {\n name: \"hr attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: 0,\n type: \"text\",\n content: (content: string) => check(content.trim(), \"only\") !== null\n }\n ]\n },\n {\n shift: -2,\n type: \"hr\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const textChild = inline.children![0];\n const content = textChild.content.trim();\n const range = check(content, \"only\")!;\n\n const hr = tokens[index - 2];\n addAttrs(hr, content, range, options.allowed);\n\n // Remove paragraph_open + inline + paragraph_close\n tokens.splice(index - 1, 3);\n }\n };\n};\n","import type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createListRules = (options: DelimiterConfig): AttrRule[] => {\n const check = getDelimiterChecker(options.left, options.right);\n\n // Rule 1: attrs at end of a list item inline \"- item{.red}\"\n // Structure: list_item_open(-2) paragraph_open(-1) inline(0)\n const listItemEnd: AttrRule = {\n name: \"list item end\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: -1,\n type: (t: string) => t !== \"code_inline\",\n content: (content: string) => check(content.trim(), \"end\") !== null\n }\n ]\n },\n {\n shift: -1,\n type: \"paragraph_open\"\n },\n {\n shift: -2,\n type: \"list_item_open\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const lastChild = children[children.length - 1];\n const content = lastChild.content.trimEnd();\n const range = check(content, \"end\")!;\n\n const listItemOpen = tokens[index - 2];\n addAttrs(listItemOpen, content, range, options.allowed);\n\n const attrStart = content.lastIndexOf(options.left, range[0] - 1);\n lastChild.content = content.slice(0, attrStart).trimEnd();\n if (lastChild.content === \"\" && children.length > 1) children.pop();\n }\n };\n\n // Rule 1b (generic): attrs at end of a custom item title inline\n // Matches when the open token two before the inline has meta.attrsRole === \"containerItem\"\n // and the token one before has meta.attrsItemTitle === true.\n // Third-party plugins opt in by setting these meta fields on their tokens.\n const customItemEnd: AttrRule = {\n name: \"custom item end\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: -1,\n type: (t: string) => t !== \"code_inline\",\n content: (content: string) => check(content.trim(), \"end\") !== null\n }\n ]\n },\n {\n shift: -1,\n meta: (m) => m?.attrsItemTitle === true\n },\n {\n shift: -2,\n meta: (m) => m?.attrsRole === \"containerItem\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const lastChild = children[children.length - 1];\n const content = lastChild.content.trimEnd();\n const range = check(content, \"end\")!;\n\n const itemOpen = tokens[index - 2];\n addAttrs(itemOpen, content, range, options.allowed);\n\n const attrStart = content.lastIndexOf(options.left, range[0] - 1);\n lastChild.content = content.slice(0, attrStart).trimEnd();\n if (lastChild.content === \"\" && children.length > 1) children.pop();\n }\n };\n\n // Rule 1c (direct): attrs at end of a custom item inline where the open token\n // itself carries both attrsRole === \"containerItem\" AND attrsItemTitle === true.\n // Matches dt_open → inline (no intermediate title token).\n const customItemEndDirect: AttrRule = {\n name: \"custom item end direct\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: -1,\n type: (t: string) => t !== \"code_inline\",\n content: (content: string) => check(content.trim(), \"end\") !== null\n }\n ]\n },\n {\n shift: -1,\n meta: (m: Record<string, unknown> | null) =>\n m?.attrsItemTitle === true && m.attrsRole === \"containerItem\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const lastChild = children[children.length - 1];\n const content = lastChild.content.trimEnd();\n const range = check(content, \"end\")!;\n\n const itemOpen = tokens[index - 1];\n addAttrs(itemOpen, content, range, options.allowed);\n\n const attrStart = content.lastIndexOf(options.left, range[0] - 1);\n lastChild.content = content.slice(0, attrStart).trimEnd();\n if (lastChild.content === \"\" && children.length > 1) children.pop();\n }\n };\n\n // Rule 2: attrs on own paragraph after bullet/ordered list close → apply to list\n // Structure: bullet_list_close(-2) paragraph_open(-1) inline(0) paragraph_close(+1)\n const listAttr: AttrRule = {\n name: \"list attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: 0,\n type: \"text\",\n content: (content: string) => check(content.trim(), \"only\") !== null\n }\n ]\n },\n {\n shift: -1,\n type: \"paragraph_open\"\n },\n {\n shift: -2,\n type: (t: string) =>\n t === \"bullet_list_close\" || t === \"ordered_list_close\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const textChild = children[0];\n const content = textChild.content.trim();\n const range = check(content, \"only\")!;\n\n // Find the matching list_open for the close token at index-2\n const closeToken = tokens[index - 2];\n const openType = closeToken.type.replace(\"_close\", \"_open\");\n\n let depth = 1;\n let listOpenIdx = -1;\n for (let i = index - 3; i >= 0; i--) {\n const t = tokens[i];\n if (t.type === closeToken.type) depth++;\n else if (t.type === openType) {\n depth--;\n if (depth === 0) {\n listOpenIdx = i;\n break;\n }\n }\n }\n\n if (listOpenIdx === -1) return;\n addAttrs(tokens[listOpenIdx], content, range, options.allowed);\n\n // Remove paragraph_open + inline + paragraph_close\n tokens.splice(index - 1, 3);\n }\n };\n\n // Rule 2b (generic): attrs on own paragraph after a custom container close → apply to container open\n // Matches when the close token two before the paragraph has meta.attrsRole === \"container\".\n // Third-party plugins opt in by setting meta.attrsRole = \"container\" on their open/close tokens.\n const customListAttr: AttrRule = {\n name: \"custom list attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: 0,\n type: \"text\",\n content: (content: string) => check(content.trim(), \"only\") !== null\n }\n ]\n },\n {\n shift: -1,\n type: \"paragraph_open\"\n },\n {\n shift: -2,\n type: (t: string) => t.endsWith(\"_close\"),\n meta: (m) => m?.attrsRole === \"container\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const textChild = children[0];\n const content = textChild.content.trim();\n const range = check(content, \"only\")!;\n\n // Walk back to find the matching open token (same type with _open suffix)\n const closeToken = tokens[index - 2];\n const openType = closeToken.type.replace(\"_close\", \"_open\");\n\n let depth = 1;\n let listOpenIdx = -1;\n for (let i = index - 3; i >= 0; i--) {\n const t = tokens[i];\n if (t.type === closeToken.type) depth++;\n else if (t.type === openType) {\n depth--;\n if (depth === 0) {\n listOpenIdx = i;\n break;\n }\n }\n }\n\n if (listOpenIdx === -1) return;\n addAttrs(tokens[listOpenIdx], content, range, options.allowed);\n\n // Remove paragraph_open + inline + paragraph_close\n tokens.splice(index - 1, 3);\n }\n };\n\n return [\n listItemEnd,\n customItemEnd,\n customItemEndDirect,\n listAttr,\n customListAttr\n ];\n};\n","import type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createSoftbreakRule = (options: DelimiterConfig): AttrRule => {\n const check = getDelimiterChecker(options.left, options.right);\n\n return {\n name: \"softbreak attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n // second-to-last child must be a softbreak\n index: -2,\n type: \"softbreak\"\n },\n {\n // last child must be a text node containing only an attr block\n index: -1,\n type: \"text\",\n content: (content: string) => check(content.trim(), \"only\") !== null\n }\n ]\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const attrChild = children[children.length - 1];\n\n const content = attrChild.content.trim();\n const range = check(content, \"only\")!;\n\n // Walk backward to find the nearest nesting===1 opener that contains this inline\n let target = tokens[index];\n for (let i = index - 1; i >= 0; i--) {\n const t = tokens[i];\n if (t.nesting === 1) {\n target = t;\n break;\n }\n }\n\n addAttrs(target, content, range, options.allowed);\n\n // Remove the attr text child and the preceding softbreak\n children.splice(children.length - 2, 2);\n }\n };\n};\n","// TableMeta lives on Token.meta which markdown-it types as any — casts narrow to the rule-specific shape.\n/* oxlint-disable typescript/no-unsafe-type-assertion */\nimport type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createTableRules = (options: DelimiterConfig): AttrRule[] => {\n const check = getDelimiterChecker(options.left, options.right);\n\n // Rule 1: table-level attrs — standalone paragraph after the table \"\\n{.class}\"\n const tableAttrs: AttrRule = {\n name: \"table attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: 0,\n type: \"text\",\n content: (content: string) => check(content.trim(), \"only\") !== null\n }\n ]\n },\n {\n shift: -1,\n type: \"paragraph_open\"\n },\n {\n shift: -2,\n type: \"table_close\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const content = inline.children![0].content.trim();\n const range = check(content, \"only\")!;\n\n // Find the matching table_open (start from table_close at index-2)\n let tableOpenIdx = -1;\n let depth = 1;\n for (let i = index - 3; i >= 0; i--) {\n const t = tokens[i];\n if (t.type === \"table_close\") depth++;\n else if (t.type === \"table_open\") {\n depth--;\n if (depth === 0) {\n tableOpenIdx = i;\n break;\n }\n }\n }\n if (tableOpenIdx === -1) return;\n\n addAttrs(tokens[tableOpenIdx], content, range, options.allowed);\n\n // Remove paragraph_open + inline + paragraph_close\n tokens.splice(index - 1, 3);\n }\n };\n\n // Rule 2: table cell attrs — \"cell content {.class}\" inside td/th\n const tableCellAttrs: AttrRule = {\n name: \"table cell attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: -1,\n type: \"text\",\n content: (content: string) => check(content.trim(), \"end\") !== null\n }\n ]\n },\n {\n shift: -1,\n type: (t: string) => t === \"td_open\" || t === \"th_open\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const lastChild = children[children.length - 1];\n const content = lastChild.content.trimEnd();\n const range = check(content, \"end\")!;\n\n const cellOpen = tokens[index - 1];\n addAttrs(cellOpen, content, range, options.allowed);\n\n const attrStart = content.lastIndexOf(options.left, range[0] - 1);\n lastChild.content = content.slice(0, attrStart).trimEnd();\n if (lastChild.content === \"\" && children.length > 1) children.pop();\n }\n };\n\n // Rule 3: track column count in thead (stored as metadata for rowspan/colspan calc)\n interface TableMeta {\n cols: number;\n rowspan: number[];\n }\n\n const colTracker: AttrRule = {\n name: \"table column tracker\",\n tests: [{ shift: 0, type: \"tr_open\" }],\n transform(tokens, index) {\n // Count th tokens in this row to know column count; stored on thead_open meta\n let cols = 0;\n for (let i = index + 1; i < tokens.length; i++) {\n const t = tokens[i];\n if (t.type === \"tr_close\") break;\n if (t.type === \"th_open\") cols++;\n }\n if (cols === 0) return;\n\n // Find thead_open and store column count\n for (let i = index - 1; i >= 0; i--) {\n const t = tokens[i];\n if (t.type === \"thead_open\") {\n t.meta = t.meta ?? {};\n (t.meta as TableMeta).cols = cols;\n break;\n }\n if (t.type === \"table_open\") break;\n }\n }\n };\n\n // Rule 4: colspan/rowspan calculation — remove phantom cells, adjust span values\n const spanCalc: AttrRule = {\n name: \"table span calculator\",\n tests: [{ shift: 0, type: \"tbody_open\" }],\n transform(tokens, index) {\n // Find matching thead_open to get column count\n let cols = 0;\n for (let i = index - 1; i >= 0; i--) {\n const t = tokens[i];\n if (t.type === \"thead_open\") {\n cols = (t.meta as TableMeta | undefined)?.cols ?? 0;\n break;\n }\n if (t.type === \"table_open\") break;\n }\n if (cols === 0) return;\n\n // Find the tbody_close\n let tbodyClose = index + 1;\n let depth = 1;\n while (tbodyClose < tokens.length && depth > 0) {\n const t = tokens[tbodyClose];\n if (t.type === \"tbody_open\") depth++;\n else if (t.type === \"tbody_close\") depth--;\n tbodyClose++;\n }\n tbodyClose--;\n\n // Process each row within tbody\n const occupied: number[] = Array.from({ length: cols }, () => 0);\n\n let i = index + 1;\n while (i < tbodyClose) {\n const t = tokens[i];\n if (t.type === \"tr_open\") {\n // Decrement all occupied counts\n for (let c = 0; c < cols; c++) {\n if (occupied[c] > 0) occupied[c]--;\n }\n\n // Collect td tokens in this row\n const tdIndices: number[] = [];\n for (let j = i + 1; j < tbodyClose; j++) {\n if (tokens[j].type === \"tr_close\") break;\n if (tokens[j].type === \"td_open\") tdIndices.push(j);\n }\n\n // Assign cells to columns, skipping occupied ones\n let col = 0;\n let tdIdx = 0;\n\n while (col < cols && tdIdx < tdIndices.length) {\n // Skip occupied columns (from rowspan)\n while (col < cols && occupied[col] > 0) col++;\n if (col >= cols) break;\n\n const tdOpen = tokens[tdIndices[tdIdx]];\n const rowspanAttr = tdOpen.attrGet(\"rowspan\");\n const colspanAttr = tdOpen.attrGet(\"colspan\");\n const rowspan = rowspanAttr ? parseInt(rowspanAttr, 10) : 1;\n let colspan = colspanAttr ? parseInt(colspanAttr, 10) : 1;\n\n // Count how many consecutive free columns are available\n let freeCols = 0;\n for (let c = col; c < cols && occupied[c] === 0; c++) freeCols++;\n\n // Clamp colspan to available free columns\n if (colspan > freeCols) {\n colspan = freeCols;\n if (colspan === 1) {\n // Remove colspan attr if it resolved to 1 (keep as-is if explicitly set)\n // We keep it to match reference behavior: colspan=\"1\" is left on token\n }\n tdOpen.attrSet(\"colspan\", String(colspan));\n }\n\n // Mark columns occupied by this cell's rowspan\n for (let c = col; c < col + colspan && c < cols; c++) {\n if (rowspan > 1) occupied[c] = rowspan - 1;\n }\n\n col += colspan;\n tdIdx++;\n }\n\n // Remove phantom cells beyond assigned ones\n // (cells that were merged away by rowspan from a previous row)\n while (tdIdx < tdIndices.length) {\n const phantomStart = tdIndices[tdIdx];\n // Find the matching td_close\n let phantomEnd = phantomStart + 1;\n while (\n phantomEnd < tokens.length &&\n tokens[phantomEnd].type !== \"td_close\"\n ) {\n phantomEnd++;\n }\n tokens.splice(phantomStart, phantomEnd - phantomStart + 1);\n tbodyClose -= phantomEnd - phantomStart + 1;\n // Don't increment tdIdx since we just spliced\n }\n }\n i++;\n }\n }\n };\n\n return [tableAttrs, tableCellAttrs, colTracker, spanCalc];\n};\n","import type { AttrsOptions, AttrRuleName, DelimiterConfig } from \"../types.js\";\nimport type { AttrRule } from \"./types.js\";\nimport { createBlockRule } from \"./block.js\";\nimport { createInlineRules } from \"./inline.js\";\nimport { createFenceRule } from \"./fence.js\";\nimport { createHeadingRule } from \"./heading.js\";\nimport { createHrRule } from \"./hr.js\";\nimport { createListRules } from \"./list.js\";\nimport { createSoftbreakRule } from \"./softbreak.js\";\nimport { createTableRules } from \"./table.js\";\n\nconst ALL_RULE_NAMES: AttrRuleName[] = [\n \"fence\",\n \"inline\",\n \"table\",\n \"list\",\n \"heading\",\n \"hr\",\n \"softbreak\",\n \"block\"\n];\n\nconst ALL_RULE_SET = new Set<string>(ALL_RULE_NAMES);\n\nexport const createRules = (\n options: DelimiterConfig & Pick<AttrsOptions, \"rule\">\n): AttrRule[] => {\n const { rule = \"all\" } = options;\n\n let enabled: Set<string>;\n if (rule === \"all\" || rule === true) {\n enabled = ALL_RULE_SET;\n } else if (!rule || (Array.isArray(rule) && rule.length === 0)) {\n return [];\n } else {\n enabled = new Set(rule.filter((r) => ALL_RULE_SET.has(r)));\n }\n\n const rules: AttrRule[] = [];\n\n if (enabled.has(\"fence\")) rules.push(createFenceRule(options));\n if (enabled.has(\"inline\")) rules.push(...createInlineRules(options));\n if (enabled.has(\"table\")) rules.push(...createTableRules(options));\n if (enabled.has(\"list\")) rules.push(...createListRules(options));\n if (enabled.has(\"heading\")) rules.push(createHeadingRule(options));\n if (enabled.has(\"hr\")) rules.push(createHrRule(options));\n if (enabled.has(\"softbreak\")) rules.push(createSoftbreakRule(options));\n if (enabled.has(\"block\")) rules.push(createBlockRule(options));\n\n return rules;\n};\n","import type { PluginWithOptions } from \"markdown-it\";\nimport type { AttrsOptions, DelimiterRange } from \"./types.js\";\nimport { createRules } from \"./rules/index.js\";\nimport { testRule } from \"./helper/index.js\";\n\n/** markdown-it plugin for attribute lists (`{.class #id key=value}`) on elements. */\nexport const attrs: PluginWithOptions<AttrsOptions> = (\n md,\n { left = \"{\", right = \"}\", allowed = [], rule = \"all\" } = {}\n) => {\n const rules = createRules({ left, right, allowed, rule });\n\n md.core.ruler.before(\"linkify\", \"attrs\", (state) => {\n const { tokens } = state;\n\n for (let index = 0; index < tokens.length; index++) {\n for (let ruleIndex = 0; ruleIndex < rules.length; ruleIndex++) {\n const pattern = rules[ruleIndex];\n let position: number | null = null;\n let range: DelimiterRange | null = null;\n\n const match = pattern.tests.every((test) => {\n const result = testRule(tokens, index, test);\n if (result.position != null) position = result.position;\n if (result.range) range = result.range;\n return result.match;\n });\n\n if (match) {\n const modified = pattern.transform(tokens, index, position!, range!);\n\n if (\n modified !== false &&\n (pattern.name === \"inline attributes\" ||\n pattern.name === \"inline nesting self-close\")\n ) {\n ruleIndex--;\n }\n }\n }\n }\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/helper/getAttrs.ts","../src/helper/addAttrs.ts","../src/helper/getDelimiterChecker.ts","../src/helper/testRule.ts","../src/helper/getMatchingOpeningToken.ts","../src/helper/containers.ts","../src/rules/block.ts","../src/rules/inline.ts","../src/rules/fence.ts","../src/rules/heading.ts","../src/rules/hr.ts","../src/rules/list.ts","../src/rules/softbreak.ts","../src/rules/table.ts","../src/rules/rules.ts","../src/plugin.ts"],"sourcesContent":["import type { Attr, DelimiterRange } from \"../types.js\";\n\nconst CLASS_MARKER = 46; // '.'\nconst ID_MARKER = 35; // '#'\nconst PAIR_SEPARATOR = 32; // ' '\nconst KEY_SEPARATOR = 61; // '='\nconst QUOTE_MARKER = 34; // '\"'\n\nconst DISALLOWED_KEY_CHARS = new Set([9, 10, 12, 32, 47, 62, 34, 39, 61]);\n\nexport const getAttrs = (\n str: string,\n range: DelimiterRange,\n allowed: Array<string | RegExp>\n): Attr[] => {\n let key = \"\";\n let value = \"\";\n let parsingKey = true;\n let valueInsideQuotes = false;\n const attrs: Attr[] = [];\n\n for (let i = range[0]; i < range[1]; i++) {\n const code = str.charCodeAt(i);\n\n if (code === KEY_SEPARATOR && parsingKey) {\n parsingKey = false;\n continue;\n }\n\n if (code === CLASS_MARKER && key === \"\") {\n key =\n str.charCodeAt(i + 1) === CLASS_MARKER ? (i++, \"css-module\") : \"class\";\n parsingKey = false;\n continue;\n }\n\n if (code === ID_MARKER && key === \"\") {\n key = \"id\";\n parsingKey = false;\n continue;\n }\n\n if (code === QUOTE_MARKER) {\n if (value === \"\" && !valueInsideQuotes) {\n valueInsideQuotes = true;\n } else if (valueInsideQuotes) {\n valueInsideQuotes = false;\n }\n continue;\n }\n\n if (code === PAIR_SEPARATOR && !valueInsideQuotes) {\n if (key !== \"\") {\n attrs.push([key, value]);\n key = \"\";\n value = \"\";\n parsingKey = true;\n }\n continue;\n }\n\n if (parsingKey) {\n if (!DISALLOWED_KEY_CHARS.has(code)) key += str[i];\n } else {\n value += str[i];\n }\n }\n\n if (key !== \"\") attrs.push([key, value]);\n\n if (allowed.length === 0) return attrs;\n return attrs.filter(([attr]) =>\n allowed.some((item) =>\n item instanceof RegExp ? item.test(attr) : item === attr\n )\n );\n};\n","import type Token from \"markdown-it/lib/token.mjs\";\nimport type { DelimiterRange } from \"../types.js\";\nimport { getAttrs } from \"./getAttrs.js\";\n\nexport const addAttrs = (\n token: Token,\n content: string,\n range: DelimiterRange,\n allowed: Array<string | RegExp>\n): void => {\n for (const [key, value] of getAttrs(content, range, allowed)) {\n if (key === \"class\" || key === \"css-module\") {\n token.attrJoin(key, value);\n } else {\n token.attrPush([key, value]);\n }\n }\n};\n","import type { DelimiterRange } from \"../types.js\";\n\ntype DelimiterPosition = \"start\" | \"end\" | \"only\";\n\nexport type DelimiterChecker = (\n str: string,\n pos: DelimiterPosition\n) => DelimiterRange | null;\n\n/**\n * Returns a function that checks whether `str` contains a valid attribute\n * block at the given position (\"start\", \"end\", or \"only\") and returns the\n * [start, end] range of the content inside the delimiters, or null if no\n * match. The returned range is exclusive of the delimiter characters.\n *\n * A valid block must contain at least one character (i.e. `{}` is invalid),\n * and the outer delimiters must not be repeated (i.e. `{{}}` is invalid).\n */\nexport const getDelimiterChecker = (\n left: string,\n right: string\n): DelimiterChecker => {\n const ll = left.length;\n const rl = right.length;\n const minLen = ll + 1 + rl;\n const doubleLeft = left + left;\n const doubleRight = right + right;\n\n return (str, pos): DelimiterRange | null => {\n if (str.length < minLen) return null;\n\n if (pos === \"start\" || pos === \"only\") {\n if (!str.startsWith(left)) return null;\n if (str.startsWith(doubleLeft)) return null;\n }\n\n if (pos === \"end\" || pos === \"only\") {\n if (!str.endsWith(right)) return null;\n if (str.endsWith(doubleRight)) return null;\n }\n\n if (pos === \"only\") {\n const contentEnd = str.length - rl;\n if (contentEnd <= ll) return null;\n // `{.a} {#b}` is text followed by a block, as \"end\" reads it, not one block.\n if (str.lastIndexOf(left, contentEnd - 1) !== 0) return null;\n return [ll, contentEnd];\n }\n\n if (pos === \"start\") {\n const end = str.indexOf(right, ll + 1);\n if (end === -1) return null;\n return [ll, end];\n }\n\n // pos === \"end\"\n const start = str.lastIndexOf(left, str.length - rl - 1);\n if (start === -1) return null;\n if (start >= ll && str.startsWith(left, start - ll)) return null;\n return [start + ll, str.length - rl];\n };\n};\n","// Token.meta is typed `any` by markdown-it; casts bridge to our richer rule-test predicates.\n/* oxlint-disable typescript/no-unsafe-type-assertion */\nimport type Token from \"markdown-it/lib/token.mjs\";\nimport type { DelimiterRange } from \"../types.js\";\nimport type { DelimiterChecker } from \"./getDelimiterChecker.js\";\n\nexport interface RuleTest {\n /** Offset from the current token index. Mutually exclusive with `position`. */\n shift?: number;\n /** Absolute token index. Mutually exclusive with `shift`. */\n position?: number;\n /** Token type must equal this string. */\n type?: string | ((t: string) => boolean);\n /** Token tag must equal this string. */\n tag?: string;\n /** Token nesting must equal this value. */\n nesting?: number | ((n: number) => boolean);\n /** Inspect token content; called with (content, token, tokens, index). */\n content?: string | ((c: string) => boolean);\n /** Inspect token.meta; predicate receives the meta object (may be null). */\n meta?: (meta: Record<string, unknown> | null) => boolean;\n /** Inspect a child token at the given index (negative = from end). */\n children?: Array<Omit<RuleTest, \"shift\" | \"position\"> & { index?: number }>;\n /** If set, use this delimiter checker to extract a range from token content. */\n attrChecker?: DelimiterChecker;\n /** Which position argument to pass to attrChecker (\"start\"|\"end\"|\"only\"). */\n attrPos?: \"start\" | \"end\" | \"only\";\n}\n\nexport interface TestResult {\n match: boolean;\n position: number | null;\n range: DelimiterRange | null;\n}\n\nconst matches = (test: unknown, actual: unknown): boolean => {\n if (typeof test === \"function\")\n return (test as (v: unknown) => boolean)(actual);\n return test === actual;\n};\n\nconst testChild = (\n child: Token,\n childTest: Omit<RuleTest, \"shift\" | \"position\">\n): { match: boolean; range: DelimiterRange | null } => {\n let range: DelimiterRange | null = null;\n\n if (childTest.type !== undefined && !matches(childTest.type, child.type)) {\n return { match: false, range: null };\n }\n if (\n childTest.nesting !== undefined &&\n !matches(childTest.nesting, child.nesting)\n ) {\n return { match: false, range: null };\n }\n if (childTest.tag !== undefined && child.tag !== childTest.tag) {\n return { match: false, range: null };\n }\n if (childTest.content !== undefined) {\n if (!matches(childTest.content, child.content))\n return { match: false, range: null };\n }\n if (childTest.attrChecker) {\n range = childTest.attrChecker(child.content, childTest.attrPos ?? \"only\");\n if (!range) return { match: false, range: null };\n }\n\n return { match: true, range };\n};\n\nexport const testRule = (\n tokens: Token[],\n index: number,\n test: RuleTest\n): TestResult => {\n let tokenIndex: number;\n if (test.position !== undefined) {\n tokenIndex =\n test.position < 0 ? tokens.length + test.position : test.position;\n } else {\n tokenIndex = index + (test.shift ?? 0);\n }\n\n const token = tokens[tokenIndex];\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (!token) return { match: false, position: null, range: null };\n\n let range: DelimiterRange | null = null;\n\n if (test.type !== undefined && !matches(test.type, token.type)) {\n return { match: false, position: null, range: null };\n }\n if (test.nesting !== undefined && !matches(test.nesting, token.nesting)) {\n return { match: false, position: null, range: null };\n }\n if (test.tag !== undefined && token.tag !== test.tag) {\n return { match: false, position: null, range: null };\n }\n if (test.content !== undefined && !matches(test.content, token.content)) {\n return { match: false, position: null, range: null };\n }\n if (\n test.meta !== undefined &&\n !test.meta((token.meta as Record<string, unknown> | null) ?? null)\n ) {\n return { match: false, position: null, range: null };\n }\n if (test.attrChecker) {\n range = test.attrChecker(token.content, test.attrPos ?? \"only\");\n if (!range) return { match: false, position: null, range: null };\n }\n\n if (test.children) {\n const children = token.children ?? [];\n for (const childTest of test.children) {\n const idx =\n childTest.index !== undefined\n ? childTest.index < 0\n ? children.length + childTest.index\n : childTest.index\n : -1;\n\n if (idx >= 0) {\n const child = children[idx];\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (!child) return { match: false, position: null, range: null };\n const result = testChild(child, childTest);\n if (!result.match) return { match: false, position: null, range: null };\n if (result.range) range = result.range;\n } else {\n // No index: find any matching child\n const found = children.some((child) => {\n const result = testChild(child, childTest);\n if (result.range) range = result.range;\n return result.match;\n });\n if (!found) return { match: false, position: null, range: null };\n }\n }\n }\n\n return { match: true, position: tokenIndex, range };\n};\n","import type Token from \"markdown-it/lib/token.mjs\";\n\n/**\n * Given a closing or self-closing token at `index`, returns its matching\n * opening token by walking backwards to find the token of the same type at\n * the same nesting level. Returns the token itself for nesting === 0.\n */\nexport const getMatchingOpeningToken = (\n tokens: Token[],\n index: number\n): Token | null => {\n const token = tokens[index];\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (!token) return null;\n if (token.type === \"softbreak\") return null;\n if (token.nesting === 0) return token;\n\n const target = token.type.replace(/_close$/, \"_open\");\n let depth = 0;\n\n for (let i = index; i >= 0; i--) {\n const t = tokens[i];\n if (t.type === token.type) depth++;\n else if (t.type === target) {\n depth--;\n if (depth === 0) return t;\n }\n }\n\n return null;\n};\n","/**\n * A block a line can be written in, outermost first: a blockquote, by how many\n * `>` markers lead up to its own, or a list item, by the column its content\n * starts at.\n */\nexport type LineContainer =\n | { kind: \"quote\"; markers: number }\n | { kind: \"item\"; column: number };\n\n/**\n * How many of `containers`, outermost first, a line is written in: a line that\n * lazily continues a paragraph has fewer `>` markers, or less indentation,\n * than the blocks around that paragraph. Tabs count as one column.\n */\nexport const containersKept = (\n line: string,\n containers: readonly LineContainer[]\n): number => {\n const prefix = /^[ \\t>]*/.exec(line)?.[0] ?? \"\";\n const markers = prefix.split(\">\").length - 1;\n let kept = 0;\n for (const container of containers) {\n if (\n container.kind === \"quote\"\n ? markers < container.markers\n : prefix.length < container.column\n )\n break;\n kept++;\n }\n return kept;\n};\n\n/**\n * The columns the content of the list items opened on a line starts at, in\n * the order they open, as CommonMark reads a list marker: up to four spaces\n * after it belong to the marker, more start indented content one column after.\n */\nexport const itemColumns = (line: string): number[] => {\n const columns: number[] = [];\n let pos = 0;\n for (;;) {\n while (line[pos] === \" \" || line[pos] === \"\\t\") pos++;\n if (line[pos] === \">\") {\n pos++;\n continue;\n }\n const marker = /^(?:[-+*]|\\d{1,9}[.)])(?=[ \\t]|$)/.exec(line.slice(pos));\n if (!marker) return columns;\n const end = pos + marker[0].length;\n let spaces = 0;\n while (line[end + spaces] === \" \" || line[end + spaces] === \"\\t\") spaces++;\n const column =\n end + spaces === line.length || spaces > 4 ? end + 1 : end + spaces;\n columns.push(column);\n if (spaces > 4) return columns;\n pos = column;\n }\n};\n","import type { DelimiterConfig } from \"../types.js\";\nimport {\n addAttrs,\n getDelimiterChecker,\n getMatchingOpeningToken\n} from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\n// Token types that should not be treated as attr targets\nconst SKIP_TYPES = new Set([\n \"code_inline\",\n \"math_inline\",\n \"fence\",\n \"code_block\"\n]);\n\nexport const createBlockRule = (options: DelimiterConfig): AttrRule => {\n const check = getDelimiterChecker(options.left, options.right);\n\n return {\n name: \"block attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: -1,\n // Only literal text can end in an attribute block: an image's `content` is its alt text, a code span's is its code.\n type: \"text\",\n content: (content: string) => check(content.trim(), \"end\") !== null\n }\n ]\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const lastChild = children[children.length - 1];\n\n const content = lastChild.content.trimEnd();\n const range = check(content, \"end\")!;\n\n // Find the block-level opening token that contains this inline\n // Walk backwards: skip the paragraph_open immediately before, then\n // look for the outermost open that wraps this inline token.\n let openToken = null;\n\n // First: find the _close token that closes the block containing this inline\n // by walking forward from the inline's position\n let closeIdx = index + 1;\n while (closeIdx < tokens.length && tokens[closeIdx].nesting !== -1) {\n closeIdx++;\n }\n\n if (closeIdx < tokens.length) {\n openToken = getMatchingOpeningToken(tokens, closeIdx);\n }\n\n if (!openToken) return;\n if (SKIP_TYPES.has(openToken.type)) return;\n\n addAttrs(openToken, content, range, options.allowed);\n\n // Strip the attr block from the last child's content\n const attrStart = content.lastIndexOf(options.left, range[0] - 1);\n lastChild.content = content.slice(0, attrStart).trimEnd();\n\n // Drop the child if now empty\n if (lastChild.content === \"\" && children.length > 1) {\n children.pop();\n }\n }\n };\n};\n","import type Token from \"markdown-it/lib/token.mjs\";\nimport type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createInlineRules = (options: DelimiterConfig): AttrRule[] => {\n const check = getDelimiterChecker(options.left, options.right);\n\n // Blocks that open the text right after an element go on it, and the text\n // after them stays, as in markdown-it-attrs.\n const takeLeadingAttrs = (\n target: Token,\n children: Token[],\n i: number\n ): void => {\n const child = children[i];\n let content = child.content;\n let range = check(content, \"start\");\n while (range) {\n addAttrs(target, content, range, options.allowed);\n content = content.slice(range[1] + options.right.length);\n range = check(content, \"start\");\n }\n if (content) child.content = content;\n else children.splice(i, 1);\n };\n\n // Handles self-closing inline elements that render attributes: `code` and\n // images. Other nesting-0 tokens (hard breaks, raw HTML) drop attributes when\n // rendered, so they are left for the end-of-block rule, as in markdown-it-attrs.\n const selfClose: AttrRule = {\n name: \"inline nesting self-close\",\n tests: [{ shift: 0, type: \"inline\" }],\n transform(tokens, index) {\n const token = tokens[index];\n const children = token.children!;\n let modified = false;\n\n for (let i = children.length - 1; i >= 0; i--) {\n const child = children[i];\n if (child.type !== \"text\") continue;\n\n if (!check(child.content, \"start\")) continue;\n\n const prev = children[i - 1];\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (prev?.type !== \"image\" && prev?.type !== \"code_inline\") continue;\n\n takeLeadingAttrs(prev, children, i);\n modified = true;\n }\n\n return modified;\n }\n };\n\n // Handles closing inline elements: em, strong, s, etc. (nesting === -1)\n const closing: AttrRule = {\n name: \"inline attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\"\n }\n ],\n transform(tokens, index) {\n const token = tokens[index];\n const children = token.children!;\n let modified = false;\n\n for (let i = children.length - 1; i >= 0; i--) {\n const child = children[i];\n if (child.type !== \"text\") continue;\n\n if (!check(child.content, \"start\")) continue;\n\n // The preceding sibling must be a closing tag (nesting === -1)\n const prev = children[i - 1];\n // oxlint-disable-next-line typescript/no-unnecessary-condition\n if (!prev || prev.nesting !== -1) continue;\n\n // Find the matching opening token among children\n const openType = prev.type.replace(/_close$/, \"_open\");\n let openIdx = -1;\n for (let j = i - 2; j >= 0; j--) {\n if (\n children[j].type === openType &&\n children[j].level === prev.level\n ) {\n openIdx = j;\n break;\n }\n }\n if (openIdx === -1) continue;\n\n takeLeadingAttrs(children[openIdx], children, i);\n modified = true;\n }\n\n return modified;\n }\n };\n\n return [selfClose, closing];\n};\n","import type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createFenceRule = (options: DelimiterConfig): AttrRule => {\n const check = getDelimiterChecker(options.left, options.right);\n\n return {\n name: \"fence attributes\",\n tests: [\n {\n shift: 0,\n type: \"fence\"\n }\n ],\n transform(tokens, index) {\n const token = tokens[index];\n const info = token.info.trim();\n const range = check(info, \"end\") ?? check(info, \"only\");\n if (!range) return;\n addAttrs(token, info, range, options.allowed);\n // Strip the attr block from the info string, preserving the language tag\n token.info = info\n .slice(0, info.lastIndexOf(options.left, range[0] - 1))\n .trimEnd();\n // markdown-it's fence renderer appends the language class to an existing\n // `class` attribute but otherwise adds `class` last. Reserve the slot\n // first, so `class` leads as it does in remd (mdast-util-to-hast creates\n // the language class before applying attributes, and a remark plugin\n // cannot reorder it). The renderer wrapper trims the leading space.\n if (token.info && token.attrIndex(\"class\") < 0) {\n token.attrs = [[\"class\", \"\"], ...(token.attrs ?? [])];\n token.meta = { ...token.meta, attrsReservedClass: true };\n }\n }\n };\n};\n","import type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createHeadingRule = (options: DelimiterConfig): AttrRule => {\n const check = getDelimiterChecker(options.left, options.right);\n\n return {\n name: \"heading attributes\",\n // Anchored on the inline token, so the inline rules see it first and an\n // element ending the heading (`**b**{.x}`) takes the block.\n tests: [\n {\n shift: -1,\n type: \"heading_open\"\n },\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: -1,\n // Only literal text can end in an attribute block: an image's `content` is its alt text, a code span's is its code.\n type: \"text\",\n content: (content: string) => check(content.trim(), \"end\") !== null\n }\n ]\n }\n ],\n transform(tokens, index) {\n const openToken = tokens[index - 1];\n const inline = tokens[index];\n const children = inline.children!;\n const lastChild = children[children.length - 1];\n\n const content = lastChild.content;\n const trimmed = content.trimEnd();\n const range = check(trimmed, \"end\")!;\n\n addAttrs(openToken, trimmed, range, options.allowed);\n\n // Strip the attr block from the last child content\n const before = trimmed.slice(\n 0,\n trimmed.lastIndexOf(options.left, range[0] - 1)\n );\n lastChild.content = before.trimEnd();\n\n // Drop the child entirely if it's now empty\n if (lastChild.content === \"\" && children.length > 1) {\n children.pop();\n }\n }\n };\n};\n","import type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createHrRule = (options: DelimiterConfig): AttrRule => {\n const check = getDelimiterChecker(options.left, options.right);\n\n return {\n name: \"hr attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: 0,\n type: \"text\",\n content: (content: string) => check(content.trim(), \"only\") !== null\n }\n ]\n },\n {\n shift: -2,\n type: \"hr\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const textChild = inline.children![0];\n const content = textChild.content.trim();\n const range = check(content, \"only\")!;\n\n const hr = tokens[index - 2];\n addAttrs(hr, content, range, options.allowed);\n\n // Remove paragraph_open + inline + paragraph_close\n tokens.splice(index - 1, 3);\n }\n };\n};\n","import type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createListRules = (options: DelimiterConfig): AttrRule[] => {\n const check = getDelimiterChecker(options.left, options.right);\n\n // Rule 1: attrs at end of a list item inline \"- item{.red}\"\n // Structure: list_item_open(-2) paragraph_open(-1) inline(0)\n const listItemEnd: AttrRule = {\n name: \"list item end\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: -1,\n // Only literal text can end in an attribute block: an image's `content` is its alt text, a code span's is its code.\n type: \"text\",\n content: (content: string) => check(content.trim(), \"end\") !== null\n }\n ]\n },\n {\n shift: -1,\n type: \"paragraph_open\"\n },\n {\n shift: -2,\n type: \"list_item_open\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const lastChild = children[children.length - 1];\n const content = lastChild.content.trimEnd();\n const range = check(content, \"end\")!;\n\n const listItemOpen = tokens[index - 2];\n addAttrs(listItemOpen, content, range, options.allowed);\n\n const attrStart = content.lastIndexOf(options.left, range[0] - 1);\n lastChild.content = content.slice(0, attrStart).trimEnd();\n if (lastChild.content === \"\" && children.length > 1) children.pop();\n }\n };\n\n // Rule 1b (generic): attrs at end of a custom item title inline\n // Matches when the open token two before the inline has meta.attrsRole === \"containerItem\"\n // and the token one before has meta.attrsItemTitle === true.\n // Third-party plugins opt in by setting these meta fields on their tokens.\n const customItemEnd: AttrRule = {\n name: \"custom item end\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: -1,\n // Only literal text can end in an attribute block: an image's `content` is its alt text, a code span's is its code.\n type: \"text\",\n content: (content: string) => check(content.trim(), \"end\") !== null\n }\n ]\n },\n {\n shift: -1,\n meta: (m) => m?.attrsItemTitle === true\n },\n {\n shift: -2,\n meta: (m) => m?.attrsRole === \"containerItem\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const lastChild = children[children.length - 1];\n const content = lastChild.content.trimEnd();\n const range = check(content, \"end\")!;\n\n const itemOpen = tokens[index - 2];\n addAttrs(itemOpen, content, range, options.allowed);\n\n const attrStart = content.lastIndexOf(options.left, range[0] - 1);\n lastChild.content = content.slice(0, attrStart).trimEnd();\n if (lastChild.content === \"\" && children.length > 1) children.pop();\n }\n };\n\n // Rule 1c (direct): attrs at end of a custom item inline where the open token\n // itself carries both attrsRole === \"containerItem\" AND attrsItemTitle === true.\n // Matches dt_open → inline (no intermediate title token).\n const customItemEndDirect: AttrRule = {\n name: \"custom item end direct\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: -1,\n // Only literal text can end in an attribute block: an image's `content` is its alt text, a code span's is its code.\n type: \"text\",\n content: (content: string) => check(content.trim(), \"end\") !== null\n }\n ]\n },\n {\n shift: -1,\n meta: (m: Record<string, unknown> | null) =>\n m?.attrsItemTitle === true && m.attrsRole === \"containerItem\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const lastChild = children[children.length - 1];\n const content = lastChild.content.trimEnd();\n const range = check(content, \"end\")!;\n\n const itemOpen = tokens[index - 1];\n addAttrs(itemOpen, content, range, options.allowed);\n\n const attrStart = content.lastIndexOf(options.left, range[0] - 1);\n lastChild.content = content.slice(0, attrStart).trimEnd();\n if (lastChild.content === \"\" && children.length > 1) children.pop();\n }\n };\n\n // Rule 2: attrs on own paragraph after bullet/ordered list close → apply to list\n // Structure: bullet_list_close(-2) paragraph_open(-1) inline(0) paragraph_close(+1)\n const listAttr: AttrRule = {\n name: \"list attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: 0,\n type: \"text\",\n content: (content: string) => check(content.trim(), \"only\") !== null\n }\n ]\n },\n {\n shift: -1,\n type: \"paragraph_open\"\n },\n {\n shift: -2,\n type: (t: string) =>\n t === \"bullet_list_close\" || t === \"ordered_list_close\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const textChild = children[0];\n const content = textChild.content.trim();\n const range = check(content, \"only\")!;\n\n // Find the matching list_open for the close token at index-2\n const closeToken = tokens[index - 2];\n const openType = closeToken.type.replace(\"_close\", \"_open\");\n\n let depth = 1;\n let listOpenIdx = -1;\n for (let i = index - 3; i >= 0; i--) {\n const t = tokens[i];\n if (t.type === closeToken.type) depth++;\n else if (t.type === openType) {\n depth--;\n if (depth === 0) {\n listOpenIdx = i;\n break;\n }\n }\n }\n\n if (listOpenIdx === -1) return;\n addAttrs(tokens[listOpenIdx], content, range, options.allowed);\n\n // Remove paragraph_open + inline + paragraph_close\n tokens.splice(index - 1, 3);\n }\n };\n\n // Rule 2b (generic): attrs on own paragraph after a custom container close → apply to container open\n // Matches when the close token two before the paragraph has meta.attrsRole === \"container\".\n // Third-party plugins opt in by setting meta.attrsRole = \"container\" on their open/close tokens.\n const customListAttr: AttrRule = {\n name: \"custom list attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: 0,\n type: \"text\",\n content: (content: string) => check(content.trim(), \"only\") !== null\n }\n ]\n },\n {\n shift: -1,\n type: \"paragraph_open\"\n },\n {\n shift: -2,\n type: (t: string) => t.endsWith(\"_close\"),\n meta: (m) => m?.attrsRole === \"container\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const textChild = children[0];\n const content = textChild.content.trim();\n const range = check(content, \"only\")!;\n\n // Walk back to find the matching open token (same type with _open suffix)\n const closeToken = tokens[index - 2];\n const openType = closeToken.type.replace(\"_close\", \"_open\");\n\n let depth = 1;\n let listOpenIdx = -1;\n for (let i = index - 3; i >= 0; i--) {\n const t = tokens[i];\n if (t.type === closeToken.type) depth++;\n else if (t.type === openType) {\n depth--;\n if (depth === 0) {\n listOpenIdx = i;\n break;\n }\n }\n }\n\n if (listOpenIdx === -1) return;\n addAttrs(tokens[listOpenIdx], content, range, options.allowed);\n\n // Remove paragraph_open + inline + paragraph_close\n tokens.splice(index - 1, 3);\n }\n };\n\n return [\n listItemEnd,\n customItemEnd,\n customItemEndDirect,\n listAttr,\n customListAttr\n ];\n};\n","import type Token from \"markdown-it/lib/token.mjs\";\nimport type { DelimiterConfig } from \"../types.js\";\nimport {\n addAttrs,\n containersKept,\n getDelimiterChecker,\n itemColumns\n} from \"../helper/index.js\";\nimport type { LineContainer } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\n/** A container the line holding an attribute block can be written in. */\ninterface Container {\n open: Token;\n /** The token the block goes on when the line is written outside the container. */\n target: Token;\n line: LineContainer;\n}\n\nexport const createSoftbreakRule = (options: DelimiterConfig): AttrRule => {\n const check = getDelimiterChecker(options.left, options.right);\n\n // A block on a line of its own, ending a paragraph or setext heading after a\n // soft or hard break, goes on the block that ends right before it at the\n // level the line is written, as kramdown places a block IAL: the paragraph\n // (its list item, in a tight list), or, for a line lazily written outside\n // some of the blockquotes and list items around it, the outermost of those it\n // leaves (a list item's list). markdown-it-attrs can't tell those levels\n // apart, as the token stream drops the line's indentation; the source keeps it.\n return {\n name: \"softbreak attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: -2,\n type: (type: string) => type === \"softbreak\" || type === \"hardbreak\"\n },\n {\n index: -1,\n type: \"text\",\n content: (content: string) => check(content.trim(), \"only\") !== null\n }\n ]\n }\n ],\n transform(tokens, index, _position, _range, src) {\n const inline = tokens[index];\n const children = inline.children!;\n const content = children[children.length - 1].content.trim();\n const range = check(content, \"only\")!;\n\n // The blocks around the inline, innermost first, up to the first that\n // holds its own source (a panel tokenized from its body), which token\n // maps inside it index instead.\n const ancestors: Token[] = [];\n let source = src;\n let level = inline.level;\n for (let i = index - 1; i >= 0 && level > 0; i--) {\n const token = tokens[i];\n if (token.nesting !== 1 || token.level >= level) continue;\n level = token.level;\n const meta: unknown = token.meta;\n const own =\n typeof meta === \"object\" && meta !== null && \"attrsSource\" in meta\n ? meta.attrsSource\n : undefined;\n if (typeof own === \"string\") {\n source = own;\n break;\n }\n ancestors.push(token);\n }\n const block = ancestors.at(0);\n if (!block) return;\n\n const lines = source.split(\"\\n\");\n const containers: Container[] = [];\n let quotes = 0;\n for (let i = ancestors.length - 1; i >= 1; i--) {\n const open = ancestors[i];\n if (open.type === \"blockquote_open\") {\n containers.push({\n open,\n target: open,\n line: { kind: \"quote\", markers: ++quotes }\n });\n } else if (open.type === \"list_item_open\" && open.map) {\n // Items opened on the same line as this one, outside it, come first there.\n const before = containers.filter(\n (c) =>\n c.open.type === \"list_item_open\" &&\n c.open.map?.[0] === open.map![0]\n ).length;\n const column = itemColumns(lines[open.map[0]] ?? \"\").at(before);\n if (column === undefined) return;\n containers.push({\n open,\n target: ancestors.at(i + 1) ?? open,\n line: { kind: \"item\", column }\n });\n }\n }\n\n const line = inline.map ? (lines[inline.map[1] - 1] ?? \"\") : \"\";\n const kept = inline.map\n ? containersKept(\n line,\n containers.map((c) => c.line)\n )\n : containers.length;\n\n let target = block;\n if (kept < containers.length) target = containers[kept].target;\n // A tight list hides its paragraphs, so the item shows the attributes.\n else if (block.hidden && ancestors[1]?.type === \"list_item_open\")\n target = ancestors[1];\n addAttrs(target, content, range, options.allowed);\n\n // Remove the attr text, and a soft break before it; keep a hard break,\n // as markdown-it-attrs does.\n const isSoft = children[children.length - 2].type === \"softbreak\";\n children.splice(children.length - (isSoft ? 2 : 1), isSoft ? 2 : 1);\n }\n };\n};\n","// TableMeta lives on Token.meta which markdown-it types as any — casts narrow to the rule-specific shape.\n/* oxlint-disable typescript/no-unsafe-type-assertion */\nimport type { DelimiterConfig } from \"../types.js\";\nimport { addAttrs, getDelimiterChecker } from \"../helper/index.js\";\nimport type { AttrRule } from \"./types.js\";\n\nexport const createTableRules = (options: DelimiterConfig): AttrRule[] => {\n const check = getDelimiterChecker(options.left, options.right);\n\n // Rule 1: table-level attrs — standalone paragraph after the table \"\\n{.class}\"\n const tableAttrs: AttrRule = {\n name: \"table attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: 0,\n type: \"text\",\n content: (content: string) => check(content.trim(), \"only\") !== null\n }\n ]\n },\n {\n shift: -1,\n type: \"paragraph_open\"\n },\n {\n shift: -2,\n type: \"table_close\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const content = inline.children![0].content.trim();\n const range = check(content, \"only\")!;\n\n // Find the matching table_open (start from table_close at index-2)\n let tableOpenIdx = -1;\n let depth = 1;\n for (let i = index - 3; i >= 0; i--) {\n const t = tokens[i];\n if (t.type === \"table_close\") depth++;\n else if (t.type === \"table_open\") {\n depth--;\n if (depth === 0) {\n tableOpenIdx = i;\n break;\n }\n }\n }\n if (tableOpenIdx === -1) return;\n\n addAttrs(tokens[tableOpenIdx], content, range, options.allowed);\n\n // Remove paragraph_open + inline + paragraph_close\n tokens.splice(index - 1, 3);\n }\n };\n\n // Rule 2: table cell attrs — \"cell content {.class}\" inside td/th\n const tableCellAttrs: AttrRule = {\n name: \"table cell attributes\",\n tests: [\n {\n shift: 0,\n type: \"inline\",\n children: [\n {\n index: -1,\n type: \"text\",\n content: (content: string) => check(content.trim(), \"end\") !== null\n }\n ]\n },\n {\n shift: -1,\n type: (t: string) => t === \"td_open\" || t === \"th_open\"\n }\n ],\n transform(tokens, index) {\n const inline = tokens[index];\n const children = inline.children!;\n const lastChild = children[children.length - 1];\n const content = lastChild.content.trimEnd();\n const range = check(content, \"end\")!;\n\n const cellOpen = tokens[index - 1];\n addAttrs(cellOpen, content, range, options.allowed);\n\n const attrStart = content.lastIndexOf(options.left, range[0] - 1);\n lastChild.content = content.slice(0, attrStart).trimEnd();\n if (lastChild.content === \"\" && children.length > 1) children.pop();\n }\n };\n\n // Rule 3: track column count in thead (stored as metadata for rowspan/colspan calc)\n interface TableMeta {\n cols: number;\n rowspan: number[];\n }\n\n const colTracker: AttrRule = {\n name: \"table column tracker\",\n tests: [{ shift: 0, type: \"tr_open\" }],\n transform(tokens, index) {\n // Count th tokens in this row to know column count; stored on thead_open meta\n let cols = 0;\n for (let i = index + 1; i < tokens.length; i++) {\n const t = tokens[i];\n if (t.type === \"tr_close\") break;\n if (t.type === \"th_open\") cols++;\n }\n if (cols === 0) return;\n\n // Find thead_open and store column count\n for (let i = index - 1; i >= 0; i--) {\n const t = tokens[i];\n if (t.type === \"thead_open\") {\n t.meta = t.meta ?? {};\n (t.meta as TableMeta).cols = cols;\n break;\n }\n if (t.type === \"table_open\") break;\n }\n }\n };\n\n // Rule 4: colspan/rowspan calculation — remove phantom cells, adjust span values\n const spanCalc: AttrRule = {\n name: \"table span calculator\",\n tests: [{ shift: 0, type: \"tbody_open\" }],\n transform(tokens, index) {\n // Find matching thead_open to get column count\n let cols = 0;\n for (let i = index - 1; i >= 0; i--) {\n const t = tokens[i];\n if (t.type === \"thead_open\") {\n cols = (t.meta as TableMeta | undefined)?.cols ?? 0;\n break;\n }\n if (t.type === \"table_open\") break;\n }\n if (cols === 0) return;\n\n // Find the tbody_close\n let tbodyClose = index + 1;\n let depth = 1;\n while (tbodyClose < tokens.length && depth > 0) {\n const t = tokens[tbodyClose];\n if (t.type === \"tbody_open\") depth++;\n else if (t.type === \"tbody_close\") depth--;\n tbodyClose++;\n }\n tbodyClose--;\n\n // Process each row within tbody\n const occupied: number[] = Array.from({ length: cols }, () => 0);\n\n let i = index + 1;\n while (i < tbodyClose) {\n const t = tokens[i];\n if (t.type === \"tr_open\") {\n // Decrement all occupied counts\n for (let c = 0; c < cols; c++) {\n if (occupied[c] > 0) occupied[c]--;\n }\n\n // Collect td tokens in this row\n const tdIndices: number[] = [];\n for (let j = i + 1; j < tbodyClose; j++) {\n if (tokens[j].type === \"tr_close\") break;\n if (tokens[j].type === \"td_open\") tdIndices.push(j);\n }\n\n // Assign cells to columns, skipping occupied ones\n let col = 0;\n let tdIdx = 0;\n\n while (col < cols && tdIdx < tdIndices.length) {\n // Skip occupied columns (from rowspan)\n while (col < cols && occupied[col] > 0) col++;\n if (col >= cols) break;\n\n const tdOpen = tokens[tdIndices[tdIdx]];\n const rowspanAttr = tdOpen.attrGet(\"rowspan\");\n const colspanAttr = tdOpen.attrGet(\"colspan\");\n const rowspan = rowspanAttr ? parseInt(rowspanAttr, 10) : 1;\n let colspan = colspanAttr ? parseInt(colspanAttr, 10) : 1;\n\n // Count how many consecutive free columns are available\n let freeCols = 0;\n for (let c = col; c < cols && occupied[c] === 0; c++) freeCols++;\n\n // Clamp colspan to available free columns\n if (colspan > freeCols) {\n colspan = freeCols;\n if (colspan === 1) {\n // Remove colspan attr if it resolved to 1 (keep as-is if explicitly set)\n // We keep it to match reference behavior: colspan=\"1\" is left on token\n }\n tdOpen.attrSet(\"colspan\", String(colspan));\n }\n\n // Mark columns occupied by this cell's rowspan\n for (let c = col; c < col + colspan && c < cols; c++) {\n if (rowspan > 1) occupied[c] = rowspan - 1;\n }\n\n col += colspan;\n tdIdx++;\n }\n\n // Remove phantom cells beyond assigned ones\n // (cells that were merged away by rowspan from a previous row)\n while (tdIdx < tdIndices.length) {\n const phantomStart = tdIndices[tdIdx];\n // Find the matching td_close\n let phantomEnd = phantomStart + 1;\n while (\n phantomEnd < tokens.length &&\n tokens[phantomEnd].type !== \"td_close\"\n ) {\n phantomEnd++;\n }\n tokens.splice(phantomStart, phantomEnd - phantomStart + 1);\n tbodyClose -= phantomEnd - phantomStart + 1;\n // Don't increment tdIdx since we just spliced\n }\n }\n i++;\n }\n }\n };\n\n return [tableAttrs, tableCellAttrs, colTracker, spanCalc];\n};\n","import type { AttrsOptions, AttrRuleName, DelimiterConfig } from \"../types.js\";\nimport type { AttrRule } from \"./types.js\";\nimport { createBlockRule } from \"./block.js\";\nimport { createInlineRules } from \"./inline.js\";\nimport { createFenceRule } from \"./fence.js\";\nimport { createHeadingRule } from \"./heading.js\";\nimport { createHrRule } from \"./hr.js\";\nimport { createListRules } from \"./list.js\";\nimport { createSoftbreakRule } from \"./softbreak.js\";\nimport { createTableRules } from \"./table.js\";\n\nconst ALL_RULE_NAMES: AttrRuleName[] = [\n \"fence\",\n \"inline\",\n \"table\",\n \"list\",\n \"heading\",\n \"hr\",\n \"softbreak\",\n \"block\"\n];\n\nconst ALL_RULE_SET = new Set<string>(ALL_RULE_NAMES);\n\nexport const createRules = (\n options: DelimiterConfig & Pick<AttrsOptions, \"rule\">\n): AttrRule[] => {\n const { rule = \"all\" } = options;\n\n let enabled: Set<string>;\n if (rule === \"all\" || rule === true) {\n enabled = ALL_RULE_SET;\n } else if (!rule || (Array.isArray(rule) && rule.length === 0)) {\n return [];\n } else {\n enabled = new Set(rule.filter((r) => ALL_RULE_SET.has(r)));\n }\n\n const rules: AttrRule[] = [];\n\n if (enabled.has(\"fence\")) rules.push(createFenceRule(options));\n if (enabled.has(\"inline\")) rules.push(...createInlineRules(options));\n // Before the list rules, so a list item's line of its own is placed before\n // the item reads a block ending its first line.\n if (enabled.has(\"softbreak\")) rules.push(createSoftbreakRule(options));\n if (enabled.has(\"table\")) rules.push(...createTableRules(options));\n if (enabled.has(\"list\")) rules.push(...createListRules(options));\n if (enabled.has(\"heading\")) rules.push(createHeadingRule(options));\n if (enabled.has(\"hr\")) rules.push(createHrRule(options));\n if (enabled.has(\"block\")) rules.push(createBlockRule(options));\n\n return rules;\n};\n","import type { PluginWithOptions } from \"markdown-it\";\nimport type { AttrsOptions, DelimiterRange } from \"./types.js\";\nimport { createRules } from \"./rules/index.js\";\nimport { testRule } from \"./helper/index.js\";\n\n/** markdown-it plugin for attribute lists (`{.class #id key=value}`) on elements. */\nexport const attrs: PluginWithOptions<AttrsOptions> = (\n md,\n { left = \"{\", right = \"}\", allowed = [], rule = \"all\" } = {}\n) => {\n const rules = createRules({ left, right, allowed, rule });\n\n // A fence whose class slot the fence rule reserved renders as\n // `class=\" language-x\"`; drop the leading space.\n const renderFence = md.renderer.rules.fence;\n if (renderFence) {\n md.renderer.rules.fence = (tokens, idx, opts, env, self): string => {\n const html = renderFence(tokens, idx, opts, env, self);\n return tokens[idx].meta?.attrsReservedClass\n ? html.replace(' class=\" ', ' class=\"')\n : html;\n };\n }\n\n md.core.ruler.before(\"linkify\", \"attrs\", (state) => {\n const { tokens } = state;\n\n for (let index = 0; index < tokens.length; index++) {\n for (let ruleIndex = 0; ruleIndex < rules.length; ruleIndex++) {\n const pattern = rules[ruleIndex];\n let position: number | null = null;\n let range: DelimiterRange | null = null;\n\n const match = pattern.tests.every((test) => {\n const result = testRule(tokens, index, test);\n if (result.position != null) position = result.position;\n if (result.range) range = result.range;\n return result.match;\n });\n\n if (match) {\n const modified = pattern.transform(\n tokens,\n index,\n position!,\n range!,\n state.src\n );\n\n if (\n modified !== false &&\n (pattern.name === \"inline attributes\" ||\n pattern.name === \"inline nesting self-close\")\n ) {\n ruleIndex--;\n }\n }\n }\n }\n });\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mirrordown/mdit-attrs",
3
3
  "description": "A markdown-it plugin for attribute lists ({.class #id key=value}) that set classes, IDs, and attributes on elements.",
4
- "version": "0.1.3",
4
+ "version": "0.2.0",
5
5
  "license": "MIT",
6
6
  "author": "Drake Costa <drake@saeris.io> (https://saeris.gg)",
7
7
  "repository": {