@orz/ui-markdown 0.0.0-stage → 0.0.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.
Files changed (52) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +175 -2
  3. package/dist/attachment-links.d.ts +20 -0
  4. package/dist/attachment-links.d.ts.map +1 -0
  5. package/dist/attachment-links.js +27 -0
  6. package/dist/attachment-links.js.map +1 -0
  7. package/dist/content.d.ts +31 -0
  8. package/dist/content.d.ts.map +1 -0
  9. package/dist/content.js +78 -0
  10. package/dist/content.js.map +1 -0
  11. package/dist/embeds.d.ts +18 -0
  12. package/dist/embeds.d.ts.map +1 -0
  13. package/dist/embeds.js +59 -0
  14. package/dist/embeds.js.map +1 -0
  15. package/dist/external-links.d.ts +23 -0
  16. package/dist/external-links.d.ts.map +1 -0
  17. package/dist/external-links.js +43 -0
  18. package/dist/external-links.js.map +1 -0
  19. package/dist/index.d.ts +7 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +6 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/lib/markdown-processor.d.ts +23 -0
  24. package/dist/lib/markdown-processor.d.ts.map +1 -0
  25. package/dist/lib/markdown-processor.js +35 -0
  26. package/dist/lib/markdown-processor.js.map +1 -0
  27. package/dist/lib/rehype-details.d.ts +13 -0
  28. package/dist/lib/rehype-details.d.ts.map +1 -0
  29. package/dist/lib/rehype-details.js +256 -0
  30. package/dist/lib/rehype-details.js.map +1 -0
  31. package/dist/lib/rehype-source-lines.d.ts +23 -0
  32. package/dist/lib/rehype-source-lines.d.ts.map +1 -0
  33. package/dist/lib/rehype-source-lines.js +77 -0
  34. package/dist/lib/rehype-source-lines.js.map +1 -0
  35. package/dist/lib/remark-frontmatter-table.d.ts +119 -0
  36. package/dist/lib/remark-frontmatter-table.d.ts.map +1 -0
  37. package/dist/lib/remark-frontmatter-table.js +212 -0
  38. package/dist/lib/remark-frontmatter-table.js.map +1 -0
  39. package/dist/lib/remark-rejected-urls.d.ts +23 -0
  40. package/dist/lib/remark-rejected-urls.d.ts.map +1 -0
  41. package/dist/lib/remark-rejected-urls.js +79 -0
  42. package/dist/lib/remark-rejected-urls.js.map +1 -0
  43. package/dist/markdown.d.ts +30 -0
  44. package/dist/markdown.d.ts.map +1 -0
  45. package/dist/markdown.js +146 -0
  46. package/dist/markdown.js.map +1 -0
  47. package/dist/plugin.d.ts +39 -0
  48. package/dist/plugin.d.ts.map +1 -0
  49. package/dist/plugin.js +2 -0
  50. package/dist/plugin.js.map +1 -0
  51. package/package.json +66 -3
  52. package/styles.css +293 -0
@@ -0,0 +1,35 @@
1
+ import remarkFrontmatter from "remark-frontmatter";
2
+ import remarkGfm from "remark-gfm";
3
+ import remarkParse from "remark-parse";
4
+ import { unified } from "unified";
5
+ import { FRONTMATTER_FLAVOURS, remarkFrontmatterTable, } from "./remark-frontmatter-table.js";
6
+ import { remarkRejectedUrlsAsText } from "./remark-rejected-urls.js";
7
+ /**
8
+ * Static Markdown syntax shared by every parser and renderer.
9
+ *
10
+ * Keep runtime-dependent plugins (references, say) in the caller: their
11
+ * options belong to the app's context. Keeping
12
+ * this array at module scope also lets renderers retain plugin-list identity
13
+ * instead of rebuilding the invariant prefix on every render.
14
+ *
15
+ * The order is significant. Rejected URLs are restored to source text before
16
+ * later tokenizers see them, and `remarkFrontmatterTable` consumes the nodes
17
+ * produced by `remarkFrontmatter`. Without that tokenizer, frontmatter lines
18
+ * that begin with digits are parsed as ordered-list items (T-383).
19
+ */
20
+ export const MARKDOWN_SYNTAX_PLUGINS = [
21
+ remarkGfm,
22
+ remarkRejectedUrlsAsText,
23
+ [remarkFrontmatter, FRONTMATTER_FLAVOURS],
24
+ remarkFrontmatterTable,
25
+ ];
26
+ const processor = unified().use(remarkParse).use(MARKDOWN_SYNTAX_PLUGINS);
27
+ /**
28
+ * `runSync`, not `parse` alone: `parse` stops at the tokenizer and runs no
29
+ * transformer, so `remarkFrontmatterTable` — which is one — would never fire
30
+ * and the caller would hold the `yaml` leaf while the DOM held a table.
31
+ */
32
+ export function parseMarkdown(source) {
33
+ return processor.runSync(processor.parse(source), source);
34
+ }
35
+ //# sourceMappingURL=markdown-processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-processor.js","sourceRoot":"","sources":["../../src/lib/markdown-processor.ts"],"names":[],"mappings":"AACA,OAAO,iBAAiB,MAAM,oBAAoB,CAAC;AACnD,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,WAAW,MAAM,cAAc,CAAC;AACvC,OAAO,EAAsB,OAAO,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAkB;IACpD,SAAS;IACT,wBAAwB;IACxB,CAAC,iBAAiB,EAAE,oBAAoB,CAAC;IACzC,sBAAsB;CACvB,CAAC;AACF,MAAM,SAAS,GAAG,OAAO,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;AAE1E;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,OAAO,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,CAAU,CAAC;AACrE,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { Root } from "hast";
2
+ /**
3
+ * Cut exactly two tags out of the escaping that raw HTML otherwise gets.
4
+ *
5
+ * react-markdown replaces every `raw` node with a text node holding its
6
+ * source, which is why an unsupported tag reaches the reader as the characters
7
+ * they typed. This plugin runs in the window before that, turns the literals
8
+ * of `MARKER` into elements it builds from constants, and leaves every other
9
+ * `raw` node exactly where it was — so the set of elements the document can
10
+ * hold grows by `details` and `summary` and by nothing else.
11
+ */
12
+ export declare function rehypeDetails(): (tree: Root) => void;
13
+ //# sourceMappingURL=rehype-details.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rehype-details.d.ts","sourceRoot":"","sources":["../../src/lib/rehype-details.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA2B,IAAI,EAAe,MAAM,MAAM,CAAC;AAmQvE;;;;;;;;;GASG;AACH,wBAAgB,aAAa,WACb,IAAI,UA+BnB"}
@@ -0,0 +1,256 @@
1
+ /**
2
+ * HTML whitespace, spelled out instead of `\s`: that class also matches NBSP
3
+ * and the Unicode space separators, and every character this recogniser
4
+ * accepts has to be one a reviewer can read off the grammar.
5
+ */
6
+ const S = "[ \\t\\n\\f\\r]";
7
+ /**
8
+ * The five literals the recogniser knows, and the whole of what it knows.
9
+ * Everything else — `<details class="x">`, `<details open="open">`,
10
+ * `<details/>`, `<detailsfoo>`, `< details>` — falls through untouched and
11
+ * reaches the reader as escaped source, which is what raw HTML has always
12
+ * done here.
13
+ *
14
+ * Alternatives rather than one pattern with an optional attribute, so that
15
+ * `open` is decided by *which literal matched* and never by reading the
16
+ * match: see `foldElement`.
17
+ */
18
+ const MARKER = new RegExp([
19
+ `(?<detailsOpen><details${S}*>)`,
20
+ `(?<detailsOpenExpanded><details${S}+open${S}*>)`,
21
+ `(?<detailsClose></details${S}*>)`,
22
+ `(?<summaryOpen><summary${S}*>)`,
23
+ `(?<summaryClose></summary${S}*>)`,
24
+ ].join("|"), "gi");
25
+ function isMarker(piece) {
26
+ return "marker" in piece;
27
+ }
28
+ /**
29
+ * The only path from a recognised literal to an element. Its arguments are the
30
+ * two constants the recogniser chose between; the matched source is not one of
31
+ * them and cannot be reached from in here. That is what makes "no byte of the
32
+ * document ever becomes an attribute value" a property of this signature
33
+ * rather than of how tightly the regex above is written — a regex loose enough
34
+ * to accept `<details onclick=x>` would still produce nothing but an empty
35
+ * `<details>`.
36
+ */
37
+ function foldElement(tagName, open) {
38
+ return {
39
+ type: "element",
40
+ tagName,
41
+ properties: open ? { open: true } : {},
42
+ children: [],
43
+ };
44
+ }
45
+ /**
46
+ * Where `consumed` ends, counted from `start`. Lines come out exact wherever
47
+ * this is used, because a raw node's value holds one newline per source line
48
+ * it spans; columns and offsets are short by whatever a container strips off
49
+ * the front of each line (`> ` in a blockquote), and the fold, stamp and
50
+ * decoration passes all read lines.
51
+ */
52
+ function advance(start, consumed) {
53
+ const lines = consumed.split("\n");
54
+ const breaks = lines.length - 1;
55
+ return {
56
+ line: start.line + breaks,
57
+ column: breaks === 0
58
+ ? start.column + consumed.length
59
+ : (lines[breaks]?.length ?? 0) + 1,
60
+ offset: start.offset === undefined ? undefined : start.offset + consumed.length,
61
+ };
62
+ }
63
+ function rawAt(value, start) {
64
+ if (start === undefined)
65
+ return { type: "raw", value };
66
+ return {
67
+ type: "raw",
68
+ value,
69
+ position: { start, end: advance(start, value) },
70
+ };
71
+ }
72
+ function kindOf(groups) {
73
+ if (groups.detailsClose !== undefined)
74
+ return "details-close";
75
+ if (groups.summaryOpen !== undefined)
76
+ return "summary-open";
77
+ if (groups.summaryClose !== undefined)
78
+ return "summary-close";
79
+ return "details-open";
80
+ }
81
+ /**
82
+ * One raw node cut into the literals it holds and the text between them, or
83
+ * null when it holds none — a node nothing matched keeps its identity, which
84
+ * is the same rule `<Markdown>` follows for its component map (T-60).
85
+ *
86
+ * Matching starts anywhere inside the value rather than at its front: a single
87
+ * raw node routinely carries a whole block of HTML, and
88
+ * `<details><summary>t</summary><script>alert(1)</script></details>` has to
89
+ * come apart into two elements and one string of escaped source.
90
+ */
91
+ function splitRaw(node) {
92
+ MARKER.lastIndex = 0;
93
+ let match = MARKER.exec(node.value);
94
+ if (match === null)
95
+ return null;
96
+ const start = node.position?.start;
97
+ const pointAt = (index) => start === undefined
98
+ ? undefined
99
+ : index === 0
100
+ ? start
101
+ : advance(start, node.value.slice(0, index));
102
+ const pieces = [];
103
+ let consumed = 0;
104
+ while (match !== null) {
105
+ if (match.index > consumed) {
106
+ pieces.push(rawAt(node.value.slice(consumed, match.index), pointAt(consumed)));
107
+ }
108
+ const groups = match.groups ?? {};
109
+ const whole = match.index === 0 && match[0].length === node.value.length ? node : null;
110
+ pieces.push({
111
+ marker: kindOf(groups),
112
+ open: groups.detailsOpenExpanded !== undefined,
113
+ source: whole ?? rawAt(match[0], pointAt(match.index)),
114
+ });
115
+ consumed = match.index + match[0].length;
116
+ match = MARKER.exec(node.value);
117
+ }
118
+ if (consumed < node.value.length) {
119
+ pieces.push(rawAt(node.value.slice(consumed), pointAt(consumed)));
120
+ }
121
+ return pieces;
122
+ }
123
+ /** Every marker nothing paired with goes back to being raw, i.e. to source text. */
124
+ function resolve(pieces) {
125
+ return pieces.map((piece) => (isMarker(piece) ? piece.source : piece));
126
+ }
127
+ function spanning(open, close) {
128
+ const start = open.position?.start;
129
+ const end = close.position?.end;
130
+ return start === undefined || end === undefined ? undefined : { start, end };
131
+ }
132
+ /** The `details-close` that matches the open marker at `from`; -1 for none. */
133
+ function matchingClose(pieces, from) {
134
+ let depth = 0;
135
+ for (let i = from + 1; i < pieces.length; i++) {
136
+ const piece = pieces[i];
137
+ if (piece === undefined || !isMarker(piece))
138
+ continue;
139
+ if (piece.marker === "details-open")
140
+ depth++;
141
+ else if (piece.marker === "details-close") {
142
+ if (depth === 0)
143
+ return i;
144
+ depth--;
145
+ }
146
+ }
147
+ return -1;
148
+ }
149
+ /**
150
+ * The first `<summary>…</summary>` of a fold, as its own element. A second one
151
+ * in the same fold, and any that sits outside a fold altogether, keeps its
152
+ * markers and so reaches the reader as source — without this pass, a rejected
153
+ * `<details onclick=x>` would leave its `<summary>` behind as a stray element
154
+ * floating in the document, which is the one place "a rejected tag shows up
155
+ * whole, as text" would otherwise have an exception.
156
+ */
157
+ function pairSummary(pieces) {
158
+ const open = pieces.findIndex((piece) => isMarker(piece) && piece.marker === "summary-open");
159
+ if (open < 0)
160
+ return pieces;
161
+ const close = pieces.findIndex((piece, i) => i > open && isMarker(piece) && piece.marker === "summary-close");
162
+ if (close < 0)
163
+ return pieces;
164
+ const openMarker = pieces[open];
165
+ const closeMarker = pieces[close];
166
+ if (openMarker === undefined ||
167
+ closeMarker === undefined ||
168
+ !isMarker(openMarker) ||
169
+ !isMarker(closeMarker)) {
170
+ return pieces;
171
+ }
172
+ const element = foldElement("summary", false);
173
+ element.children = resolve(pieces.slice(open + 1, close));
174
+ element.position = spanning(openMarker.source, closeMarker.source);
175
+ return [...pieces.slice(0, open), element, ...pieces.slice(close + 1)];
176
+ }
177
+ /**
178
+ * Pair the `details` literals of one children array, innermost pairs last.
179
+ * A marker whose partner sits in another parent — `<details>` opened in a list
180
+ * item and closed at the top level — finds nothing here and stays source.
181
+ */
182
+ function pairDetails(pieces, made) {
183
+ const out = [];
184
+ for (let i = 0; i < pieces.length; i++) {
185
+ const piece = pieces[i];
186
+ if (piece === undefined)
187
+ continue;
188
+ if (!isMarker(piece) || piece.marker !== "details-open") {
189
+ out.push(piece);
190
+ continue;
191
+ }
192
+ const close = matchingClose(pieces, i);
193
+ const closeMarker = close < 0 ? undefined : pieces[close];
194
+ if (closeMarker === undefined || !isMarker(closeMarker)) {
195
+ out.push(piece);
196
+ continue;
197
+ }
198
+ const element = foldElement("details", piece.open);
199
+ element.children = resolve(pairSummary(pairDetails(pieces.slice(i + 1, close), made)));
200
+ element.position = spanning(piece.source, closeMarker.source);
201
+ made.add(element);
202
+ out.push(element);
203
+ i = close;
204
+ }
205
+ return out;
206
+ }
207
+ /**
208
+ * Where a fold may be recognised. `p` and the phrasing elements are absent on
209
+ * purpose: HTML forbids `<details>` inside `<p>`, and CommonMark gives only
210
+ * the block form a node of its own, so `a <details>b</details> c` is a line
211
+ * whose author meant those characters.
212
+ */
213
+ const FLOW_PARENTS = new Set(["blockquote", "li", "td", "th"]);
214
+ /**
215
+ * Cut exactly two tags out of the escaping that raw HTML otherwise gets.
216
+ *
217
+ * react-markdown replaces every `raw` node with a text node holding its
218
+ * source, which is why an unsupported tag reaches the reader as the characters
219
+ * they typed. This plugin runs in the window before that, turns the literals
220
+ * of `MARKER` into elements it builds from constants, and leaves every other
221
+ * `raw` node exactly where it was — so the set of elements the document can
222
+ * hold grows by `details` and `summary` and by nothing else.
223
+ */
224
+ export function rehypeDetails() {
225
+ return (tree) => {
226
+ const made = new Set();
227
+ const visit = (parent, recognise) => {
228
+ if (recognise) {
229
+ const pieces = [];
230
+ let cut = false;
231
+ for (const child of parent.children) {
232
+ const parts = child.type === "raw" ? splitRaw(child) : null;
233
+ if (parts === null) {
234
+ pieces.push(child);
235
+ continue;
236
+ }
237
+ pieces.push(...parts);
238
+ cut = true;
239
+ }
240
+ if (cut) {
241
+ parent.children = resolve(pairDetails(pieces, made));
242
+ }
243
+ }
244
+ for (const child of parent.children) {
245
+ if (child.type !== "element")
246
+ continue;
247
+ // A fold this pass built has had its own children paired already, and
248
+ // re-reading them would let a rejected literal that is now plain text
249
+ // pair with something it never stood beside.
250
+ visit(child, !made.has(child) && FLOW_PARENTS.has(child.tagName));
251
+ }
252
+ };
253
+ visit(tree, true);
254
+ };
255
+ }
256
+ //# sourceMappingURL=rehype-details.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rehype-details.js","sourceRoot":"","sources":["../../src/lib/rehype-details.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,MAAM,CAAC,GAAG,iBAAiB,CAAC;AAE5B;;;;;;;;;;GAUG;AACH,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;IACE,0BAA0B,CAAC,KAAK;IAChC,kCAAkC,CAAC,QAAQ,CAAC,KAAK;IACjD,4BAA4B,CAAC,KAAK;IAClC,0BAA0B,CAAC,KAAK;IAChC,4BAA4B,CAAC,KAAK;CACnC,CAAC,IAAI,CAAC,GAAG,CAAC,EACX,IAAI,CACL,CAAC;AAmBF,SAAS,QAAQ,CAAC,KAAY;IAC5B,OAAO,QAAQ,IAAI,KAAK,CAAC;AAC3B,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,WAAW,CAAC,OAA8B,EAAE,IAAa;IAChE,OAAO;QACL,IAAI,EAAE,SAAS;QACf,OAAO;QACP,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;QACtC,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,OAAO,CAAC,KAAY,EAAE,QAAgB;IAC7C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAChC,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,IAAI,GAAG,MAAM;QACzB,MAAM,EACJ,MAAM,KAAK,CAAC;YACV,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM;YAChC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC;QACtC,MAAM,EACJ,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM;KAC1E,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAC,KAAa,EAAE,KAAwB;IACpD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IACvD,OAAO;QACL,IAAI,EAAE,KAAK;QACX,KAAK;QACL,QAAQ,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE;KAChD,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,MAA0C;IACxD,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS;QAAE,OAAO,eAAe,CAAC;IAC9D,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS;QAAE,OAAO,cAAc,CAAC;IAC5D,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS;QAAE,OAAO,eAAe,CAAC;IAC9D,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,QAAQ,CAAC,IAAS;IACzB,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC;IACrB,IAAI,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC;IACnC,MAAM,OAAO,GAAG,CAAC,KAAa,EAAqB,EAAE,CACnD,KAAK,KAAK,SAAS;QACjB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,KAAK,KAAK,CAAC;YACX,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACnD,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,OAAO,KAAK,KAAK,IAAI,EAAE,CAAC;QACtB,IAAI,KAAK,CAAC,KAAK,GAAG,QAAQ,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAClE,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;QAClC,MAAM,KAAK,GACT,KAAK,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC3E,MAAM,CAAC,IAAI,CAAC;YACV,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;YACtB,IAAI,EAAE,MAAM,CAAC,mBAAmB,KAAK,SAAS;YAC9C,MAAM,EAAE,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;SACvD,CAAC,CAAC;QACH,QAAQ,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACzC,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IACD,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,oFAAoF;AACpF,SAAS,OAAO,CAAC,MAAe;IAC9B,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,QAAQ,CAAC,IAAS,EAAE,KAAU;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC;IACnC,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC;IAChC,OAAO,KAAK,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AAC/E,CAAC;AAED,+EAA+E;AAC/E,SAAS,aAAa,CAAC,MAAe,EAAE,IAAY;IAClD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QACtD,IAAI,KAAK,CAAC,MAAM,KAAK,cAAc;YAAE,KAAK,EAAE,CAAC;aACxC,IAAI,KAAK,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;YAC1C,IAAI,KAAK,KAAK,CAAC;gBAAE,OAAO,CAAC,CAAC;YAC1B,KAAK,EAAE,CAAC;QACV,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,WAAW,CAAC,MAAe;IAClC,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAC3B,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,cAAc,CAC9D,CAAC;IACF,IAAI,IAAI,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAC5B,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CACX,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,eAAe,CAClE,CAAC;IACF,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAC7B,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAClC,IACE,UAAU,KAAK,SAAS;QACxB,WAAW,KAAK,SAAS;QACzB,CAAC,QAAQ,CAAC,UAAU,CAAC;QACrB,CAAC,QAAQ,CAAC,WAAW,CAAC,EACtB,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC9C,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IAC1D,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;AACzE,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,MAAe,EAAE,IAAkB;IACtD,MAAM,GAAG,GAAY,EAAE,CAAC;IACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;YACxD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChB,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACvC,MAAM,WAAW,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1D,IAAI,WAAW,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACxD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChB,SAAS;QACX,CAAC;QACD,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACnD,OAAO,CAAC,QAAQ,GAAG,OAAO,CACxB,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAC3D,CAAC;QACF,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QAC9D,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClB,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClB,CAAC,GAAG,KAAK,CAAC;IACZ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAE/D;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,CAAC,IAAU,EAAE,EAAE;QACpB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAW,CAAC;QAChC,MAAM,KAAK,GAAG,CAAC,MAAsB,EAAE,SAAkB,EAAQ,EAAE;YACjE,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,MAAM,GAAY,EAAE,CAAC;gBAC3B,IAAI,GAAG,GAAG,KAAK,CAAC;gBAChB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAA4B,EAAE,CAAC;oBACxD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC5D,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;wBACnB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;wBACnB,SAAS;oBACX,CAAC;oBACD,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;oBACtB,GAAG,GAAG,IAAI,CAAC;gBACb,CAAC;gBACD,IAAI,GAAG,EAAE,CAAC;oBACR,MAAM,CAAC,QAAQ,GAAG,OAAO,CACvB,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CACA,CAAC;gBAC9B,CAAC;YACH,CAAC;YACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACpC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;oBAAE,SAAS;gBACvC,sEAAsE;gBACtE,sEAAsE;gBACtE,6CAA6C;gBAC7C,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YACpE,CAAC;QACH,CAAC,CAAC;QACF,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { Root } from "hast";
2
+ export declare const SOURCE_LINE_ATTR = "data-loc";
3
+ /**
4
+ * Where a code block's contents begin in the source (T-52). The stamped
5
+ * range starts at the opening fence for fenced blocks but at the first code
6
+ * line for indented ones; the renderer records the resolved start so
7
+ * selection anchoring can map a code renderer's per-line rows back to source lines
8
+ * without re-deriving markdown syntax.
9
+ */
10
+ export declare const CODE_CONTENT_START_ATTR = "data-loc-content-start";
11
+ /** `data-loc="start-end"` → 1-based inclusive source line range. */
12
+ export declare function parseSourceLoc(value: string | null | undefined): {
13
+ start: number;
14
+ end: number;
15
+ } | null;
16
+ /**
17
+ * Rehype plugin stamping every block element with the markdown source line
18
+ * range it was rendered from. This is the whole bridge between "what the
19
+ * reader selected in the rendered document" and "which source lines the
20
+ * anchor stores" — remark/rehype keep positions intact, so no offset math.
21
+ */
22
+ export declare function rehypeSourceLines(): (tree: Root) => void;
23
+ //# sourceMappingURL=rehype-source-lines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rehype-source-lines.d.ts","sourceRoot":"","sources":["../../src/lib/rehype-source-lines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,MAAM,CAAC;AAmC1C,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAE3C;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,2BAA2B,CAAC;AAEhE,oEAAoE;AACpE,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKvC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,WACjB,IAAI,UAmBnB"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Block-level tags that make useful annotation anchors. Inline elements are
3
+ * skipped: a selection maps to its closest block, which is the granularity
4
+ * an annotation anchors at.
5
+ *
6
+ * `tr` is on the list even though it nests inside `table` (T-142). A GFM
7
+ * table row is exactly one source line, so stamping rows is what lets one
8
+ * edited cell highlight its own row instead of washing the whole table
9
+ * green; the table keeps its stamp as the fallback for table-wide
10
+ * selections. Consumers resolve nesting by taking the innermost match.
11
+ *
12
+ * `details` is here for a second reason on top of that one (T-385): a reader
13
+ * who closes a fold leaves every annotation inside it with a zero rect, and
14
+ * whatever lays out marks beside them has to walk up the stamped ancestors to
15
+ * find something it can still measure — the fold's own header.
16
+ */
17
+ const BLOCK_TAGS = new Set([
18
+ "p",
19
+ "h1",
20
+ "h2",
21
+ "h3",
22
+ "h4",
23
+ "h5",
24
+ "h6",
25
+ "li",
26
+ "pre",
27
+ "blockquote",
28
+ "details",
29
+ "table",
30
+ "tr",
31
+ "hr",
32
+ ]);
33
+ export const SOURCE_LINE_ATTR = "data-loc";
34
+ /**
35
+ * Where a code block's contents begin in the source (T-52). The stamped
36
+ * range starts at the opening fence for fenced blocks but at the first code
37
+ * line for indented ones; the renderer records the resolved start so
38
+ * selection anchoring can map a code renderer's per-line rows back to source lines
39
+ * without re-deriving markdown syntax.
40
+ */
41
+ export const CODE_CONTENT_START_ATTR = "data-loc-content-start";
42
+ /** `data-loc="start-end"` → 1-based inclusive source line range. */
43
+ export function parseSourceLoc(value) {
44
+ if (!value)
45
+ return null;
46
+ const match = /^(\d+)-(\d+)$/.exec(value);
47
+ if (!match)
48
+ return null;
49
+ return { start: Number(match[1]), end: Number(match[2]) };
50
+ }
51
+ /**
52
+ * Rehype plugin stamping every block element with the markdown source line
53
+ * range it was rendered from. This is the whole bridge between "what the
54
+ * reader selected in the rendered document" and "which source lines the
55
+ * anchor stores" — remark/rehype keep positions intact, so no offset math.
56
+ */
57
+ export function rehypeSourceLines() {
58
+ return (tree) => {
59
+ const visit = (node) => {
60
+ if (node.type === "element" &&
61
+ BLOCK_TAGS.has(node.tagName) &&
62
+ node.position?.start.line !== undefined &&
63
+ node.position.end.line !== undefined) {
64
+ node.properties[SOURCE_LINE_ATTR] =
65
+ `${node.position.start.line}-${node.position.end.line}`;
66
+ }
67
+ if ("children" in node) {
68
+ for (const child of node.children) {
69
+ if (child.type === "element")
70
+ visit(child);
71
+ }
72
+ }
73
+ };
74
+ visit(tree);
75
+ };
76
+ }
77
+ //# sourceMappingURL=rehype-source-lines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rehype-source-lines.js","sourceRoot":"","sources":["../../src/lib/rehype-source-lines.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IACzB,GAAG;IACH,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,YAAY;IACZ,SAAS;IACT,OAAO;IACP,IAAI;IACJ,IAAI;CACL,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,wBAAwB,CAAC;AAEhE,oEAAoE;AACpE,MAAM,UAAU,cAAc,CAC5B,KAAgC;IAEhC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CAAC,IAAU,EAAE,EAAE;QACpB,MAAM,KAAK,GAAG,CAAC,IAAoB,EAAE,EAAE;YACrC,IACE,IAAI,CAAC,IAAI,KAAK,SAAS;gBACvB,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;gBAC5B,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,KAAK,SAAS;gBACvC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,EACpC,CAAC;gBACD,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC;oBAC/B,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YAC5D,CAAC;YACD,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;gBACvB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAClC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;wBAAE,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC7C,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,119 @@
1
+ import type { Parent, Root, Text } from "mdast";
2
+ import type { Plugin } from "unified";
3
+ /**
4
+ * The subtree a frontmatter block becomes (T-240). Registered with mdast below
5
+ * rather than cast into place, so a walker over the mdast tree narrows on
6
+ * these types the way it does on a table's.
7
+ */
8
+ export interface Frontmatter extends Parent {
9
+ type: "frontmatter";
10
+ children: FrontmatterBody[];
11
+ }
12
+ export interface FrontmatterBody extends Parent {
13
+ type: "frontmatterBody";
14
+ children: FrontmatterFieldNode[];
15
+ }
16
+ export interface FrontmatterFieldNode extends Parent {
17
+ type: "frontmatterField";
18
+ children: Array<FrontmatterKey | FrontmatterValue>;
19
+ }
20
+ export interface FrontmatterKey extends Parent {
21
+ type: "frontmatterKey";
22
+ children: Text[];
23
+ }
24
+ export interface FrontmatterValue extends Parent {
25
+ type: "frontmatterValue";
26
+ children: Text[];
27
+ }
28
+ declare module "mdast" {
29
+ interface RootContentMap {
30
+ frontmatter: Frontmatter;
31
+ frontmatterBody: FrontmatterBody;
32
+ frontmatterField: FrontmatterFieldNode;
33
+ frontmatterKey: FrontmatterKey;
34
+ frontmatterValue: FrontmatterValue;
35
+ /**
36
+ * `remark-frontmatter`'s other flavour. Core mdast registers `yaml` and
37
+ * leaves this one to whoever turns TOML on.
38
+ */
39
+ toml: Omit<import("mdast").Yaml, "type"> & {
40
+ type: "toml";
41
+ };
42
+ }
43
+ }
44
+ /**
45
+ * One field of a frontmatter block: where its key and its value each sit in
46
+ * the source, as absolute half-open offsets. `key` is null for a line that has
47
+ * no key at all — TOML's `[section]`, or anything ahead of the first field.
48
+ */
49
+ export type FrontmatterField = {
50
+ key: {
51
+ start: number;
52
+ end: number;
53
+ } | null;
54
+ value: {
55
+ start: number;
56
+ end: number;
57
+ };
58
+ /** 1-based source lines, inclusive; `endLine` grows with continuation lines. */
59
+ line: number;
60
+ endLine: number;
61
+ };
62
+ /**
63
+ * The flavours `remark-frontmatter` is switched on for. A module constant because it is passed as a
64
+ * plugin option, and a fresh array on every render is a fresh plugin list:
65
+ * react-markdown rebuilds the whole document, and a rebuilt text node
66
+ * collapses whatever selection was sitting in it (T-60).
67
+ */
68
+ export declare const FRONTMATTER_FLAVOURS: Array<"yaml" | "toml">;
69
+ /**
70
+ * Cut a frontmatter block into fields, one line at a time — deliberately not
71
+ * by parsing YAML (T-240).
72
+ *
73
+ * Decorating the rendered text by source offset rests on every rendered
74
+ * character sitting at a known source offset: a word-level highlight is mapped
75
+ * back onto the source by addition, a text node is entered only while its span
76
+ * and its value agree character for character, and a reader's line/column
77
+ * selection is turned into an offset. Parsing and rendering the
78
+ * *result* breaks all three at once — a key can be normalised, the order
79
+ * reshuffled, `~` spelled `null` — so what comes out of here is only ever a
80
+ * verbatim slice of the source. That is also what lets an annotation anchor on
81
+ * one key or one value, and what lets the page's own search find them.
82
+ *
83
+ * The price, stated where a reader will look for it: a `meta:` with indented
84
+ * children lands whole in one value cell, because a continuation line has
85
+ * nothing but its indentation to say it is one. `white-space: pre-wrap` on the
86
+ * cell keeps that readable; expanding a nested map into rows of its own needs
87
+ * real YAML semantics and is out of scope here.
88
+ */
89
+ export declare function frontmatterFields(source: string, block: {
90
+ start: {
91
+ line: number;
92
+ };
93
+ end: {
94
+ line: number;
95
+ };
96
+ }, sep: string): FrontmatterField[];
97
+ /**
98
+ * remark plugin: swap each `yaml` / `toml` node for a two-column table of its
99
+ * fields (T-240). It consumes what `remark-frontmatter` produces, so it has to
100
+ * run after it.
101
+ *
102
+ * A table-shaped subtree rather than a bespoke one, because anything that
103
+ * already compares tables reads that shape: it knows `table` / `tableRow` /
104
+ * `tableCell`, pairs rows by their leftmost cell, and splices a removed row
105
+ * back where it stood. Frontmatter is a two-column table whose keys are the
106
+ * row keys, so nothing new has to be taught — the data is laid out at an
107
+ * entrance that exists.
108
+ *
109
+ * Custom node types plus `data.hName`, not real mdast `table` nodes: the
110
+ * `table` handler in `mdast-util-to-hast` makes row 0 a `<thead>` header, and
111
+ * frontmatter has no header — the first field would be drawn as one. `hName`
112
+ * renames an element after that handler has run and cannot undo what it did,
113
+ * so the unknown-node route is the only one that controls the output exactly.
114
+ * It also puts the `<tbody>` there explicitly, which is what keeps a pass
115
+ * that restores a removed field's stand-in row from appending it to the end of
116
+ * the table instead of into its body.
117
+ */
118
+ export declare const remarkFrontmatterTable: Plugin<[], Root>;
119
+ //# sourceMappingURL=remark-frontmatter-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remark-frontmatter-table.d.ts","sourceRoot":"","sources":["../../src/lib/remark-frontmatter-table.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAQ,MAAM,EAAE,IAAI,EAAe,IAAI,EAAE,MAAM,OAAO,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAKtC;;;;GAIG;AACH,MAAM,WAAW,WAAY,SAAQ,MAAM;IACzC,IAAI,EAAE,aAAa,CAAC;IACpB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,eAAgB,SAAQ,MAAM;IAC7C,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,oBAAoB,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,oBAAqB,SAAQ,MAAM;IAClD,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,cAAc,GAAG,gBAAgB,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,cAAe,SAAQ,MAAM;IAC5C,IAAI,EAAE,gBAAgB,CAAC;IACvB,QAAQ,EAAE,IAAI,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,gBAAiB,SAAQ,MAAM;IAC9C,IAAI,EAAE,kBAAkB,CAAC;IACzB,QAAQ,EAAE,IAAI,EAAE,CAAC;CAClB;AAUD,OAAO,QAAQ,OAAO,CAAC;IACrB,UAAU,cAAc;QACtB,WAAW,EAAE,WAAW,CAAC;QACzB,eAAe,EAAE,eAAe,CAAC;QACjC,gBAAgB,EAAE,oBAAoB,CAAC;QACvC,cAAc,EAAE,cAAc,CAAC;QAC/B,gBAAgB,EAAE,gBAAgB,CAAC;QACnC;;;WAGG;QACH,IAAI,EAAE,IAAI,CAAC,OAAO,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;KAC7D;CACF;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3C,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAoB,CAAC;AAc7E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EACzD,GAAG,EAAE,MAAM,GACV,gBAAgB,EAAE,CAkDpB;AAkID;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,CAgBnD,CAAC"}