Markdown parser fork with extended syntax for personal use.
at hack 343 lines 11 kB view raw
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>&lt;a /&gt;\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}