Markdown parser fork with extended syntax for personal use.
at main 537 lines 17 kB view raw
1use markdown::{ 2 mdast::{Image, Link, Node, Paragraph, Root, Text}, 3 message, to_html, to_html_with_options, to_mdast, 4 unist::Position, 5 CompileOptions, Options, 6}; 7use pretty_assertions::assert_eq; 8 9#[test] 10fn link_resource() -> Result<(), message::Message> { 11 let danger = Options { 12 compile: CompileOptions { 13 allow_dangerous_html: true, 14 allow_dangerous_protocol: true, 15 ..Default::default() 16 }, 17 ..Default::default() 18 }; 19 20 assert_eq!( 21 to_html("[link](/uri \"title\")"), 22 "<p><a href=\"/uri\" title=\"title\">link</a></p>", 23 "should support links" 24 ); 25 26 assert_eq!( 27 to_html("[link](/uri)"), 28 "<p><a href=\"/uri\">link</a></p>", 29 "should support links w/o title" 30 ); 31 32 assert_eq!( 33 to_html("[link]()"), 34 "<p><a href=\"\">link</a></p>", 35 "should support links w/o destination" 36 ); 37 38 assert_eq!( 39 to_html("[link](<>)"), 40 "<p><a href=\"\">link</a></p>", 41 "should support links w/ empty enclosed destination" 42 ); 43 44 assert_eq!( 45 to_html("[link](/my uri)"), 46 "<p>[link](/my uri)</p>", 47 "should not support links w/ spaces in destination" 48 ); 49 50 assert_eq!( 51 to_html("[link](</my uri>)"), 52 "<p><a href=\"/my%20uri\">link</a></p>", 53 "should support links w/ spaces in enclosed destination" 54 ); 55 56 assert_eq!( 57 to_html("[link](foo\nbar)"), 58 "<p>[link](foo\nbar)</p>", 59 "should not support links w/ line endings in destination" 60 ); 61 62 assert_eq!( 63 to_html_with_options("[link](<foo\nbar>)", &danger)?, 64 "<p>[link](<foo\nbar>)</p>", 65 "should not support links w/ line endings in enclosed destination" 66 ); 67 68 assert_eq!( 69 to_html("[a](<b)c>)"), 70 "<p><a href=\"b)c\">a</a></p>", 71 "should support links w/ closing parens in destination" 72 ); 73 74 assert_eq!( 75 to_html("[link](<foo\\>)"), 76 "<p>[link](&lt;foo&gt;)</p>", 77 "should not support links w/ enclosed destinations w/o end" 78 ); 79 80 assert_eq!( 81 to_html_with_options("[a](<b)c\n[a](<b)c>\n[a](<b>c)", &danger)?, 82 "<p>[a](&lt;b)c\n[a](&lt;b)c&gt;\n[a](<b>c)</p>", 83 "should not support links w/ unmatched enclosed destinations" 84 ); 85 86 assert_eq!( 87 to_html("[link](\\(foo\\))"), 88 "<p><a href=\"(foo)\">link</a></p>", 89 "should support links w/ destinations w/ escaped parens" 90 ); 91 92 assert_eq!( 93 to_html("[link](foo(and(bar)))"), 94 "<p><a href=\"foo(and(bar))\">link</a></p>", 95 "should support links w/ destinations w/ balanced parens" 96 ); 97 98 assert_eq!( 99 to_html("[link](foo\\(and\\(bar\\))"), 100 "<p><a href=\"foo(and(bar)\">link</a></p>", 101 "should support links w/ destinations w/ escaped parens" 102 ); 103 104 assert_eq!( 105 to_html("[link](<foo(and(bar)>)"), 106 "<p><a href=\"foo(and(bar)\">link</a></p>", 107 "should support links w/ enclosed destinations w/ parens" 108 ); 109 110 assert_eq!( 111 to_html_with_options("[link](foo\\)\\:)", &danger)?, 112 "<p><a href=\"foo):\">link</a></p>", 113 "should support links w/ escapes in destinations" 114 ); 115 116 assert_eq!( 117 to_html("[link](#fragment)"), 118 "<p><a href=\"#fragment\">link</a></p>", 119 "should support links w/ destinations to fragments" 120 ); 121 122 assert_eq!( 123 to_html("[link](http://example.com#fragment)"), 124 "<p><a href=\"http://example.com#fragment\">link</a></p>", 125 "should support links w/ destinations to URLs w/ fragments" 126 ); 127 128 assert_eq!( 129 to_html("[link](http://example.com?foo=3#frag)"), 130 "<p><a href=\"http://example.com?foo=3#frag\">link</a></p>", 131 "should support links w/ destinations to URLs w/ search and fragments" 132 ); 133 134 assert_eq!( 135 to_html("[link](foo\\bar)"), 136 "<p><a href=\"foo%5Cbar\">link</a></p>", 137 "should not support non-punctuation character escapes in links" 138 ); 139 140 assert_eq!( 141 to_html("[link](foo%20b&auml;)"), 142 "<p><a href=\"foo%20b%C3%A4\">link</a></p>", 143 "should support character references in links" 144 ); 145 146 assert_eq!( 147 to_html("[link](\"title\")"), 148 "<p><a href=\"%22title%22\">link</a></p>", 149 "should not support links w/ only a title" 150 ); 151 152 assert_eq!( 153 to_html("[link](/url \"title\")"), 154 "<p><a href=\"/url\" title=\"title\">link</a></p>", 155 "should support titles w/ double quotes" 156 ); 157 158 assert_eq!( 159 to_html("[link](/url 'title')"), 160 "<p><a href=\"/url\" title=\"title\">link</a></p>", 161 "should support titles w/ single quotes" 162 ); 163 164 assert_eq!( 165 to_html("[link](/url (title))"), 166 "<p><a href=\"/url\" title=\"title\">link</a></p>", 167 "should support titles w/ parens" 168 ); 169 170 assert_eq!( 171 to_html("[link](/url \"title \\\"&quot;\")"), 172 "<p><a href=\"/url\" title=\"title &quot;&quot;\">link</a></p>", 173 "should support character references and escapes in titles" 174 ); 175 176 assert_eq!( 177 to_html("[link](/url \"title\")"), 178 "<p><a href=\"/url%C2%A0%22title%22\">link</a></p>", 179 "should not support unicode whitespace between destination and title" 180 ); 181 182 assert_eq!( 183 to_html("[link](/url \"title \"and\" title\")"), 184 "<p>[link](/url &quot;title &quot;and&quot; title&quot;)</p>", 185 "should not support nested balanced quotes in title" 186 ); 187 188 assert_eq!( 189 to_html("[link](/url 'title \"and\" title')"), 190 "<p><a href=\"/url\" title=\"title &quot;and&quot; title\">link</a></p>", 191 "should support the other quotes in titles" 192 ); 193 194 assert_eq!( 195 to_html("[link]( /uri\n \"title\" )"), 196 "<p><a href=\"/uri\" title=\"title\">link</a></p>", 197 "should support whitespace around destination and title (1)" 198 ); 199 200 assert_eq!( 201 to_html("[link](\t\n/uri \"title\")"), 202 "<p><a href=\"/uri\" title=\"title\">link</a></p>", 203 "should support whitespace around destination and title (2)" 204 ); 205 206 assert_eq!( 207 to_html("[link](/uri \"title\"\t\n)"), 208 "<p><a href=\"/uri\" title=\"title\">link</a></p>", 209 "should support whitespace around destination and title (3)" 210 ); 211 212 assert_eq!( 213 to_html("[link] (/uri)"), 214 "<p>[link] (/uri)</p>", 215 "should not support whitespace between label and resource" 216 ); 217 218 assert_eq!( 219 to_html("[link [foo [bar]]](/uri)"), 220 "<p><a href=\"/uri\">link [foo [bar]]</a></p>", 221 "should support balanced brackets" 222 ); 223 224 assert_eq!( 225 to_html("[link] bar](/uri)"), 226 "<p>[link] bar](/uri)</p>", 227 "should not support unbalanced brackets (1)" 228 ); 229 230 assert_eq!( 231 to_html("[link [bar](/uri)"), 232 "<p>[link <a href=\"/uri\">bar</a></p>", 233 "should not support unbalanced brackets (2)" 234 ); 235 236 assert_eq!( 237 to_html("[link \\[bar](/uri)"), 238 "<p><a href=\"/uri\">link [bar</a></p>", 239 "should support characer escapes" 240 ); 241 242 assert_eq!( 243 to_html("[link *foo **bar** `#`*](/uri)"), 244 "<p><a href=\"/uri\">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>", 245 "should support content" 246 ); 247 248 assert_eq!( 249 to_html("[![moon](moon.jpg)](/uri)"), 250 "<p><a href=\"/uri\"><img src=\"moon.jpg\" alt=\"moon\" /></a></p>", 251 "should support an image as content" 252 ); 253 254 assert_eq!( 255 to_html("[foo [bar](/uri)](/uri)"), 256 "<p>[foo <a href=\"/uri\">bar</a>](/uri)</p>", 257 "should not support links in links (1)" 258 ); 259 260 assert_eq!( 261 to_html("[foo *[bar [baz](/uri)](/uri)*](/uri)"), 262 "<p>[foo <em>[bar <a href=\"/uri\">baz</a>](/uri)</em>](/uri)</p>", 263 "should not support links in links (2)" 264 ); 265 266 assert_eq!( 267 to_html("![[[foo](uri1)](uri2)](uri3)"), 268 "<p><img src=\"uri3\" alt=\"[foo](uri2)\" /></p>", 269 "should not support links in links (3)" 270 ); 271 272 assert_eq!( 273 to_html("*[foo*](/uri)"), 274 "<p>*<a href=\"/uri\">foo*</a></p>", 275 "should prefer links over emphasis (1)" 276 ); 277 278 assert_eq!( 279 to_html("[foo *bar](baz*)"), 280 "<p><a href=\"baz*\">foo *bar</a></p>", 281 "should prefer links over emphasis (2)" 282 ); 283 284 assert_eq!( 285 to_html_with_options("[foo <bar attr=\"](baz)\">", &danger)?, 286 "<p>[foo <bar attr=\"](baz)\"></p>", 287 "should prefer HTML over links" 288 ); 289 290 assert_eq!( 291 to_html("[foo`](/uri)`"), 292 "<p>[foo<code>](/uri)</code></p>", 293 "should prefer code over links" 294 ); 295 296 assert_eq!( 297 to_html("[foo<http://example.com/?search=](uri)>"), 298 "<p>[foo<a href=\"http://example.com/?search=%5D(uri)\">http://example.com/?search=](uri)</a></p>", 299 "should prefer autolinks over links" 300 ); 301 302 assert_eq!( 303 to_html("[foo<http://example.com/?search=](uri)>"), 304 "<p>[foo<a href=\"http://example.com/?search=%5D(uri)\">http://example.com/?search=](uri)</a></p>", 305 "should prefer autolinks over links" 306 ); 307 308 // Extra 309 assert_eq!( 310 to_html("[]()"), 311 "<p><a href=\"\"></a></p>", 312 "should support an empty link" 313 ); 314 315 // See: <https://github.com/commonmark/commonmark.js/issues/192> 316 assert_eq!( 317 to_html("[](<> \"\")"), 318 "<p><a href=\"\"></a></p>", 319 "should ignore an empty title" 320 ); 321 322 assert_eq!( 323 to_html_with_options("[a](<b>\"c\")", &danger)?, 324 "<p>[a](<b>&quot;c&quot;)</p>", 325 "should require whitespace between enclosed destination and title" 326 ); 327 328 assert_eq!( 329 to_html("[](<"), 330 "<p>[](&lt;</p>", 331 "should not support an unclosed enclosed destination" 332 ); 333 334 assert_eq!( 335 to_html("[]("), 336 "<p>[](</p>", 337 "should not support an unclosed destination" 338 ); 339 340 assert_eq!( 341 to_html("[](\\<)"), 342 "<p><a href=\"%3C\"></a></p>", 343 "should support unenclosed link destination starting w/ escapes" 344 ); 345 346 assert_eq!( 347 to_html("[](<\\<>)"), 348 "<p><a href=\"%3C\"></a></p>", 349 "should support enclosed link destination starting w/ escapes" 350 ); 351 352 assert_eq!( 353 to_html("[](\\"), 354 "<p>[](\\</p>", 355 "should not support unenclosed link destination starting w/ an incorrect escape" 356 ); 357 358 assert_eq!( 359 to_html("[](<\\"), 360 "<p>[](&lt;\\</p>", 361 "should not support enclosed link destination starting w/ an incorrect escape" 362 ); 363 364 assert_eq!( 365 to_html("[](a \""), 366 "<p>[](a &quot;</p>", 367 "should not support an eof in a link title (1)" 368 ); 369 370 assert_eq!( 371 to_html("[](a '"), 372 "<p>[](a '</p>", 373 "should not support an eof in a link title (2)" 374 ); 375 376 assert_eq!( 377 to_html("[](a ("), 378 "<p>[](a (</p>", 379 "should not support an eof in a link title (3)" 380 ); 381 382 assert_eq!( 383 to_html("[](a \"\\"), 384 "<p>[](a &quot;\\</p>", 385 "should not support an eof in a link title escape (1)" 386 ); 387 388 assert_eq!( 389 to_html("[](a '\\"), 390 "<p>[](a '\\</p>", 391 "should not support an eof in a link title escape (2)" 392 ); 393 394 assert_eq!( 395 to_html("[](a (\\"), 396 "<p>[](a (\\</p>", 397 "should not support an eof in a link title escape (3)" 398 ); 399 400 assert_eq!( 401 to_html("[](a \"\\\"\")"), 402 "<p><a href=\"a\" title=\"&quot;\"></a></p>", 403 "should support a character escape to start a link title (1)" 404 ); 405 406 assert_eq!( 407 to_html("[](a '\\'')"), 408 "<p><a href=\"a\" title=\"\'\"></a></p>", 409 "should support a character escape to start a link title (2)" 410 ); 411 412 assert_eq!( 413 to_html("[](a (\\)))"), 414 "<p><a href=\"a\" title=\")\"></a></p>", 415 "should support a character escape to start a link title (3)" 416 ); 417 418 assert_eq!( 419 to_html("[&amp;&copy;&](example.com/&amp;&copy;& \"&amp;&copy;&\")"), 420 "<p><a href=\"example.com/&amp;%C2%A9&amp;\" title=\"&amp;©&amp;\">&amp;©&amp;</a></p>", 421 "should support character references in links" 422 ); 423 424 assert_eq!( 425 to_html("[a](1())"), 426 "<p><a href=\"1()\">a</a></p>", 427 "should support 1 set of parens" 428 ); 429 430 assert_eq!( 431 to_html("[a](1(2()))"), 432 "<p><a href=\"1(2())\">a</a></p>", 433 "should support 2 sets of parens" 434 ); 435 436 assert_eq!( 437 to_html( 438 "[a](1(2(3(4(5(6(7(8(9(10(11(12(13(14(15(16(17(18(19(20(21(22(23(24(25(26(27(28(29(30(31(32()))))))))))))))))))))))))))))))))"), 439 "<p><a href=\"1(2(3(4(5(6(7(8(9(10(11(12(13(14(15(16(17(18(19(20(21(22(23(24(25(26(27(28(29(30(31(32())))))))))))))))))))))))))))))))\">a</a></p>", 440 "should support 32 sets of parens" 441 ); 442 443 assert_eq!( 444 to_html( 445 "[a](1(2(3(4(5(6(7(8(9(10(11(12(13(14(15(16(17(18(19(20(21(22(23(24(25(26(27(28(29(30(31(32(33())))))))))))))))))))))))))))))))))"), 446 "<p>[a](1(2(3(4(5(6(7(8(9(10(11(12(13(14(15(16(17(18(19(20(21(22(23(24(25(26(27(28(29(30(31(32(33())))))))))))))))))))))))))))))))))</p>", 447 "should not support 33 or more sets of parens" 448 ); 449 450 assert_eq!( 451 to_html("[a](b \"\n c\")"), 452 "<p><a href=\"b\" title=\"\nc\">a</a></p>", 453 "should support an eol at the start of a title" 454 ); 455 456 assert_eq!( 457 to_html("[a](b( \"c\")"), 458 "<p>[a](b( &quot;c&quot;)</p>", 459 "should not support whitespace when unbalanced in a raw destination" 460 ); 461 462 assert_eq!( 463 to_html("[a](\0)"), 464 "<p><a href=\"%EF%BF%BD\">a</a></p>", 465 "should support a single NUL character as a link resource" 466 ); 467 468 assert_eq!( 469 to_mdast( 470 "a [alpha]() b [bravo](charlie 'delta') c.", 471 &Default::default() 472 )?, 473 Node::Root(Root { 474 children: vec![Node::Paragraph(Paragraph { 475 children: vec![ 476 Node::Text(Text { 477 value: "a ".into(), 478 position: Some(Position::new(1, 1, 0, 1, 3, 2)) 479 }), 480 Node::Link(Link { 481 url: String::new(), 482 title: None, 483 children: vec![Node::Text(Text { 484 value: "alpha".into(), 485 position: Some(Position::new(1, 4, 3, 1, 9, 8)) 486 }),], 487 position: Some(Position::new(1, 3, 2, 1, 12, 11)) 488 }), 489 Node::Text(Text { 490 value: " b ".into(), 491 position: Some(Position::new(1, 12, 11, 1, 15, 14)) 492 }), 493 Node::Link(Link { 494 url: "charlie".into(), 495 title: Some("delta".into()), 496 children: vec![Node::Text(Text { 497 value: "bravo".into(), 498 position: Some(Position::new(1, 16, 15, 1, 21, 20)) 499 }),], 500 position: Some(Position::new(1, 15, 14, 1, 39, 38)) 501 }), 502 Node::Text(Text { 503 value: " c.".into(), 504 position: Some(Position::new(1, 39, 38, 1, 42, 41)) 505 }) 506 ], 507 position: Some(Position::new(1, 1, 0, 1, 42, 41)) 508 })], 509 position: Some(Position::new(1, 1, 0, 1, 42, 41)) 510 }), 511 "should support link (resource) as `Link`s in mdast" 512 ); 513 514 assert_eq!( 515 to_mdast("[![name](image)](url)", &Default::default())?, 516 Node::Root(Root { 517 children: vec![Node::Paragraph(Paragraph { 518 children: vec![Node::Link(Link { 519 children: vec![Node::Image(Image { 520 alt: "name".into(), 521 url: "image".into(), 522 title: None, 523 position: Some(Position::new(1, 2, 1, 1, 16, 15)), 524 }),], 525 url: "url".into(), 526 title: None, 527 position: Some(Position::new(1, 1, 0, 1, 22, 21)), 528 }),], 529 position: Some(Position::new(1, 1, 0, 1, 22, 21)), 530 }),], 531 position: Some(Position::new(1, 1, 0, 1, 22, 21)) 532 }), 533 "should support nested links in mdast" 534 ); 535 536 Ok(()) 537}