@tanstack/markdown 0.0.3 → 0.0.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAuC,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAA;AAG3J,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAGpF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAsChF;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAwBlF;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAE9F"}
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../src/html.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAyD,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAA;AAG7K,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAGpF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAwChF;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CA0BlF;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAE9F"}
package/dist/html.js CHANGED
@@ -21,7 +21,7 @@ export function renderBlock(node, options = {}) {
21
21
  case 'list': {
22
22
  const tag = node.ordered ? 'ol' : 'ul';
23
23
  const start = node.ordered && node.start && node.start !== 1 ? ` start="${node.start}"` : '';
24
- const items = node.items.map(item => `<li>${renderListItemChildren(item.children, item.checked, options)}</li>`).join('\n');
24
+ const items = node.items.map(item => `<li>${renderListItemChildren(item.children, item.checked, node.loose, options)}</li>`).join('\n');
25
25
  return `<${tag}${start}>\n${items}\n</${tag}>`;
26
26
  }
27
27
  case 'blockquote':
@@ -33,6 +33,8 @@ export function renderBlock(node, options = {}) {
33
33
  .join('')}</tbody>`;
34
34
  return `<table>${header}${body}</table>`;
35
35
  }
36
+ case 'footnotes':
37
+ return renderFootnotes(node.items, options);
36
38
  case 'thematicBreak':
37
39
  return '<hr>';
38
40
  case 'html':
@@ -57,7 +59,9 @@ export function renderInline(node, options = {}) {
57
59
  case 'emphasis':
58
60
  return `<em>${renderInlines(node.children, options)}</em>`;
59
61
  case 'strike':
60
- return `<s>${renderInlines(node.children, options)}</s>`;
62
+ return `<del>${renderInlines(node.children, options)}</del>`;
63
+ case 'footnoteReference':
64
+ return `<sup><a id="user-content-fnref-${escapeAttr(node.id)}" data-footnote-ref="" aria-describedby="footnote-label" href="#user-content-fn-${escapeAttr(node.id)}">${node.number}</a></sup>`;
61
65
  case 'link':
62
66
  return `<a href="${escapeAttr(node.href)}"${node.title ? ` title="${escapeAttr(node.title)}"` : ''}>${renderInlines(node.children, options)}</a>`;
63
67
  case 'image':
@@ -76,7 +80,6 @@ function renderInlines(nodes, options) {
76
80
  }
77
81
  function renderCodeBlock(node, options) {
78
82
  const lang = node.lang ?? 'plaintext';
79
- const codeAttrs = ` class="language-${escapeAttr(lang)}"`;
80
83
  const preAttrs = [
81
84
  'class="tm-code"',
82
85
  `data-lang="${escapeAttr(lang)}"`,
@@ -86,25 +89,20 @@ function renderCodeBlock(node, options) {
86
89
  ]
87
90
  .filter(Boolean)
88
91
  .join(' ');
89
- const highlighter = options.highlighter;
90
- const highlightOptions = {
91
- ...(node.highlightLines ? { highlightLines: node.highlightLines } : {}),
92
- ...(options.codeLineNumbers !== undefined ? { lineNumbers: options.codeLineNumbers } : {}),
93
- };
94
- const html = highlighter ? highlighter(node.value, lang, highlightOptions) : escapeHtml(node.value);
95
- const pre = `<pre ${preAttrs}><code${codeAttrs}>${html}</code></pre>`;
92
+ const html = options.highlighter?.(node.value, lang, {
93
+ ...(node.highlightLines && { highlightLines: node.highlightLines }),
94
+ ...(options.codeLineNumbers !== undefined && { lineNumbers: options.codeLineNumbers }),
95
+ }) ?? escapeHtml(node.value);
96
+ const pre = `<pre ${preAttrs}><code class="language-${escapeAttr(lang)}">${html}</code></pre>`;
96
97
  if (!node.title)
97
98
  return pre;
98
99
  return `<figure class="tm-code-frame" data-lang="${escapeAttr(lang)}"><figcaption>${escapeHtml(node.title)}</figcaption>${pre}</figure>`;
99
100
  }
100
- function renderListItemChildren(children, checked, options) {
101
- const [first, ...rest] = children;
101
+ function renderListItemChildren(children, checked, loose, options) {
102
+ const first = children[0];
102
103
  const task = checked === undefined ? '' : `<input type="checkbox" disabled${checked ? ' checked' : ''}> `;
103
- if (checked !== undefined && first?.type === 'paragraph') {
104
- const firstLine = `${task}${renderInlines(first.children, options)}`;
105
- const restHtml = rest.map(child => renderBlock(child, options)).join('\n');
106
- return restHtml ? `${firstLine}\n${restHtml}` : firstLine;
107
- }
104
+ if ((checked !== undefined || !loose) && first?.type === 'paragraph')
105
+ return `${task}${renderInlines(first.children, options)}${children.length > 1 ? `\n${children.slice(1).map(child => renderBlock(child, options)).join('\n')}` : ''}`;
108
106
  return `${task}${children.map(child => renderBlock(child, options)).join('\n')}`;
109
107
  }
110
108
  function renderCallout(node, options) {
@@ -112,6 +110,24 @@ function renderCallout(node, options) {
112
110
  const children = node.children.map(child => renderBlock(child, options)).join('\n');
113
111
  return `<div class="markdown-alert markdown-alert-${escapeAttr(kind)}"><p class="markdown-alert-title">${escapeHtml(node.title)}</p><div class="markdown-alert-content">${children}</div></div>`;
114
112
  }
113
+ function renderFootnotes(items, options) {
114
+ const renderedItems = items.map(item => `<li id="user-content-fn-${escapeAttr(item.id)}">\n${renderFootnoteItem(item, options)}\n</li>`).join('\n');
115
+ return `<section data-footnotes="" class="footnotes"><h2 id="footnote-label" class="sr-only">Footnotes${renderHeadingAnchor('footnote-label', options)}</h2>\n<ol>\n${renderedItems}\n</ol>\n</section>`;
116
+ }
117
+ function renderFootnoteItem(item, options) {
118
+ const backref = ` <a data-footnote-backref="" aria-label="Back to reference ${item.number}" class="data-footnote-backref" href="#user-content-fnref-${escapeAttr(item.id)}">&#8617;</a>`;
119
+ const lastIndex = item.children.length - 1;
120
+ if (lastIndex < 0)
121
+ return `<p>${backref.trimStart()}</p>`;
122
+ return item.children
123
+ .map((child, index) => {
124
+ if (index === lastIndex && child.type === 'paragraph') {
125
+ return `<p>${renderInlines(child.children, options)}${backref}</p>`;
126
+ }
127
+ return renderBlock(child, options);
128
+ })
129
+ .join('\n');
130
+ }
115
131
  function renderComponent(node, options) {
116
132
  const tag = node.tagName ?? 'md-comment-component';
117
133
  const attrs = renderComponentAttrs(node);
@@ -135,14 +151,11 @@ function renderExtension(node, options) {
135
151
  return undefined;
136
152
  }
137
153
  function renderHeadingAnchor(id, options) {
138
- if (!id || !options.headingAnchors)
154
+ const headingAnchors = options.headingAnchors;
155
+ if (!id || !headingAnchors)
139
156
  return '';
140
- const anchorOptions = typeof options.headingAnchors === 'object' ? options.headingAnchors : {};
141
- const content = anchorOptions.content ?? '#';
142
- const className = anchorOptions.className ?? 'anchor-heading anchor-heading-link';
143
- const ariaHidden = anchorOptions.ariaHidden ?? true;
144
- const tabIndex = anchorOptions.tabIndex ?? -1;
145
- return `<a href="#${escapeAttr(id)}" aria-hidden="${ariaHidden}" class="${escapeAttr(className)}" tabindex="${tabIndex}">${escapeHtml(content)}</a>`;
157
+ const anchorOptions = typeof headingAnchors === 'object' ? headingAnchors : {};
158
+ return `<a href="#${escapeAttr(id)}" aria-hidden="${anchorOptions.ariaHidden ?? true}" class="${escapeAttr(anchorOptions.className ?? 'anchor-heading anchor-heading-link')}" tabindex="${anchorOptions.tabIndex ?? -1}">${escapeHtml(anchorOptions.content ?? '#')}</a>`;
146
159
  }
147
160
  function renderComponentAttrs(node) {
148
161
  const props = {
package/dist/inline.js CHANGED
@@ -1,4 +1,4 @@
1
- import { normalizeReferenceLabel, sanitizeUrl } from './utils.js';
1
+ import { footnoteId, normalizeReferenceLabel, sanitizeUrl } from './utils.js';
2
2
  export function parseInline(value, options = {}) {
3
3
  const nodes = parseInlineRaw(value, options);
4
4
  let result = mergeText(nodes);
@@ -61,6 +61,13 @@ function parseInlineRaw(value, options) {
61
61
  }
62
62
  }
63
63
  if (char === '[') {
64
+ const footnote = parseFootnoteReference(value, index, options);
65
+ if (footnote) {
66
+ pushText();
67
+ nodes.push(footnote.node);
68
+ index = footnote.end;
69
+ continue;
70
+ }
64
71
  const parsed = parseLinkish(value, index, options);
65
72
  if (parsed) {
66
73
  const href = sanitizeUrl(parsed.href);
@@ -110,6 +117,18 @@ function parseInlineRaw(value, options) {
110
117
  index += 2;
111
118
  continue;
112
119
  }
120
+ if (char === '~') {
121
+ const close = findSingleTildeDelimiter(value, index + 1);
122
+ if (close !== -1) {
123
+ pushText();
124
+ nodes.push({
125
+ type: 'strike',
126
+ children: parseInlineRaw(value.slice(index + 1, close), options),
127
+ });
128
+ index = close + 1;
129
+ continue;
130
+ }
131
+ }
113
132
  if (char === '*' || char === '_') {
114
133
  const close = findDelimiter(value, index + 1, char);
115
134
  if (close !== -1 && !isIntrawordUnderscore(value, index, close, char)) {
@@ -137,6 +156,31 @@ function parseInlineRaw(value, options) {
137
156
  pushText();
138
157
  return nodes;
139
158
  }
159
+ function parseFootnoteReference(value, open, options) {
160
+ if (value[open + 1] !== '^')
161
+ return undefined;
162
+ const close = value.indexOf(']', open + 2);
163
+ if (close === -1)
164
+ return undefined;
165
+ const label = value.slice(open + 2, close);
166
+ const key = normalizeReferenceLabel(label);
167
+ const definition = options.footnotes?.[key];
168
+ if (!definition || !options.footnoteOrder)
169
+ return undefined;
170
+ let orderIndex = options.footnoteOrder.indexOf(key);
171
+ if (orderIndex === -1) {
172
+ options.footnoteOrder.push(key);
173
+ orderIndex = options.footnoteOrder.length - 1;
174
+ }
175
+ return {
176
+ node: {
177
+ type: 'footnoteReference',
178
+ id: footnoteId(definition.label),
179
+ number: orderIndex + 1,
180
+ },
181
+ end: close + 1,
182
+ };
183
+ }
140
184
  function parseLinkish(value, open, options) {
141
185
  const closeBracket = findBalanced(value, open, '[', ']');
142
186
  if (closeBracket === -1)
@@ -148,7 +192,7 @@ function parseLinkish(value, open, options) {
148
192
  return undefined;
149
193
  const destination = value.slice(closeBracket + 2, closeParen).trim();
150
194
  const parsed = parseDestination(destination);
151
- if (!parsed.href)
195
+ if (!parsed)
152
196
  return undefined;
153
197
  return {
154
198
  label,
@@ -161,8 +205,7 @@ function parseLinkish(value, open, options) {
161
205
  const closeReference = findBalanced(value, closeBracket + 1, '[', ']');
162
206
  if (closeReference === -1)
163
207
  return undefined;
164
- const explicitReference = value.slice(closeBracket + 2, closeReference);
165
- const definition = options.references?.[normalizeReferenceLabel(explicitReference || label)];
208
+ const definition = options.references?.[normalizeReferenceLabel(value.slice(closeBracket + 2, closeReference))];
166
209
  if (!definition)
167
210
  return undefined;
168
211
  return {
@@ -222,25 +265,32 @@ function findDelimiter(value, start, delimiter) {
222
265
  }
223
266
  return -1;
224
267
  }
268
+ function findSingleTildeDelimiter(value, start) {
269
+ if (isWhitespace(value[start] ?? ''))
270
+ return -1;
271
+ for (let index = start; index < value.length; index++) {
272
+ if (value[index - 1] === '\\')
273
+ continue;
274
+ if (value[index] !== '~')
275
+ continue;
276
+ if (value[index + 1] === '~')
277
+ continue;
278
+ if (isWhitespace(value[index - 1] ?? ''))
279
+ return -1;
280
+ return index;
281
+ }
282
+ return -1;
283
+ }
225
284
  function isIntrawordUnderscore(value, open, close, delimiter) {
226
285
  if (delimiter !== '_')
227
286
  return false;
228
287
  return /\w/.test(value[open - 1] ?? '') && /\w/.test(value[close + 1] ?? '');
229
288
  }
230
- function textFromMarkdown(value) {
231
- return inlineText(parseInlineRaw(value, {}));
289
+ function isWhitespace(value) {
290
+ return /\s/.test(value);
232
291
  }
233
- function inlineText(nodes) {
234
- let value = '';
235
- for (const node of nodes) {
236
- if (node.type === 'text' || node.type === 'inlineCode')
237
- value += node.value;
238
- else if ('children' in node)
239
- value += inlineText(node.children);
240
- else if (node.type === 'image')
241
- value += node.alt;
242
- }
243
- return value;
292
+ function textFromMarkdown(value) {
293
+ return parseInlineRaw(value, {}).map(node => (node.type === 'text' || node.type === 'inlineCode' ? node.value : '')).join('');
244
294
  }
245
295
  function mergeText(nodes) {
246
296
  const result = [];
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAOV,gBAAgB,EAChB,YAAY,EAGb,MAAM,YAAY,CAAA;AAKnB,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,gBAAgB,CAoC5F"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAOV,gBAAgB,EAChB,YAAY,EAGb,MAAM,YAAY,CAAA;AAKnB,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,gBAAgB,CAwC5F"}
package/dist/parser.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { parseInline } from './inline.js';
2
- import { createSlugger, isBlank, normalizeInput, normalizeReferenceLabel, plainText, stripIndent } from './utils.js';
2
+ import { createSlugger, footnoteId, isBlank, normalizeInput, normalizeReferenceLabel, plainText, stripIndent } from './utils.js';
3
3
  export function parseMarkdown(markdown, options = {}) {
4
4
  const normalized = normalizeInput(markdown);
5
5
  const frontmatterEnabled = options.frontmatter !== false;
@@ -12,19 +12,23 @@ export function parseMarkdown(markdown, options = {}) {
12
12
  lines = lines.slice(end + 1);
13
13
  }
14
14
  }
15
- const referenceResult = extractReferenceDefinitions(lines);
16
- lines = referenceResult.lines;
17
- const parseOptions = Object.keys(referenceResult.references).length === 0
18
- ? options
19
- : {
15
+ const definitions = extractDefinitions(lines);
16
+ lines = definitions.lines;
17
+ const footnoteOrder = [];
18
+ const hasReferences = Object.keys(definitions.references).length > 0;
19
+ const hasFootnotes = Object.keys(definitions.footnotes).length > 0;
20
+ const parseOptions = hasReferences || hasFootnotes
21
+ ? {
20
22
  ...options,
21
- references: {
22
- ...referenceResult.references,
23
- ...options.references,
24
- },
25
- };
23
+ ...(hasReferences ? { references: definitions.references } : {}),
24
+ ...(hasFootnotes ? { footnotes: definitions.footnotes, footnoteOrder } : {}),
25
+ }
26
+ : options;
26
27
  const parser = new BlockParser(lines, parseOptions, createSlugger());
27
28
  const children = parser.parse();
29
+ if (hasFootnotes && footnoteOrder.length > 0) {
30
+ children.push(createFootnotesBlock(definitions.footnotes, footnoteOrder, parseOptions));
31
+ }
28
32
  let document = frontmatter === undefined ? { type: 'root', children } : { type: 'root', frontmatter, children };
29
33
  for (const extension of parseOptions.extensions ?? []) {
30
34
  document = extension.transformDocument?.(document, { options: parseOptions }) ?? document;
@@ -157,6 +161,7 @@ class BlockParser {
157
161
  const ordered = first.ordered;
158
162
  const baseIndent = first.indent;
159
163
  const start = ordered ? first.number : undefined;
164
+ let loose = false;
160
165
  while (this.index < this.lines.length) {
161
166
  const marker = listMarker(this.current());
162
167
  if (!marker || marker.ordered !== ordered || marker.indent !== baseIndent)
@@ -174,6 +179,9 @@ class BlockParser {
174
179
  if (nextMarker && nextMarker.indent === baseIndent && nextMarker.ordered === ordered)
175
180
  break;
176
181
  if (isBlank(line)) {
182
+ if (!this.next())
183
+ break;
184
+ loose = true;
177
185
  itemLines.push('');
178
186
  this.index++;
179
187
  continue;
@@ -189,9 +197,18 @@ class BlockParser {
189
197
  this.index++;
190
198
  }
191
199
  const children = new BlockParser(itemLines, this.options, this.slugger).parse();
192
- items.push(checked === undefined ? { type: 'listItem', children } : { type: 'listItem', checked, children });
200
+ const item = { type: 'listItem', children };
201
+ if (checked !== undefined)
202
+ item.checked = checked;
203
+ items.push(item);
193
204
  }
194
- return ordered && start !== undefined ? { type: 'list', ordered, start, items } : { type: 'list', ordered, items };
205
+ return {
206
+ type: 'list',
207
+ ordered,
208
+ ...(ordered && start !== undefined ? { start } : {}),
209
+ ...(loose && { loose: true }),
210
+ items,
211
+ };
195
212
  }
196
213
  parseTable() {
197
214
  const header = this.current();
@@ -277,12 +294,15 @@ function parseCodeInfo(info) {
277
294
  ...(highlightLines.length ? { highlightLines } : {}),
278
295
  };
279
296
  }
280
- function extractReferenceDefinitions(lines) {
297
+ function extractDefinitions(lines) {
281
298
  const references = {};
299
+ const footnotes = {};
282
300
  const remaining = [];
283
301
  let fenceMarker;
284
302
  let fenceSize = 0;
285
- for (const line of lines) {
303
+ let index = 0;
304
+ while (index < lines.length) {
305
+ const line = lines[index];
286
306
  const fence = line.match(/^ {0,3}(`{3,}|~{3,})/);
287
307
  if (fence) {
288
308
  const marker = fence[1][0];
@@ -295,18 +315,50 @@ function extractReferenceDefinitions(lines) {
295
315
  fenceSize = 0;
296
316
  }
297
317
  remaining.push(line);
318
+ index++;
298
319
  continue;
299
320
  }
300
321
  if (!fenceMarker) {
322
+ const footnote = line.match(/^ {0,3}\[\^([^\]\n]+)\]:[ \t]*(.*)$/);
323
+ if (footnote) {
324
+ const label = footnote[1];
325
+ const content = [footnote[2] ?? ''];
326
+ index++;
327
+ while (index < lines.length) {
328
+ const continuation = lines[index];
329
+ if (!/^(?: {4,}|\t)/.test(continuation))
330
+ break;
331
+ content.push(continuation.replace(/^(?: {4}|\t)/, ''));
332
+ index++;
333
+ }
334
+ footnotes[normalizeReferenceLabel(label)] = { label, content: content.join('\n') };
335
+ continue;
336
+ }
301
337
  const definition = line.match(/^ {0,3}\[([^\]\n]+)\]:[ \t]*(\S+)[ \t]*$/);
302
338
  if (definition) {
303
339
  references[normalizeReferenceLabel(definition[1])] = { href: definition[2].replace(/^<|>$/g, '') };
340
+ index++;
304
341
  continue;
305
342
  }
306
343
  }
307
344
  remaining.push(line);
345
+ index++;
346
+ }
347
+ return { lines: remaining, references, footnotes };
348
+ }
349
+ function createFootnotesBlock(footnotes, footnoteOrder, options) {
350
+ const items = [];
351
+ for (let index = 0; index < footnoteOrder.length; index++) {
352
+ const definition = footnotes[footnoteOrder[index]];
353
+ if (!definition)
354
+ continue;
355
+ items.push({
356
+ id: footnoteId(definition.label),
357
+ number: index + 1,
358
+ children: new BlockParser(normalizeInput(definition.content).split('\n'), options, createSlugger()).parse(),
359
+ });
308
360
  }
309
- return { lines: remaining, references };
361
+ return { type: 'footnotes', items };
310
362
  }
311
363
  function parseLineRanges(value) {
312
364
  const lines = new Set();
@@ -349,7 +401,7 @@ function looksLikeTableHeader(header, delimiter) {
349
401
  if (!header.includes('|'))
350
402
  return false;
351
403
  const cells = splitTableRow(delimiter);
352
- return cells.length > 0 && cells.every(cell => /^:?-{3,}:?$/.test(cell.trim()));
404
+ return cells.length > 0 && cells.every(cell => /^:?-{2,}:?$/.test(cell.trim()));
353
405
  }
354
406
  function splitTableRow(value) {
355
407
  let row = value.trim();
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAiB,UAAU,EAAE,aAAa,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAA;AAEnH,KAAK,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;AAExE,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,UAAU,CAAC,EAAE,YAAY,CAAA;CAC1B;AAED,MAAM,WAAW,aAAc,SAAQ,oBAAoB;IACzD,QAAQ,EAAE,aAAa,CAAA;CACxB;AAED,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,EAAE,aAAa,GAAG,YAAY,CAE9E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,GAAE,oBAAyB,GAAG,SAAS,CAGvG;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,GAAE,oBAAyB,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,CA2DhH;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,GAAE,oBAAyB,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAuB/G"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAmC,UAAU,EAAE,aAAa,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAA;AAErI,KAAK,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;AAExE,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,UAAU,CAAC,EAAE,YAAY,CAAA;CAC1B;AAED,MAAM,WAAW,aAAc,SAAQ,oBAAoB;IACzD,QAAQ,EAAE,aAAa,CAAA;CACxB;AAED,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,EAAE,aAAa,GAAG,YAAY,CAE9E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,GAAE,oBAAyB,GAAG,SAAS,CAGvG;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,GAAE,oBAAyB,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,CA6DhH;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,GAAE,oBAAyB,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAwC/G"}
package/dist/react.js CHANGED
@@ -17,12 +17,14 @@ export function renderBlockReact(node, options = {}, key) {
17
17
  return renderCodeBlockReact(node, options, key);
18
18
  case 'list': {
19
19
  const tag = node.ordered ? 'ol' : 'ul';
20
- return h(options, tag, { key, ...(node.ordered && node.start && node.start !== 1 ? { start: node.start } : {}) }, node.items.map((item, index) => h(options, 'li', { key: index }, renderListItemChildrenReact(item.children, item.checked, options, `${index}`))));
20
+ return h(options, tag, { key, ...(node.ordered && node.start && node.start !== 1 ? { start: node.start } : {}) }, node.items.map((item, index) => h(options, 'li', { key: index }, renderListItemChildrenReact(item.children, item.checked, node.loose, options, `${index}`))));
21
21
  }
22
22
  case 'blockquote':
23
23
  return h(options, 'blockquote', { key }, node.children.map((child, index) => renderBlockReact(child, options, `${key}:${index}`)));
24
24
  case 'table':
25
25
  return h(options, 'table', { key }, h(options, 'thead', null, h(options, 'tr', null, node.header.map((cell, index) => renderTableCellReact('th', cell, node.align[index], options, index)))), h(options, 'tbody', null, node.rows.map((row, rowIndex) => h(options, 'tr', { key: rowIndex }, row.map((cell, index) => renderTableCellReact('td', cell, node.align[index], options, index))))));
26
+ case 'footnotes':
27
+ return renderFootnotesReact(node.items, options, key);
26
28
  case 'thematicBreak':
27
29
  return h(options, 'hr', { key });
28
30
  case 'html':
@@ -46,7 +48,14 @@ export function renderInlineReact(node, options = {}, key) {
46
48
  case 'emphasis':
47
49
  return h(options, 'em', { key }, renderInlines(node.children, options));
48
50
  case 'strike':
49
- return h(options, 's', { key }, renderInlines(node.children, options));
51
+ return h(options, 'del', { key }, renderInlines(node.children, options));
52
+ case 'footnoteReference':
53
+ return h(options, 'sup', { key }, h(options, 'a', {
54
+ id: `user-content-fnref-${node.id}`,
55
+ 'data-footnote-ref': '',
56
+ 'aria-describedby': 'footnote-label',
57
+ href: `#user-content-fn-${node.id}`,
58
+ }, node.number));
50
59
  case 'link':
51
60
  return h(options, 'a', { key, href: node.href, ...(node.title ? { title: node.title } : {}) }, renderInlines(node.children, options));
52
61
  case 'image':
@@ -73,8 +82,8 @@ function renderCodeBlockReact(node, options, key) {
73
82
  ? {
74
83
  dangerouslySetInnerHTML: {
75
84
  __html: highlighter(node.value, lang, {
76
- ...(node.highlightLines ? { highlightLines: node.highlightLines } : {}),
77
- ...(options.codeLineNumbers !== undefined ? { lineNumbers: options.codeLineNumbers } : {}),
85
+ ...(node.highlightLines && { highlightLines: node.highlightLines }),
86
+ ...(options.codeLineNumbers !== undefined && { lineNumbers: options.codeLineNumbers }),
78
87
  }),
79
88
  },
80
89
  }
@@ -90,7 +99,7 @@ function renderCodeBlockReact(node, options, key) {
90
99
  return h(options, Fragment, { key }, pre);
91
100
  return h(options, 'figure', { key, className: 'tm-code-frame', 'data-lang': lang }, h(options, 'figcaption', null, node.title), pre);
92
101
  }
93
- function renderListItemChildrenReact(children, checked, options, key) {
102
+ function renderListItemChildrenReact(children, checked, loose, options, key) {
94
103
  const [first, ...rest] = children;
95
104
  const task = checked === undefined
96
105
  ? []
@@ -108,14 +117,41 @@ function renderListItemChildrenReact(children, checked, options, key) {
108
117
  return [
109
118
  ...task,
110
119
  ...renderInlines(first.children, options),
111
- ...rest.map((child, childIndex) => renderBlockReact(child, options, `${key}:${childIndex + 1}`)),
120
+ ...rest.flatMap((child, childIndex) => renderListChildReact(child, loose, options, `${key}:${childIndex + 1}`)),
112
121
  ];
113
122
  }
114
- return [...task, ...children.map((child, childIndex) => renderBlockReact(child, options, `${key}:${childIndex}`))];
123
+ return [...task, ...children.flatMap((child, childIndex) => renderListChildReact(child, loose, options, `${key}:${childIndex}`))];
124
+ }
125
+ function renderListChildReact(child, loose, options, key) {
126
+ return !loose && child.type === 'paragraph' ? renderInlines(child.children, options) : [renderBlockReact(child, options, key)];
115
127
  }
116
128
  function renderTableCellReact(tag, cell, align, options, key) {
117
129
  return h(options, tag, { key, ...(align ? { style: { textAlign: align } } : {}) }, renderInlines(cell.children, options));
118
130
  }
131
+ function renderFootnotesReact(items, options, key) {
132
+ return h(options, 'section', { key, 'data-footnotes': '', className: 'footnotes' }, h(options, 'h2', { id: 'footnote-label', className: 'sr-only' }, 'Footnotes', renderHeadingAnchorReact('footnote-label', options)), h(options, 'ol', null, items.map(item => h(options, 'li', { key: item.id, id: `user-content-fn-${item.id}` }, renderFootnoteItemReact(item, options)))));
133
+ }
134
+ function renderFootnoteItemReact(item, options) {
135
+ const lastIndex = item.children.length - 1;
136
+ const backref = renderFootnoteBackrefReact(item, options, 'backref');
137
+ if (lastIndex < 0)
138
+ return [h(options, 'p', { key: 'backref-wrapper' }, backref)];
139
+ return item.children.map((child, index) => {
140
+ if (index === lastIndex && child.type === 'paragraph') {
141
+ return h(options, 'p', { key: index }, renderInlines(child.children, options), ' ', backref);
142
+ }
143
+ return renderBlockReact(child, options, `${index}`);
144
+ });
145
+ }
146
+ function renderFootnoteBackrefReact(item, options, key) {
147
+ return h(options, 'a', {
148
+ key,
149
+ 'data-footnote-backref': '',
150
+ 'aria-label': `Back to reference ${item.number}`,
151
+ className: 'data-footnote-backref',
152
+ href: `#user-content-fnref-${item.id}`,
153
+ }, '\u21a9');
154
+ }
119
155
  function h(options, tag, props, ...children) {
120
156
  const component = typeof tag === 'string' ? options.components?.[tag] ?? tag : tag;
121
157
  return createElement(component, props, ...children);
package/dist/types.d.ts CHANGED
@@ -5,7 +5,7 @@ export interface MarkdownDocument {
5
5
  frontmatter?: string;
6
6
  headings?: MarkdownHeading[];
7
7
  }
8
- export type BlockNode = HeadingNode | ParagraphNode | CodeBlockNode | ListNode | BlockquoteNode | TableNode | ThematicBreakNode | HtmlBlockNode | CalloutNode | ComponentNode;
8
+ export type BlockNode = HeadingNode | ParagraphNode | CodeBlockNode | ListNode | BlockquoteNode | TableNode | FootnotesNode | ThematicBreakNode | HtmlBlockNode | CalloutNode | ComponentNode;
9
9
  export interface HeadingNode {
10
10
  type: 'heading';
11
11
  depth: 1 | 2 | 3 | 4 | 5 | 6;
@@ -31,6 +31,7 @@ export interface ListNode {
31
31
  type: 'list';
32
32
  ordered: boolean;
33
33
  start?: number;
34
+ loose?: boolean;
34
35
  items: ListItemNode[];
35
36
  }
36
37
  export interface ListItemNode {
@@ -52,6 +53,15 @@ export interface TableCellNode {
52
53
  type: 'tableCell';
53
54
  children: InlineNode[];
54
55
  }
56
+ export interface FootnotesNode {
57
+ type: 'footnotes';
58
+ items: FootnoteItemNode[];
59
+ }
60
+ export interface FootnoteItemNode {
61
+ id: string;
62
+ number: number;
63
+ children: BlockNode[];
64
+ }
55
65
  export interface ThematicBreakNode {
56
66
  type: 'thematicBreak';
57
67
  }
@@ -73,7 +83,7 @@ export interface ComponentNode {
73
83
  tagName?: string;
74
84
  properties?: Record<string, string>;
75
85
  }
76
- export type InlineNode = TextNode | CodeSpanNode | StrongNode | EmphasisNode | StrikeNode | LinkNode | ImageNode | BreakNode | HtmlInlineNode;
86
+ export type InlineNode = TextNode | CodeSpanNode | StrongNode | EmphasisNode | StrikeNode | FootnoteReferenceNode | LinkNode | ImageNode | BreakNode | HtmlInlineNode;
77
87
  export interface TextNode {
78
88
  type: 'text';
79
89
  value: string;
@@ -94,6 +104,11 @@ export interface StrikeNode {
94
104
  type: 'strike';
95
105
  children: InlineNode[];
96
106
  }
107
+ export interface FootnoteReferenceNode {
108
+ type: 'footnoteReference';
109
+ id: string;
110
+ number: number;
111
+ }
97
112
  export interface LinkNode {
98
113
  type: 'link';
99
114
  href: string;
@@ -145,6 +160,8 @@ export interface ParseOptions {
145
160
  headingIds?: boolean | ((text: string, index: number) => string);
146
161
  extensions?: MarkdownExtension[];
147
162
  references?: Record<string, LinkReferenceDefinition>;
163
+ footnotes?: Record<string, FootnoteDefinition>;
164
+ footnoteOrder?: string[];
148
165
  }
149
166
  export interface RenderOptions extends ParseOptions {
150
167
  highlighter?: CodeHighlighter;
@@ -174,4 +191,8 @@ export interface LinkReferenceDefinition {
174
191
  href: string;
175
192
  title?: string;
176
193
  }
194
+ export interface FootnoteDefinition {
195
+ label: string;
196
+ content: string;
197
+ }
177
198
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/utils.d.ts CHANGED
@@ -8,5 +8,6 @@ export declare function plainText(nodes: InlineNode[]): string;
8
8
  export declare function createSlugger(): (value: string) => string;
9
9
  export declare function sanitizeUrl(value: string): string;
10
10
  export declare function normalizeReferenceLabel(value: string): string;
11
+ export declare function footnoteId(label: string): string;
11
12
  export declare function splitLines(value: string): string[];
12
13
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAU5C,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAQrD;AAED,wBAAgB,aAAa,KAGnB,OAAO,MAAM,YActB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAIlD"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAU5C,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAQrD;AAED,wBAAgB,aAAa,KAGnB,OAAO,MAAM,YActB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAIlD"}
package/dist/utils.js CHANGED
@@ -63,7 +63,12 @@ export function sanitizeUrl(value) {
63
63
  return trimmed;
64
64
  }
65
65
  export function normalizeReferenceLabel(value) {
66
- return value.trim().replace(/\s+/g, ' ').toLowerCase();
66
+ return value.trim().toLowerCase();
67
+ }
68
+ export function footnoteId(label) {
69
+ return normalizeReferenceLabel(label)
70
+ .replace(/[^a-z0-9_-]+/g, '-')
71
+ .replace(/^-+|-+$/g, '');
67
72
  }
68
73
  export function splitLines(value) {
69
74
  const lines = value.split('\n');
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@tanstack/markdown",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "description": "A tiny deterministic TanStack-flavored markdown renderer.",
6
6
  "license": "MIT",
7
+ "packageManager": "pnpm@11.4.0",
7
8
  "sideEffects": false,
8
9
  "files": [
9
10
  "dist",
@@ -52,6 +53,14 @@
52
53
  "import": "./dist/extensions/tabs.js"
53
54
  }
54
55
  },
56
+ "scripts": {
57
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
58
+ "typecheck": "tsc --noEmit",
59
+ "test": "vitest run",
60
+ "bench": "tsx scripts/bench.ts",
61
+ "size": "tsx scripts/measure-size.ts",
62
+ "research": "pnpm run size && pnpm run bench"
63
+ },
55
64
  "publishConfig": {
56
65
  "access": "public"
57
66
  },
@@ -82,13 +91,5 @@
82
91
  "typescript": "^5.8.0",
83
92
  "unified": "^11.0.5",
84
93
  "vitest": "^3.2.0"
85
- },
86
- "scripts": {
87
- "build": "rm -rf dist && tsc -p tsconfig.build.json",
88
- "typecheck": "tsc --noEmit",
89
- "test": "vitest run",
90
- "bench": "tsx scripts/bench.ts",
91
- "size": "tsx scripts/measure-size.ts",
92
- "research": "pnpm run size && pnpm run bench"
93
94
  }
94
- }
95
+ }