Markdown parser fork with extended syntax for personal use.
1mod test_utils;
2use markdown::{
3 mdast::{List, ListItem, MdxJsxFlowElement, Node, Paragraph, Root, Text},
4 message, to_html_with_options, to_mdast,
5 unist::Position,
6 Constructs, Options, ParseOptions,
7};
8use pretty_assertions::assert_eq;
9use test_utils::swc::{parse_esm, parse_expression};
10
11#[test]
12fn mdx_jsx_flow_agnostic() -> Result<(), message::Message> {
13 let mdx = Options {
14 parse: ParseOptions::mdx(),
15 ..Default::default()
16 };
17
18 assert_eq!(
19 to_html_with_options("<a />", &mdx)?,
20 "",
21 "should support a self-closing element"
22 );
23
24 // Note: in MDX, indented code is turned off:
25 assert_eq!(
26 to_html_with_options(
27 " <a />",
28 &Options {
29 parse: ParseOptions {
30 constructs: Constructs {
31 html_flow: false,
32 mdx_jsx_flow: true,
33 ..Default::default()
34 },
35 ..Default::default()
36 },
37 ..Default::default()
38 }
39 )?,
40 "<pre><code><a />\n</code></pre>",
41 "should prefer indented code over jsx if it’s enabled"
42 );
43
44 assert_eq!(
45 to_html_with_options(
46 " <a />",
47 &Options {
48 parse: ParseOptions {
49 constructs: Constructs {
50 html_flow: false,
51 mdx_jsx_flow: true,
52 ..Default::default()
53 },
54 ..Default::default()
55 },
56 ..Default::default()
57 }
58 )?,
59 "",
60 "should support indented jsx if indented code is enabled"
61 );
62
63 assert_eq!(
64 to_html_with_options("<a></a>", &mdx)?,
65 "",
66 "should support a closed element"
67 );
68
69 assert_eq!(
70 to_html_with_options("<a>\nb\n</a>", &mdx)?,
71 "<p>b</p>\n",
72 "should support an element w/ content"
73 );
74
75 assert_eq!(
76 to_html_with_options("<a>\n- b\n</a>", &mdx)?,
77 "<ul>\n<li>b</li>\n</ul>\n",
78 "should support an element w/ containers as content"
79 );
80
81 assert_eq!(
82 to_html_with_options("<a b c:d e=\"\" f={/* g */} {...h} />", &mdx)?,
83 "",
84 "should support attributes"
85 );
86
87 Ok(())
88}
89
90// Flow is mostly the same as `text`, so we only test the relevant
91// differences.
92#[test]
93fn mdx_jsx_flow_essence() -> Result<(), message::Message> {
94 let mdx = Options {
95 parse: ParseOptions::mdx(),
96 ..Default::default()
97 };
98
99 assert_eq!(
100 to_html_with_options("<a />", &mdx)?,
101 "",
102 "should support an element"
103 );
104
105 assert_eq!(
106 to_html_with_options("<a>\n- b\n</a>", &mdx)?,
107 "<ul>\n<li>b</li>\n</ul>\n",
108 "should support an element around a container"
109 );
110
111 assert_eq!(
112 to_html_with_options("<x\n y\n> \nb\n </x>", &mdx)?,
113 "<p>b</p>\n",
114 "should support a dangling `>` in a tag (not a block quote)"
115 );
116
117 assert_eq!(
118 to_html_with_options("<a> \nb\n </a>", &mdx)?,
119 "<p>b</p>\n",
120 "should support trailing initial and final whitespace around tags"
121 );
122
123 assert_eq!(
124 to_html_with_options("<a> <b>\t\nc\n </b> </a>", &mdx)?,
125 "<p>c</p>\n",
126 "should support tags after tags"
127 );
128
129 // This is to make sure `document` passes errors through properly.
130 assert_eq!(
131 to_html_with_options("* <!a>\n1. b", &mdx)
132 .err()
133 .unwrap().to_string(),
134 "1:4: Unexpected character `!` (U+0021) before name, expected a character that can start a name, such as a letter, `$`, or `_` (note: to create a comment in MDX, use `{/* text */}`) (markdown-rs:unexpected-character)",
135 "should handle crash in containers gracefully"
136 );
137
138 assert_eq!(
139 to_html_with_options("> <X\n/>", &mdx).err().unwrap().to_string(),
140 "2:1: Unexpected lazy line in jsx in container, expected line to be prefixed with `>` when in a block quote, whitespace when in a list, etc (markdown-rs:unexpected-lazy)",
141 "should not support lazy flow (1)"
142 );
143
144 assert_eq!(
145 to_html_with_options("> a\n> <X\n/>", &mdx)
146 .err()
147 .unwrap().to_string(),
148 "3:1: Unexpected lazy line in jsx in container, expected line to be prefixed with `>` when in a block quote, whitespace when in a list, etc (markdown-rs:unexpected-lazy)",
149 "should not support lazy flow (2)"
150 );
151
152 assert_eq!(
153 to_html_with_options("> <a b='\nc'/>", &mdx)
154 .err()
155 .unwrap().to_string(),
156 "2:1: Unexpected lazy line in jsx in container, expected line to be prefixed with `>` when in a block quote, whitespace when in a list, etc (markdown-rs:unexpected-lazy)",
157 "should not support lazy flow (3)"
158 );
159
160 assert_eq!(
161 to_html_with_options("> <a b='c\n'/>", &mdx)
162 .err()
163 .unwrap().to_string(),
164 "2:1: Unexpected lazy line in jsx in container, expected line to be prefixed with `>` when in a block quote, whitespace when in a list, etc (markdown-rs:unexpected-lazy)",
165 "should not support lazy flow (4)"
166 );
167
168 assert_eq!(
169 to_html_with_options("> <a b='c\nd'/>", &mdx)
170 .err()
171 .unwrap().to_string(),
172 "2:1: Unexpected lazy line in jsx in container, expected line to be prefixed with `>` when in a block quote, whitespace when in a list, etc (markdown-rs:unexpected-lazy)",
173 "should not support lazy flow (5)"
174 );
175
176 assert_eq!(
177 to_html_with_options("> <a b={c\nd}/>", &mdx)
178 .err()
179 .unwrap().to_string(),
180 "2:1: Unexpected lazy line in expression in container, expected line to be prefixed with `>` when in a block quote, whitespace when in a list, etc (markdown-rs:unexpected-lazy)",
181 "should not support lazy flow (6)"
182 );
183
184 assert_eq!(
185 to_html_with_options("> <a {b\nc}/>", &mdx)
186 .err()
187 .unwrap().to_string(),
188 "2:1: Unexpected lazy line in expression in container, expected line to be prefixed with `>` when in a block quote, whitespace when in a list, etc (markdown-rs:unexpected-lazy)",
189 "should not support lazy flow (7)"
190 );
191
192 assert_eq!(
193 to_html_with_options("> a\n<X />", &mdx)?,
194 "<blockquote>\n<p>a</p>\n</blockquote>\n",
195 "should not support lazy flow (8)"
196 );
197
198 assert_eq!(
199 to_mdast("<>\n * a\n</>", &mdx.parse)?,
200 Node::Root(Root {
201 children: vec![Node::MdxJsxFlowElement(MdxJsxFlowElement {
202 name: None,
203 attributes: vec![],
204 children: vec![Node::List(List {
205 ordered: false,
206 spread: false,
207 start: None,
208 children: vec![Node::ListItem(ListItem {
209 checked: None,
210 spread: false,
211 children: vec![Node::Paragraph(Paragraph {
212 children: vec![Node::Text(Text {
213 value: "a".into(),
214 position: Some(Position::new(2, 5, 7, 2, 6, 8))
215 }),],
216 position: Some(Position::new(2, 5, 7, 2, 6, 8))
217 })],
218 position: Some(Position::new(2, 1, 3, 2, 6, 8))
219 })],
220 position: Some(Position::new(2, 1, 3, 2, 6, 8))
221 })],
222 position: Some(Position::new(1, 1, 0, 3, 4, 12))
223 })],
224 position: Some(Position::new(1, 1, 0, 3, 4, 12))
225 }),
226 "should support mdx jsx (flow) as `MdxJsxFlowElement`s in mdast"
227 );
228
229 Ok(())
230}
231
232// Flow is mostly the same as `text`, so we only test the relevant
233// differences.
234#[test]
235fn mdx_jsx_flow_interleaving_with_expressions() -> Result<(), message::Message> {
236 let mdx = Options {
237 parse: ParseOptions::mdx(),
238 ..Default::default()
239 };
240 let swc = Options {
241 parse: ParseOptions {
242 constructs: Constructs::mdx(),
243 mdx_esm_parse: Some(Box::new(parse_esm)),
244 mdx_expression_parse: Some(Box::new(parse_expression)),
245 ..Default::default()
246 },
247 ..Default::default()
248 };
249
250 assert_eq!(
251 to_html_with_options("<div>\n{1}\n</div>", &mdx)?,
252 "",
253 "should support tags and expressions (unaware)"
254 );
255
256 assert_eq!(
257 to_html_with_options("<div>\n{'}'}\n</div>", &swc)?,
258 "",
259 "should support tags and expressions (aware)"
260 );
261
262 assert_eq!(
263 to_html_with_options("x<em>{1}</em>", &swc)?,
264 "<p>x</p>",
265 "should support tags and expressions with text before (text)"
266 );
267
268 assert_eq!(
269 to_html_with_options("<em>x{1}</em>", &swc)?,
270 "<p>x</p>",
271 "should support tags and expressions with text between, early (text)"
272 );
273
274 assert_eq!(
275 to_html_with_options("<em>{1}x</em>", &swc)?,
276 "<p>x</p>",
277 "should support tags and expressions with text between, late (text)"
278 );
279
280 assert_eq!(
281 to_html_with_options("<em>{1}</em>x", &swc)?,
282 "<p>x</p>",
283 "should support tags and expressions with text after (text)"
284 );
285
286 assert_eq!(
287 to_html_with_options("<x/>{1}", &swc)?,
288 "",
289 "should support a tag and then an expression (flow)"
290 );
291
292 assert_eq!(
293 to_html_with_options("<x/>{1}x", &swc)?,
294 "<p>x</p>",
295 "should support a tag, an expression, then text (text)"
296 );
297
298 assert_eq!(
299 to_html_with_options("x<x/>{1}", &swc)?,
300 "<p>x</p>",
301 "should support text, a tag, then an expression (text)"
302 );
303
304 assert_eq!(
305 to_html_with_options("{1}<x/>", &swc)?,
306 "",
307 "should support an expression and then a tag (flow)"
308 );
309
310 assert_eq!(
311 to_html_with_options("{1}<x/>x", &swc)?,
312 "<p>x</p>",
313 "should support an expression, a tag, then text (text)"
314 );
315
316 assert_eq!(
317 to_html_with_options("x{1}<x/>", &swc)?,
318 "<p>x</p>",
319 "should support text, an expression, then a tag (text)"
320 );
321
322 assert_eq!(
323 to_html_with_options("<x>{[\n'',\n{c:''}\n]}</x>", &swc)?,
324 "",
325 "should nicely interleaf (micromark/micromark-extension-mdx-jsx#9)"
326 );
327
328 assert_eq!(
329 to_html_with_options(
330 "
331<style>{`
332 .foo {}
333 .bar {}
334`}</style>
335 ",
336 &swc
337 )?,
338 "",
339 "should nicely interleaf (mdx-js/mdx#1945)"
340 );
341
342 Ok(())
343}