Markdown parser fork with extended syntax for personal use.
1#![allow(clippy::needless_raw_string_hashes)]
2
3// To do: clippy introduced this in 1.72 but breaks when it fixes it.
4// Remove when solved.
5
6use markdown::{
7 mdast::{Delete, Node, Paragraph, Root, Text},
8 message, to_html, to_html_with_options, to_mdast,
9 unist::Position,
10 Options, ParseOptions,
11};
12use pretty_assertions::assert_eq;
13
14#[test]
15fn gfm_strikethrough() -> Result<(), message::Message> {
16 assert_eq!(
17 to_html("a ~b~ c"),
18 "<p>a ~b~ c</p>",
19 "should ignore strikethrough by default"
20 );
21
22 assert_eq!(
23 to_html_with_options("a ~b~", &Options::gfm())?,
24 "<p>a <del>b</del></p>",
25 "should support strikethrough w/ one tilde"
26 );
27
28 assert_eq!(
29 to_html_with_options("a ~~b~~", &Options::gfm())?,
30 "<p>a <del>b</del></p>",
31 "should support strikethrough w/ two tildes"
32 );
33
34 assert_eq!(
35 to_html_with_options("a ~~~b~~~", &Options::gfm())?,
36 "<p>a ~~~b~~~</p>",
37 "should not support strikethrough w/ three tildes"
38 );
39
40 assert_eq!(
41 to_html_with_options("a \\~~~b~~ c", &Options::gfm())?,
42 "<p>a ~<del>b</del> c</p>",
43 "should support strikethrough after an escaped tilde"
44 );
45
46 assert_eq!(
47 to_html_with_options("a ~~b ~~c~~ d~~ e", &Options::gfm())?,
48 "<p>a <del>b <del>c</del> d</del> e</p>",
49 "should support nested strikethrough"
50 );
51
52 assert_eq!(
53 to_html_with_options("a ~-1~ b", &Options::gfm())?,
54 "<p>a <del>-1</del> b</p>",
55 "should open if preceded by whitespace and followed by punctuation"
56 );
57
58 assert_eq!(
59 to_html_with_options("a ~b.~ c", &Options::gfm())?,
60 "<p>a <del>b.</del> c</p>",
61 "should close if preceded by punctuation and followed by whitespace"
62 );
63
64 assert_eq!(
65 to_html_with_options("~b.~.", &Options::gfm())?,
66 "<p><del>b.</del>.</p>",
67 "should close if preceded and followed by punctuation"
68 );
69
70 assert_eq!(
71 to_html_with_options(
72 r###"
73# Balanced
74
75a ~one~ b
76
77a ~~two~~ b
78
79a ~~~three~~~ b
80
81a ~~~~four~~~~ b
82
83# Unbalanced
84
85a ~one/two~~ b
86
87a ~one/three~~~ b
88
89a ~one/four~~~~ b
90
91***
92
93a ~~two/one~ b
94
95a ~~two/three~~~ b
96
97a ~~two/four~~~~ b
98
99***
100
101a ~~~three/one~ b
102
103a ~~~three/two~~ b
104
105a ~~~three/four~~~~ b
106
107***
108
109a ~~~~four/one~ b
110
111a ~~~~four/two~~ b
112
113a ~~~~four/three~~~ b
114
115## Multiple
116
117a ~one b one~ c one~ d
118
119a ~one b two~~ c one~ d
120
121a ~one b one~ c two~~ d
122
123a ~~two b two~~ c two~~ d
124
125a ~~two b one~ c two~~ d
126
127a ~~two b two~~ c one~ d
128"###,
129 &Options::gfm()
130 )?,
131 r###"<h1>Balanced</h1>
132<p>a <del>one</del> b</p>
133<p>a <del>two</del> b</p>
134<p>a ~~~three~~~ b</p>
135<p>a ~~~~four~~~~ b</p>
136<h1>Unbalanced</h1>
137<p>a ~one/two~~ b</p>
138<p>a ~one/three~~~ b</p>
139<p>a ~one/four~~~~ b</p>
140<hr />
141<p>a ~~two/one~ b</p>
142<p>a ~~two/three~~~ b</p>
143<p>a ~~two/four~~~~ b</p>
144<hr />
145<p>a ~~~three/one~ b</p>
146<p>a ~~~three/two~~ b</p>
147<p>a ~~~three/four~~~~ b</p>
148<hr />
149<p>a ~~~~four/one~ b</p>
150<p>a ~~~~four/two~~ b</p>
151<p>a ~~~~four/three~~~ b</p>
152<h2>Multiple</h2>
153<p>a <del>one b one</del> c one~ d</p>
154<p>a <del>one b two~~ c one</del> d</p>
155<p>a <del>one b one</del> c two~~ d</p>
156<p>a <del>two b two</del> c two~~ d</p>
157<p>a <del>two b one~ c two</del> d</p>
158<p>a <del>two b two</del> c one~ d</p>
159"###,
160 "should handle balance like GitHub"
161 );
162
163 assert_eq!(
164 to_html_with_options(
165 r###"
166# Flank
167
168a oneRight~ b oneRight~ c oneRight~ d
169
170a oneRight~ b oneRight~ c ~oneLeft d
171
172a oneRight~ b ~oneLeft c oneRight~ d
173
174a ~oneLeft b oneRight~ c oneRight~ d
175
176a ~oneLeft b oneRight~ c ~oneLeft d
177
178a ~oneLeft b ~oneLeft c oneRight~ d
179
180a ~oneLeft b ~oneLeft c ~oneLeft d
181
182***
183
184a twoRight~~ b twoRight~~ c twoRight~~ d
185
186a twoRight~~ b twoRight~~ c ~~twoLeft d
187
188a twoRight~~ b ~~twoLeft c twoRight~~ d
189
190a ~~twoLeft b twoRight~~ c twoRight~~ d
191
192a ~~twoLeft b twoRight~~ c ~~twoLeft d
193
194a ~~twoLeft b ~~twoLeft c twoRight~~ d
195
196a ~~twoLeft b ~~twoLeft c ~~twoLeft d
197"###,
198 &Options::gfm()
199 )?,
200 r###"<h1>Flank</h1>
201<p>a oneRight~ b oneRight~ c oneRight~ d</p>
202<p>a oneRight~ b oneRight~ c ~oneLeft d</p>
203<p>a oneRight~ b <del>oneLeft c oneRight</del> d</p>
204<p>a <del>oneLeft b oneRight</del> c oneRight~ d</p>
205<p>a <del>oneLeft b oneRight</del> c ~oneLeft d</p>
206<p>a ~oneLeft b <del>oneLeft c oneRight</del> d</p>
207<p>a ~oneLeft b ~oneLeft c ~oneLeft d</p>
208<hr />
209<p>a twoRight~~ b twoRight~~ c twoRight~~ d</p>
210<p>a twoRight~~ b twoRight~~ c ~~twoLeft d</p>
211<p>a twoRight~~ b <del>twoLeft c twoRight</del> d</p>
212<p>a <del>twoLeft b twoRight</del> c twoRight~~ d</p>
213<p>a <del>twoLeft b twoRight</del> c ~~twoLeft d</p>
214<p>a ~~twoLeft b <del>twoLeft c twoRight</del> d</p>
215<p>a ~~twoLeft b ~~twoLeft c ~~twoLeft d</p>
216"###,
217 "should handle flanking like GitHub"
218 );
219
220 assert_eq!(
221 to_html_with_options(
222 r###"
223# Interlpay
224
225## Interleave with attention
226
227a ~~two *emphasis* two~~ b
228
229a ~~two **strong** two~~ b
230
231a *marker ~~two marker* two~~ b
232
233a ~~two *marker two~~ marker* b
234
235## Interleave with links
236
237a ~~two [resource](#) two~~ b
238
239a ~~two [reference][#] two~~ b
240
241a [label start ~~two label end](#) two~~ b
242
243a ~~two [label start two~~ label end](#) b
244
245a ~~two [label start ~one one~ label end](#) two~~ b
246
247a ~one [label start ~~two two~~ label end](#) one~ b
248
249a ~one [label start ~one one~ label end](#) one~ b
250
251a ~~two [label start ~~two two~~ label end](#) two~~ b
252
253[#]: #
254
255## Interleave with code (text)
256
257a ~~two `code` two~~ b
258
259a ~~two `code two~~` b
260
261a `code start ~~two code end` two~~ b
262
263a ~~two `code start two~~ code end` b
264
265a ~~two `code start ~one one~ code end` two~~ b
266
267a ~one `code start ~~two two~~ code end` one~ b
268
269a ~one `code start ~one one~ code end` one~ b
270
271a ~~two `code start ~~two two~~ code end` two~~ b
272
273## Emphasis/strong/strikethrough interplay
274
275a ***~~xxx~~*** zzz
276
277b ***xxx***zzz
278
279c **xxx**zzz
280
281d *xxx*zzz
282
283e ***~~xxx~~***yyy
284
285f **~~xxx~~**yyy
286
287g *~~xxx~~*yyy
288
289h ***~~xxx~~*** zzz
290
291i **~~xxx~~** zzz
292
293j *~~xxx~~* zzz
294
295k ~~~**xxx**~~~ zzz
296
297l ~~~xxx~~~zzz
298
299m ~~xxx~~zzz
300
301n ~xxx~zzz
302
303o ~~~**xxx**~~~yyy
304
305p ~~**xxx**~~yyy
306
307r ~**xxx**~yyy
308
309s ~~~**xxx**~~~ zzz
310
311t ~~**xxx**~~ zzz
312
313u ~**xxx**~ zzz
314"###,
315 &Options::gfm()
316 )?,
317 r###"<h1>Interlpay</h1>
318<h2>Interleave with attention</h2>
319<p>a <del>two <em>emphasis</em> two</del> b</p>
320<p>a <del>two <strong>strong</strong> two</del> b</p>
321<p>a <em>marker ~~two marker</em> two~~ b</p>
322<p>a <del>two *marker two</del> marker* b</p>
323<h2>Interleave with links</h2>
324<p>a <del>two <a href="#">resource</a> two</del> b</p>
325<p>a <del>two <a href="#">reference</a> two</del> b</p>
326<p>a <a href="#">label start ~~two label end</a> two~~ b</p>
327<p>a ~~two <a href="#">label start two~~ label end</a> b</p>
328<p>a <del>two <a href="#">label start <del>one one</del> label end</a> two</del> b</p>
329<p>a <del>one <a href="#">label start <del>two two</del> label end</a> one</del> b</p>
330<p>a <del>one <a href="#">label start <del>one one</del> label end</a> one</del> b</p>
331<p>a <del>two <a href="#">label start <del>two two</del> label end</a> two</del> b</p>
332<h2>Interleave with code (text)</h2>
333<p>a <del>two <code>code</code> two</del> b</p>
334<p>a ~~two <code>code two~~</code> b</p>
335<p>a <code>code start ~~two code end</code> two~~ b</p>
336<p>a ~~two <code>code start two~~ code end</code> b</p>
337<p>a <del>two <code>code start ~one one~ code end</code> two</del> b</p>
338<p>a <del>one <code>code start ~~two two~~ code end</code> one</del> b</p>
339<p>a <del>one <code>code start ~one one~ code end</code> one</del> b</p>
340<p>a <del>two <code>code start ~~two two~~ code end</code> two</del> b</p>
341<h2>Emphasis/strong/strikethrough interplay</h2>
342<p>a <em><strong><del>xxx</del></strong></em> zzz</p>
343<p>b <em><strong>xxx</strong></em>zzz</p>
344<p>c <strong>xxx</strong>zzz</p>
345<p>d <em>xxx</em>zzz</p>
346<p>e <em><strong><del>xxx</del></strong></em>yyy</p>
347<p>f <strong><del>xxx</del></strong>yyy</p>
348<p>g <em><del>xxx</del></em>yyy</p>
349<p>h <em><strong><del>xxx</del></strong></em> zzz</p>
350<p>i <strong><del>xxx</del></strong> zzz</p>
351<p>j <em><del>xxx</del></em> zzz</p>
352<p>k ~~~<strong>xxx</strong>~~~ zzz</p>
353<p>l ~~~xxx~~~zzz</p>
354<p>m <del>xxx</del>zzz</p>
355<p>n <del>xxx</del>zzz</p>
356<p>o ~~~<strong>xxx</strong>~~~yyy</p>
357<p>p ~~<strong>xxx</strong>~~yyy</p>
358<p>r ~<strong>xxx</strong>~yyy</p>
359<p>s ~~~<strong>xxx</strong>~~~ zzz</p>
360<p>t <del><strong>xxx</strong></del> zzz</p>
361<p>u <del><strong>xxx</strong></del> zzz</p>
362"###,
363 "should handle interplay like GitHub"
364 );
365
366 assert_eq!(
367 to_html_with_options("a*~b~*c\n\na*.b.*c", &Options::gfm())?,
368 "<p>a<em><del>b</del></em>c</p>\n<p>a*.b.*c</p>",
369 "should handle interplay w/ other attention markers (GFM)"
370 );
371
372 assert_eq!(
373 to_html("a*~b~*c\n\na*.b.*c"),
374 "<p>a*~b~*c</p>\n<p>a*.b.*c</p>",
375 "should handle interplay w/ other attention markers (CM reference)"
376 );
377
378 assert_eq!(
379 to_html_with_options(
380 "a ~b~ ~~c~~ d",
381 &Options {
382 parse: ParseOptions {
383 gfm_strikethrough_single_tilde: false,
384 ..ParseOptions::gfm()
385 },
386 ..Options::gfm()
387 }
388 )?,
389 "<p>a ~b~ <del>c</del> d</p>",
390 "should not support strikethrough w/ one tilde if `singleTilde: false`"
391 );
392
393 assert_eq!(
394 to_html_with_options(
395 "a ~b~ ~~c~~ d",
396 &Options {
397 parse: ParseOptions {
398 gfm_strikethrough_single_tilde: true,
399 ..ParseOptions::gfm()
400 },
401 ..Options::gfm()
402 }
403 )?,
404 "<p>a <del>b</del> <del>c</del> d</p>",
405 "should support strikethrough w/ one tilde if `singleTilde: true`"
406 );
407
408 assert_eq!(
409 to_mdast("a ~~alpha~~ b.", &ParseOptions::gfm())?,
410 Node::Root(Root {
411 children: vec![Node::Paragraph(Paragraph {
412 children: vec![
413 Node::Text(Text {
414 value: "a ".into(),
415 position: Some(Position::new(1, 1, 0, 1, 3, 2))
416 }),
417 Node::Delete(Delete {
418 children: vec![Node::Text(Text {
419 value: "alpha".into(),
420 position: Some(Position::new(1, 5, 4, 1, 10, 9))
421 }),],
422 position: Some(Position::new(1, 3, 2, 1, 12, 11))
423 }),
424 Node::Text(Text {
425 value: " b.".into(),
426 position: Some(Position::new(1, 12, 11, 1, 15, 14))
427 }),
428 ],
429 position: Some(Position::new(1, 1, 0, 1, 15, 14))
430 })],
431 position: Some(Position::new(1, 1, 0, 1, 15, 14))
432 }),
433 "should support GFM strikethrough as `Delete`s in mdast"
434 );
435
436 Ok(())
437}