markdown-to-jsx 8.0.0 → 9.0.0-rc.1
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 +383 -132
- package/dist/html.cjs +105 -0
- package/dist/html.d.cts +356 -0
- package/dist/html.d.ts +356 -0
- package/dist/html.js +105 -0
- package/dist/html.js.map +15 -0
- package/dist/index.cjs +108 -2
- package/dist/index.d.cts +342 -0
- package/dist/index.d.ts +338 -408
- package/dist/index.js +108 -0
- package/dist/index.js.map +15 -0
- package/dist/markdown.cjs +130 -0
- package/dist/markdown.d.cts +41 -0
- package/dist/markdown.d.ts +41 -0
- package/dist/markdown.js +130 -0
- package/dist/markdown.js.map +15 -0
- package/dist/react.cjs +108 -0
- package/dist/react.d.cts +348 -0
- package/dist/react.d.ts +348 -0
- package/dist/react.js +108 -0
- package/dist/react.js.map +15 -0
- package/package.json +87 -73
- package/dist/debug.module.js +0 -1755
- package/dist/debug.module.js.map +0 -1
- package/dist/index.cjs.d.ts +0 -6
- package/dist/index.cjs.map +0 -1
- package/dist/index.modern.js +0 -2
- package/dist/index.modern.js.map +0 -1
- package/dist/index.module.js +0 -2
- package/dist/index.module.js.map +0 -1
- package/dist/index.umd.js +0 -2
- package/dist/index.umd.js.map +0 -1
- package/dist/match.d.ts +0 -42
package/README.md
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
[](https://badge.fury.io/js/markdown-to-jsx) [](https://npm-stat.com/charts.html?package=markdown-to-jsx)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`markdown-to-jsx` is a gfm+commonmark compliant markdown parser and compiler toolchain for JavaScript and TypeScript-based projects. It is extremely fast, capable of processing large documents fast enough for real-time interactivity.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Some special features of the library:
|
|
6
|
+
|
|
7
|
+
- Arbitrary HTML is supported and parsed into the appropriate JSX representation
|
|
8
|
+
without `dangerouslySetInnerHTML`
|
|
9
|
+
|
|
10
|
+
- Any HTML tags rendered by the compiler and/or `<Markdown>` component can be overridden to include additional props or even a different HTML representation entirely.
|
|
11
|
+
|
|
12
|
+
- All GFM special syntaxes are supported, including tables, task lists, strikethrough, autolinks, and more.
|
|
13
|
+
|
|
14
|
+
- Fenced code blocks with [highlight.js](https://highlightjs.org/) support; see [Syntax highlighting](#syntax-highlighting) for instructions on setting up highlight.js.
|
|
15
|
+
|
|
16
|
+
## Table of Contents
|
|
6
17
|
|
|
7
18
|
<!-- TOC -->
|
|
8
19
|
|
|
20
|
+
- [Table of Contents](#table-of-contents)
|
|
9
21
|
- [Upgrading](#upgrading)
|
|
22
|
+
- [From v8.x to v9.x](#from-v8x-to-v9x)
|
|
10
23
|
- [From v7.x to v8.x](#from-v7x-to-v8x)
|
|
11
24
|
- [Installation](#installation)
|
|
12
25
|
- [Usage](#usage)
|
|
@@ -24,10 +37,8 @@ The most lightweight, customizable React markdown component.
|
|
|
24
37
|
- [options.renderRule](#optionsrenderrule)
|
|
25
38
|
- [options.sanitizer](#optionssanitizer)
|
|
26
39
|
- [options.slugify](#optionsslugify)
|
|
27
|
-
- [options.namedCodesToUnicode](#optionsnamedcodestounicode)
|
|
28
40
|
- [options.disableAutoLink](#optionsdisableautolink)
|
|
29
41
|
- [options.disableParsingRawHTML](#optionsdisableparsingrawhtml)
|
|
30
|
-
- [options.ast](#optionsast)
|
|
31
42
|
- [Syntax highlighting](#syntax-highlighting)
|
|
32
43
|
- [Handling shortcodes](#handling-shortcodes)
|
|
33
44
|
- [Getting the smallest possible bundle size](#getting-the-smallest-possible-bundle-size)
|
|
@@ -36,31 +47,106 @@ The most lightweight, customizable React markdown component.
|
|
|
36
47
|
- [Passing props to stringified React components](#passing-props-to-stringified-react-components)
|
|
37
48
|
- [Significant indentation inside arbitrary HTML](#significant-indentation-inside-arbitrary-html)
|
|
38
49
|
- [Code blocks](#code-blocks)
|
|
39
|
-
- [
|
|
50
|
+
- [Entry Points](#entry-points)
|
|
51
|
+
- [Main](#main)
|
|
52
|
+
- [React](#react)
|
|
53
|
+
- [HTML](#html)
|
|
54
|
+
- [Markdown](#markdown)
|
|
55
|
+
- [Using The Parser Low-Level AST API](#using-the-parser-low-level-ast-api)
|
|
56
|
+
- [AST Anatomy](#ast-anatomy)
|
|
57
|
+
- [Node Types](#node-types)
|
|
58
|
+
- [Example AST Structure](#example-ast-structure)
|
|
59
|
+
- [Type Checking](#type-checking)
|
|
40
60
|
- [Changelog](#changelog)
|
|
41
61
|
- [Donate](#donate)
|
|
42
62
|
|
|
43
63
|
<!-- /TOC -->
|
|
44
64
|
|
|
45
|
-
|
|
65
|
+
## Upgrading
|
|
46
66
|
|
|
47
|
-
|
|
67
|
+
### From v8.x to v9.x
|
|
48
68
|
|
|
49
|
-
|
|
50
|
-
without `dangerouslySetInnerHTML`
|
|
69
|
+
**Breaking Changes:**
|
|
51
70
|
|
|
52
|
-
-
|
|
53
|
-
props or even a different HTML representation entirely.
|
|
71
|
+
- **`ast` option removed**: The `ast: true` option on `compiler()` has been removed. Use the new `parser()` function instead to access the AST directly.
|
|
54
72
|
|
|
55
|
-
|
|
73
|
+
```typescript
|
|
74
|
+
// Before (v8)
|
|
75
|
+
import { compiler } from 'markdown-to-jsx'
|
|
76
|
+
const ast = compiler('# Hello world', { ast: true })
|
|
56
77
|
|
|
57
|
-
|
|
78
|
+
// After (v9)
|
|
79
|
+
import { parser } from 'markdown-to-jsx'
|
|
80
|
+
const ast = parser('# Hello world')
|
|
81
|
+
```
|
|
58
82
|
|
|
59
|
-
|
|
83
|
+
- **`namedCodesToUnicode` option removed**: The `namedCodesToUnicode` option has been removed. All named HTML entities are now supported by default via the full entity list, so custom entity mappings are no longer needed.
|
|
60
84
|
|
|
61
|
-
|
|
85
|
+
```typescript
|
|
86
|
+
// Before (v8)
|
|
87
|
+
import { compiler } from 'markdown-to-jsx'
|
|
88
|
+
compiler('≤ symbol', { namedCodesToUnicode: { le: '\u2264' } })
|
|
62
89
|
|
|
63
|
-
|
|
90
|
+
// After (v9)
|
|
91
|
+
import { compiler } from 'markdown-to-jsx'
|
|
92
|
+
compiler('≤ symbol') // All entities supported automatically
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**New Features:**
|
|
96
|
+
|
|
97
|
+
- **New `parser` function**: Provides direct access to the parsed AST without rendering. This is the recommended way to get AST nodes.
|
|
98
|
+
|
|
99
|
+
- **New entry points**: React-specific, HTML-specific, and markdown-specific entry points are now available for better tree-shaking and separation of concerns.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// React-specific usage
|
|
103
|
+
import Markdown, { compiler, parser } from 'markdown-to-jsx/react'
|
|
104
|
+
|
|
105
|
+
// HTML string output
|
|
106
|
+
import { compiler, astToHTML, parser } from 'markdown-to-jsx/html'
|
|
107
|
+
|
|
108
|
+
// Markdown string output (round-trip compilation)
|
|
109
|
+
import { compiler, astToMarkdown, parser } from 'markdown-to-jsx/markdown'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Migration Guide:**
|
|
113
|
+
|
|
114
|
+
1. **Replace `compiler(..., { ast: true })` with `parser()`**:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// Before
|
|
118
|
+
import { compiler } from 'markdown-to-jsx'
|
|
119
|
+
const ast = compiler(markdown, { ast: true })
|
|
120
|
+
|
|
121
|
+
// After
|
|
122
|
+
import { parser } from 'markdown-to-jsx'
|
|
123
|
+
const ast = parser(markdown)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
2. **Migrate React imports to `/react` entry point** (optional but recommended):
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
// Before
|
|
130
|
+
import Markdown, { compiler } from 'markdown-to-jsx'
|
|
131
|
+
|
|
132
|
+
// After (recommended)
|
|
133
|
+
import Markdown, { compiler } from 'markdown-to-jsx/react'
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
3. **Remove `namedCodesToUnicode` option**: All named HTML entities are now supported automatically, so you can remove any custom entity mappings.
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
// Before
|
|
140
|
+
compiler('≤ symbol', { namedCodesToUnicode: { le: '\u2264' } })
|
|
141
|
+
|
|
142
|
+
// After
|
|
143
|
+
compiler('≤ symbol') // Works automatically
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Note:** The main entry point (`markdown-to-jsx`) continues to work for backward compatibility, but React code there is deprecated and will be removed in a future major release. Consider migrating to `markdown-to-jsx/react` for React-specific usage.
|
|
147
|
+
|
|
148
|
+
<details>
|
|
149
|
+
<summary>### Older Migration Guides</summary>
|
|
64
150
|
|
|
65
151
|
### From v7.x to v8.x
|
|
66
152
|
|
|
@@ -86,6 +172,8 @@ if (node.type === RuleType.textBolded) { ... }
|
|
|
86
172
|
if (node.type === RuleType.textFormatted && node.bold) { ... }
|
|
87
173
|
```
|
|
88
174
|
|
|
175
|
+
</details>
|
|
176
|
+
|
|
89
177
|
## Installation
|
|
90
178
|
|
|
91
179
|
Install `markdown-to-jsx` with your favorite package manager.
|
|
@@ -100,7 +188,7 @@ npm i markdown-to-jsx
|
|
|
100
188
|
|
|
101
189
|
ES6-style usage\*:
|
|
102
190
|
|
|
103
|
-
```
|
|
191
|
+
```tsx
|
|
104
192
|
import Markdown from 'markdown-to-jsx'
|
|
105
193
|
import React from 'react'
|
|
106
194
|
import { render } from 'react-dom'
|
|
@@ -134,37 +222,36 @@ But this string would be considered "block" due to the existence of a header tag
|
|
|
134
222
|
|
|
135
223
|
However, if you really want all input strings to be treated as "block" layout, simply pass `options.forceBlock = true` like this:
|
|
136
224
|
|
|
137
|
-
```
|
|
138
|
-
|
|
225
|
+
```tsx
|
|
226
|
+
<Markdown options={{ forceBlock: true }}>Hello there old chap!</Markdown>
|
|
139
227
|
|
|
140
228
|
// or
|
|
141
229
|
|
|
142
230
|
compiler('Hello there old chap!', { forceBlock: true })
|
|
143
231
|
|
|
144
232
|
// renders
|
|
145
|
-
|
|
233
|
+
<p>Hello there old chap!</p>
|
|
146
234
|
```
|
|
147
235
|
|
|
148
236
|
#### options.forceInline
|
|
149
237
|
|
|
150
238
|
The inverse is also available by passing `options.forceInline = true`:
|
|
151
239
|
|
|
152
|
-
```
|
|
153
|
-
|
|
240
|
+
```tsx
|
|
241
|
+
<Markdown options={{ forceInline: true }}># You got it babe!</Markdown>
|
|
154
242
|
|
|
155
243
|
// or
|
|
156
|
-
|
|
157
244
|
compiler('# You got it babe!', { forceInline: true })
|
|
158
245
|
|
|
159
246
|
// renders
|
|
160
|
-
|
|
247
|
+
<span># You got it babe!</span>
|
|
161
248
|
```
|
|
162
249
|
|
|
163
250
|
#### options.wrapper
|
|
164
251
|
|
|
165
252
|
When there are multiple children to be rendered, the compiler will wrap the output in a `div` by default. You can override this default by setting the `wrapper` option to either a string (React Element) or a component.
|
|
166
253
|
|
|
167
|
-
```
|
|
254
|
+
```tsx
|
|
168
255
|
const str = '# Heck Yes\n\nThis is great!'
|
|
169
256
|
|
|
170
257
|
<Markdown options={{ wrapper: 'article' }}>
|
|
@@ -187,7 +274,7 @@ compiler(str, { wrapper: 'article' });
|
|
|
187
274
|
|
|
188
275
|
To get an array of children back without a wrapper, set `wrapper` to `null`. This is particularly useful when using `compiler(…)` directly.
|
|
189
276
|
|
|
190
|
-
```
|
|
277
|
+
```tsx
|
|
191
278
|
compiler('One\n\nTwo\n\nThree', { wrapper: null })
|
|
192
279
|
|
|
193
280
|
// returns
|
|
@@ -200,7 +287,7 @@ To render children at the same DOM level as `<Markdown>` with no HTML wrapper, s
|
|
|
200
287
|
|
|
201
288
|
By default, the compiler does not wrap the rendered contents if there is only a single child. You can change this by setting `forceWrapper` to `true`. If the child is inline, it will not necessarily be wrapped in a `span`.
|
|
202
289
|
|
|
203
|
-
```
|
|
290
|
+
```tsx
|
|
204
291
|
// Using `forceWrapper` with a single, inline child…
|
|
205
292
|
<Markdown options={{ wrapper: 'aside', forceWrapper: true }}>
|
|
206
293
|
Mumble, mumble…
|
|
@@ -236,7 +323,7 @@ The library does not void any tags by default to avoid surprising behavior for p
|
|
|
236
323
|
|
|
237
324
|
Pass the `options.overrides` prop to the compiler or `<Markdown>` component to seamlessly revise the rendered representation of any HTML tag. You can choose to change the component itself, add/change props, or both.
|
|
238
325
|
|
|
239
|
-
```
|
|
326
|
+
```tsx
|
|
240
327
|
import Markdown from 'markdown-to-jsx'
|
|
241
328
|
import React from 'react'
|
|
242
329
|
import { render } from 'react-dom'
|
|
@@ -304,7 +391,7 @@ One of the most interesting use cases enabled by the HTML syntax processing in `
|
|
|
304
391
|
|
|
305
392
|
By adding an override for the components you plan to use in markdown documents, it's possible to dynamically render almost anything. One possible scenario could be writing documentation:
|
|
306
393
|
|
|
307
|
-
```
|
|
394
|
+
```tsx
|
|
308
395
|
import Markdown from 'markdown-to-jsx'
|
|
309
396
|
import React from 'react'
|
|
310
397
|
import { render } from 'react-dom'
|
|
@@ -339,7 +426,7 @@ render(
|
|
|
339
426
|
|
|
340
427
|
In the following case, `DatePicker` could simply run `parseInt()` on the passed `startTime` for example:
|
|
341
428
|
|
|
342
|
-
```
|
|
429
|
+
```tsx
|
|
343
430
|
import Markdown from 'markdown-to-jsx'
|
|
344
431
|
import React from 'react'
|
|
345
432
|
import { render } from 'react-dom'
|
|
@@ -376,7 +463,7 @@ render(
|
|
|
376
463
|
|
|
377
464
|
Another possibility is to use something like [recompose's `withProps()` HOC](https://github.com/acdlite/recompose/blob/main/docs/API.md#withprops) to create various pregenerated scenarios and then reference them by name in the markdown:
|
|
378
465
|
|
|
379
|
-
```
|
|
466
|
+
```tsx
|
|
380
467
|
import Markdown from 'markdown-to-jsx'
|
|
381
468
|
import React from 'react'
|
|
382
469
|
import { render } from 'react-dom'
|
|
@@ -496,7 +583,7 @@ By default a lightweight URL sanitizer function is provided to avoid common atta
|
|
|
496
583
|
|
|
497
584
|
This can be overridden and replaced with a custom sanitizer if desired via `options.sanitizer`:
|
|
498
585
|
|
|
499
|
-
```
|
|
586
|
+
```tsx
|
|
500
587
|
// sanitizer in this situation would receive:
|
|
501
588
|
// ('javascript:alert("foo")', 'a', 'href')
|
|
502
589
|
|
|
@@ -513,9 +600,9 @@ compiler('[foo](javascript:alert("foo"))', {
|
|
|
513
600
|
|
|
514
601
|
#### options.slugify
|
|
515
602
|
|
|
516
|
-
By default, a [lightweight deburring function](https://github.com/
|
|
603
|
+
By default, a [lightweight deburring function](https://github.com/quantizor/markdown-to-jsx/blob/bc2f57412332dc670f066320c0f38d0252e0f057/index.js#L261-L275) is used to generate an HTML id from headings. You can override this by passing a function to `options.slugify`. This is helpful when you are using non-alphanumeric characters (e.g. Chinese or Japanese characters) in headings. For example:
|
|
517
604
|
|
|
518
|
-
```
|
|
605
|
+
```tsx
|
|
519
606
|
<Markdown options={{ slugify: str => str }}># 中文</Markdown>
|
|
520
607
|
|
|
521
608
|
// or
|
|
@@ -528,44 +615,11 @@ compiler('# 中文', { slugify: str => str })
|
|
|
528
615
|
|
|
529
616
|
The original function is available as a library export called `slugify`.
|
|
530
617
|
|
|
531
|
-
#### options.namedCodesToUnicode
|
|
532
|
-
|
|
533
|
-
By default only a couple of named html codes are converted to unicode characters:
|
|
534
|
-
|
|
535
|
-
- `&` (`&`)
|
|
536
|
-
- `'` (`'`)
|
|
537
|
-
- `>` (`>`)
|
|
538
|
-
- `<` (`<`)
|
|
539
|
-
- ` ` (` `)
|
|
540
|
-
- `"` (`"`)
|
|
541
|
-
|
|
542
|
-
Some projects require to extend this map of named codes and unicode characters. To customize this list with additional html codes pass the option namedCodesToUnicode as object with the code names needed as in the example below:
|
|
543
|
-
|
|
544
|
-
```jsx
|
|
545
|
-
<Markdown options={{ namedCodesToUnicode: {
|
|
546
|
-
le: '\u2264',
|
|
547
|
-
ge: '\u2265',
|
|
548
|
-
'#39': '\u0027',
|
|
549
|
-
} }}>This text is ≤ than this text.</Markdown>;
|
|
550
|
-
|
|
551
|
-
// or
|
|
552
|
-
|
|
553
|
-
compiler('This text is ≤ than this text.', namedCodesToUnicode: {
|
|
554
|
-
le: '\u2264',
|
|
555
|
-
ge: '\u2265',
|
|
556
|
-
'#39': '\u0027',
|
|
557
|
-
});
|
|
558
|
-
|
|
559
|
-
// renders:
|
|
560
|
-
|
|
561
|
-
<p>This text is ≤ than this text.</p>
|
|
562
|
-
```
|
|
563
|
-
|
|
564
618
|
#### options.disableAutoLink
|
|
565
619
|
|
|
566
620
|
By default, bare URLs in the markdown document will be converted into an anchor tag. This behavior can be disabled if desired.
|
|
567
621
|
|
|
568
|
-
```
|
|
622
|
+
```tsx
|
|
569
623
|
<Markdown options={{ disableAutoLink: true }}>
|
|
570
624
|
The URL https://quantizor.dev will not be rendered as an anchor tag.
|
|
571
625
|
</Markdown>
|
|
@@ -588,7 +642,7 @@ compiler(
|
|
|
588
642
|
|
|
589
643
|
By default, raw HTML is parsed to JSX. This behavior can be disabled if desired.
|
|
590
644
|
|
|
591
|
-
```
|
|
645
|
+
```tsx
|
|
592
646
|
<Markdown options={{ disableParsingRawHTML: true }}>
|
|
593
647
|
This text has <span>html</span> in it but it won't be rendered
|
|
594
648
|
</Markdown>;
|
|
@@ -602,37 +656,24 @@ compiler('This text has <span>html</span> in it but it won't be rendered', { dis
|
|
|
602
656
|
<span>This text has <span>html</span> in it but it won't be rendered</span>
|
|
603
657
|
```
|
|
604
658
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
When `ast: true`, the compiler returns the parsed AST structure instead of rendered JSX. **This is the first time the AST is accessible to users!**
|
|
608
|
-
|
|
609
|
-
```tsx
|
|
610
|
-
import { compiler } from 'markdown-to-jsx'
|
|
611
|
-
import type { MarkdownToJSX } from 'markdown-to-jsx'
|
|
659
|
+
### Syntax highlighting
|
|
612
660
|
|
|
613
|
-
|
|
614
|
-
const ast = compiler('# Hello world', { ast: true })
|
|
661
|
+
When using [fenced code blocks](https://www.markdownguide.org/extended-syntax/#syntax-highlighting) with language annotation, that language will be added to the `<code>` element as `class="lang-${language}"`. For best results, you can use `options.overrides` to provide an appropriate syntax highlighting integration like this one using `highlight.js`:
|
|
615
662
|
|
|
616
|
-
|
|
617
|
-
|
|
663
|
+
```html
|
|
664
|
+
<!-- Add the following tags to your page <head> to automatically load hljs and styles: -->
|
|
665
|
+
<link
|
|
666
|
+
rel="stylesheet"
|
|
667
|
+
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/obsidian.min.css"
|
|
668
|
+
/>
|
|
618
669
|
|
|
619
|
-
|
|
670
|
+
<script
|
|
671
|
+
crossorigin
|
|
672
|
+
src="https://unpkg.com/@highlightjs/cdn-assets@11.9.0/highlight.min.js"
|
|
673
|
+
></script>
|
|
620
674
|
```
|
|
621
675
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
- AST manipulation and transformation
|
|
625
|
-
- Custom rendering logic without re-parsing
|
|
626
|
-
- Caching parsed AST for performance
|
|
627
|
-
- Linting or validation of markdown structure
|
|
628
|
-
|
|
629
|
-
When footnotes are present, the returned value will be an object with `ast` and `footnotes` properties instead of just the AST array.
|
|
630
|
-
|
|
631
|
-
### Syntax highlighting
|
|
632
|
-
|
|
633
|
-
When using [fenced code blocks](https://www.markdownguide.org/extended-syntax/#syntax-highlighting) with language annotation, that language will be added to the `<code>` element as `class="lang-${language}"`. For best results, you can use `options.overrides` to provide an appropriate syntax highlighting integration like this one using `highlight.js`:
|
|
634
|
-
|
|
635
|
-
````jsx
|
|
676
|
+
````tsx
|
|
636
677
|
import { Markdown, RuleType } from 'markdown-to-jsx'
|
|
637
678
|
|
|
638
679
|
const mdContainingFencedCodeBlock = '```js\nconsole.log("Hello world!");\n```\n'
|
|
@@ -650,23 +691,6 @@ function App() {
|
|
|
650
691
|
)
|
|
651
692
|
}
|
|
652
693
|
|
|
653
|
-
/**
|
|
654
|
-
* Add the following tags to your page <head> to automatically load hljs and styles:
|
|
655
|
-
|
|
656
|
-
<link
|
|
657
|
-
rel="stylesheet"
|
|
658
|
-
href="https://unpkg.com/@highlightjs/cdn-assets@11.9.0/styles/nord.min.css"
|
|
659
|
-
/>
|
|
660
|
-
|
|
661
|
-
* NOTE: for best performance, load individual languages you need instead of all
|
|
662
|
-
of them. See their docs for more info: https://highlightjs.org/
|
|
663
|
-
|
|
664
|
-
<script
|
|
665
|
-
crossorigin
|
|
666
|
-
src="https://unpkg.com/@highlightjs/cdn-assets@11.9.0/highlight.min.js"
|
|
667
|
-
></script>
|
|
668
|
-
*/
|
|
669
|
-
|
|
670
694
|
function SyntaxHighlightedCode(props) {
|
|
671
695
|
const ref = (React.useRef < HTMLElement) | (null > null)
|
|
672
696
|
|
|
@@ -831,40 +855,267 @@ The two leading spaces in front of "# Hello" would be left-trimmed from all line
|
|
|
831
855
|
<div>
|
|
832
856
|
```js
|
|
833
857
|
var some = code();
|
|
834
|
-
|
|
858
|
+
```
|
|
835
859
|
</div>
|
|
836
860
|
````
|
|
837
861
|
|
|
838
|
-
##
|
|
862
|
+
## Entry Points
|
|
839
863
|
|
|
840
|
-
|
|
864
|
+
`markdown-to-jsx` provides multiple entry points for different use cases:
|
|
841
865
|
|
|
842
|
-
|
|
843
|
-
import { compiler } from 'markdown-to-jsx'
|
|
844
|
-
import React from 'react'
|
|
845
|
-
import { render } from 'react-dom'
|
|
866
|
+
### Main
|
|
846
867
|
|
|
847
|
-
|
|
868
|
+
The legacy\*default entry point exports everything, including the React compiler and component:
|
|
848
869
|
|
|
849
|
-
|
|
850
|
-
|
|
870
|
+
```tsx
|
|
871
|
+
import Markdown, { compiler, parser } from 'markdown-to-jsx'
|
|
872
|
+
```
|
|
851
873
|
|
|
852
|
-
|
|
853
|
-
|
|
874
|
+
_The React code in this entry point is deprecated and will be removed in a future major release, migrate to `markdown-to-jsx/react`._
|
|
875
|
+
|
|
876
|
+
### React
|
|
877
|
+
|
|
878
|
+
For React-specific usage, import from the `/react` entry point:
|
|
879
|
+
|
|
880
|
+
```tsx
|
|
881
|
+
import Markdown, { compiler, parser, astToJSX } from 'markdown-to-jsx/react'
|
|
882
|
+
|
|
883
|
+
// Use compiler for markdown → JSX
|
|
884
|
+
const jsxElement = compiler('# Hello world')
|
|
885
|
+
|
|
886
|
+
const markdown = `# Hello world`
|
|
887
|
+
|
|
888
|
+
function App() {
|
|
889
|
+
return <Markdown children={markdown} />
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// Or use parser + astToJSX for total control
|
|
893
|
+
const ast = parser('# Hello world')
|
|
894
|
+
const jsxElement2 = astToJSX(ast)
|
|
854
895
|
```
|
|
855
896
|
|
|
856
|
-
|
|
897
|
+
### HTML
|
|
857
898
|
|
|
858
|
-
|
|
859
|
-
|
|
899
|
+
For HTML string output (server-side rendering), import from the `/html` entry point:
|
|
900
|
+
|
|
901
|
+
```tsx
|
|
902
|
+
import { compiler, html, parser } from 'markdown-to-jsx/html'
|
|
903
|
+
|
|
904
|
+
// Convenience function that combines parsing and HTML rendering
|
|
905
|
+
const htmlString = compiler('# Hello world')
|
|
906
|
+
// Returns: '<h1>Hello world</h1>'
|
|
907
|
+
|
|
908
|
+
// Or use parser + html separately for more control
|
|
909
|
+
const ast = parser('# Hello world')
|
|
910
|
+
const htmlString2 = html(ast)
|
|
860
911
|
```
|
|
861
912
|
|
|
913
|
+
### Markdown
|
|
914
|
+
|
|
915
|
+
For markdown-to-markdown compilation (normalization and formatting), import from the `/markdown` entry point:
|
|
916
|
+
|
|
917
|
+
```typescript
|
|
918
|
+
import { compiler, astToMarkdown, parser } from 'markdown-to-jsx/markdown'
|
|
919
|
+
|
|
920
|
+
// Convenience function that parses and recompiles markdown
|
|
921
|
+
const normalizedMarkdown = compiler('# Hello world\n\nExtra spaces!')
|
|
922
|
+
// Returns: '# Hello world\n\nExtra spaces!\n'
|
|
923
|
+
|
|
924
|
+
// Or work with AST directly
|
|
925
|
+
const ast = parser('# Hello world')
|
|
926
|
+
const normalizedMarkdown2 = astToMarkdown(ast)
|
|
927
|
+
// Returns: '# Hello world\n'
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
## Using The Parser (Low-Level AST API)
|
|
931
|
+
|
|
932
|
+
The `parser` function provides direct access to the parsed AST without rendering:
|
|
933
|
+
|
|
934
|
+
```tsx
|
|
935
|
+
import { parser } from 'markdown-to-jsx'
|
|
936
|
+
import type { MarkdownToJSX } from 'markdown-to-jsx'
|
|
937
|
+
|
|
938
|
+
// Parse markdown to AST
|
|
939
|
+
const ast = parser('# Hello world')
|
|
940
|
+
|
|
941
|
+
// TypeScript: AST is MarkdownToJSX.ASTNode[]
|
|
942
|
+
console.log(ast) // Array of parsed nodes
|
|
943
|
+
|
|
944
|
+
// You can then render with html() or compiler()
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
The `parser` function accepts:
|
|
948
|
+
|
|
949
|
+
- `source: string` - markdown source
|
|
950
|
+
- `state?: MarkdownToJSX.State` - parsing state (defaults: `{ inline: false, refs: {} }`)
|
|
951
|
+
- `options?: MarkdownToJSX.Options` - parsing options
|
|
952
|
+
|
|
953
|
+
Use `parser` when you need:
|
|
954
|
+
|
|
955
|
+
- Direct AST access without React rendering
|
|
956
|
+
- Custom rendering logic
|
|
957
|
+
- AST manipulation before rendering
|
|
958
|
+
|
|
959
|
+
## AST Anatomy
|
|
960
|
+
|
|
961
|
+
The Abstract Syntax Tree (AST) is a structured representation of parsed markdown. Each node in the AST has a `type` property that identifies its kind, and type-specific properties.
|
|
962
|
+
|
|
963
|
+
**Important:** The first node in the AST is typically a `RuleType.refCollection` node that contains all reference definitions found in the document, including footnotes (stored with keys prefixed with `^`). This node is skipped during rendering but is useful for accessing reference data. Footnotes are automatically extracted from the refCollection and rendered in a `<footer>` element by both `compiler()` and `astToJSX()`.
|
|
964
|
+
|
|
965
|
+
### Node Types
|
|
966
|
+
|
|
967
|
+
The AST consists of the following node types (use `RuleType` to check node types):
|
|
968
|
+
|
|
969
|
+
**Block-level nodes:**
|
|
970
|
+
|
|
971
|
+
- `RuleType.heading` - Headings (`# Heading`)
|
|
972
|
+
```tsx
|
|
973
|
+
{ type: RuleType.heading, level: 1, id: "heading", children: [...] }
|
|
974
|
+
```
|
|
975
|
+
- `RuleType.paragraph` - Paragraphs
|
|
976
|
+
```tsx
|
|
977
|
+
{ type: RuleType.paragraph, children: [...] }
|
|
978
|
+
```
|
|
979
|
+
- `RuleType.codeBlock` - Fenced code blocks (```)
|
|
980
|
+
```tsx
|
|
981
|
+
{ type: RuleType.codeBlock, lang: "javascript", text: "code content" }
|
|
982
|
+
```
|
|
983
|
+
- `RuleType.blockQuote` - Blockquotes (`>`)
|
|
984
|
+
```tsx
|
|
985
|
+
{ type: RuleType.blockQuote, children: [...], alert?: "note" }
|
|
986
|
+
```
|
|
987
|
+
- `RuleType.orderedList` / `RuleType.unorderedList` - Lists
|
|
988
|
+
```tsx
|
|
989
|
+
{ type: RuleType.orderedList, items: [[...]], start?: 1 }
|
|
990
|
+
{ type: RuleType.unorderedList, items: [[...]], ordered: false }
|
|
991
|
+
```
|
|
992
|
+
- `RuleType.table` - Tables
|
|
993
|
+
```tsx
|
|
994
|
+
{ type: RuleType.table, header: [...], cells: [[...]], align: [...] }
|
|
995
|
+
```
|
|
996
|
+
- `RuleType.htmlBlock` - HTML blocks
|
|
997
|
+
```tsx
|
|
998
|
+
{ type: RuleType.htmlBlock, tag: "div", attrs: {}, children: [...] }
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
**Inline nodes:**
|
|
1002
|
+
|
|
1003
|
+
- `RuleType.text` - Plain text
|
|
1004
|
+
```tsx
|
|
1005
|
+
{ type: RuleType.text, text: "Hello world" }
|
|
1006
|
+
```
|
|
1007
|
+
- `RuleType.textFormatted` - Bold, italic, etc.
|
|
1008
|
+
```tsx
|
|
1009
|
+
{ type: RuleType.textFormatted, tag: "strong", children: [...] }
|
|
1010
|
+
```
|
|
1011
|
+
- `RuleType.codeInline` - Inline code (`` ` ``)
|
|
1012
|
+
```tsx
|
|
1013
|
+
{ type: RuleType.codeInline, text: "code" }
|
|
1014
|
+
```
|
|
1015
|
+
- `RuleType.link` - Links
|
|
1016
|
+
```tsx
|
|
1017
|
+
{ type: RuleType.link, target: "https://example.com", children: [...] }
|
|
1018
|
+
```
|
|
1019
|
+
- `RuleType.image` - Images
|
|
1020
|
+
```tsx
|
|
1021
|
+
{ type: RuleType.image, target: "image.png", alt: "description" }
|
|
1022
|
+
```
|
|
1023
|
+
- `RuleType.refLink` / `RuleType.refImage` - Reference-style links/images
|
|
1024
|
+
```tsx
|
|
1025
|
+
{ type: RuleType.refLink, ref: "linkref", children: [...] }
|
|
1026
|
+
```
|
|
1027
|
+
|
|
1028
|
+
**Other nodes:**
|
|
1029
|
+
|
|
1030
|
+
- `RuleType.breakLine` - Hard line breaks (` `)
|
|
1031
|
+
- `RuleType.breakThematic` - Horizontal rules (`---`)
|
|
1032
|
+
- `RuleType.gfmTask` - GFM task list items (`- [ ]`)
|
|
1033
|
+
- `RuleType.refCollection` - Reference definitions collection (appears at AST root, includes footnotes with `^` prefix)
|
|
1034
|
+
- `RuleType.footnote` - Footnote definition node (not rendered, stored in refCollection)
|
|
1035
|
+
- `RuleType.footnoteReference` - Footnote reference (`[^identifier]`)
|
|
1036
|
+
|
|
1037
|
+
### Example AST Structure
|
|
1038
|
+
|
|
1039
|
+
````tsx
|
|
1040
|
+
import { parser, RuleType } from 'markdown-to-jsx'
|
|
1041
|
+
|
|
1042
|
+
const ast = parser(`# Hello World
|
|
1043
|
+
|
|
1044
|
+
This is a **paragraph** with [a link](https://example.com).
|
|
1045
|
+
|
|
1046
|
+
[linkref]: https://example.com
|
|
1047
|
+
|
|
1048
|
+
```javascript
|
|
1049
|
+
console.log('code')
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
`)
|
|
1053
|
+
|
|
1054
|
+
// AST structure:
|
|
1055
|
+
[
|
|
1056
|
+
// Reference collection (first node, if references exist)
|
|
1057
|
+
{
|
|
1058
|
+
type: RuleType.refCollection,
|
|
1059
|
+
refs: {
|
|
1060
|
+
linkref: { target: 'https://example.com', title: undefined },
|
|
1061
|
+
},
|
|
1062
|
+
},
|
|
1063
|
+
{
|
|
1064
|
+
type: RuleType.heading,
|
|
1065
|
+
level: 1,
|
|
1066
|
+
id: 'hello-world',
|
|
1067
|
+
children: [{ type: RuleType.text, text: 'Hello World' }],
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
type: RuleType.paragraph,
|
|
1071
|
+
children: [
|
|
1072
|
+
{ type: RuleType.text, text: 'This is a ' },
|
|
1073
|
+
{
|
|
1074
|
+
type: RuleType.textFormatted,
|
|
1075
|
+
tag: 'strong',
|
|
1076
|
+
children: [{ type: RuleType.text, text: 'paragraph' }],
|
|
1077
|
+
},
|
|
1078
|
+
{ type: RuleType.text, text: ' with ' },
|
|
1079
|
+
{
|
|
1080
|
+
type: RuleType.link,
|
|
1081
|
+
target: 'https://example.com',
|
|
1082
|
+
children: [{ type: RuleType.text, text: 'a link' }],
|
|
1083
|
+
},
|
|
1084
|
+
{ type: RuleType.text, text: '.' },
|
|
1085
|
+
],
|
|
1086
|
+
},
|
|
1087
|
+
{
|
|
1088
|
+
type: RuleType.codeBlock,
|
|
1089
|
+
lang: 'javascript',
|
|
1090
|
+
text: "console.log('code')",
|
|
1091
|
+
},
|
|
1092
|
+
]
|
|
1093
|
+
|
|
1094
|
+
````
|
|
1095
|
+
|
|
1096
|
+
### Type Checking
|
|
1097
|
+
|
|
1098
|
+
Use `RuleType` constants to check node types:
|
|
1099
|
+
|
|
1100
|
+
```tsx
|
|
1101
|
+
import { RuleType } from 'markdown-to-jsx'
|
|
1102
|
+
|
|
1103
|
+
if (node.type === RuleType.heading) {
|
|
1104
|
+
const heading = node as MarkdownToJSX.HeadingNode
|
|
1105
|
+
console.log(`Heading level ${heading.level}: ${heading.id}`)
|
|
1106
|
+
}
|
|
1107
|
+
```
|
|
1108
|
+
|
|
1109
|
+
**When to use `compiler` vs `parser` vs `<Markdown>`:**
|
|
1110
|
+
|
|
1111
|
+
- Use `<Markdown>` when you need a simple React component that renders markdown to JSX.
|
|
1112
|
+
- Use `compiler` when you need React JSX output from markdown (the component uses this internally).
|
|
1113
|
+
- Use `parser` + `astToJSX` when you need the AST for custom processing before rendering to JSX, or just the AST itself.
|
|
1114
|
+
|
|
862
1115
|
## Changelog
|
|
863
1116
|
|
|
864
|
-
See [Github Releases](https://github.com/
|
|
1117
|
+
See [Github Releases](https://github.com/quantizor/markdown-to-jsx/releases).
|
|
865
1118
|
|
|
866
1119
|
## Donate
|
|
867
1120
|
|
|
868
|
-
Like this library? It's developed entirely on a volunteer basis; chip in a few bucks if you can via the Sponsor link!
|
|
869
|
-
|
|
870
|
-
MIT
|
|
1121
|
+
Like this library? It's developed entirely on a volunteer basis; chip in a few bucks if you can via the [Sponsor link](https://github.com/sponsors/quantizor)!
|