@tanstack/markdown 0.0.13 → 0.0.14

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/README.md CHANGED
@@ -1,17 +1,37 @@
1
+ <div align="center">
2
+ <picture>
3
+ <source
4
+ media="(prefers-color-scheme: dark)"
5
+ srcset="https://tanstack.com/api/readme/markdown.png?theme=dark"
6
+ />
7
+ <source
8
+ media="(prefers-color-scheme: light)"
9
+ srcset="https://tanstack.com/api/readme/markdown.png"
10
+ />
11
+ <img
12
+ src="https://tanstack.com/api/readme/markdown.png"
13
+ alt="TanStack Markdown"
14
+ width="900"
15
+ />
16
+ </picture>
17
+ </div>
18
+
1
19
  # TanStack Markdown
2
20
 
3
21
  A tiny, fast, deterministic Markdown parser and renderer for blogs and documentation.
4
22
 
5
23
  - 4.9 KB gzip parser
6
24
  - 6.7 KB gzip HTML renderer
7
- - 6.7 KB gzip React adapter
8
- - 6.7 KB gzip Octane adapter
25
+ - 6.6 KB gzip React adapter
26
+ - 6.6 KB gzip Octane adapter
9
27
  - zero runtime dependencies
10
28
  - serializable AST
11
29
  - safe defaults for raw HTML and executable URLs
12
30
  - optional docs extensions and external syntax highlighting
13
31
  - optional AI streaming profile
14
32
 
33
+ Bundle sizes include the parser and exclude framework runtimes and syntax highlighters.
34
+
15
35
  ```bash
16
36
  pnpm add @tanstack/markdown
17
37
  ```
@@ -1 +1 @@
1
- {"version":3,"file":"callouts.d.ts","sourceRoot":"","sources":["../../src/extensions/callouts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEjE,wBAAgB,iBAAiB,IAAI,iBAAiB,CAKrD;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,GAAG,SAAS,CA+B/H"}
1
+ {"version":3,"file":"callouts.d.ts","sourceRoot":"","sources":["../../src/extensions/callouts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEjE,wBAAgB,iBAAiB,IAAI,iBAAiB,CAKrD;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,GAAG,SAAS,CAyB/H"}
@@ -15,11 +15,6 @@ export function parseCalloutBlock(context) {
15
15
  let cursor = context.index + 1;
16
16
  while (cursor < context.lines.length) {
17
17
  const line = context.lines[cursor] ?? '';
18
- if (/^\s*$/.test(line)) {
19
- body.push('');
20
- cursor++;
21
- continue;
22
- }
23
18
  const quoted = line.match(/^ {0,3}>\s?(.*)$/);
24
19
  if (!quoted)
25
20
  break;
@@ -1 +1 @@
1
- {"version":3,"file":"comment-components.d.ts","sourceRoot":"","sources":["../../src/extensions/comment-components.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEnE,MAAM,WAAW,uBAAuB;IACtC,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,aAAa,CAAA;CAC5D;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACnC;AAED,wBAAgB,0BAA0B,CAAC,OAAO,GAAE,uBAA4B,GAAG,iBAAiB,CAKnG;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACpE,OAAO,GAAE,uBAA4B,GACpC,aAAa,GAAG,SAAS,CA2C3B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAQhF;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOrE"}
1
+ {"version":3,"file":"comment-components.d.ts","sourceRoot":"","sources":["../../src/extensions/comment-components.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEnE,MAAM,WAAW,uBAAuB;IACtC,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,aAAa,CAAA;CAC5D;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACnC;AAED,wBAAgB,0BAA0B,CAAC,OAAO,GAAE,uBAA4B,GAAG,iBAAiB,CAKnG;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACpE,OAAO,GAAE,uBAA4B,GACpC,aAAa,GAAG,SAAS,CA0B3B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAQhF;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOrE"}
@@ -9,35 +9,26 @@ export function parseCommentComponentBlock(context, options = {}) {
9
9
  const start = parseComponentComment(line);
10
10
  if (!start)
11
11
  return undefined;
12
- if (!start.block) {
13
- context.consume(1);
14
- return transform({
15
- type: 'component',
16
- name: start.name,
17
- attributes: start.attributes,
18
- children: [],
19
- }, options);
20
- }
21
- const body = [];
22
- let cursor = context.index + 1;
23
- let foundEnd = false;
24
- while (cursor < context.lines.length) {
25
- const candidate = context.lines[cursor] ?? '';
26
- if (isEndComment(candidate, start.name)) {
27
- foundEnd = true;
28
- cursor++;
29
- break;
12
+ let body;
13
+ let consumed = 1;
14
+ if (start.block) {
15
+ const end = new RegExp(`^ {0,3}<!--\\s*::end:${start.name}\\s*-->\\s*$`, 'i');
16
+ for (let cursor = context.index + 1; cursor < context.lines.length; cursor++) {
17
+ if (end.test(context.lines[cursor])) {
18
+ body = context.lines.slice(context.index + 1, cursor).join('\n');
19
+ consumed = cursor - context.index + 1;
20
+ break;
21
+ }
30
22
  }
31
- body.push(candidate);
32
- cursor++;
33
23
  }
34
- context.consume(foundEnd ? cursor - context.index : 1);
35
- return transform({
24
+ context.consume(consumed);
25
+ const node = {
36
26
  type: 'component',
37
27
  name: start.name,
38
28
  attributes: start.attributes,
39
- children: foundEnd ? context.parseBlocks(body.join('\n')) : [],
40
- }, options);
29
+ children: body === undefined ? [] : context.parseBlocks(body),
30
+ };
31
+ return options.transformComponent?.(node) ?? node;
41
32
  }
42
33
  export function parseComponentComment(line) {
43
34
  const match = line.match(/^ {0,3}<!--\s*::(start:)?([A-Za-z][\w-]*)(.*?)\s*-->\s*$/);
@@ -50,19 +41,10 @@ export function parseComponentComment(line) {
50
41
  };
51
42
  }
52
43
  export function parseAttributes(value) {
53
- const attrs = {};
44
+ const attrs = Object.create(null);
54
45
  const regex = /([A-Za-z_][\w:-]*)(?:=(?:"([^"]*)"|'([^']*)'|([^\s"']+)))?/g;
55
46
  for (const match of value.matchAll(regex)) {
56
47
  attrs[match[1]] = match[2] ?? match[3] ?? match[4] ?? 'true';
57
48
  }
58
49
  return attrs;
59
50
  }
60
- function transform(node, options) {
61
- return options.transformComponent?.(node) ?? node;
62
- }
63
- function isEndComment(line, name) {
64
- return new RegExp(`^ {0,3}<!--\\s*::end:${escapeRegex(name)}\\s*-->\\s*$`, 'i').test(line);
65
- }
66
- function escapeRegex(value) {
67
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
68
- }
@@ -13,13 +13,13 @@ export function headingCollectionExtension(options = {}) {
13
13
  export function collectMarkdownHeadings(document, options = {}) {
14
14
  const headings = [];
15
15
  const skip = new Set(options.skipComponentNames ?? ['tabs']);
16
- collectFromBlocks(document.children, headings, undefined, false, skip);
16
+ collectFromBlocks(document.children, headings, undefined, skip);
17
17
  return headings;
18
18
  }
19
- function collectFromBlocks(blocks, headings, framework, insideSkippedComponent, skipComponentNames) {
19
+ function collectFromBlocks(blocks, headings, framework, skipComponentNames) {
20
20
  for (const block of blocks) {
21
21
  if (block.type === 'heading') {
22
- if (!insideSkippedComponent && block.id) {
22
+ if (block.id) {
23
23
  const heading = {
24
24
  id: block.id,
25
25
  text: plainText(block.children),
@@ -34,18 +34,19 @@ function collectFromBlocks(blocks, headings, framework, insideSkippedComponent,
34
34
  }
35
35
  if (block.type === 'list') {
36
36
  for (const item of block.items)
37
- collectFromBlocks(item.children, headings, framework, insideSkippedComponent, skipComponentNames);
37
+ collectFromBlocks(item.children, headings, framework, skipComponentNames);
38
38
  continue;
39
39
  }
40
40
  if (block.type === 'blockquote' || block.type === 'callout') {
41
- collectFromBlocks(block.children, headings, framework, insideSkippedComponent, skipComponentNames);
41
+ collectFromBlocks(block.children, headings, framework, skipComponentNames);
42
42
  continue;
43
43
  }
44
44
  if (block.type === 'component') {
45
45
  const name = block.name.toLowerCase();
46
- const nextInsideSkippedComponent = insideSkippedComponent || skipComponentNames.has(name);
46
+ if (skipComponentNames.has(name))
47
+ continue;
47
48
  const nextFramework = block.tagName === 'md-framework-panel' ? block.properties?.['data-framework'] ?? framework : framework;
48
- collectFromBlocks(block.children, headings, nextFramework, nextInsideSkippedComponent, skipComponentNames);
49
+ collectFromBlocks(block.children, headings, nextFramework, skipComponentNames);
49
50
  }
50
51
  }
51
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/extensions/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAe,MAAM,aAAa,CAAA;AAGxE,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,SAAS,EAAE,CAAA;CACtB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAsBxD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE,CAsB5F;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAWtD;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,CAmCzF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,UAEnD"}
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/extensions/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAG3D,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,SAAS,EAAE,CAAA;CACtB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAsBxD;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE,CAqB5F;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAWtD;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,CA4BzF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,UAEnD"}
@@ -23,8 +23,7 @@ export function blocksToText(blocks) {
23
23
  .join('\n');
24
24
  }
25
25
  export function splitByHeading(children, forcedDepth) {
26
- const headings = children.filter((child) => child.type === 'heading');
27
- const depth = forcedDepth ?? Math.min(...headings.map(heading => heading.depth));
26
+ const depth = forcedDepth ?? children.reduce((depth, child) => child.type === 'heading' ? Math.min(depth, child.depth) : depth, Infinity);
28
27
  if (!Number.isFinite(depth))
29
28
  return [];
30
29
  const sections = [];
@@ -63,7 +62,7 @@ export function markFrameworkHeadings(blocks, framework) {
63
62
  framework,
64
63
  };
65
64
  }
66
- if (block.type === 'blockquote' || block.type === 'callout') {
65
+ if (block.type === 'blockquote' || block.type === 'callout' || block.type === 'component') {
67
66
  return {
68
67
  ...block,
69
68
  children: markFrameworkHeadings(block.children, framework),
@@ -78,12 +77,6 @@ export function markFrameworkHeadings(blocks, framework) {
78
77
  })),
79
78
  };
80
79
  }
81
- if (block.type === 'component') {
82
- return {
83
- ...block,
84
- children: markFrameworkHeadings(block.children, framework),
85
- };
86
- }
87
80
  return block;
88
81
  });
89
82
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../src/extensions/tabs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,aAAa,EAAE,MAAM,aAAa,CAAA;AAK3D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CAQzE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CAkCpE;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CA4B9E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CAiCvE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CA2BvE"}
1
+ {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../src/extensions/tabs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,aAAa,EAAE,MAAM,aAAa,CAAA;AAK3D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CAQzE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CAkCpE;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CA0B9E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CAgCvE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,GAAG,aAAa,CA2BvE"}
@@ -45,16 +45,13 @@ export function transformFileTabs(node) {
45
45
  };
46
46
  }
47
47
  export function transformPackageManagerTabs(node) {
48
- const packagesByFramework = {};
48
+ const packagesByFramework = Object.create(null);
49
49
  for (const line of blocksToText(node.children).split('\n')) {
50
- const trimmed = line.trim();
51
- if (!trimmed)
52
- continue;
53
- const colon = trimmed.indexOf(':');
50
+ const colon = line.indexOf(':');
54
51
  if (colon === -1)
55
52
  continue;
56
- const framework = trimmed.slice(0, colon).trim().toLowerCase();
57
- const packages = trimmed.slice(colon + 1).trim().split(/\s+/).filter(Boolean);
53
+ const framework = line.slice(0, colon).trim().toLowerCase();
54
+ const packages = line.slice(colon + 1).trim().split(/\s+/).filter(Boolean);
58
55
  if (!framework || packages.length === 0)
59
56
  continue;
60
57
  packagesByFramework[framework] ??= [];
@@ -76,13 +73,13 @@ export function transformPackageManagerTabs(node) {
76
73
  }
77
74
  export function transformBundlerTabs(node) {
78
75
  const sections = splitByHeading(node.children);
79
- const selected = sections.filter(section => isBundler(section.name.toLowerCase()));
76
+ const selected = bundlers.flatMap(bundler => {
77
+ const section = sections.find(section => section.name.toLowerCase() === bundler);
78
+ return section ? [section] : [];
79
+ });
80
80
  if (!selected.length)
81
81
  return node;
82
- const tabs = bundlers
83
- .map(bundler => selected.find(section => section.name.toLowerCase() === bundler))
84
- .filter((section) => Boolean(section))
85
- .map(section => ({ slug: section.name.toLowerCase(), name: section.name.toLowerCase() }));
82
+ const tabs = selected.map(section => ({ slug: section.name.toLowerCase(), name: section.name.toLowerCase() }));
86
83
  return {
87
84
  ...node,
88
85
  properties: {
@@ -90,15 +87,14 @@ export function transformBundlerTabs(node) {
90
87
  'data-attributes': JSON.stringify({ tabs }),
91
88
  'data-bundler-meta': JSON.stringify({ bundlers: tabs.map(tab => tab.slug) }),
92
89
  },
93
- children: tabs.map((tab, index) => {
94
- const section = selected.find(section => section.name.toLowerCase() === tab.slug);
90
+ children: selected.map((section, index) => {
95
91
  return {
96
92
  type: 'component',
97
93
  name: 'tab-panel',
98
94
  tagName: 'md-tab-panel',
99
95
  attributes: {},
100
96
  properties: {
101
- 'data-tab-slug': tab.slug,
97
+ 'data-tab-slug': section.name.toLowerCase(),
102
98
  'data-tab-index': String(index),
103
99
  'data-content': section.children.length === 1 && section.children[0]?.type === 'code' ? 'code-only' : 'mixed',
104
100
  },
@@ -140,6 +136,3 @@ function resolveInstallMode(value) {
140
136
  return mode;
141
137
  return 'install';
142
138
  }
143
- function isBundler(value) {
144
- return bundlers.includes(value);
145
- }
package/dist/html.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { parseMarkdown } from './parser.js';
2
- import { escapeAttr, escapeHtml } from './utils.js';
2
+ import { escapeAttr, escapeHtml, footnoteReferenceId } from './utils.js';
3
3
  export function renderHtml(input, options = {}) {
4
4
  const document = typeof input === 'string' ? parseMarkdown(input, options) : input;
5
5
  return document.children.map(node => renderBlock(node, options)).join('\n');
@@ -20,7 +20,7 @@ export function renderBlock(node, options = {}) {
20
20
  return renderCodeBlock(node, options);
21
21
  case 'list': {
22
22
  const tag = node.ordered ? 'ol' : 'ul';
23
- const start = node.ordered && node.start && node.start !== 1 ? ` start="${node.start}"` : '';
23
+ const start = node.ordered && node.start !== undefined && node.start !== 1 ? ` start="${node.start}"` : '';
24
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
  }
@@ -63,7 +63,7 @@ export function renderInline(node, options = {}) {
63
63
  case 'strike':
64
64
  return `<del>${renderInlines(node.children, options)}</del>`;
65
65
  case 'footnoteReference':
66
- return `<sup><a id="user-content-fnref-${escapeAttr(footnoteReferenceId(node))}" data-footnote-ref="" aria-describedby="footnote-label" href="#user-content-fn-${escapeAttr(node.id)}">${node.number}</a></sup>`;
66
+ return `<sup><a id="user-content-fnref-${escapeAttr(footnoteReferenceId(node.id, node.referenceIndex))}" data-footnote-ref="" aria-describedby="footnote-label" href="#user-content-fn-${escapeAttr(node.id)}">${node.number}</a></sup>`;
67
67
  case 'link':
68
68
  return `<a href="${escapeAttr(node.href)}"${node.title ? ` title="${escapeAttr(node.title)}"` : ''}>${renderInlines(node.children, options)}</a>`;
69
69
  case 'image':
@@ -82,15 +82,10 @@ function renderInlines(nodes, options) {
82
82
  }
83
83
  function renderCodeBlock(node, options) {
84
84
  const lang = node.lang ?? 'plaintext';
85
- const preAttrs = [
86
- `class="tm-code${options.codeLineNumbers ? ' tm-code--line-numbers' : ''}"`,
87
- `data-lang="${escapeAttr(lang)}"`,
88
- node.title ? `data-code-title="${escapeAttr(node.title)}"` : '',
89
- node.file ? `data-filename="${escapeAttr(node.file)}"` : '',
90
- node.framework ? `data-framework="${escapeAttr(node.framework)}"` : '',
91
- ]
92
- .filter(Boolean)
93
- .join(' ');
85
+ const preAttrs = `class="tm-code${options.codeLineNumbers ? ' tm-code--line-numbers' : ''}" data-lang="${escapeAttr(lang)}"`
86
+ + (node.title ? ` data-code-title="${escapeAttr(node.title)}"` : '')
87
+ + (node.file ? ` data-filename="${escapeAttr(node.file)}"` : '')
88
+ + (node.framework ? ` data-framework="${escapeAttr(node.framework)}"` : '');
94
89
  const html = options.highlighter?.(node.value, lang, {
95
90
  ...(node.highlightLines && { highlightLines: node.highlightLines }),
96
91
  ...(options.codeLineNumbers !== undefined && { lineNumbers: options.codeLineNumbers }),
@@ -101,14 +96,18 @@ function renderCodeBlock(node, options) {
101
96
  return `<figure class="tm-code-frame" data-lang="${escapeAttr(lang)}"><figcaption>${escapeHtml(node.title)}</figcaption>${pre}</figure>`;
102
97
  }
103
98
  function renderListItemChildren(children, checked, loose, options) {
104
- const first = children[0];
105
- const task = checked === undefined ? '' : `<input type="checkbox" disabled${checked ? ' checked' : ''}> `;
106
- if (first?.type === 'paragraph') {
107
- const content = `${task}${renderInlines(first.children, options)}`;
108
- const rest = children.length > 1 ? `\n${children.slice(1).map(child => renderBlock(child, options)).join('\n')}` : '';
109
- return `${loose ? `<p>${content}</p>` : content}${rest}`;
99
+ let result = checked === undefined ? '' : `<input type="checkbox" disabled${checked ? ' checked' : ''}> `;
100
+ for (let index = 0; index < children.length; index++) {
101
+ const child = children[index];
102
+ if (child.type === 'paragraph' && (!loose || index === 0)) {
103
+ result += renderInlines(child.children, options);
104
+ if (loose)
105
+ result = `<p>${result}</p>`;
106
+ }
107
+ else
108
+ result += (index ? '\n' : '') + renderBlock(child, options);
110
109
  }
111
- return `${task}${children.map(child => renderBlock(child, options)).join('\n')}`;
110
+ return result;
112
111
  }
113
112
  function renderCallout(node, options) {
114
113
  const kind = node.kind.toLowerCase();
@@ -122,29 +121,26 @@ function renderFootnotes(items, options) {
122
121
  function renderFootnoteItem(item, options) {
123
122
  const backref = renderFootnoteBackrefs(item);
124
123
  const lastIndex = item.children.length - 1;
125
- if (lastIndex < 0)
126
- return `<p>${backref.trimStart()}</p>`;
127
- return item.children
124
+ const result = item.children
128
125
  .map((child, index) => {
129
126
  if (index === lastIndex && child.type === 'paragraph') {
130
127
  return `<p>${renderInlines(child.children, options)}${backref}</p>`;
131
128
  }
132
129
  return renderBlock(child, options);
133
- })
134
- .join('\n');
130
+ });
131
+ if (item.children[lastIndex]?.type !== 'paragraph')
132
+ result.push(`<p>${backref.trimStart()}</p>`);
133
+ return result.join('\n');
135
134
  }
136
135
  function renderFootnoteBackrefs(item) {
137
136
  let result = '';
138
137
  for (let index = 1; index <= (item.referenceCount ?? 1); index++) {
139
- const referenceId = index === 1 ? item.id : `${item.id}-${index}`;
138
+ const referenceId = footnoteReferenceId(item.id, index);
140
139
  const label = index === 1 ? `${item.number}` : `${item.number}-${index}`;
141
140
  result += ` <a data-footnote-backref="" aria-label="Back to reference ${label}" class="data-footnote-backref" href="#user-content-fnref-${escapeAttr(referenceId)}">&#8617;</a>`;
142
141
  }
143
142
  return result;
144
143
  }
145
- function footnoteReferenceId(node) {
146
- return node.referenceIndex && node.referenceIndex > 1 ? `${node.id}-${node.referenceIndex}` : node.id;
147
- }
148
144
  function renderComponent(node, options) {
149
145
  const tag = node.tagName ?? 'md-comment-component';
150
146
  const attrs = renderComponentAttrs(node);
@@ -183,8 +179,5 @@ function renderComponentAttrs(node) {
183
179
  if (!props['data-attributes'])
184
180
  props['data-attributes'] = JSON.stringify(node.attributes);
185
181
  }
186
- const entries = Object.entries(props);
187
- if (!entries.length)
188
- return '';
189
- return ` ${entries.map(([key, value]) => `${key}="${escapeAttr(value)}"`).join(' ')}`;
182
+ return Object.entries(props).map(([key, value]) => ` ${key}="${escapeAttr(value)}"`).join('');
190
183
  }
@@ -1 +1 @@
1
- {"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../src/inline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAG1D,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,UAAU,EAAE,CASnF"}
1
+ {"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../src/inline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAG1D,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,UAAU,EAAE,CAQnF"}