Markdown parser fork with extended syntax for personal use.
1mod test_utils;
2use markdown::{
3 mdast::{
4 AttributeContent, AttributeValue, AttributeValueExpression, Emphasis, MdxFlowExpression,
5 MdxJsxAttribute, MdxJsxExpressionAttribute, MdxJsxFlowElement, MdxJsxTextElement, Node,
6 Paragraph, Root, Text,
7 },
8 message, to_html_with_options, to_mdast,
9 unist::Position,
10 Constructs, Options, ParseOptions,
11};
12use pretty_assertions::assert_eq;
13use test_utils::swc::{parse_esm, parse_expression};
14
15#[test]
16fn mdx_jsx_text_core() -> Result<(), message::Message> {
17 let mdx = Options {
18 parse: ParseOptions::mdx(),
19 ..Default::default()
20 };
21
22 assert_eq!(
23 to_html_with_options("a <b> c", &mdx)?,
24 "<p>a c</p>",
25 "should support mdx jsx (text) if enabled"
26 );
27
28 assert_eq!(
29 to_html_with_options("a <b/> c.", &mdx)?,
30 "<p>a c.</p>",
31 "should support a self-closing element"
32 );
33
34 assert_eq!(
35 to_html_with_options("a <b></b> c.", &mdx)?,
36 "<p>a c.</p>",
37 "should support a closed element"
38 );
39
40 assert_eq!(
41 to_html_with_options("a <></> c.", &mdx)?,
42 "<p>a c.</p>",
43 "should support fragments"
44 );
45
46 assert_eq!(
47 to_html_with_options("a <b>*b*</b> c.", &mdx)?,
48 "<p>a <em>b</em> c.</p>",
49 "should support markdown inside elements"
50 );
51
52 assert_eq!(
53 to_mdast("{1}<a/>", &mdx.parse)?,
54 Node::Root(Root {
55 children: vec![
56 Node::MdxFlowExpression(MdxFlowExpression {
57 value: "1".into(),
58 position: Some(Position::new(1, 1, 0, 1, 4, 3)),
59 stops: vec![(0, 1)]
60 }),
61 Node::MdxJsxFlowElement(MdxJsxFlowElement {
62 name: Some("a".into()),
63 attributes: vec![],
64 children: vec![],
65 position: Some(Position::new(1, 4, 3, 1, 8, 7))
66 })
67 ],
68 position: Some(Position::new(1, 1, 0, 1, 8, 7))
69 }),
70 "should support mdx jsx (text) with expression child"
71 );
72
73 assert_eq!(
74 to_mdast("<a>{1}</a>", &mdx.parse)?,
75 Node::Root(Root {
76 children: vec![Node::MdxJsxFlowElement(MdxJsxFlowElement {
77 name: Some("a".into()),
78 attributes: vec![],
79 children: vec![Node::MdxFlowExpression(MdxFlowExpression {
80 value: "1".into(),
81 position: Some(Position::new(1, 4, 3, 1, 7, 6)),
82 stops: vec![(0, 4)]
83 })],
84 position: Some(Position::new(1, 1, 0, 1, 11, 10))
85 }),],
86 position: Some(Position::new(1, 1, 0, 1, 11, 10))
87 }),
88 "should support mdx jsx (text) with expression child"
89 );
90
91 assert_eq!(
92 to_mdast("a <b /> c.", &mdx.parse)?,
93 Node::Root(Root {
94 children: vec![Node::Paragraph(Paragraph {
95 children: vec![
96 Node::Text(Text {
97 value: "a ".into(),
98 position: Some(Position::new(1, 1, 0, 1, 3, 2))
99 }),
100 Node::MdxJsxTextElement(MdxJsxTextElement {
101 name: Some("b".into()),
102 attributes: vec![],
103 children: vec![],
104 position: Some(Position::new(1, 3, 2, 1, 8, 7))
105 }),
106 Node::Text(Text {
107 value: " c.".into(),
108 position: Some(Position::new(1, 8, 7, 1, 11, 10))
109 })
110 ],
111 position: Some(Position::new(1, 1, 0, 1, 11, 10))
112 })],
113 position: Some(Position::new(1, 1, 0, 1, 11, 10))
114 }),
115 "should support mdx jsx (text) as `MdxJsxTextElement`s in mdast (self-closing)"
116 );
117
118 assert_eq!(
119 to_mdast("a <b>*c*</b> d.", &mdx.parse)?,
120 Node::Root(Root {
121 children: vec![Node::Paragraph(Paragraph {
122 children: vec![
123 Node::Text(Text {
124 value: "a ".into(),
125 position: Some(Position::new(1, 1, 0, 1, 3, 2))
126 }),
127 Node::MdxJsxTextElement(MdxJsxTextElement {
128 name: Some("b".into()),
129 attributes: vec![],
130 children: vec![
131 Node::Emphasis(Emphasis {
132 children: vec![
133 Node::Text(Text {
134 value: "c".into(),
135 position: Some(Position::new(1, 7, 6, 1, 8, 7))
136 }),
137 ],
138 position: Some(Position::new(1, 6, 5, 1, 9, 8))
139 }),
140 ],
141 position: Some(Position::new(1, 3, 2, 1, 13, 12))
142 }),
143 Node::Text(Text {
144 value: " d.".into(),
145 position: Some(Position::new(1, 13, 12, 1, 16, 15))
146 })
147 ],
148 position: Some(Position::new(1, 1, 0, 1, 16, 15))
149 })],
150 position: Some(Position::new(1, 1, 0, 1, 16, 15))
151 }),
152 "should support mdx jsx (text) as `MdxJsxTextElement`s in mdast (matched open and close tags)"
153 );
154
155 assert_eq!(
156 to_mdast("<a:b />.", &mdx.parse)?,
157 Node::Root(Root {
158 children: vec![Node::Paragraph(Paragraph {
159 children: vec![
160 Node::MdxJsxTextElement(MdxJsxTextElement {
161 name: Some("a:b".into()),
162 attributes: vec![],
163 children: vec![],
164 position: Some(Position::new(1, 1, 0, 1, 8, 7))
165 }),
166 Node::Text(Text {
167 value: ".".into(),
168 position: Some(Position::new(1, 8, 7, 1, 9, 8))
169 })
170 ],
171 position: Some(Position::new(1, 1, 0, 1, 9, 8))
172 })],
173 position: Some(Position::new(1, 1, 0, 1, 9, 8))
174 }),
175 "should support mdx jsx (text) as `MdxJsxTextElement`s in mdast (namespace in tag name)"
176 );
177
178 assert_eq!(
179 to_mdast("<a.b.c />.", &mdx.parse)?,
180 Node::Root(Root {
181 children: vec![Node::Paragraph(Paragraph {
182 children: vec![
183 Node::MdxJsxTextElement(MdxJsxTextElement {
184 name: Some("a.b.c".into()),
185 attributes: vec![],
186 children: vec![],
187 position: Some(Position::new(1, 1, 0, 1, 10, 9))
188 }),
189 Node::Text(Text {
190 value: ".".into(),
191 position: Some(Position::new(1, 10, 9, 1, 11, 10))
192 })
193 ],
194 position: Some(Position::new(1, 1, 0, 1, 11, 10))
195 })],
196 position: Some(Position::new(1, 1, 0, 1, 11, 10))
197 }),
198 "should support mdx jsx (text) as `MdxJsxTextElement`s in mdast (members in tag name)"
199 );
200
201 assert_eq!(
202 to_mdast("<a {...b} />.", &mdx.parse)?,
203 Node::Root(Root {
204 children: vec![Node::Paragraph(Paragraph {
205 children: vec![
206 Node::MdxJsxTextElement(MdxJsxTextElement {
207 name: Some("a".into()),
208 attributes: vec![AttributeContent::Expression(MdxJsxExpressionAttribute {
209 value: "...b".into(),
210 stops: vec![(0, 4)]
211 })],
212 children: vec![],
213 position: Some(Position::new(1, 1, 0, 1, 13, 12))
214 }),
215 Node::Text(Text {
216 value: ".".into(),
217 position: Some(Position::new(1, 13, 12, 1, 14, 13))
218 })
219 ],
220 position: Some(Position::new(1, 1, 0, 1, 14, 13))
221 })],
222 position: Some(Position::new(1, 1, 0, 1, 14, 13))
223 }),
224 "should support mdx jsx (text) as `MdxJsxTextElement`s in mdast (attribute expression)"
225 );
226
227 assert_eq!(
228 to_mdast("<a b c:d />.", &mdx.parse)?,
229 Node::Root(Root {
230 children: vec![Node::Paragraph(Paragraph {
231 children: vec![
232 Node::MdxJsxTextElement(MdxJsxTextElement {
233 name: Some("a".into()),
234 attributes: vec![
235 AttributeContent::Property(MdxJsxAttribute {
236 name: "b".into(),
237 value: None,
238 }),
239 AttributeContent::Property(MdxJsxAttribute {
240 name: "c:d".into(),
241 value: None,
242 })
243 ],
244 children: vec![],
245 position: Some(Position::new(1, 1, 0, 1, 12, 11))
246 }),
247 Node::Text(Text {
248 value: ".".into(),
249 position: Some(Position::new(1, 12, 11, 1, 13, 12))
250 })
251 ],
252 position: Some(Position::new(1, 1, 0, 1, 13, 12))
253 })],
254 position: Some(Position::new(1, 1, 0, 1, 13, 12))
255 }),
256 "should support mdx jsx (text) as `MdxJsxTextElement`s in mdast (property names)"
257 );
258
259 assert_eq!(
260 to_mdast("<a b='c' d=\"e\" f={g} />.", &mdx.parse)?,
261 Node::Root(Root {
262 children: vec![Node::Paragraph(Paragraph {
263 children: vec![
264 Node::MdxJsxTextElement(MdxJsxTextElement {
265 name: Some("a".into()),
266 attributes: vec![
267 AttributeContent::Property(MdxJsxAttribute {
268 name: "b".into(),
269 value: Some(AttributeValue::Literal("c".into())),
270 }),
271 AttributeContent::Property(MdxJsxAttribute {
272 name: "d".into(),
273 value: Some(AttributeValue::Literal("e".into())),
274 }),
275 AttributeContent::Property(MdxJsxAttribute {
276 name: "f".into(),
277 value: Some(AttributeValue::Expression(AttributeValueExpression {
278 value: "g".into(),
279 stops: vec![(0, 18)]
280 })),
281 }),
282 ],
283 children: vec![],
284 position: Some(Position::new(1, 1, 0, 1, 24, 23))
285 }),
286 Node::Text(Text {
287 value: ".".into(),
288 position: Some(Position::new(1, 24, 23, 1, 25, 24))
289 })
290 ],
291 position: Some(Position::new(1, 1, 0, 1, 25, 24))
292 })],
293 position: Some(Position::new(1, 1, 0, 1, 25, 24))
294 }),
295 "should support mdx jsx (text) as `MdxJsxTextElement`s in mdast (attribute values)"
296 );
297
298 assert_eq!(
299 to_mdast("<a b=' & © Æ Ď ¾ ℋ ⅆ ∲ ≧̸' />.", &mdx.parse)?,
300 Node::Root(Root {
301 children: vec![Node::Paragraph(Paragraph {
302 children: vec![
303 Node::MdxJsxTextElement(MdxJsxTextElement {
304 name: Some("a".into()),
305 attributes: vec![
306 AttributeContent::Property(MdxJsxAttribute {
307 name: "b".into(),
308 value: Some(AttributeValue::Literal("\u{a0} & © Æ Ď ¾ ℋ ⅆ ∲ ≧̸".into())),
309 }),
310 ],
311 children: vec![],
312 position: Some(Position::new(1, 1, 0, 1, 120, 119))
313 }),
314 Node::Text(Text {
315 value: ".".into(),
316 position: Some(Position::new(1, 120, 119, 1, 121, 120))
317 })
318 ],
319 position: Some(Position::new(1, 1, 0, 1, 121, 120))
320 })],
321 position: Some(Position::new(1, 1, 0, 1, 121, 120))
322 }),
323 "should support character references (HTML 4, named) in JSX attribute values"
324 );
325
326 assert_eq!(
327 to_mdast(
328 "<a b='# Ӓ Ϡ �' c='" ആ ಫ' />.",
329 &mdx.parse
330 )?,
331 Node::Root(Root {
332 children: vec![Node::Paragraph(Paragraph {
333 children: vec![
334 Node::MdxJsxTextElement(MdxJsxTextElement {
335 name: Some("a".into()),
336 attributes: vec![
337 AttributeContent::Property(MdxJsxAttribute {
338 name: "b".into(),
339 value: Some(AttributeValue::Literal("# Ӓ Ϡ �".into())),
340 }),
341 AttributeContent::Property(MdxJsxAttribute {
342 name: "c".into(),
343 value: Some(AttributeValue::Literal("\" ആ ಫ".into())),
344 }),
345 ],
346 children: vec![],
347 position: Some(Position::new(1, 1, 0, 1, 63, 62))
348 }),
349 Node::Text(Text {
350 value: ".".into(),
351 position: Some(Position::new(1, 63, 62, 1, 64, 63))
352 })
353 ],
354 position: Some(Position::new(1, 1, 0, 1, 64, 63))
355 })],
356 position: Some(Position::new(1, 1, 0, 1, 64, 63))
357 }),
358 "should support character references (numeric) in JSX attribute values"
359 );
360
361 assert_eq!(
362 to_mdast("<a b='  &x; &#; &#x; � &#abcdef0; &ThisIsNotDefined; &hi?;' />.", &mdx.parse)?,
363 Node::Root(Root {
364 children: vec![Node::Paragraph(Paragraph {
365 children: vec![
366 Node::MdxJsxTextElement(MdxJsxTextElement {
367 name: Some("a".into()),
368 attributes: vec![
369 AttributeContent::Property(MdxJsxAttribute {
370 name: "b".into(),
371 value: Some(AttributeValue::Literal("  &x; &#; &#x; � &#abcdef0; &ThisIsNotDefined; &hi?;".into())),
372 })
373 ],
374 children: vec![],
375 position: Some(Position::new(1, 1, 0, 1, 78, 77))
376 }),
377 Node::Text(Text {
378 value: ".".into(),
379 position: Some(Position::new(1, 78, 77, 1, 79, 78))
380 })
381 ],
382 position: Some(Position::new(1, 1, 0, 1, 79, 78))
383 })],
384 position: Some(Position::new(1, 1, 0, 1, 79, 78))
385 }),
386 "should not support things that look like character references but aren’t"
387 );
388
389 assert_eq!(
390 to_mdast("<a\u{3000}b \u{3000}c\u{3000} d\u{3000}/>.", &mdx.parse)?,
391 Node::Root(Root {
392 children: vec![Node::Paragraph(Paragraph {
393 children: vec![
394 Node::MdxJsxTextElement(MdxJsxTextElement {
395 name: Some("a".into()),
396 attributes: vec![
397 AttributeContent::Property(MdxJsxAttribute {
398 name: "b".into(),
399 value: None,
400 }),
401 AttributeContent::Property(MdxJsxAttribute {
402 name: "c".into(),
403 value: None,
404 }),
405 AttributeContent::Property(MdxJsxAttribute {
406 name: "d".into(),
407 value: None,
408 })
409 ],
410 children: vec![],
411 position: Some(Position::new(1, 1, 0, 1, 22, 21))
412 }),
413 Node::Text(Text {
414 value: ".".into(),
415 position: Some(Position::new(1, 22, 21, 1, 23, 22))
416 })
417 ],
418 position: Some(Position::new(1, 1, 0, 1, 23, 22))
419 })],
420 position: Some(Position::new(1, 1, 0, 1, 23, 22))
421 }),
422 "should support unicode whitespace in a lot of places"
423 );
424
425 assert_eq!(
426 to_mdast("<a\nb \nc\n d\n/>.", &mdx.parse)?,
427 Node::Root(Root {
428 children: vec![Node::Paragraph(Paragraph {
429 children: vec![
430 Node::MdxJsxTextElement(MdxJsxTextElement {
431 name: Some("a".into()),
432 attributes: vec![
433 AttributeContent::Property(MdxJsxAttribute {
434 name: "b".into(),
435 value: None,
436 }),
437 AttributeContent::Property(MdxJsxAttribute {
438 name: "c".into(),
439 value: None,
440 }),
441 AttributeContent::Property(MdxJsxAttribute {
442 name: "d".into(),
443 value: None,
444 })
445 ],
446 children: vec![],
447 position: Some(Position::new(1, 1, 0, 5, 3, 13))
448 }),
449 Node::Text(Text {
450 value: ".".into(),
451 position: Some(Position::new(5, 3, 13, 5, 4, 14))
452 })
453 ],
454 position: Some(Position::new(1, 1, 0, 5, 4, 14))
455 })],
456 position: Some(Position::new(1, 1, 0, 5, 4, 14))
457 }),
458 "should support line endings in a lot of places"
459 );
460
461 assert_eq!(
462 to_mdast("a </b> c", &mdx.parse).err().unwrap().to_string(),
463 "1:4: Unexpected closing slash `/` in tag, expected an open tag first (markdown-rs:unexpected-closing-slash)",
464 "should crash when building the ast on a closing tag if none is open"
465 );
466
467 assert_eq!(
468 to_mdast("a <b> c </b/> d", &mdx.parse)
469 .err()
470 .unwrap()
471 .to_string(),
472 "1:12: Unexpected self-closing slash `/` in closing tag, expected the end of the tag (markdown-rs:unexpected-self-closing-slash)",
473 "should crash when building the ast on a closing tag with a self-closing slash"
474 );
475
476 assert_eq!(
477 to_mdast("a <b> c </b d> e", &mdx.parse)
478 .err()
479 .unwrap()
480 .to_string(),
481 "1:13: Unexpected attribute in closing tag, expected the end of the tag (markdown-rs:unexpected-attribute)",
482 "should crash when building the ast on a closing tag with an attribute"
483 );
484
485 assert_eq!(
486 to_mdast("a <>b</c> d", &mdx.parse)
487 .err()
488 .unwrap().to_string(),
489 "1:6-1:10: Unexpected closing tag `</c>`, expected corresponding closing tag for `<>` (1:3) (markdown-rs:end-tag-mismatch)",
490 "should crash when building the ast on mismatched tags (1)"
491 );
492
493 assert_eq!(
494 to_mdast("a <b>c</> d", &mdx.parse)
495 .err()
496 .unwrap().to_string(),
497 "1:7-1:10: Unexpected closing tag `</>`, expected corresponding closing tag for `<b>` (1:3) (markdown-rs:end-tag-mismatch)",
498 "should crash when building the ast on mismatched tags (2)"
499 );
500
501 assert_eq!(
502 to_mdast("*a <b>c* d</b>.", &mdx.parse)
503 .err()
504 .unwrap()
505 .to_string(),
506 "1:9: Expected a closing tag for `<b>` (1:4) before the end of `Emphasis` (markdown-rs:end-tag-mismatch)",
507 "should crash when building the ast on mismatched interleaving (1)"
508 );
509
510 assert_eq!(
511 to_mdast("<a>b *c</a> d*.", &mdx.parse).err().unwrap().to_string(),
512 "1:8: Expected the closing tag `</a>` either before the start of `Emphasis` (1:6), or another opening tag after that start (markdown-rs:end-tag-mismatch)",
513 "should crash when building the ast on mismatched interleaving (2)"
514 );
515
516 assert_eq!(
517 to_mdast("a <b>.", &mdx.parse).err().unwrap().to_string(),
518 "1:7: Expected a closing tag for `<b>` (1:3) before the end of `Paragraph` (markdown-rs:end-tag-mismatch)",
519 "should crash when building the ast on mismatched interleaving (3)"
520 );
521
522 // Note: this is flow, not text.
523 assert_eq!(
524 to_mdast("<a>", &mdx.parse).err().unwrap().to_string(),
525 "1:4: Expected a closing tag for `<a>` (1:1) (markdown-rs:end-tag-mismatch)",
526 "should crash when building the ast on mismatched interleaving (4)"
527 );
528
529 assert_eq!(
530 to_mdast("<a><b></b>", &mdx.parse)
531 .err()
532 .unwrap()
533 .to_string(),
534 "1:11: Expected a closing tag for `<a>` (1:1) (markdown-rs:end-tag-mismatch)",
535 "should crash on unclosed jsx after closed jsx"
536 );
537
538 Ok(())
539}
540
541#[test]
542fn mdx_jsx_text_agnosic() -> Result<(), message::Message> {
543 let mdx = Options {
544 parse: ParseOptions::mdx(),
545 ..Default::default()
546 };
547
548 assert_eq!(
549 to_html_with_options("a <b /> c", &mdx)?,
550 "<p>a c</p>",
551 "should support a self-closing element"
552 );
553
554 assert_eq!(
555 to_html_with_options("a <b> c </b> d", &mdx)?,
556 "<p>a c d</p>",
557 "should support a closed element"
558 );
559
560 assert_eq!(
561 to_html_with_options("a <b> c", &mdx)?,
562 "<p>a c</p>",
563 "should support an unclosed element"
564 );
565
566 assert_eq!(
567 to_html_with_options("a <b {1 + 1} /> c", &mdx)?,
568 "<p>a c</p>",
569 "should support an attribute expression"
570 );
571
572 assert_eq!(
573 to_html_with_options("a <b c={1 + 1} /> d", &mdx)?,
574 "<p>a d</p>",
575 "should support an attribute value expression"
576 );
577
578 Ok(())
579}
580
581#[test]
582fn mdx_jsx_text_gnostic() -> Result<(), message::Message> {
583 let swc = Options {
584 parse: ParseOptions {
585 constructs: Constructs::mdx(),
586 mdx_esm_parse: Some(Box::new(parse_esm)),
587 mdx_expression_parse: Some(Box::new(parse_expression)),
588 ..Default::default()
589 },
590 ..Default::default()
591 };
592
593 assert_eq!(
594 to_html_with_options("a <b /> c", &swc)?,
595 "<p>a c</p>",
596 "should support a self-closing element"
597 );
598
599 assert_eq!(
600 to_html_with_options("a <b> c </b> d", &swc)?,
601 "<p>a c d</p>",
602 "should support a closed element"
603 );
604
605 assert_eq!(
606 to_html_with_options("a <b> c", &swc)?,
607 "<p>a c</p>",
608 "should support an unclosed element"
609 );
610
611 assert_eq!(
612 to_html_with_options("a <b {...c} /> d", &swc)?,
613 "<p>a d</p>",
614 "should support an attribute expression"
615 );
616
617 assert_eq!(
618 to_html_with_options("a <b {...{c: 1, d: Infinity, e: false}} /> f", &swc)?,
619 "<p>a f</p>",
620 "should support more complex attribute expression (1)"
621 );
622
623 assert_eq!(
624 to_html_with_options("a <b {...[1, Infinity, false]} /> d", &swc)?,
625 "<p>a d</p>",
626 "should support more complex attribute expression (2)"
627 );
628
629 assert_eq!(
630 to_html_with_options("a <b c={1 + 1} /> d", &swc)?,
631 "<p>a d</p>",
632 "should support an attribute value expression"
633 );
634
635 assert_eq!(
636 to_html_with_options("a <b c={} /> d", &swc)
637 .err()
638 .unwrap()
639 .to_string(),
640 "1:15: Could not parse expression with swc: Unexpected eof (mdx:swc)",
641 "should crash on an empty attribute value expression"
642 );
643
644 assert_eq!(
645 to_html_with_options("a <b {1 + 1} /> c", &swc)
646 .err()
647 .unwrap()
648 .to_string(),
649 "1:18: Could not parse expression with swc: Expected ',', got '}' (mdx:swc)",
650 "should crash on a non-spread attribute expression"
651 );
652
653 assert_eq!(
654 to_html_with_options("a <b c={?} /> d", &swc)
655 .err()
656 .unwrap()
657 .to_string(),
658 "1:16: Could not parse expression with swc: Expression expected (mdx:swc)",
659 "should crash on invalid JS in an attribute value expression"
660 );
661
662 assert_eq!(
663 to_html_with_options("a <b {?} /> c", &swc)
664 .err()
665 .unwrap().to_string(),
666 "1:14: Could not parse expression with swc: Unexpected token `?`. Expected identifier, string literal, numeric literal or [ for the computed key (mdx:swc)",
667 "should crash on invalid JS in an attribute expression"
668 );
669
670 assert_eq!(
671 to_html_with_options("a <b{c=d}={}/> f", &swc)
672 .err()
673 .unwrap().to_string(),
674 "1:6: Unexpected prop in spread (such as `{x}`): only a spread is supported (such as `{...x}`) (mdx:swc)",
675 "should crash on invalid JS in an attribute expression (2)"
676 );
677
678 assert_eq!(
679 to_html_with_options("a <b c={(2)} d={<e />} /> f", &swc)?,
680 "<p>a f</p>",
681 "should support parenthesized expressions"
682 );
683
684 Ok(())
685}
686
687#[test]
688fn mdx_jsx_text_complete() -> Result<(), message::Message> {
689 let mdx = Options {
690 parse: ParseOptions::mdx(),
691 ..Default::default()
692 };
693
694 assert_eq!(
695 to_html_with_options("a <b> c", &mdx)?,
696 "<p>a c</p>",
697 "should support an unclosed element"
698 );
699
700 assert_eq!(
701 to_html_with_options("a <> c", &mdx)?,
702 "<p>a c</p>",
703 "should support an unclosed fragment"
704 );
705
706 assert_eq!(
707 to_html_with_options("a < \t>b</>", &mdx)?,
708 "<p>a < \t>b</p>",
709 "should *not* support whitespace in the opening tag (fragment)"
710 );
711
712 assert_eq!(
713 to_html_with_options("a < \nb\t>b</b>", &mdx)?,
714 "<p>a <\nb\t>b</p>",
715 "should *not* support whitespace in the opening tag (named)"
716 );
717
718 assert_eq!(
719 to_html_with_options("a <!> b", &mdx)
720 .err()
721 .unwrap().to_string(),
722 "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)",
723 "should crash on a nonconforming start identifier"
724 );
725
726 assert_eq!(
727 to_html_with_options("a </(> b.", &mdx)
728 .err()
729 .unwrap().to_string(),
730 "1:5: Unexpected character `(` (U+0028) before name, expected a character that can start a name, such as a letter, `$`, or `_` (markdown-rs:unexpected-character)",
731 "should crash on a nonconforming start identifier in a closing tag"
732 );
733
734 assert_eq!(
735 to_html_with_options("a <π /> b.", &mdx)?,
736 "<p>a b.</p>",
737 "should support non-ascii identifier start characters"
738 );
739
740 assert_eq!(
741 to_html_with_options("a <© /> b.", &mdx)
742 .err()
743 .unwrap().to_string(),
744 "1:4: Unexpected character U+00A9 before name, expected a character that can start a name, such as a letter, `$`, or `_` (markdown-rs:unexpected-character)",
745 "should crash on non-conforming non-ascii identifier start characters"
746 );
747
748 assert_eq!(
749 to_html_with_options("a <!--b-->", &mdx)
750 .err()
751 .unwrap().to_string(),
752 "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)",
753 "should crash nicely on what might be a comment"
754 );
755
756 assert_eq!(
757 to_html_with_options("a <// b\nc/>", &mdx)
758 .err()
759 .unwrap().to_string(),
760 "1:5: Unexpected character `/` (U+002F) before name, expected a character that can start a name, such as a letter, `$`, or `_` (note: JS comments in JSX tags are not supported in MDX) (markdown-rs:unexpected-character)",
761 "should crash nicely on JS line comments inside tags (1)"
762 );
763
764 assert_eq!(
765 to_html_with_options("a <b// c\nd/>", &mdx)
766 .err()
767 .unwrap().to_string(),
768 "1:6: Unexpected character `/` (U+002F) after self-closing slash, expected `>` to end the tag (note: JS comments in JSX tags are not supported in MDX) (markdown-rs:unexpected-character)",
769 "should crash nicely JS line comments inside tags (2)"
770 );
771
772 assert_eq!(
773 to_html_with_options("a </*b*/c>", &mdx)
774 .err()
775 .unwrap().to_string(),
776 "1:5: Unexpected character `*` (U+002A) before name, expected a character that can start a name, such as a letter, `$`, or `_` (markdown-rs:unexpected-character)",
777 "should crash nicely JS multiline comments inside tags (1)"
778 );
779
780 assert_eq!(
781 to_html_with_options("a <b/*c*/>", &mdx)
782 .err()
783 .unwrap().to_string(),
784 "1:6: Unexpected character `*` (U+002A) after self-closing slash, expected `>` to end the tag (markdown-rs:unexpected-character)",
785 "should crash nicely JS multiline comments inside tags (2)"
786 );
787
788 assert_eq!(
789 to_html_with_options("a <a\u{200C}b /> b.", &mdx)?,
790 "<p>a b.</p>",
791 "should support non-ascii identifier continuation characters"
792 );
793
794 assert_eq!(
795 to_html_with_options("a <a¬ /> b.", &mdx)
796 .err()
797 .unwrap().to_string(),
798 "1:5: Unexpected character U+00AC in name, expected a name character such as letters, digits, `$`, or `_`; whitespace before attributes; or the end of the tag (markdown-rs:unexpected-character)",
799 "should crash on non-conforming non-ascii identifier continuation characters"
800 );
801
802 assert_eq!(
803 to_html_with_options("a <b@c.d>", &mdx)
804 .err()
805 .unwrap().to_string(),
806 "1:5: Unexpected character `@` (U+0040) in name, expected a name character such as letters, digits, `$`, or `_`; whitespace before attributes; or the end of the tag (note: to create a link in MDX, use `[text](url)`) (markdown-rs:unexpected-character)",
807 "should crash nicely on what might be an email link"
808 );
809
810 assert_eq!(
811 to_html_with_options("a <a-->b</a-->.", &mdx)?,
812 "<p>a b.</p>",
813 "should support dashes in names"
814 );
815
816 assert_eq!(
817 to_html_with_options("a <a?> c.", &mdx)
818 .err()
819 .unwrap().to_string(),
820 "1:5: Unexpected character `?` (U+003F) in name, expected a name character such as letters, digits, `$`, or `_`; whitespace before attributes; or the end of the tag (markdown-rs:unexpected-character)",
821 "should crash on nonconforming identifier continuation characters"
822 );
823
824 assert_eq!(
825 to_html_with_options("a <abc . def.ghi>b</abc.def . ghi>.", &mdx)?,
826 "<p>a b.</p>",
827 "should support dots in names for method names"
828 );
829
830 assert_eq!(
831 to_html_with_options("a <b.c@d.e>", &mdx)
832 .err()
833 .unwrap().to_string(),
834 "1:7: Unexpected character `@` (U+0040) in member name, expected a name character such as letters, digits, `$`, or `_`; whitespace before attributes; or the end of the tag (note: to create a link in MDX, use `[text](url)`) (markdown-rs:unexpected-character)",
835 "should crash nicely on what might be an email link in member names"
836 );
837
838 assert_eq!(
839 to_html_with_options("a <svg: rect>b</ svg :rect>.", &mdx)?,
840 "<p>a b.</p>",
841 "should support colons in names for local names"
842 );
843
844 assert_eq!(
845 to_html_with_options("a <a:+> c.", &mdx)
846 .err()
847 .unwrap().to_string(),
848 "1:6: Unexpected character `+` (U+002B) before local name, expected a character that can start a name, such as a letter, `$`, or `_` (note: to create a link in MDX, use `[text](url)`) (markdown-rs:unexpected-character)",
849 "should crash on a nonconforming character to start a local name"
850 );
851
852 assert_eq!(
853 to_html_with_options("a <http://example.com>", &mdx)
854 .err()
855 .unwrap().to_string(),
856 "1:9: Unexpected character `/` (U+002F) before local name, expected a character that can start a name, such as a letter, `$`, or `_` (note: to create a link in MDX, use `[text](url)`) (markdown-rs:unexpected-character)",
857 "should crash nicely on what might be a protocol in local names"
858 );
859
860 assert_eq!(
861 to_html_with_options("a <http: >", &mdx)
862 .err()
863 .unwrap().to_string(),
864 "1:10: Unexpected character `>` (U+003E) before local name, expected a character that can start a name, such as a letter, `$`, or `_` (markdown-rs:unexpected-character)",
865 "should crash nicely on what might be a protocol in local names"
866 );
867
868 assert_eq!(
869 to_html_with_options("a <a:b|> c.", &mdx)
870 .err()
871 .unwrap().to_string(),
872 "1:7: Unexpected character `|` (U+007C) in local name, expected a name character such as letters, digits, `$`, or `_`; whitespace before attributes; or the end of the tag (markdown-rs:unexpected-character)",
873 "should crash on a nonconforming character in a local name"
874 );
875
876 assert_eq!(
877 to_html_with_options("a <a..> c.", &mdx)
878 .err()
879 .unwrap().to_string(),
880 "1:6: Unexpected character `.` (U+002E) before member name, expected a character that can start an attribute name, such as a letter, `$`, or `_`; whitespace before attributes; or the end of the tag (markdown-rs:unexpected-character)",
881 "should crash on a nonconforming character to start a member name"
882 );
883
884 assert_eq!(
885 to_html_with_options("a <a.b,> c.", &mdx)
886 .err()
887 .unwrap().to_string(),
888 "1:7: Unexpected character `,` (U+002C) in member name, expected a name character such as letters, digits, `$`, or `_`; whitespace before attributes; or the end of the tag (markdown-rs:unexpected-character)",
889 "should crash on a nonconforming character in a member name"
890 );
891
892 assert_eq!(
893 to_html_with_options("a <a:b .> c.", &mdx)
894 .err()
895 .unwrap().to_string(),
896 "1:8: Unexpected character `.` (U+002E) after local name, expected a character that can start an attribute name, such as a letter, `$`, or `_`; whitespace before attributes; or the end of the tag (markdown-rs:unexpected-character)",
897 "should crash on a nonconforming character after a local name"
898 );
899
900 assert_eq!(
901 to_html_with_options("a <a.b :> c.", &mdx)
902 .err()
903 .unwrap().to_string(),
904 "1:8: Unexpected character `:` (U+003A) after member name, expected a character that can start an attribute name, such as a letter, `$`, or `_`; whitespace before attributes; or the end of the tag (markdown-rs:unexpected-character)",
905 "should crash on a nonconforming character after a member name"
906 );
907
908 assert_eq!(
909 to_html_with_options("a <a => c.", &mdx)
910 .err()
911 .unwrap().to_string(),
912 "1:6: Unexpected character `=` (U+003D) after name, expected a character that can start an attribute name, such as a letter, `$`, or `_`; whitespace before attributes; or the end of the tag (markdown-rs:unexpected-character)",
913 "should crash on a nonconforming character after name"
914 );
915
916 assert_eq!(
917 to_html_with_options("a <b {...props} {...rest}>c</b>.", &mdx)?,
918 "<p>a c.</p>",
919 "should support attribute expressions"
920 );
921
922 assert_eq!(
923 to_html_with_options("a <b {...{\"a\": \"b\"}}>c</b>.", &mdx)?,
924 "<p>a c.</p>",
925 "should support nested balanced braces in attribute expressions"
926 );
927
928 assert_eq!(
929 to_html_with_options("<a{...b}/>.", &mdx)?,
930 "<p>.</p>",
931 "should support attribute expressions directly after a name"
932 );
933
934 assert_eq!(
935 to_html_with_options("<a.b{...c}/>.", &mdx)?,
936 "<p>.</p>",
937 "should support attribute expressions directly after a member name"
938 );
939
940 assert_eq!(
941 to_html_with_options("<a:b{...c}/>.", &mdx)?,
942 "<p>.</p>",
943 "should support attribute expressions directly after a local name"
944 );
945
946 assert_eq!(
947 to_html_with_options("a <b c{...d}/>.", &mdx)?,
948 "<p>a .</p>",
949 "should support attribute expressions directly after boolean attributes"
950 );
951
952 assert_eq!(
953 to_html_with_options("a <b c:d{...e}/>.", &mdx)?,
954 "<p>a .</p>",
955 "should support attribute expressions directly after boolean qualified attributes"
956 );
957
958 assert_eq!(
959 to_html_with_options("a <b a {...props} b>c</b>.", &mdx)?,
960 "<p>a c.</p>",
961 "should support attribute expressions and normal attributes"
962 );
963
964 assert_eq!(
965 to_html_with_options("a <b c d=\"d\"\t\tefg=\"e\">c</b>.", &mdx)?,
966 "<p>a c.</p>",
967 "should support attributes"
968 );
969
970 assert_eq!(
971 to_html_with_options("a <b {...p}~>c</b>.", &mdx)
972 .err()
973 .unwrap().to_string(),
974 "1:12: Unexpected character `~` (U+007E) before attribute name, expected a character that can start an attribute name, such as a letter, `$`, or `_`; whitespace before attributes; or the end of the tag (markdown-rs:unexpected-character)",
975 "should crash on a nonconforming character before an attribute name"
976 );
977
978 assert_eq!(
979 to_html_with_options("a <b {...", &mdx)
980 .err()
981 .unwrap().to_string(),
982 "1:10: Unexpected end of file in expression, expected a corresponding closing brace for `{` (markdown-rs:unexpected-eof)",
983 "should crash on a missing closing brace in attribute expression"
984 );
985
986 assert_eq!(
987 to_html_with_options("a <a b@> c.", &mdx)
988 .err()
989 .unwrap().to_string(),
990 "1:7: Unexpected character `@` (U+0040) in attribute name, expected an attribute name character such as letters, digits, `$`, or `_`; `=` to initialize a value; whitespace before attributes; or the end of the tag (markdown-rs:unexpected-character)",
991 "should crash on a nonconforming character in attribute name"
992 );
993
994 assert_eq!(
995 to_html_with_options("a <b xml :\tlang\n= \"de-CH\" foo:bar>c</b>.", &mdx)?,
996 "<p>a c.</p>",
997 "should support prefixed attributes"
998 );
999
1000 assert_eq!(
1001 to_html_with_options("a <b a b : c d : e = \"f\" g/>.", &mdx)?,
1002 "<p>a .</p>",
1003 "should support prefixed and normal attributes"
1004 );
1005
1006 assert_eq!(
1007 to_html_with_options("a <a b 1> c.", &mdx)
1008 .err()
1009 .unwrap().to_string(),
1010 "1:8: Unexpected character `1` (U+0031) after attribute name, expected a character that can start an attribute name, such as a letter, `$`, or `_`; `=` to initialize a value; or the end of the tag (markdown-rs:unexpected-character)",
1011 "should crash on a nonconforming character after an attribute name"
1012 );
1013
1014 assert_eq!(
1015 to_html_with_options("a <a b:#> c.", &mdx)
1016 .err()
1017 .unwrap().to_string(),
1018 "1:8: Unexpected character `#` (U+0023) before local attribute name, expected a character that can start an attribute name, such as a letter, `$`, or `_`; `=` to initialize a value; or the end of the tag (markdown-rs:unexpected-character)",
1019 "should crash on a nonconforming character to start a local attribute name"
1020 );
1021
1022 assert_eq!(
1023 to_html_with_options("a <a b:c%> c.", &mdx)
1024 .err()
1025 .unwrap().to_string(),
1026 "1:9: Unexpected character `%` (U+0025) in local attribute name, expected an attribute name character such as letters, digits, `$`, or `_`; `=` to initialize a value; whitespace before attributes; or the end of the tag (markdown-rs:unexpected-character)",
1027 "should crash on a nonconforming character in a local attribute name"
1028 );
1029
1030 assert_eq!(
1031 to_html_with_options("a <a b:c ^> c.", &mdx)
1032 .err()
1033 .unwrap().to_string(),
1034 "1:10: Unexpected character `^` (U+005E) after local attribute name, expected a character that can start an attribute name, such as a letter, `$`, or `_`; `=` to initialize a value; or the end of the tag (markdown-rs:unexpected-character)",
1035 "should crash on a nonconforming character after a local attribute name"
1036 );
1037
1038 assert_eq!(
1039 to_html_with_options("a <b c={1 + 1}>c</b>.", &mdx)?,
1040 "<p>a c.</p>",
1041 "should support attribute value expressions"
1042 );
1043
1044 assert_eq!(
1045 to_html_with_options("a <b c={1 + ({a: 1}).a}>c</b>.", &mdx)?,
1046 "<p>a c.</p>",
1047 "should support nested balanced braces in attribute value expressions"
1048 );
1049
1050 assert_eq!(
1051 to_html_with_options("a <a b=``> c.", &mdx)
1052 .err()
1053 .unwrap().to_string(),
1054 "1:8: Unexpected character `` ` `` (U+0060) before attribute value, expected a character that can start an attribute value, such as `\"`, `'`, or `{` (markdown-rs:unexpected-character)",
1055 "should crash on a nonconforming character before an attribute value"
1056 );
1057
1058 assert_eq!(
1059 to_html_with_options("a <a b=<c />> d.", &mdx)
1060 .err()
1061 .unwrap().to_string(),
1062 "1:8: Unexpected character `<` (U+003C) before attribute value, expected a character that can start an attribute value, such as `\"`, `'`, or `{` (note: to use an element or fragment as a prop value in MDX, use `{<element />}`) (markdown-rs:unexpected-character)",
1063 "should crash nicely on what might be a fragment, element as prop value"
1064 );
1065
1066 assert_eq!(
1067 to_html_with_options("a <a b=\"> c.", &mdx)
1068 .err()
1069 .unwrap().to_string(),
1070 "1:13: Unexpected end of file in attribute value, expected a corresponding closing quote `\"` (U+0022) (markdown-rs:unexpected-eof)",
1071 "should crash on a missing closing quote in double quoted attribute value"
1072 );
1073
1074 assert_eq!(
1075 to_html_with_options("a <a b=\"> c.", &mdx)
1076 .err()
1077 .unwrap().to_string(),
1078 "1:13: Unexpected end of file in attribute value, expected a corresponding closing quote `\"` (U+0022) (markdown-rs:unexpected-eof)",
1079 "should crash on a missing closing quote in single quoted attribute value"
1080 );
1081
1082 assert_eq!(
1083 to_html_with_options("a <a b={> c.", &mdx)
1084 .err()
1085 .unwrap().to_string(),
1086 "1:13: Unexpected end of file in expression, expected a corresponding closing brace for `{` (markdown-rs:unexpected-eof)",
1087 "should crash on a missing closing brace in an attribute value expression"
1088 );
1089
1090 assert_eq!(
1091 to_html_with_options("a <a b=\"\"*> c.", &mdx)
1092 .err()
1093 .unwrap().to_string(),
1094 "1:10: Unexpected character `*` (U+002A) before attribute name, expected a character that can start an attribute name, such as a letter, `$`, or `_`; whitespace before attributes; or the end of the tag (markdown-rs:unexpected-character)",
1095 "should crash on a nonconforming character after an attribute value"
1096 );
1097
1098 assert_eq!(
1099 to_html_with_options("<a b=\"\"c/>.", &mdx)?,
1100 "<p>.</p>",
1101 "should support an attribute directly after a value"
1102 );
1103
1104 assert_eq!(
1105 to_html_with_options("<a{...b}c/>.", &mdx)?,
1106 "<p>.</p>",
1107 "should support an attribute directly after an attribute expression"
1108 );
1109
1110 assert_eq!(
1111 to_html_with_options("a <a/b> c.", &mdx)
1112 .err()
1113 .unwrap().to_string(),
1114 "1:6: Unexpected character `b` (U+0062) after self-closing slash, expected `>` to end the tag (markdown-rs:unexpected-character)",
1115 "should crash on a nonconforming character after a self-closing slash"
1116 );
1117
1118 assert_eq!(
1119 to_html_with_options("<a/ \t>.", &mdx)?,
1120 "<p>.</p>",
1121 "should support whitespace directly after closing slash"
1122 );
1123
1124 assert_eq!(
1125 to_html_with_options("a > c.", &mdx).err(),
1126 None,
1127 "should *not* crash on closing angle in text"
1128 );
1129
1130 assert_eq!(
1131 to_html_with_options("a <>`<`</> c.", &mdx).err(),
1132 None,
1133 "should *not* crash on opening angle in tick code in an element"
1134 );
1135
1136 assert_eq!(
1137 to_html_with_options("a <>`` ``` ``</>", &mdx).err(),
1138 None,
1139 "should *not* crash on ticks in tick code in an element"
1140 );
1141
1142 assert_eq!(
1143 to_html_with_options("a </> c.", &mdx)?,
1144 "<p>a c.</p>",
1145 "should support a closing tag w/o open elements"
1146 );
1147
1148 assert_eq!(
1149 to_html_with_options("a <></b>", &mdx)?,
1150 "<p>a </p>",
1151 "should support mismatched tags (1)"
1152 );
1153 assert_eq!(
1154 to_html_with_options("a <b></>", &mdx)?,
1155 "<p>a </p>",
1156 "should support mismatched tags (2)"
1157 );
1158 assert_eq!(
1159 to_html_with_options("a <a.b></a>", &mdx)?,
1160 "<p>a </p>",
1161 "should support mismatched tags (3)"
1162 );
1163 assert_eq!(
1164 to_html_with_options("a <a></a.b>", &mdx)?,
1165 "<p>a </p>",
1166 "should support mismatched tags (4)"
1167 );
1168 assert_eq!(
1169 to_html_with_options("a <a.b></a.c>", &mdx)?,
1170 "<p>a </p>",
1171 "should support mismatched tags (5)"
1172 );
1173 assert_eq!(
1174 to_html_with_options("a <a:b></a>", &mdx)?,
1175 "<p>a </p>",
1176 "should support mismatched tags (6)"
1177 );
1178 assert_eq!(
1179 to_html_with_options("a <a></a:b>", &mdx)?,
1180 "<p>a </p>",
1181 "should support mismatched tags (7)"
1182 );
1183 assert_eq!(
1184 to_html_with_options("a <a:b></a:c>", &mdx)?,
1185 "<p>a </p>",
1186 "should support mismatched tags (8)"
1187 );
1188 assert_eq!(
1189 to_html_with_options("a <a:b></a.b>", &mdx)?,
1190 "<p>a </p>",
1191 "should support mismatched tags (9)"
1192 );
1193
1194 assert_eq!(
1195 to_html_with_options("a <a>b</a/>", &mdx)?,
1196 "<p>a b</p>",
1197 "should support a closing self-closing tag"
1198 );
1199
1200 assert_eq!(
1201 to_html_with_options("a <a>b</a b>", &mdx)?,
1202 "<p>a b</p>",
1203 "should support a closing tag w/ attributes"
1204 );
1205
1206 assert_eq!(
1207 to_html_with_options("a <>b <>c</> d</>.", &mdx)?,
1208 "<p>a b c d.</p>",
1209 "should support nested tags"
1210 );
1211
1212 assert_eq!(
1213 to_html_with_options(
1214 "<x y=\"Character references can be used: ", ', <, >, {, and }, they can be named, decimal, or hexadecimal: © ≠ 𝌆\" />.",
1215 &mdx
1216 )?,
1217 "<p>.</p>",
1218 "should support character references in attribute values"
1219 );
1220
1221 assert_eq!(
1222 to_html_with_options(
1223 "<x>Character references can be used: ", ', <, >, {, and }, they can be named, decimal, or hexadecimal: © ≠ 𝌆</x>.",
1224 &mdx
1225 )?,
1226 "<p>Character references can be used: ", ', <, >, {, and }, they can be named, decimal, or hexadecimal: © ≠ 𝌆.</p>",
1227 "should support character references in text"
1228 );
1229
1230 assert_eq!(
1231 to_html_with_options("<x />.", &mdx)?,
1232 "<p>.</p>",
1233 "should support as text if the closing tag is not the last thing"
1234 );
1235
1236 assert_eq!(
1237 to_html_with_options("a <x />", &mdx)?,
1238 "<p>a </p>",
1239 "should support as text if the opening is not the first thing"
1240 );
1241
1242 assert_eq!(
1243 to_html_with_options("a *open <b> close* </b> c.", &mdx)?,
1244 "<p>a <em>open close</em> c.</p>",
1245 "should not care about precedence between attention (emphasis)"
1246 );
1247
1248 assert_eq!(
1249 to_html_with_options("a **open <b> close** </b> c.", &mdx)?,
1250 "<p>a <strong>open close</strong> c.</p>",
1251 "should not care about precedence between attention (strong)"
1252 );
1253
1254 assert_eq!(
1255 to_html_with_options("a [open <b> close](c) </b> d.", &mdx)?,
1256 "<p>a <a href=\"c\">open close</a> d.</p>",
1257 "should not care about precedence between label (link)"
1258 );
1259
1260 assert_eq!(
1261 to_html_with_options("a  </b> d.", &mdx)?,
1262 "<p>a <img src=\"c\" alt=\"open close\" /> d.</p>",
1263 "should not care about precedence between label (image)"
1264 );
1265
1266 assert_eq!(
1267 to_html_with_options("> a <b>\n> c </b> d.", &mdx)?,
1268 "<blockquote>\n<p>a \nc d.</p>\n</blockquote>",
1269 "should support line endings in elements"
1270 );
1271
1272 assert_eq!(
1273 to_html_with_options("> a <b c=\"d\ne\" /> f", &mdx)?,
1274 "<blockquote>\n<p>a f</p>\n</blockquote>",
1275 "should support line endings in attribute values"
1276 );
1277
1278 assert_eq!(
1279 to_html_with_options("> a <b c={d\ne} /> f", &mdx)?,
1280 "<blockquote>\n<p>a f</p>\n</blockquote>",
1281 "should support line endings in attribute value expressions"
1282 );
1283
1284 assert_eq!(
1285 to_html_with_options("> a <b {c\nd} /> e", &mdx)?,
1286 "<blockquote>\n<p>a e</p>\n</blockquote>",
1287 "should support line endings in attribute expressions"
1288 );
1289
1290 assert_eq!(
1291 to_html_with_options("> a <b\n/> c", &mdx)?,
1292 "<blockquote>\n<p>a c</p>\n</blockquote>",
1293 "should support lazy text (1)"
1294 );
1295
1296 assert_eq!(
1297 to_html_with_options("> a <b c='\nd'/> e", &mdx)?,
1298 "<blockquote>\n<p>a e</p>\n</blockquote>",
1299 "should support lazy text (2)"
1300 );
1301
1302 assert_eq!(
1303 to_html_with_options("> a <b c='d\n'/> e", &mdx)?,
1304 "<blockquote>\n<p>a e</p>\n</blockquote>",
1305 "should support lazy text (3)"
1306 );
1307
1308 assert_eq!(
1309 to_html_with_options("> a <b c='d\ne'/> f", &mdx)?,
1310 "<blockquote>\n<p>a f</p>\n</blockquote>",
1311 "should support lazy text (4)"
1312 );
1313
1314 assert_eq!(
1315 to_html_with_options("> a <b c={d\ne}/> f", &mdx)?,
1316 "<blockquote>\n<p>a f</p>\n</blockquote>",
1317 "should support lazy text (5)"
1318 );
1319
1320 assert_eq!(
1321 to_html_with_options("1 < 3", &mdx)?,
1322 "<p>1 < 3</p>",
1323 "should allow `<` followed by markdown whitespace as text in markdown"
1324 );
1325
1326 Ok(())
1327}