mirror of
https://github.com/xoofx/markdig.git
synced 2026-02-04 05:44:50 +00:00
Compare commits
796 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7dd9321a97 | ||
|
|
c22d681c20 | ||
|
|
ffe7f56bc2 | ||
|
|
16c0b6a3fa | ||
|
|
db867dee48 | ||
|
|
d35b1b82ea | ||
|
|
8b829a2dea | ||
|
|
4f7ef61303 | ||
|
|
831a529338 | ||
|
|
4f5e9cd334 | ||
|
|
cb0b3a6292 | ||
|
|
4390ff289e | ||
|
|
be53e778be | ||
|
|
0eab0a3107 | ||
|
|
8fa47427ac | ||
|
|
bca544575b | ||
|
|
0017dbffc4 | ||
|
|
569efa357a | ||
|
|
7e9df72173 | ||
|
|
b2fcb1cc37 | ||
|
|
8758ba460f | ||
|
|
477a290538 | ||
|
|
0fc112a6b8 | ||
|
|
b7aea44502 | ||
|
|
0545faa9af | ||
|
|
ea67a295b2 | ||
|
|
d53128d56d | ||
|
|
ba192ce065 | ||
|
|
42462d71ac | ||
|
|
6e0363aa91 | ||
|
|
e9be3725d6 | ||
|
|
38f4332de1 | ||
|
|
bcc123d240 | ||
|
|
144e8ad156 | ||
|
|
55a7eae4d4 | ||
|
|
d96862378d | ||
|
|
8acf5a548e | ||
|
|
222a99c7e4 | ||
|
|
ac4a75bdf9 | ||
|
|
fc2e1ab896 | ||
|
|
ef7f20482e | ||
|
|
fc50e2e2e7 | ||
|
|
4d513acf6b | ||
|
|
32b1ee7eaa | ||
|
|
3e2a498ae7 | ||
|
|
e0ac9b7ddf | ||
|
|
bbf10a7ad0 | ||
|
|
62a0992e5e | ||
|
|
b2e49d174e | ||
|
|
5e218721e7 | ||
|
|
c64cd53ac3 | ||
|
|
920ab6cb60 | ||
|
|
3ef1d735d5 | ||
|
|
47c6c49f5c | ||
|
|
a19f78342f | ||
|
|
edb4c6c3cb | ||
|
|
4b6d7c78f5 | ||
|
|
0386cfd617 | ||
|
|
5c52a7249d | ||
|
|
14fb550704 | ||
|
|
741d09a4e8 | ||
|
|
34d9fa2bcc | ||
|
|
8ee50a265d | ||
|
|
eb002db3c7 | ||
|
|
a15203a061 | ||
|
|
b0a2f19ed7 | ||
|
|
a9d78e04a1 | ||
|
|
a8b6e2c2e4 | ||
|
|
665f5f5e51 | ||
|
|
86a72c3582 | ||
|
|
784b999d6c | ||
|
|
be3a893d3d | ||
|
|
2679c84788 | ||
|
|
3d005d6444 | ||
|
|
09593ff3da | ||
|
|
f0269fc61f | ||
|
|
2d97628cfd | ||
|
|
ee97d32ef0 | ||
|
|
9ca5cdcb31 | ||
|
|
5f453fbe92 | ||
|
|
8300a9cca2 | ||
|
|
f7d763230d | ||
|
|
cce1b99edc | ||
|
|
2dca2119fa | ||
|
|
faf0a20816 | ||
|
|
68196c1ce6 | ||
|
|
fdf125d05d | ||
|
|
46133715ab | ||
|
|
ae726b3796 | ||
|
|
4151ac2287 | ||
|
|
305f722899 | ||
|
|
abc8aa25b7 | ||
|
|
e6bb83ecdf | ||
|
|
e6ea8ad274 | ||
|
|
1f3cf5962f | ||
|
|
83b3427805 | ||
|
|
3ff3f1ccb9 | ||
|
|
5d91f0e26f | ||
|
|
9af462e412 | ||
|
|
e1ba52da20 | ||
|
|
70ee97d5c7 | ||
|
|
da916a1700 | ||
|
|
5548246703 | ||
|
|
097fc5c4e0 | ||
|
|
168ad39ff6 | ||
|
|
54e065aabe | ||
|
|
98d58797d9 | ||
|
|
2f0dd2a6a7 | ||
|
|
247209870e | ||
|
|
ef5b958267 | ||
|
|
7d61df2c0c | ||
|
|
51f9da1974 | ||
|
|
9321628b9c | ||
|
|
525e2c7fb8 | ||
|
|
1f9b70636f | ||
|
|
d4f43f826f | ||
|
|
62788b1101 | ||
|
|
c3c4d37b82 | ||
|
|
333bf04274 | ||
|
|
dab4b7176d | ||
|
|
25ec56e1be | ||
|
|
3455fd12da | ||
|
|
ae5d47a0ed | ||
|
|
1ff721d512 | ||
|
|
2c130504e2 | ||
|
|
6405b16692 | ||
|
|
2e1912a23d | ||
|
|
71c680388c | ||
|
|
3f50b3fd0b | ||
|
|
99b250b4c9 | ||
|
|
655bf13df0 | ||
|
|
d2c89a3a06 | ||
|
|
754d11fd44 | ||
|
|
1252e49ba4 | ||
|
|
d18487ae53 | ||
|
|
f401d5082e | ||
|
|
dd6418d108 | ||
|
|
7875e4bce9 | ||
|
|
2e1b1a1fdc | ||
|
|
fa2b157c1a | ||
|
|
e4e6406546 | ||
|
|
1cff10270a | ||
|
|
87023184cb | ||
|
|
aecdf2192e | ||
|
|
0a36382126 | ||
|
|
0057b368ec | ||
|
|
3033284096 | ||
|
|
9b1b791b18 | ||
|
|
2b7d205701 | ||
|
|
89b28659b1 | ||
|
|
446b1bcc0d | ||
|
|
ec7a4a6902 | ||
|
|
07a77142f4 | ||
|
|
3606f234b8 | ||
|
|
616eed62bd | ||
|
|
99f55e9ddc | ||
|
|
f8ab1cccc5 | ||
|
|
f24067cd16 | ||
|
|
9af96ba2b4 | ||
|
|
c99f7dd96a | ||
|
|
bf28cbd33f | ||
|
|
2040e23545 | ||
|
|
2761e36b6b | ||
|
|
891334134c | ||
|
|
0987fab6f2 | ||
|
|
ed5eea5e27 | ||
|
|
f73cbe4e76 | ||
|
|
aefad219cf | ||
|
|
76c3e88c58 | ||
|
|
afe4308e91 | ||
|
|
606556b692 | ||
|
|
253be5c362 | ||
|
|
33037d1034 | ||
|
|
f16ee828db | ||
|
|
a76305f39b | ||
|
|
f52a41e167 | ||
|
|
4d172bf905 | ||
|
|
890b2cda2a | ||
|
|
c818670919 | ||
|
|
a78a0b7016 | ||
|
|
6a0c9aeb47 | ||
|
|
b1cfcf2431 | ||
|
|
b411522a23 | ||
|
|
1d2977d47b | ||
|
|
ee8c87c357 | ||
|
|
25959174d5 | ||
|
|
033ddaf6a8 | ||
|
|
f3f7584c39 | ||
|
|
d00ca4acc1 | ||
|
|
d9663ef2e6 | ||
|
|
3106a49d02 | ||
|
|
a47a6890e7 | ||
|
|
7d21f8b003 | ||
|
|
15f6205adc | ||
|
|
e6dd2cf3d4 | ||
|
|
ea6592b773 | ||
|
|
5cd20efe3e | ||
|
|
31c7ba5862 | ||
|
|
0272840a62 | ||
|
|
8886b48634 | ||
|
|
64cd8ec262 | ||
|
|
a1e19912a9 | ||
|
|
ca51967fb1 | ||
|
|
bb3a4f372c | ||
|
|
1d6a464c5d | ||
|
|
0fe5c17a93 | ||
|
|
f879d55b4a | ||
|
|
6d3a3584ac | ||
|
|
ea13b33f1a | ||
|
|
9b2ec2e2e5 | ||
|
|
d8dffc28b4 | ||
|
|
0735042599 | ||
|
|
d1f99cdb69 | ||
|
|
d0a2ae2b50 | ||
|
|
dd4d1b349f | ||
|
|
e33281b8ae | ||
|
|
50d42560da | ||
|
|
a1e96d717b | ||
|
|
56278657fd | ||
|
|
b7202084d2 | ||
|
|
88052168d0 | ||
|
|
27cb88773a | ||
|
|
fe3d5b0ccf | ||
|
|
86759e44e1 | ||
|
|
dd60990d3d | ||
|
|
a3a9496c6f | ||
|
|
d09013ba14 | ||
|
|
9499660f83 | ||
|
|
df24ab9846 | ||
|
|
40a8cd09b6 | ||
|
|
b556f06d31 | ||
|
|
54e61d3b91 | ||
|
|
221afcc4d3 | ||
|
|
f1fc64af42 | ||
|
|
b39614f10c | ||
|
|
5bda352f7a | ||
|
|
4f08094de0 | ||
|
|
13a733a061 | ||
|
|
d010a4f21e | ||
|
|
a353c59e26 | ||
|
|
01c8aedced | ||
|
|
01d8842ac1 | ||
|
|
69a2261562 | ||
|
|
09905db72a | ||
|
|
754409c8fa | ||
|
|
cd67a3049a | ||
|
|
277aef341a | ||
|
|
9a5ef61bd1 | ||
|
|
ed6c59dd07 | ||
|
|
4deeac538a | ||
|
|
b05161d20e | ||
|
|
d02adf1bf3 | ||
|
|
f767b649e6 | ||
|
|
bdec15d943 | ||
|
|
fe4ac6643a | ||
|
|
eb72bc6d4f | ||
|
|
f484366612 | ||
|
|
bb5e45b939 | ||
|
|
2b41e47170 | ||
|
|
3c16852219 | ||
|
|
744417c7a2 | ||
|
|
4039e11e08 | ||
|
|
3c73a2d05a | ||
|
|
1ef247b093 | ||
|
|
d45d8873f5 | ||
|
|
396a03567c | ||
|
|
6a98e204a5 | ||
|
|
210a6612c7 | ||
|
|
27c35b3b09 | ||
|
|
ac1db841d5 | ||
|
|
09f29615c1 | ||
|
|
05e5a3f2bb | ||
|
|
6d238de69e | ||
|
|
5b88dbb90a | ||
|
|
fbd822cef7 | ||
|
|
0e22a120f1 | ||
|
|
590f3d0b1b | ||
|
|
23766d84fa | ||
|
|
14e9e618a2 | ||
|
|
f523cb243b | ||
|
|
1064818b49 | ||
|
|
befd1ca846 | ||
|
|
65c671d014 | ||
|
|
25bc0b8bf6 | ||
|
|
343a2a17e1 | ||
|
|
5100ed0b68 | ||
|
|
95dd2c148c | ||
|
|
354db6b306 | ||
|
|
50313a36dc | ||
|
|
77d5dcb6dd | ||
|
|
1c88fb65c8 | ||
|
|
db9660d090 | ||
|
|
39ab066e2d | ||
|
|
47f395dad7 | ||
|
|
04e195cdb2 | ||
|
|
3b3872ffe3 | ||
|
|
c7cda0df45 | ||
|
|
7651e75bfa | ||
|
|
ea99cd6115 | ||
|
|
3af4f33b5d | ||
|
|
41e8d5e5fc | ||
|
|
5a73c2bf2b | ||
|
|
f542fd0a88 | ||
|
|
5a6300823c | ||
|
|
6dcef438c4 | ||
|
|
40206c4d76 | ||
|
|
24ecfc93f3 | ||
|
|
8eb52c50ec | ||
|
|
9965597256 | ||
|
|
987580e71e | ||
|
|
bba3ef04ee | ||
|
|
d8a594a151 | ||
|
|
60c64b67c7 | ||
|
|
7f0b39a44a | ||
|
|
57784cedc6 | ||
|
|
80b918e6f5 | ||
|
|
64883152c9 | ||
|
|
20bd561062 | ||
|
|
035ce17386 | ||
|
|
bc4dbd1b35 | ||
|
|
1d8266b86d | ||
|
|
b5293b907f | ||
|
|
a11676ed7e | ||
|
|
18e9486c95 | ||
|
|
ef452c292c | ||
|
|
325495a367 | ||
|
|
d854b0b941 | ||
|
|
ca38da576e | ||
|
|
b15b05015e | ||
|
|
5266ae965b | ||
|
|
42b201d8c2 | ||
|
|
d232e847dd | ||
|
|
1b5d9d46fc | ||
|
|
6b1b5165ca | ||
|
|
7719ef503f | ||
|
|
f01b5281fd | ||
|
|
3e4e6d6627 | ||
|
|
16ffc052a3 | ||
|
|
22853d9782 | ||
|
|
8164c1fa8d | ||
|
|
8a42f74a6c | ||
|
|
19a5a07763 | ||
|
|
dd68351235 | ||
|
|
c346e55a46 | ||
|
|
ffdfd427ce | ||
|
|
edbf832e0a | ||
|
|
7887cf7348 | ||
|
|
e6432038b5 | ||
|
|
f8df3c80e1 | ||
|
|
664c824f8b | ||
|
|
95cbf0e6d2 | ||
|
|
b2a542b43e | ||
|
|
f1b736f918 | ||
|
|
282da043b7 | ||
|
|
4519d3820a | ||
|
|
37325f1bdc | ||
|
|
1bbe20dca1 | ||
|
|
b237d70298 | ||
|
|
632f400a74 | ||
|
|
a302db679c | ||
|
|
653972847c | ||
|
|
832f86cf5f | ||
|
|
103434eb9b | ||
|
|
f9dd201563 | ||
|
|
9b9243a61f | ||
|
|
91dbfce18e | ||
|
|
57692a557b | ||
|
|
02bd8149ac | ||
|
|
0920001f45 | ||
|
|
cde939f79c | ||
|
|
f932b3c87a | ||
|
|
b2a7baa079 | ||
|
|
1c37c996dc | ||
|
|
da99af68c6 | ||
|
|
03858dc5c8 | ||
|
|
ebedc6829d | ||
|
|
28322c3645 | ||
|
|
c3395e6779 | ||
|
|
cc47d33c7d | ||
|
|
fedbe2adc5 | ||
|
|
8efc082d1d | ||
|
|
6c2702f9fd | ||
|
|
4824f460c0 | ||
|
|
46fc840c35 | ||
|
|
ce3078dcf2 | ||
|
|
b8255a87cf | ||
|
|
4f6ad47c6a | ||
|
|
d6d6f9c5c1 | ||
|
|
92b06f0954 | ||
|
|
ecd625d40b | ||
|
|
7e81747662 | ||
|
|
cffe5b2f4b | ||
|
|
c349ead32c | ||
|
|
07e6a13378 | ||
|
|
1b54bb157c | ||
|
|
e23fae26c8 | ||
|
|
2501c6aaf6 | ||
|
|
e390a870cc | ||
|
|
e4892fc86d | ||
|
|
dfc67021ee | ||
|
|
25db2774c3 | ||
|
|
22271db431 | ||
|
|
446764873d | ||
|
|
bdb5119806 | ||
|
|
f3bb06531e | ||
|
|
9a74f3708e | ||
|
|
57033311dc | ||
|
|
bda2f8c9ad | ||
|
|
0d5d3ddb2a | ||
|
|
3f8e50031b | ||
|
|
949d5c0c25 | ||
|
|
31e163f9f7 | ||
|
|
b1440ab788 | ||
|
|
6e55d84f01 | ||
|
|
595dbb9af4 | ||
|
|
d1576fd2ee | ||
|
|
1fe05639c9 | ||
|
|
8afff09b3e | ||
|
|
694747471a | ||
|
|
dfcd5cddfa | ||
|
|
a99b7f4572 | ||
|
|
7d7598db54 | ||
|
|
8767a1d8ed | ||
|
|
16c0829d9e | ||
|
|
fc5d832432 | ||
|
|
7292acc27a | ||
|
|
d05bc1572d | ||
|
|
5aa138425f | ||
|
|
c56041811b | ||
|
|
790bff3baf | ||
|
|
571e04fe28 | ||
|
|
c847996146 | ||
|
|
2782d3b4c3 | ||
|
|
582a76f8f0 | ||
|
|
030d676497 | ||
|
|
0794213eef | ||
|
|
427dc849f7 | ||
|
|
e598047964 | ||
|
|
15546732dd | ||
|
|
7bd238852d | ||
|
|
0f406039a0 | ||
|
|
1cd9cdfca0 | ||
|
|
812c4fabe6 | ||
|
|
85f8f59786 | ||
|
|
b0839f114c | ||
|
|
431fecb1c6 | ||
|
|
7620b2b760 | ||
|
|
ad18514824 | ||
|
|
c68a488717 | ||
|
|
e2f0f00831 | ||
|
|
fea2ca5adf | ||
|
|
f77bd0b36d | ||
|
|
20243a79a0 | ||
|
|
a097247272 | ||
|
|
f3cb0712ca | ||
|
|
eedfc3cd9c | ||
|
|
5f4b049ce0 | ||
|
|
20edf26c40 | ||
|
|
4192a00e20 | ||
|
|
4346c52ef0 | ||
|
|
42683e043d | ||
|
|
96c469018e | ||
|
|
f64ac47841 | ||
|
|
c29b7d2942 | ||
|
|
0f7e3b8c52 | ||
|
|
6dff16a612 | ||
|
|
8e15c8bc6a | ||
|
|
558db1fd70 | ||
|
|
796b143316 | ||
|
|
3402805ebb | ||
|
|
c3600c2ba5 | ||
|
|
4ba98f594a | ||
|
|
544a64e5c9 | ||
|
|
f17320702a | ||
|
|
d883694ac4 | ||
|
|
42fba26ea2 | ||
|
|
595dacf213 | ||
|
|
75adfa3fe8 | ||
|
|
0bb8139450 | ||
|
|
60784901b2 | ||
|
|
5020fdd3b1 | ||
|
|
bd4ea56d2a | ||
|
|
fbc8a4116c | ||
|
|
9af318d334 | ||
|
|
88e561c3ae | ||
|
|
1ca82eb058 | ||
|
|
66007c6bbf | ||
|
|
14d4286fd7 | ||
|
|
58b1a48f5b | ||
|
|
5e1eaf8590 | ||
|
|
c946295d96 | ||
|
|
97cbf11f8b | ||
|
|
8d4394e7c6 | ||
|
|
fbdb8cf063 | ||
|
|
964538ec79 | ||
|
|
9a30883e2a | ||
|
|
6408705f82 | ||
|
|
523582e588 | ||
|
|
aaff022e7c | ||
|
|
37eb6aa529 | ||
|
|
9b7356b05e | ||
|
|
33d3bc1330 | ||
|
|
07a2980d5b | ||
|
|
2d8872f2a1 | ||
|
|
16a9bbc84e | ||
|
|
0e5338a709 | ||
|
|
9139e0142b | ||
|
|
9a38312df0 | ||
|
|
d808dcf6f8 | ||
|
|
d5985fc94c | ||
|
|
994687d5ae | ||
|
|
2f4e958ab2 | ||
|
|
26beaa81da | ||
|
|
de5ed11963 | ||
|
|
b557d51276 | ||
|
|
27a8345943 | ||
|
|
131163ff9a | ||
|
|
241f674b99 | ||
|
|
194edee243 | ||
|
|
0995fa0cec | ||
|
|
6717be5210 | ||
|
|
e15745f346 | ||
|
|
a513b0c587 | ||
|
|
72adb963e8 | ||
|
|
aac7df6b87 | ||
|
|
4cf4bfb58f | ||
|
|
59630aec8e | ||
|
|
70c4f6deda | ||
|
|
e2b3f812cb | ||
|
|
fc8adc70e0 | ||
|
|
72c2c06fcb | ||
|
|
7174e32b7a | ||
|
|
600219529c | ||
|
|
d7fd04d14c | ||
|
|
2147e434f7 | ||
|
|
7bd00d115f | ||
|
|
80ef9d2799 | ||
|
|
d6a705d76c | ||
|
|
42472085a6 | ||
|
|
3897e875ee | ||
|
|
c63392657d | ||
|
|
34579b51a1 | ||
|
|
1bb35c5fc1 | ||
|
|
0c408951b8 | ||
|
|
218a094f0d | ||
|
|
3cc405b05b | ||
|
|
d58db530bb | ||
|
|
3628dc3b17 | ||
|
|
89ff42805d | ||
|
|
48866a2609 | ||
|
|
9cc5856c1c | ||
|
|
a4bb174a77 | ||
|
|
82987fa879 | ||
|
|
2df2ff17c5 | ||
|
|
4e4825cb3f | ||
|
|
ed2371beae | ||
|
|
2c2898769e | ||
|
|
001a99ab77 | ||
|
|
9233ec220c | ||
|
|
bb30dc21c5 | ||
|
|
c761fa2243 | ||
|
|
9d172ffcc1 | ||
|
|
1863e22328 | ||
|
|
c591d1950f | ||
|
|
339fcc9152 | ||
|
|
3a54f06540 | ||
|
|
3f305a25a8 | ||
|
|
5a210223b6 | ||
|
|
a7786d934d | ||
|
|
cb3c1f1505 | ||
|
|
50b33b8512 | ||
|
|
80790b5038 | ||
|
|
311c28ae60 | ||
|
|
9906a0554f | ||
|
|
7e92f1881d | ||
|
|
41911806a0 | ||
|
|
610f1519b0 | ||
|
|
29aa56b4f1 | ||
|
|
5004ecedb7 | ||
|
|
ba06a796dc | ||
|
|
b1d6f34976 | ||
|
|
28f4236a57 | ||
|
|
0739a82735 | ||
|
|
3ac9f2e788 | ||
|
|
d9607cc687 | ||
|
|
f0573ef9e2 | ||
|
|
017a3bd7e2 | ||
|
|
d6f9a1055c | ||
|
|
2612e9d565 | ||
|
|
1076d7af10 | ||
|
|
850cecfa6c | ||
|
|
bfdb03bd78 | ||
|
|
56b6e329d5 | ||
|
|
006e384d1a | ||
|
|
9cd9b683a5 | ||
|
|
e01e2c3d2b | ||
|
|
97ce0da564 | ||
|
|
26c5ce59b5 | ||
|
|
d2d94ecf39 | ||
|
|
0ec82bb81d | ||
|
|
ad9e941cb0 | ||
|
|
27dab6ca6d | ||
|
|
762196f03b | ||
|
|
26a565fa45 | ||
|
|
4369db1a43 | ||
|
|
d83f1f87cc | ||
|
|
14027f4be3 | ||
|
|
8bcfb53607 | ||
|
|
700bb21e03 | ||
|
|
1bc9d9083c | ||
|
|
1d7bb021a7 | ||
|
|
3305a74b06 | ||
|
|
6312bc0515 | ||
|
|
b595383281 | ||
|
|
bf85964543 | ||
|
|
d5b020b784 | ||
|
|
8ab0467e78 | ||
|
|
74fe3be7c7 | ||
|
|
b47ae8d9ba | ||
|
|
a926e1a326 | ||
|
|
6048406f52 | ||
|
|
1edf14c742 | ||
|
|
d4bb7c0a51 | ||
|
|
ba4e463517 | ||
|
|
2d0dae4ebb | ||
|
|
1a9d923c44 | ||
|
|
013ec0bf80 | ||
|
|
f82e874cb7 | ||
|
|
976fc569fa | ||
|
|
5aab21f0bf | ||
|
|
1df8344576 | ||
|
|
9eb84cf95e | ||
|
|
47d45b5577 | ||
|
|
ebcc286df0 | ||
|
|
f11d8037ac | ||
|
|
f668b3fe38 | ||
|
|
5ca4e31332 | ||
|
|
a8fbe79e30 | ||
|
|
bdb09b9820 | ||
|
|
79348ebea8 | ||
|
|
b366c1a5e3 | ||
|
|
a5e53b014f | ||
|
|
c2f21e21c8 | ||
|
|
81b8dce7a8 | ||
|
|
e6223f86d8 | ||
|
|
2054c16662 | ||
|
|
95641e562f | ||
|
|
e4953931c7 | ||
|
|
93b5b7a091 | ||
|
|
4f52e893ee | ||
|
|
23ede077a1 | ||
|
|
d5e6f17683 | ||
|
|
4d5980a485 | ||
|
|
19dd902519 | ||
|
|
f046a46275 | ||
|
|
25e9eafa8b | ||
|
|
f4ff981008 | ||
|
|
a1b48aff89 | ||
|
|
0aa34caa82 | ||
|
|
98ce9b1a06 | ||
|
|
ab157b21ea | ||
|
|
53c72d3031 | ||
|
|
165e2f97d0 | ||
|
|
6c577059ad | ||
|
|
0ea4dc769b | ||
|
|
a9b626e810 | ||
|
|
b90d6f9769 | ||
|
|
f0ea008c46 | ||
|
|
c43d5ccd63 | ||
|
|
d6d7b398e4 | ||
|
|
e1032e5094 | ||
|
|
a32ac298c5 | ||
|
|
2e6ab670cb | ||
|
|
72b7fce48c | ||
|
|
fa281f1ca1 | ||
|
|
1b92311aeb | ||
|
|
a593212f03 | ||
|
|
c4ec928953 | ||
|
|
e7df7fabeb | ||
|
|
1c187f2d81 | ||
|
|
da66cf90c3 | ||
|
|
0e8bd7407f | ||
|
|
d70f14addb | ||
|
|
e7b9eea3a5 | ||
|
|
97af9d822d | ||
|
|
cf7a09ab76 | ||
|
|
e755627421 | ||
|
|
f9be64a988 | ||
|
|
d65431e6cc | ||
|
|
86fb962fdb | ||
|
|
d003837b27 | ||
|
|
fd813e3c5a | ||
|
|
a3691c4423 | ||
|
|
9506f22025 | ||
|
|
06ae907949 | ||
|
|
555523b2af | ||
|
|
3b9772f772 | ||
|
|
891c80f48c | ||
|
|
105b09e1ec | ||
|
|
9fe7596a23 | ||
|
|
82af7cadc5 | ||
|
|
800c81bb9a | ||
|
|
5653a4f7ee | ||
|
|
4f14ffe63b | ||
|
|
d57acefe56 | ||
|
|
fb61e5a8da | ||
|
|
264516bfdb | ||
|
|
6d8f8996d5 | ||
|
|
ba8557d3bf | ||
|
|
d18fd0b957 | ||
|
|
fba96774f4 | ||
|
|
0b2764ea62 | ||
|
|
64d81ed47b | ||
|
|
9a9742888b | ||
|
|
5400b30a90 | ||
|
|
673f4a4beb | ||
|
|
05a27649aa | ||
|
|
26c6b12dea | ||
|
|
9a18ca222f | ||
|
|
354f31b870 | ||
|
|
c6c2f58ec0 | ||
|
|
4a146f00f6 | ||
|
|
2c10ac59d3 | ||
|
|
9a98fb9453 | ||
|
|
b20b111385 | ||
|
|
6ac2429e2a | ||
|
|
9d52732f18 | ||
|
|
1c7f843a4c | ||
|
|
fdaf301bd6 | ||
|
|
5a9f2f3afe | ||
|
|
6a1b30761a | ||
|
|
8f8b08fad6 | ||
|
|
312b63a4c8 | ||
|
|
1598b538ab | ||
|
|
16ce46a741 | ||
|
|
4456598228 | ||
|
|
2a937c63b9 | ||
|
|
191bc940c7 | ||
|
|
05673758e3 | ||
|
|
cff2b9a8ca | ||
|
|
586095a475 | ||
|
|
eae2082a1e | ||
|
|
4576548df3 | ||
|
|
266e0c8bfd | ||
|
|
f5c07dbab5 | ||
|
|
c8a28a1ad7 | ||
|
|
72cc454314 | ||
|
|
7fe2c1f939 | ||
|
|
087e7a68b6 | ||
|
|
abeabf15a1 | ||
|
|
f9bfcaab7b | ||
|
|
afa0182f02 | ||
|
|
b83de5934d | ||
|
|
c294d3bfb4 | ||
|
|
a7cdb2351a | ||
|
|
46ef21a3ed | ||
|
|
18c8d0178c | ||
|
|
ebc79dafbd | ||
|
|
a1d2467643 | ||
|
|
8220f0fa56 | ||
|
|
ec385acc7f | ||
|
|
04c1cc62d4 | ||
|
|
abdbd65f60 | ||
|
|
1f32a060da | ||
|
|
699d80c150 | ||
|
|
56bcac7600 | ||
|
|
cab3365104 | ||
|
|
3821bd00fe | ||
|
|
62701fd0f1 | ||
|
|
1be5e60506 | ||
|
|
c9f1512358 | ||
|
|
8f23aed6af | ||
|
|
6a62ae9c69 | ||
|
|
2c3de5688b | ||
|
|
f3c08b4ec4 | ||
|
|
69e3baafe5 | ||
|
|
5844ccc395 | ||
|
|
be9c6fa54b | ||
|
|
d14f277c7b | ||
|
|
593bf08b92 | ||
|
|
85f631f868 | ||
|
|
5ad964bcb6 | ||
|
|
137a404bdc | ||
|
|
5204ec758a | ||
|
|
6f4fb69c62 | ||
|
|
0a1b37c965 | ||
|
|
90bdafb05a | ||
|
|
8cc668ae6d | ||
|
|
1787dc4590 | ||
|
|
0a9cc8fcd7 | ||
|
|
10c06daf5d | ||
|
|
a262e42980 | ||
|
|
4cd3d045d1 | ||
|
|
92357576b1 | ||
|
|
d45f67f8c2 | ||
|
|
2571cdffee |
37
.editorconfig
Normal file
37
.editorconfig
Normal file
@@ -0,0 +1,37 @@
|
||||
# EditorConfig is awesome:http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# All Files
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Solution Files
|
||||
[*.sln]
|
||||
indent_style = tab
|
||||
|
||||
# XML Project Files
|
||||
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
|
||||
indent_size = 2
|
||||
|
||||
# Configuration Files
|
||||
[*.{json,xml,yml,config,props,targets,nuspec,resx,ruleset}]
|
||||
indent_size = 2
|
||||
|
||||
# Markdown Files
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# Web Files
|
||||
[*.{htm,html,js,ts,css,scss,less}]
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
|
||||
# Bash Files
|
||||
[*.sh]
|
||||
end_of_line = lf
|
||||
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
* text=auto
|
||||
*.cs text=auto diff=csharp
|
||||
*.sln text=auto eol=crlf
|
||||
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [xoofx]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
61
.github/workflows/ci.yml
vendored
Normal file
61
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: ci
|
||||
|
||||
env:
|
||||
PROJECT_NAME: Markdig
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'doc/**'
|
||||
- 'img/**'
|
||||
- 'changelog.md'
|
||||
- 'readme.md'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 3.0.100
|
||||
|
||||
- name: Build (Release)
|
||||
run: dotnet build src -c Release
|
||||
|
||||
- name: SpecFileGen
|
||||
run: dotnet src/SpecFileGen/bin/Release/netcoreapp2.1/SpecFileGen.dll
|
||||
|
||||
- name: Test (Release)
|
||||
run: dotnet test src -c Release
|
||||
|
||||
- name: Build & Test (Debug)
|
||||
run: dotnet test src -c Debug
|
||||
|
||||
- name: Coverlet
|
||||
run: dotnet test src -c Release -f netcoreapp2.1 /p:Include=\"[${{env.PROJECT_NAME}}]*\" /p:CollectCoverage=true /p:CoverletOutputFormat=lcov
|
||||
|
||||
- name: Coveralls Upload
|
||||
uses: coverallsapp/github-action@v1.0.1
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path-to-lcov: src/${{env.PROJECT_NAME}}.Tests/coverage.netcoreapp2.1.info
|
||||
|
||||
- name: Pack
|
||||
run: dotnet pack src -c Release
|
||||
|
||||
- name: Publish
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
if ( "${{github.ref}}" -match "^refs/tags/[0-9]+\.[0-9]+\.[0-9]+$" ) {
|
||||
dotnet nuget push src\${{env.PROJECT_NAME}}\bin\Release\*.nupkg -s nuget.org -k ${{secrets.NUGET_TOKEN}}
|
||||
dotnet nuget push src\${{env.PROJECT_NAME}}.Signed\bin\Release\*.nupkg -s nuget.org -k ${{secrets.NUGET_TOKEN}}
|
||||
} else {
|
||||
echo "publish is only enabled by tagging with a release tag"
|
||||
}
|
||||
27
.gitignore
vendored
27
.gitignore
vendored
@@ -6,6 +6,8 @@
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
@@ -136,7 +138,7 @@ publish/
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
@@ -214,3 +216,26 @@ FakesAssemblies/
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Common IntelliJ Platform excludes
|
||||
|
||||
# User specific
|
||||
**/.idea/**/workspace.xml
|
||||
**/.idea/**/tasks.xml
|
||||
**/.idea/shelf/*
|
||||
**/.idea/dictionaries
|
||||
**/.idea/httpRequests/
|
||||
|
||||
# Sensitive or high-churn files
|
||||
**/.idea/**/dataSources/
|
||||
**/.idea/**/dataSources.ids
|
||||
**/.idea/**/dataSources.xml
|
||||
**/.idea/**/dataSources.local.xml
|
||||
**/.idea/**/sqlDataSources.xml
|
||||
**/.idea/**/dynamic.xml
|
||||
|
||||
# Rider
|
||||
# Rider auto-generates .iml files, and contentModel.xml
|
||||
**/.idea/**/*.iml
|
||||
**/.idea/**/contentModel.xml
|
||||
**/.idea/**/modules.xml
|
||||
|
||||
225
changelog.md
Normal file
225
changelog.md
Normal file
@@ -0,0 +1,225 @@
|
||||
# Changelog
|
||||
|
||||
## 0.21.0 (17 Aug 2020)
|
||||
- Restore support for .NET 4.5 (#)
|
||||
- Add IReadonlyList interface to ContainerBlock to unify and simplify enumeration (#425)
|
||||
- Fix relative uri detection to be cross-platform compatible (#430)
|
||||
- Escape URLs scheme (#431)
|
||||
- Fix media links (#435)
|
||||
- Fix parsing math blocks with no leading or trailing whitespace (#452)
|
||||
- Add support for autolink `tel:` uri (#453)
|
||||
- Fallback to non-punycode encoding for invalid IDN urls (#449)
|
||||
- Pipe Tables: Normalize using header column count (#455)
|
||||
- Expose IndentCount of FencedCodeBlock (#464)
|
||||
|
||||
## 0.20.0 (18 Apr 2020)
|
||||
- Markdig is now compatible only with `NETStandard 2.0`, `NETStandard 2.1`, `NETCoreApp 2.1` and `NETCoreApp 3.1`.
|
||||
- Many performance improvements from [PR #416](https://github.com/lunet-io/markdig/pull/416)
|
||||
[PR #417](https://github.com/lunet-io/markdig/pull/417)
|
||||
[PR #418](https://github.com/lunet-io/markdig/pull/418)
|
||||
[PR #421](https://github.com/lunet-io/markdig/pull/421)
|
||||
[PR #422](https://github.com/lunet-io/markdig/pull/422)
|
||||
[PR #410](https://github.com/lunet-io/markdig/pull/410)
|
||||
|
||||
## 0.18.3 (8 Mar 2020)
|
||||
- Publish NuGet Symbol packages
|
||||
|
||||
## 0.18.2 (8 Mar 2020)
|
||||
- Optimize LineReader.ReadLine in [PR #393](https://github.com/lunet-io/markdig/pull/393)
|
||||
- Use HashSet<T> instead of Dictionary<TKey, TValue> in CharacterMap<T> in [PR #394](https://github.com/lunet-io/markdig/pull/394)
|
||||
- Use BitVector128 in CharacterMap<T> in [PR #396](https://github.com/lunet-io/markdig/pull/396)
|
||||
- Optimizations in StringLineGroup in [PR #399](https://github.com/lunet-io/markdig/pull/399)
|
||||
- Fixed a bug in HeadingRenderer in [PR #402](https://github.com/lunet-io/markdig/pull/402)
|
||||
- Fixes issue #303 in [PR #404](https://github.com/lunet-io/markdig/pull/404)
|
||||
- Make output of HtmlTableRenderer XML wellformed in [PR #406](https://github.com/lunet-io/markdig/pull/406)
|
||||
|
||||
## 0.18.1 (21 Jan 2020)
|
||||
- Re-allow emojis and smileys customization, that was broken in [PR #308](https://github.com/lunet-io/markdig/pull/308) ([PR #386](https://github.com/lunet-io/markdig/pull/386))
|
||||
- Add `IHostProvider` for medialink customization (#337), support protocol-less url (#135) ([(PR #341)](https://github.com/lunet-io/markdig/pull/341))
|
||||
- Add missing Descendants<T> overload ([(PR #387)](https://github.com/lunet-io/markdig/pull/387))
|
||||
|
||||
## 0.18.0 (24 Oct 2019)
|
||||
- Ignore backslashes in GFM AutoLinks ([(PR #357)](https://github.com/lunet-io/markdig/pull/357))
|
||||
- Fix SmartyPants quote matching ([(PR #360)](https://github.com/lunet-io/markdig/pull/360))
|
||||
- Fix generic attributes with values of length 1 ([(PR #361)](https://github.com/lunet-io/markdig/pull/361))
|
||||
- Fix link text balanced bracket matching ([(PR #375)](https://github.com/lunet-io/markdig/pull/375))
|
||||
- Improve overall performance and substantially reduce allocations ([(PR #377)](https://github.com/lunet-io/markdig/pull/377))
|
||||
|
||||
## 0.17.1 (04 July 2019)
|
||||
- Fix regression when escaping HTML characters ([(PR #340)](https://github.com/lunet-io/markdig/pull/340))
|
||||
- Update Emoji Dictionary ([(PR #346)](https://github.com/lunet-io/markdig/pull/346))
|
||||
|
||||
## 0.17.0 (10 May 2019)
|
||||
- Update to latest CommonMark specs 0.29 ([(PR #327)](https://github.com/lunet-io/markdig/pull/327))
|
||||
- Add `AutoLinkOptions` with `OpenInNewWindow`, `UseHttpsForWWWLinks` ([(PR #327)](https://github.com/lunet-io/markdig/pull/327))
|
||||
- Add `DisableHeadings` extension method to `MarkdownPipelineBuilder` ([(PR #327)](https://github.com/lunet-io/markdig/pull/327))
|
||||
- Drop support for netstandard1.1 and Portable Class Libraries ([(PR #319)](https://github.com/lunet-io/markdig/pull/319))
|
||||
- Allow non-ASCII characters in url domain names ([(PR #319)](https://github.com/lunet-io/markdig/pull/319))
|
||||
- Add better support for youtu.be link ([(PR #336)](https://github.com/lunet-io/markdig/pull/336))
|
||||
- Fix backsticks in Markdown.Normalize ([(PR #334)](https://github.com/lunet-io/markdig/pull/334))
|
||||
|
||||
## 0.16.0 (25 Feb 2019)
|
||||
- Improve performance of emoji-abbreviation parser ([(PR #305)](https://github.com/lunet-io/markdig/pull/305))
|
||||
- Change output for math extension to use a rendering more compatible with existing Math JS libraries ([(PR #311)](https://github.com/lunet-io/markdig/pull/311))
|
||||
- Improve emphasis parser to allow to match more than 2 characters ([(PR #301)](https://github.com/lunet-io/markdig/pull/301))
|
||||
- Output attached attributes to a `<tr>` from a table row ([(PR #300)](https://github.com/lunet-io/markdig/pull/300))
|
||||
- Improve MarkdownObject.Descendants() search ([(PR #288)](https://github.com/lunet-io/markdig/pull/288))
|
||||
- Allow to pass a `MarkdownParserContext` ([(PR #285)](https://github.com/lunet-io/markdig/pull/285))
|
||||
|
||||
## 0.15.7 (11 Jan 2019)
|
||||
- Add configurable leading count for ATX headers ([(PR #282)](https://github.com/lunet-io/markdig/pull/282))
|
||||
- Render XML well-formed boolean attribute ([(PR #281)](https://github.com/lunet-io/markdig/pull/281))
|
||||
|
||||
## 0.15.6 (28 Dec 2018)
|
||||
- Fix potential hang when parsing LinkReferenceDefinition #278
|
||||
- Fix parsing of an invalid html entity (#277)
|
||||
- Fix IndexOutOfRangeException while parsing fenced code block with a single trailing space (#276)
|
||||
- Add tests for checking that ArgumentOutOfRangeException doesn't occur on invalid input md string (#275)
|
||||
|
||||
## 0.15.5 (11 Dec 2018)
|
||||
- Empty image alt text for link reference definitions ([(PR #254)](https://github.com/lunet-io/markdig/pull/254))
|
||||
- Fix AutoLink Match links without slash after domain ([(PR #260)](https://github.com/lunet-io/markdig/pull/260))
|
||||
- Make AutoLink ValidPreviousCharacters configurable ([(PR #264)](https://github.com/lunet-io/markdig/pull/264))
|
||||
- Ensuring line breaks when renderer does not have html enabled ([(PR #270)](https://github.com/lunet-io/markdig/pull/270))
|
||||
|
||||
## 0.15.4 (07 Oct 2018)
|
||||
- Add autolink domain GFM validation ([(PR #253)](https://github.com/lunet-io/markdig/pull/253))
|
||||
|
||||
## 0.15.3 (15 Sep 2018)
|
||||
- Add support for RTL ([(PR #239)](https://github.com/lunet-io/markdig/pull/239))
|
||||
- Add MarkdownDocument.LineCount ([(PR #241)](https://github.com/lunet-io/markdig/pull/241))
|
||||
- Fix source positions for link definitions ([(PR #243)](https://github.com/lunet-io/markdig/pull/243))
|
||||
- Add ListItemBlock.Order ([(PR #244)](https://github.com/lunet-io/markdig/pull/244))
|
||||
- Add MarkdownDocument.LineStartIndexes ([(PR #247)](https://github.com/lunet-io/markdig/pull/247))
|
||||
|
||||
## 0.15.2 (21 Aug 2018)
|
||||
- Fix footnotes parsing when they are defined after a container that has been closed in the meantime (#223)
|
||||
|
||||
## 0.15.1 (10 July 2018)
|
||||
- Add support for `netstandard2.0`
|
||||
- Make AutoIdentifierExtension thread safe
|
||||
|
||||
## 0.15.0 (4 Apr 2018)
|
||||
- Add `ConfigureNewLine` extension method to `MarkdownPipelineBuilder` ([(PR #214)](https://github.com/lunet-io/markdig/pull/214))
|
||||
- Add alternative `Use` extension method to `MarkdownPipelineBuilder` that receives an object instance ([(PR #213)](https://github.com/lunet-io/markdig/pull/213))
|
||||
- Added class attribute to media link extension ([(PR #203)](https://github.com/lunet-io/markdig/pull/203))
|
||||
- Optional link rewriter func for HtmlRenderer #143 ([(PR #201)](https://github.com/lunet-io/markdig/pull/201))
|
||||
- Upgrade NUnit3TestAdapter from 3.2 to 3.9 to address Resharper test runner problems ([(PR #199)](https://github.com/lunet-io/markdig/pull/199))
|
||||
- HTML renderer supports converting relative URLs on links and images to absolute #143 ([(PR #197)](https://github.com/lunet-io/markdig/pull/197))
|
||||
|
||||
## 0.14.9 (15 Jan 2018)
|
||||
- AutoLinkParser should to remove mailto: in outputted text ([(PR #195)](https://github.com/lunet-io/markdig/pull/195))
|
||||
- Add support for `music.yandex.ru` and `ok.ru` for MediaLinks extension ([(PR #193)](https://github.com/lunet-io/markdig/pull/193))
|
||||
## 0.14.8 (05 Dec 2017)
|
||||
- Fix potential StackOverflow exception when processing deep nested `|` delimiters (#179)
|
||||
## 0.14.7 (25 Nov 2017)
|
||||
- Fix autolink attached attributes not being displayed properly (#175)
|
||||
## 0.14.6 (21 Nov 2017)
|
||||
- Fix yaml frontmatter issue when ending with a empty line (#170)
|
||||
## 0.14.5 (18 Nov 2017)
|
||||
- Fix changelog link from nuget package
|
||||
## 0.14.4 (18 Nov 2017)
|
||||
- Add changelog.md
|
||||
- Fix bug when a thematic break is inside a fenced code block inside a pending list (#164)
|
||||
- Add support for GFM autolinks (#165, #169)
|
||||
- Better handle YAML frontmatter in case the opening `---` is never actually closed (#160)
|
||||
- Fix link conflict between a link to an image definition and heading auto-identifiers (#159)
|
||||
## 0.14.3
|
||||
- Make EmojiExtension.EnableSmiley public
|
||||
## 0.14.2
|
||||
- Fix issue with emphasis preceded/followed by an HTML entity (#157)
|
||||
- Add support for link reference definitions for Normalize renderer (#155)
|
||||
- Add option to disable smiley parsing in EmojiAndSmiley extension
|
||||
## 0.14.1
|
||||
- Fix crash in Markdown.Normalize to handle HtmlBlock correctly
|
||||
- Add better handling of bullet character for lists in Markdown.Normalize
|
||||
## 0.14.0
|
||||
- Add Markdown.ToPlainText, Add option HtmlRenderer.EnableHtmlForBlock.
|
||||
- Add Markdown.Normalize, to allow to normalize a markdown document. Add NormalizeRenderer, to render a MarkdownDocument back to markdown.
|
||||
## 0.13.4
|
||||
- Add support for single table header row without a table body rows (#141)
|
||||
- ADd support for `nomnoml` diagrams
|
||||
## 0.13.3
|
||||
- Add support for Pandoc YAML frontmatter (#138)
|
||||
## 0.13.2
|
||||
- Add support for UAP10.0 (#137)
|
||||
## 0.13.1
|
||||
- Fix indenting issue after a double digit list block using a tab (#134)
|
||||
## 0.13.0
|
||||
- Update to latest CommonMark specs 0.28
|
||||
## 0.12.3
|
||||
- Fix issue with HTML blocks for heading h2,h3,h4,h5,h6 that were not correctly identified as HTML blocks as per CommonMark spec
|
||||
## 0.12.2
|
||||
- Fix issue with generic attributes used just before a pipe table (issue #121)
|
||||
## 0.12.1
|
||||
- Fix issue with media links extension when a URL to video is used, an unexpected closing `</iframe>` was inserted (issue #119)
|
||||
## 0.12.0
|
||||
- Add new extension JiraLink support (thanks to @clarkd)
|
||||
- Fix issue in html attributes not parsing correctly properties (thanks to @meziantou)
|
||||
- Fix issues detected by an automatic static code analysis tool
|
||||
## 0.11.0
|
||||
- Fix issue with math extension and $$ block parsing not handling correctly beginning of a $$ as a inline math instead (issue #107)
|
||||
- Fix issue with custom attributes for emphasis
|
||||
- Add support for new special custom arrows emoji (`->` `<-` `<->` `<=` `=>` `<==>`)
|
||||
## 0.10.7
|
||||
- Fix issue when an url ends by a dot `.`
|
||||
## 0.10.6
|
||||
- Fix emphasis with HTML entities
|
||||
## 0.10.5
|
||||
- Several minor fixes
|
||||
## 0.10.4
|
||||
- Fix issue with autolinks
|
||||
- Normalize number of columns for tables
|
||||
## 0.10.3
|
||||
- Fix issue with pipetables shifting a cell to a new column (issue #73)
|
||||
## 0.10.2
|
||||
- Fix exception when trying to urlize an url with an unicode character outside the supported range by NormD (issue #75)
|
||||
## 0.10.1
|
||||
- Update to latest CommonMark specs
|
||||
- Fix source span for LinkReferenceDefinition
|
||||
## 0.10.0
|
||||
- Breaking change of the IMarkdownExtension to allow to receive the MarkdownPipeline for the renderers setup
|
||||
## 0.9.1
|
||||
- Fix regression bug with conflicts between autolink extension and html inline/regular links
|
||||
## 0.9.0
|
||||
- Add new Autolink extension
|
||||
## 0.8.5
|
||||
- Allow to force table column alignment to left
|
||||
## 0.8.4
|
||||
- Fix issue when calculating the span of an indented code block within a list. Make sure to include first whitespace on the line
|
||||
## 0.8.3
|
||||
- fix NullReferenceException with Gridtables extension when a single `+` is entered on a line
|
||||
## 0.8.2
|
||||
- fix potential cast exception with Abbreviation extension and empty literals
|
||||
## 0.8.1
|
||||
- new extension to disable URI escaping for non-US-ASCII characters to workaround a bug in Edge/IE
|
||||
- Fix an issue with abbreviations with left/right multiple non-punctuation/space characters
|
||||
## 0.8.0
|
||||
- Update to latest CommonMark specs
|
||||
- Fix empty literal
|
||||
- Add YAML frontmatter extension
|
||||
## 0.7.5
|
||||
- several bug fixes (pipe tables, disable HTML, special attributes, inline maths, abbreviations...)
|
||||
- add support for rowspan in grid tables
|
||||
## 0.7.4
|
||||
- Fix bug with strong emphasis starting at the beginning of a line
|
||||
## 0.7.3
|
||||
- Fix threading issue with pipeline
|
||||
## 0.7.2
|
||||
- Fix rendering of table colspan with non english locale
|
||||
- Fix grid table colspan parsing
|
||||
- Add nofollow extension for links
|
||||
## 0.7.1
|
||||
- Fix issue in smarty pants which could lead to an InvalidCastException
|
||||
- Update parsers to latest CommonMark specs
|
||||
## 0.7.0
|
||||
- Update to latest NETStandard.Library 1.6.0
|
||||
- Fix issue with digits in auto-identifier extension
|
||||
- Fix incorrect start of span calculated for code indented blocks
|
||||
## 0.6.2
|
||||
- Handle latest CommonMark specs for corner cases for emphasis (See https://talk.commonmark.org/t/emphasis-strong-emphasis-corner-cases/2123/1 )
|
||||
## 0.6.1:
|
||||
- Fix issue with autoidentifier extension overriding manual HTML attributes id on headings
|
||||
## 0.6.0
|
||||
- Fix conflicts between PipeTables and SmartyPants extensions
|
||||
- Add SelfPipeline extension
|
||||
BIN
img/BenchmarkCPU.png
Normal file
BIN
img/BenchmarkCPU.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
BIN
img/BenchmarkMemory.png
Normal file
BIN
img/BenchmarkMemory.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2016, Alexandre Mutel
|
||||
Copyright (c) 2018-2019, Alexandre Mutel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification
|
||||
|
||||
155
readme.md
155
readme.md
@@ -1,55 +1,80 @@
|
||||
# Markdig [](https://ci.appveyor.com/project/xoofx/markdig) [](https://www.nuget.org/packages/Markdig/)
|
||||
# Markdig [](https://github.com/lunet-io/markdig/actions) [](https://coveralls.io/github/lunet-io/markdig?branch=master) [](https://www.nuget.org/packages/Markdig/) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FRGHXBTP442JL)
|
||||
|
||||
<img align="right" width="160px" height="160px" src="img/markdig.png">
|
||||
|
||||
Markdig is a fast, powerfull, [CommonMark](http://commonmark.org/) compliant, extensible Markdown processor for .NET.
|
||||
Markdig is a fast, powerful, [CommonMark](http://commonmark.org/) compliant, extensible Markdown processor for .NET.
|
||||
|
||||
> NOTE: The repository is under construction. There will be a dedicated website and proper documentation at some point!
|
||||
|
||||
You can **try Markdig online** and compare it to other implementations on [babelmark3](http://babelmark.github.io/)
|
||||
You can **try Markdig online** and compare it to other implementations on [babelmark3](https://babelmark.github.io/?text=Hello+**Markdig**!)
|
||||
|
||||
## Features
|
||||
|
||||
- **Very fast parser** (no-regexp), very lightweight in terms of GC pressure. See benchmarks
|
||||
- **Abstract Syntax Tree**
|
||||
- **Very fast parser and html renderer** (no-regexp), very lightweight in terms of GC pressure. See benchmarks
|
||||
- **Abstract Syntax Tree** with precise source code location for syntax tree, useful when building a Markdown editor.
|
||||
- Checkout [MarkdownEditor for Visual Studio](https://visualstudiogallery.msdn.microsoft.com/eaab33c3-437b-4918-8354-872dfe5d1bfe) powered by Markdig!
|
||||
- Converter to **HTML**
|
||||
- Passing more than **600+ tests** from the latest [CommonMark specs](http://spec.commonmark.org/)
|
||||
- Passing more than **600+ tests** from the latest [CommonMark specs (0.29)](http://spec.commonmark.org/)
|
||||
- Includes all the core elements of CommonMark:
|
||||
- including GFM fenced code blocks.
|
||||
- including **GFM fenced code blocks**.
|
||||
- **Extensible** architecture
|
||||
- Even the core Markdown/CommonMark parsing is pluggable, so it allows to disable builtin Markdown/Commonmark parsing (e.g [Disable HTML parsing](https://github.com/lunet-io/markdig/blob/7964bd0160d4c18e4155127a4c863d61ebd8944a/src/Markdig/MarkdownExtensions.cs#L306)) or change behaviour (e.g change matching `#` of a headers with `@`)
|
||||
- Built-in with **18+ extensions**, including:
|
||||
- Built-in with **20+ extensions**, including:
|
||||
- 2 kind of tables:
|
||||
- **Pipe tables** (inspired from Github tables and [PanDoc - Pipe Tables](http://pandoc.org/README.html#extension-pipe_tables))
|
||||
- **Grid tables** (inspired from [Pandoc - Grid Tables](http://pandoc.org/README.html#extension-grid_tables))
|
||||
- **Extra emphasis** (inspired from [Pandoc - Emphasis](http://pandoc.org/README.html#strikeout) and [Markdown-it](https://markdown-it.github.io/))
|
||||
- [**Pipe tables**](src/Markdig.Tests/Specs/PipeTableSpecs.md) (inspired from GitHub tables and [PanDoc - Pipe Tables](http://pandoc.org/README.html#extension-pipe_tables))
|
||||
- [**Grid tables**](src/Markdig.Tests/Specs/GridTableSpecs.md) (inspired from [Pandoc - Grid Tables](http://pandoc.org/README.html#extension-grid_tables))
|
||||
- [**Extra emphasis**](src/Markdig.Tests/Specs/EmphasisExtraSpecs.md) (inspired from [Pandoc - Emphasis](http://pandoc.org/README.html#strikeout) and [Markdown-it](https://markdown-it.github.io/))
|
||||
- strike through `~~`,
|
||||
- Subscript `~`
|
||||
- Superscript `^`
|
||||
- Inserted `++`
|
||||
- Marked `==`
|
||||
- **Special attributes** or attached HTML attributes (inspired from [PHP Markdown Extra - Special Attributes](https://michelf.ca/projects/php-markdown/extra/#spe-attr))
|
||||
- **Definition lists** (inspired from [PHP Markdown Extra - Definitions Lists](https://michelf.ca/projects/php-markdown/extra/#def-list))
|
||||
- **Footnotes** (inspired from [PHP Markdown Extra - Footnotes](https://michelf.ca/projects/php-markdown/extra/#footnotes))
|
||||
- **Auto-identifiers** for headings (similar to [Pandoc - Auto Identifiers](http://pandoc.org/README.html#extension-auto_identifiers))
|
||||
- **Extra bullet lists**, supporting alpha bullet `a.` `b.` and roman bullet (`i`, `ii`...etc.)
|
||||
- **Media support** for media url (youtube, vimeo, mp4...etc.) (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/embedded-audio-and-video/441))
|
||||
- **Abbreviations** (inspired from [PHP Markdown Extra - Abbreviations](https://michelf.ca/projects/php-markdown/extra/#abbr))
|
||||
- **Citation** text by enclosing `""...""` (inspired by this [CommonMark discussion ](https://talk.commonmark.org/t/referencing-creative-works-with-cite/892))
|
||||
- **Custom containers** similar to fenced code block `:::` for generating a proper `<div>...</div>` instead (inspired by this [CommonMark discussion ](https://talk.commonmark.org/t/custom-container-for-block-and-inline/2051))
|
||||
- **Figures** (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/image-tag-should-expand-to-figure-when-used-with-title/265/5))
|
||||
- **Footers** (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/syntax-for-footer/2070))
|
||||
- **Mathematics**/Latex extension by enclosing `$$` for block and `$` for inline math (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/mathematics-extension/457/31))
|
||||
- **Soft lines as hard lines**
|
||||
- **Emoji** support (inspired from [Markdown-it](https://markdown-it.github.io/))
|
||||
- **SmartyPants** (inspired from [Daring Fireball - SmartyPants](https://daringfireball.net/projects/smartypants/))
|
||||
- **Bootstrap** class (to output bootstrap class)
|
||||
- Compatible with .NET 3.5, 4.0+ and .NET Core (`netstandard1.1+`)
|
||||
- [**Special attributes**](src/Markdig.Tests/Specs/GenericAttributesSpecs.md) or attached HTML attributes (inspired from [PHP Markdown Extra - Special Attributes](https://michelf.ca/projects/php-markdown/extra/#spe-attr))
|
||||
- [**Definition lists**](src/Markdig.Tests/Specs/DefinitionListSpecs.md) (inspired from [PHP Markdown Extra - Definitions Lists](https://michelf.ca/projects/php-markdown/extra/#def-list))
|
||||
- [**Footnotes**](src/Markdig.Tests/Specs/FootnotesSpecs.md) (inspired from [PHP Markdown Extra - Footnotes](https://michelf.ca/projects/php-markdown/extra/#footnotes))
|
||||
- [**Auto-identifiers**](src/Markdig.Tests/Specs/AutoIdentifierSpecs.md) for headings (similar to [Pandoc - Auto Identifiers](http://pandoc.org/README.html#extension-auto_identifiers))
|
||||
- [**Auto-links**](src/Markdig.Tests/Specs/AutoLinks.md) generates links if a text starts with `http://` or `https://` or `ftp://` or `mailto:` or `www.xxx.yyy`
|
||||
- [**Task Lists**](src/Markdig.Tests/Specs/TaskListSpecs.md) inspired from [Github Task lists](https://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments).
|
||||
- [**Extra bullet lists**](src/Markdig.Tests/Specs/ListExtraSpecs.md), supporting alpha bullet `a.` `b.` and roman bullet (`i`, `ii`...etc.)
|
||||
- [**Media support**](src/Markdig.Tests/Specs/MediaSpecs.md) for media url (youtube, vimeo, mp4...etc.) (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/embedded-audio-and-video/441))
|
||||
- [**Abbreviations**](src/Markdig.Tests/Specs/AbbreviationSpecs.md) (inspired from [PHP Markdown Extra - Abbreviations](https://michelf.ca/projects/php-markdown/extra/#abbr))
|
||||
- [**Citation**](src/Markdig.Tests/Specs/FigureFooterAndCiteSpecs.md) text by enclosing `""...""` (inspired by this [CommonMark discussion ](https://talk.commonmark.org/t/referencing-creative-works-with-cite/892))
|
||||
- [**Custom containers**](src/Markdig.Tests/Specs/CustomContainerSpecs.md) similar to fenced code block `:::` for generating a proper `<div>...</div>` instead (inspired by this [CommonMark discussion ](https://talk.commonmark.org/t/custom-container-for-block-and-inline/2051))
|
||||
- [**Figures**](src/Markdig.Tests/Specs/FigureFooterAndCiteSpecs.md) (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/image-tag-should-expand-to-figure-when-used-with-title/265/5))
|
||||
- [**Footers**](src/Markdig.Tests/Specs/FigureFooterAndCiteSpecs.md) (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/syntax-for-footer/2070))
|
||||
- [**Mathematics**](src/Markdig.Tests/Specs/MathSpecs.md)/Latex extension by enclosing `$$` for block and `$` for inline math (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/mathematics-extension/457/31))
|
||||
- [**Soft lines as hard lines**](src/Markdig.Tests/Specs/HardlineBreakSpecs.md)
|
||||
- [**Emoji**](src/Markdig.Tests/Specs/EmojiSpecs.md) support (inspired from [Markdown-it](https://markdown-it.github.io/))
|
||||
- [**SmartyPants**](src/Markdig.Tests/Specs/SmartyPantsSpecs.md) (inspired from [Daring Fireball - SmartyPants](https://daringfireball.net/projects/smartypants/))
|
||||
- [**Bootstrap**](src/Markdig.Tests/Specs/BootstrapSpecs.md) class (to output bootstrap class)
|
||||
- [**Diagrams**](src/Markdig.Tests/Specs/DiagramsSpecs.md) extension whenever a fenced code block contains a special keyword, it will be converted to a div block with the content as-is (currently, supports [`mermaid`](https://knsv.github.io/mermaid/) and [`nomnoml`](https://github.com/skanaar/nomnoml) diagrams)
|
||||
- [**YAML Front Matter**](src/Markdig.Tests/Specs/YamlSpecs.md) to parse without evaluating the front matter and to discard it from the HTML output (typically used for previewing without the front matter in MarkdownEditor)
|
||||
- [**JIRA links**](src/Markdig.Tests/Specs/JiraLinks.md) to automatically generate links for JIRA project references (Thanks to @clarkd: https://github.com/clarkd/MarkdigJiraLinker)
|
||||
- Starting with Markdig version `0.20.0+`, Markdig is compatible only with `NETStandard 2.0`, `NETStandard 2.1`, `NETCoreApp 2.1` and `NETCoreApp 3.1`.
|
||||
|
||||
If you are looking for support for an old .NET Framework 3.5 or 4.0, you can download Markdig `0.18.3`.
|
||||
|
||||
### Third Party Extensions
|
||||
|
||||
- [**WPF/XAML Markdown Renderer**: `markdig.wpf`](https://github.com/Kryptos-FR/markdig.wpf)
|
||||
- [**WPF/XAML Markdown Renderer**: `Neo.Markdig.Xaml`](https://github.com/neolithos/NeoMarkdigXaml)
|
||||
- [**Syntax highlighting**: `Markdig.SyntaxHighlighting`](https://github.com/RichardSlater/Markdig.SyntaxHighlighting)
|
||||
- [**Embedded C# scripting**: `Markdig.Extensions.ScriptCs`](https://github.com/macaba/Markdig.Extensions.ScriptCs)
|
||||
|
||||
## Documentation
|
||||
|
||||
> The repository is under construction. There will be a dedicated website and proper documentation at some point!
|
||||
|
||||
While there is not yet a dedicated documentation, you can find from the [specs documentation](src/Markdig.Tests/Specs/readme.md) how to use these extensions.
|
||||
|
||||
In the meantime, you can have a "behind the scene" article about Markdig in my blog post ["Implementing a Markdown Engine for .NET"](http://xoofx.com/blog/2016/06/13/implementing-a-markdown-processor-for-dotnet/)
|
||||
|
||||
## Download
|
||||
|
||||
Markdig is available as a NuGet package: [](https://www.nuget.org/packages/Markdig/)
|
||||
|
||||
Also [Markdig.Signed](https://www.nuget.org/packages/Markdig.Signed/) NuGet package provides signed assemblies.
|
||||
|
||||
## Usage
|
||||
|
||||
The main entry point for the API is the `Markdig.Markdown` class:
|
||||
@@ -61,7 +86,7 @@ var result = Markdown.ToHtml("This is a text with some *emphasis*");
|
||||
Console.WriteLine(result); // prints: <p>This is a text with some <em>emphasis</em></p>
|
||||
```
|
||||
|
||||
In order to activate most of all advanced extensions (except Emoji, SoftLine as HarLine and SmartyPants)
|
||||
In order to activate most of all advanced extensions (except Emoji, SoftLine as HardLine, Bootstrap, YAML Front Matter, JiraLinks and SmartyPants)
|
||||
|
||||
```csharp
|
||||
// Configure the pipeline with all advanced extensions active
|
||||
@@ -71,6 +96,10 @@ var result = Markdown.ToHtml("This is a text with some *emphasis*", pipeline);
|
||||
|
||||
You can have a look at the [MarkdownExtensions](https://github.com/lunet-io/markdig/blob/master/src/Markdig/MarkdownExtensions.cs) that describes all actionable extensions (by modifying the MarkdownPipeline)
|
||||
|
||||
## Build
|
||||
|
||||
In order to build Markdig, you need to install [.NET Core RTM](https://www.microsoft.com/net/core)
|
||||
|
||||
## License
|
||||
|
||||
This software is released under the [BSD-Clause 2 license](https://github.com/lunet-io/markdig/blob/master/license.txt).
|
||||
@@ -80,27 +109,44 @@ This software is released under the [BSD-Clause 2 license](https://github.com/lu
|
||||
|
||||
This is an early preview of the benchmarking against various implementations:
|
||||
|
||||
- Markdig: itself
|
||||
- CommonMarkCpp: [cmark](https://github.com/jgm/cmark), Reference C implementation of CommonMark, no support for extensions
|
||||
- [CommonMark.NET](https://github.com/Knagis/CommonMark.NET): CommonMark implementation for .NET, no support for extensions, port of cmark
|
||||
- [CommonMarkNet (devel)](https://github.com/AMDL/CommonMark.NET/tree/pipe-tables): An evolution of CommonMark.NET, supports extensions, not released yet
|
||||
- [MarkdownDeep](https://github.com/toptensoftware/markdowndeep) another .NET implementation
|
||||
- [MarkdownSharp](https://github.com/Kiri-rin/markdownsharp): Open source C# implementation of Markdown processor, as featured on Stack Overflow, regexp based.
|
||||
- [Moonshine](https://github.com/brandonc/moonshine): popular C Markdown processor
|
||||
**C implementations**:
|
||||
|
||||
- [cmark](https://github.com/jgm/cmark) (version: 0.25.0): Reference C implementation of CommonMark, no support for extensions
|
||||
- [Moonshine](https://github.com/brandonc/moonshine) (version: : popular C Markdown processor
|
||||
|
||||
**.NET implementations**:
|
||||
|
||||
- [Markdig](https://github.com/lunet-io/markdig) (version: 0.5.x): itself
|
||||
- [CommonMark.NET(master)](https://github.com/Knagis/CommonMark.NET) (version: 0.11.0): CommonMark implementation for .NET, no support for extensions, port of cmark
|
||||
- [CommonMark.NET(pipe_tables)](https://github.com/AMDL/CommonMark.NET/tree/pipe-tables): An evolution of CommonMark.NET, supports extensions, not released yet
|
||||
- [MarkdownDeep](https://github.com/toptensoftware/markdowndeep) (version: 1.5.0): another .NET implementation
|
||||
- [MarkdownSharp](https://github.com/Kiri-rin/markdownsharp) (version: 1.13.0): Open source C# implementation of Markdown processor, as featured on Stack Overflow, regexp based.
|
||||
- [Marked.NET](https://github.com/T-Alex/MarkedNet) (version: 1.0.5) port of original [marked.js](https://github.com/chjj/marked) project
|
||||
- [Microsoft.DocAsCode.MarkdownLite](https://github.com/dotnet/docfx/tree/dev/src/Microsoft.DocAsCode.MarkdownLite) (version: 2.0.1) used by the [docfx](https://github.com/dotnet/docfx) project
|
||||
|
||||
**JavaScript/V8 implementations**:
|
||||
|
||||
- [Strike.V8](https://github.com/SimonCropp/Strike) (version: 1.5.0) [marked.js](https://github.com/chjj/marked) running in Google V8 (not .NET based)
|
||||
|
||||
### Analysis of the results:
|
||||
|
||||
- Markdig is roughly **x100 times faster than MarkdownSharp**
|
||||
- **Among the best in CPU**, Extremelly competitive and often faster than other implementations (not feature wise equivalent)
|
||||
- Markdig is roughly **x100 times faster than MarkdownSharp**, **30x times faster than docfx**
|
||||
- **Among the best in CPU**, Extremely competitive and often faster than other implementations (not feature wise equivalent)
|
||||
- **15% to 30% less allocations** and GC pressure
|
||||
|
||||
Because Marked.NET, MarkdownSharp and DocAsCode.MarkdownLite are way too slow, they are not included in the following charts:
|
||||
|
||||
### Performance in x86:
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
### Performance for x86:
|
||||
|
||||
```
|
||||
BenchmarkDotNet-Dev=v0.9.6.0+
|
||||
BenchmarkDotNet-Dev=v0.9.7.0+
|
||||
OS=Microsoft Windows NT 6.2.9200.0
|
||||
Processor=Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz, ProcessorCount=8
|
||||
Processor=Intel(R) Core(TM) i7-4770 CPU 3.40GHz, ProcessorCount=8
|
||||
Frequency=3319351 ticks, Resolution=301.2637 ns, Timer=TSC
|
||||
HostCLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE
|
||||
JitModules=clrjit-v4.6.1080.0
|
||||
@@ -108,14 +154,18 @@ JitModules=clrjit-v4.6.1080.0
|
||||
Type=Program Mode=SingleRun LaunchCount=2
|
||||
WarmupCount=2 TargetCount=10
|
||||
|
||||
Method | Median | StdDev | Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op |
|
||||
--------------------- |---------- |---------- |------- |------ |------- |------------------- |
|
||||
TestMarkdig | 5.4332 ms | 0.0809 ms | 96.00 | 36.00 | 84.00 | 1,218,643.59 |
|
||||
TestCommonMarkCpp | 4.0150 ms | 0.1208 ms | - | - | 180.00 | 454,859.74 |
|
||||
TestCommonMarkNet | 4.5448 ms | 0.0323 ms | 193.00 | 12.00 | 84.00 | 1,406,367.27 |
|
||||
TestCommonMarkNetNew | 5.4811 ms | 0.0327 ms | 193.00 | 96.00 | 84.00 | 1,738,465.42 |
|
||||
TestMarkdownDeep | 7.5881 ms | 0.0554 ms | 205.00 | 96.00 | 84.00 | 1,758,383.79 |
|
||||
TestMoonshine | 5.8586 ms | 0.0764 ms | - | - | 215.00 | 565,000.72 |
|
||||
Method | Median | StdDev |Scaled | Gen 0 | Gen 1| Gen 2|Bytes Allocated/Op |
|
||||
--------------------------- |------------ |---------- |------ | ------ |------|---------|------------------ |
|
||||
Markdig | 5.5316 ms | 0.0372 ms | 0.71 | 56.00| 21.00| 49.00| 1,285,917.31 |
|
||||
CommonMark.NET(master) | 4.7035 ms | 0.0422 ms | 0.60 | 113.00| 7.00| 49.00| 1,502,404.60 |
|
||||
CommonMark.NET(pipe_tables) | 5.6164 ms | 0.0298 ms | 0.72 | 111.00| 56.00| 49.00| 1,863,128.13 |
|
||||
MarkdownDeep | 7.8193 ms | 0.0334 ms | 1.00 | 120.00| 56.00| 49.00| 1,884,854.85 |
|
||||
cmark | 4.2698 ms | 0.1526 ms | 0.55 | -| -| -| NA |
|
||||
Moonshine | 6.0929 ms | 0.1053 ms | 1.28 | -| -| -| NA |
|
||||
Strike.V8 | 10.5895 ms | 0.0492 ms | 1.35 | -| -| -| NA |
|
||||
Marked.NET | 207.3169 ms | 5.2628 ms | 26.51 | 0.00| 0.00| 0.00| 303,125,228.65 |
|
||||
MarkdownSharp | 675.0185 ms | 2.8447 ms | 86.32 | 40.00| 27.00| 41.00| 2,413,394.17 |
|
||||
Microsoft DocfxMarkdownLite | 166.3357 ms | 0.4529 ms | 21.27 |4,452.00|948.00|11,167.00| 180,218,359.60 |
|
||||
```
|
||||
|
||||
### Performance for x64:
|
||||
@@ -139,6 +189,12 @@ WarmupCount=2 TargetCount=10
|
||||
TestMarkdownDeep | 7.4076 ms | 0.0617 ms | 318.00 | 186.00 | 84.00 | 2,576,728.69 |
|
||||
```
|
||||
|
||||
## Donate
|
||||
|
||||
If you are using this library and find it useful for your project, please consider a donation for it!
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FRGHXBTP442JL)
|
||||
|
||||
## Credits
|
||||
|
||||
Thanks to the fantastic work done by [John Mac Farlane](http://johnmacfarlane.net/) for the CommonMark specs and all the people involved in making Markdown a better standard!
|
||||
@@ -149,6 +205,7 @@ Thanks also to the project [BenchmarkDotNet](https://github.com/PerfDotNet/Bench
|
||||
|
||||
Some decoding part (e.g HTML [EntityHelper.cs](https://github.com/lunet-io/markdig/blob/master/src/Markdig/Helpers/EntityHelper.cs)) have been re-used from [CommonMark.NET](https://github.com/Knagis/CommonMark.NET)
|
||||
|
||||
Thanks to the work done by @clarkd on the JIRA Link extension (https://github.com/clarkd/MarkdigJiraLinker), now included with this project!
|
||||
## Author
|
||||
|
||||
Alexandre MUTEL aka [xoofx](http://xoofx.com)
|
||||
|
||||
@@ -1,43 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{6A19F040-BC7C-4283-873A-177B5324F1ED}</ProjectGuid>
|
||||
<TargetFrameworks>net471</TargetFrameworks>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Markdig.Benchmarks</RootNamespace>
|
||||
<AssemblyName>Markdig.Benchmarks</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<TargetFrameworkProfile />
|
||||
<CopyNuGetImplementations>true</CopyNuGetImplementations>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="spec.md" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="CommonMarkNew, Version=0.1.0.0, Culture=neutral, PublicKeyToken=001ef8810438905d, processorArchitecture=MSIL">
|
||||
<HintPath>lib\CommonMarkNew.dll</HintPath>
|
||||
@@ -45,31 +15,12 @@
|
||||
<Aliases>newcmark</Aliases>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Build" />
|
||||
<Reference Include="Microsoft.Build.Framework" />
|
||||
<Reference Include="Microsoft.Build.Utilities.v4.0" />
|
||||
<Reference Include="MoonShine">
|
||||
<HintPath>lib\MoonShine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MarkdownDeep">
|
||||
<HintPath>lib\MarkdownDeep.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CommonMarkLib.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="TestMatchPerf.cs" />
|
||||
<Compile Include="TestStringPerf.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="cmark.dll">
|
||||
@@ -83,21 +34,16 @@
|
||||
<Content Include="spec.md">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="app.config" />
|
||||
<None Include="project.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Markdig">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Markdig\Bin\$(Configuration)\net40\Markdig.dll</HintPath>
|
||||
</Reference>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.10.6" />
|
||||
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.10.6" />
|
||||
<PackageReference Include="CommonMark.NET" Version="0.15.1" />
|
||||
<PackageReference Include="MarkdownSharp" Version="1.13.0.0" />
|
||||
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="0.8.31-beta" />
|
||||
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="1.0.41.0" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Markdig\Markdig.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(NuGetPackageRoot)' == ''">
|
||||
<NuGetPackageRoot>$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||
</PropertyGroup>
|
||||
<ImportGroup>
|
||||
<Import Project="$(NuGetPackageRoot)\Microsoft.Diagnostics.Tracing.TraceEvent\1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets" Condition="Exists('$(NuGetPackageRoot)\Microsoft.Diagnostics.Tracing.TraceEvent\1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets')" />
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -5,14 +5,9 @@ extern alias newcmark;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnostics;
|
||||
using BenchmarkDotNet.Diagnostics.Windows;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Running;
|
||||
using newcmark::CommonMark.Extension;
|
||||
using Markdig;
|
||||
|
||||
|
||||
@@ -55,7 +50,7 @@ namespace Testamina.Markdig.Benchmarks
|
||||
//CommonMark.CommonMarkConverter.Parse(reader);
|
||||
//reader.Dispose();
|
||||
//var writer = new StringWriter();
|
||||
global::CommonMark.CommonMarkConverter.Convert(text);
|
||||
CommonMark.CommonMarkConverter.Convert(text);
|
||||
//writer.Flush();
|
||||
//writer.ToString();
|
||||
}
|
||||
@@ -131,7 +126,7 @@ namespace Testamina.Markdig.Benchmarks
|
||||
var config = ManualConfig.Create(DefaultConfig.Instance);
|
||||
//var gcDiagnoser = new MemoryDiagnoser();
|
||||
//config.Add(new Job { Mode = Mode.SingleRun, LaunchCount = 2, WarmupCount = 2, IterationTime = 1024, TargetCount = 10 });
|
||||
config.Add(new Job { Mode = Mode.Throughput, LaunchCount = 2, WarmupCount = 2, TargetCount = 10 });
|
||||
//config.Add(new Job { Mode = Mode.Throughput, LaunchCount = 2, WarmupCount = 2, TargetCount = 10 });
|
||||
//config.Add(gcDiagnoser);
|
||||
|
||||
//var config = DefaultConfig.Instance;
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Testamina.Markdig.Benchmarks")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Testamina.Markdig.Benchmarks")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("6a19f040-bc7c-4283-873a-177b5324f1ed")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"profiles": {
|
||||
"CLASSIC": {
|
||||
"executablePath": "Testamina.Markdig.Benchmarks.dll",
|
||||
"workingDirectory": "..\\..\\artifacts\\bin\\Testamina.Markdig.Benchmarks\\Debug\\net45"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Markdig.Helpers;
|
||||
|
||||
namespace Testamina.Markdig.Benchmarks
|
||||
{
|
||||
@@ -52,7 +48,7 @@ namespace Testamina.Markdig.Benchmarks
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public class TestMatchPerf
|
||||
{
|
||||
private readonly TextMatchHelper matcher;
|
||||
@@ -82,4 +78,5 @@ namespace Testamina.Markdig.Benchmarks
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/></startup></configuration>
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"runtimes": {
|
||||
"win-x86": {},
|
||||
"win-x64": {}
|
||||
},
|
||||
"frameworks": {
|
||||
"net451": {
|
||||
"compilationOptions": {
|
||||
"define": [
|
||||
"CLASSIC"
|
||||
]
|
||||
},
|
||||
"frameworkAssemblies": {
|
||||
"Microsoft.Build": "4.0.0.0",
|
||||
"Microsoft.Build.Framework": "4.0.0.0",
|
||||
"Microsoft.Build.Utilities.v4.0": "4.0.0.0",
|
||||
"System.Management": "4.0.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"BenchmarkDotNet": "0.9.6",
|
||||
"BenchmarkDotNet.Diagnostics.Windows": "0.9.6",
|
||||
"CommonMark.NET": "0.11.0",
|
||||
"MarkdownSharp": "1.13.0.0",
|
||||
"Microsoft.Diagnostics.Runtime": "0.8.31-beta",
|
||||
"Microsoft.Diagnostics.Tracing.TraceEvent": "1.0.41.0"
|
||||
}
|
||||
}
|
||||
@@ -5397,7 +5397,7 @@ foo
|
||||
## Entity and numeric character references
|
||||
|
||||
All valid HTML entity references and numeric character
|
||||
references, except those occuring in code blocks and code spans,
|
||||
references, except those occurring in code blocks and code spans,
|
||||
are recognized as such and treated as equivalent to the
|
||||
corresponding Unicode characters. Conforming CommonMark parsers
|
||||
need not store information about whether a particular character
|
||||
|
||||
13
src/Markdig.Signed/Markdig.Signed.csproj
Normal file
13
src/Markdig.Signed/Markdig.Signed.csproj
Normal file
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<PackageId>Markdig.Signed</PackageId>
|
||||
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Markdig\**\*.cs" Exclude="..\Markdig\obj\**;..\Markdig\bin\**">
|
||||
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<Import Project="..\Markdig\Markdig.targets" />
|
||||
</Project>
|
||||
BIN
src/Markdig.Signed/key.snk
Normal file
BIN
src/Markdig.Signed/key.snk
Normal file
Binary file not shown.
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
BIN
src/Markdig.Tests/ArgumentOutOfRangeException.md
Normal file
BIN
src/Markdig.Tests/ArgumentOutOfRangeException.md
Normal file
Binary file not shown.
@@ -1,110 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{A0C5CB5F-5568-40AB-B945-D6D2664D51B0}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Markdig.Tests</RootNamespace>
|
||||
<AssemblyName>Markdig.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<CopyNuGetImplementations>true</CopyNuGetImplementations>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
<TargetFrameworks>net452;netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
|
||||
<OutputType>Library</OutputType>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Markdig">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\Markdig\Bin\$(Configuration)\net40\Markdig.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<PackageReference Include="coverlet.msbuild" Version="2.8.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Specs\Specs.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Specs.tt</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="TestHtmlHelper.cs" />
|
||||
<Compile Include="TestLineReader.cs" />
|
||||
<Compile Include="TestLinkHelper.cs" />
|
||||
<Compile Include="TestSourcePosition.cs" />
|
||||
<Compile Include="TestStringSliceList.cs" />
|
||||
<Compile Include="TestPlayParser.cs" />
|
||||
<Compile Include="TextAssert.cs" />
|
||||
<Compile Include="TestParser.cs" />
|
||||
<ProjectReference Include="..\Markdig\Markdig.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="project.json" />
|
||||
<None Include="Specs\AutoIdentifierSpecs.md" />
|
||||
<None Include="Specs\AbbreviationSpecs.md" />
|
||||
<None Include="Specs\FigureFooterAndCiteSpecs.md" />
|
||||
<None Include="Specs\ListExtraSpecs.md" />
|
||||
<None Include="Specs\GenericAttributesSpecs.md" />
|
||||
<None Include="Specs\CustomContainerSpecs.md" />
|
||||
<None Include="Specs\DefinitionListSpecs.md" />
|
||||
<None Include="Specs\EmojiSpecs.md" />
|
||||
<None Include="Specs\FootnotesSpecs.md" />
|
||||
<None Include="Specs\GridTableSpecs.md" />
|
||||
<None Include="Specs\HardlineBreakSpecs.md" />
|
||||
<None Include="Specs\BootstrapSpecs.md" />
|
||||
<None Include="Specs\TaskListSpecs.md" />
|
||||
<None Include="Specs\SmartyPantsSpecs.md" />
|
||||
<None Include="Specs\MediaSpecs.md" />
|
||||
<None Include="Specs\MathSpecs.md" />
|
||||
<None Include="Specs\PipeTableSpecs.md" />
|
||||
<None Include="Specs\EmphasisExtraSpecs.md" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Specs\Specs.tt">
|
||||
<Generator>TextTemplatingFileGenerator</Generator>
|
||||
<LastGenOutput>Specs.cs</LastGenOutput>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
|
||||
</Project>
|
||||
265
src/Markdig.Tests/MiscTests.cs
Normal file
265
src/Markdig.Tests/MiscTests.cs
Normal file
@@ -0,0 +1,265 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Markdig.Extensions.AutoLinks;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
public class MiscTests
|
||||
{
|
||||
[Test]
|
||||
public void LinkWithInvalidNonAsciiDomainNameIsIgnored()
|
||||
{
|
||||
// Url from https://github.com/lunet-io/markdig/issues/438
|
||||
_ = Markdown.ToHtml("[minulém díle](http://V%20minulém%20díle%20jsme%20nainstalovali%20SQL%20Server,%20který%20je%20nutný%20pro%20běh%20Configuration%20Manageru.%20Dnes%20nás%20čeká%20instalace%20WSUS,%20což%20je%20produkt,%20jež%20je%20možné%20používat%20i%20jako%20samostatnou%20funkci%20ve%20Windows%20Serveru,%20který%20se%20stará%20o%20stažení%20a%20instalaci%20aktualizací%20z%20Microsoft%20Update%20na%20klientské%20počítače.%20Stejně%20jako%20v%20předchozích%20dílech,%20tak%20i%20v%20tomto%20si%20ukážeme%20obě%20varianty%20instalace%20–%20a%20to%20jak%20instalaci%20z%20PowerShellu,%20tak%20instalaci%20pomocí%20GUI.) ");
|
||||
|
||||
// Valid IDN
|
||||
TestParser.TestSpec("[foo](http://ünicode.com)", "<p><a href=\"http://xn--nicode-2ya.com\">foo</a></p>");
|
||||
TestParser.TestSpec("[foo](http://ünicode.ünicode.com)", "<p><a href=\"http://xn--nicode-2ya.xn--nicode-2ya.com\">foo</a></p>");
|
||||
|
||||
// Invalid IDN
|
||||
TestParser.TestSpec("[foo](http://ünicode..com)", "<p><a href=\"http://%C3%BCnicode..com\">foo</a></p>");
|
||||
}
|
||||
|
||||
[TestCase("link [foo [bar]]")] // https://spec.commonmark.org/0.29/#example-508
|
||||
[TestCase("link [foo][bar]")]
|
||||
[TestCase("link [][foo][bar][]")]
|
||||
[TestCase("link [][foo][bar][[]]")]
|
||||
[TestCase("link [foo] [bar]")]
|
||||
[TestCase("link [[foo] [] [bar] [[abc]def]]")]
|
||||
[TestCase("[]")]
|
||||
[TestCase("[ ]")]
|
||||
[TestCase("[bar][]")]
|
||||
[TestCase("[bar][ foo]")]
|
||||
[TestCase("[bar][foo ][]")]
|
||||
[TestCase("[bar][fo[ ]o ][][]")]
|
||||
[TestCase("[a]b[c[d[e]f]g]h")]
|
||||
[TestCase("a[b[c[d]e]f[g]h]i foo [j]k[l[m]n]o")]
|
||||
[TestCase("a[b[c[d]e]f[g]h]i[] [][foo][bar][] foo [j]k[l[m]n]o")]
|
||||
[TestCase("a[b[c[d]e]f[g]h]i foo [j]k[l[m]n]o[][]")]
|
||||
public void LinkTextMayContainBalancedBrackets(string linkText)
|
||||
{
|
||||
string markdown = $"[{linkText}](/uri)";
|
||||
string expected = $@"<p><a href=""/uri"">{linkText}</a></p>";
|
||||
|
||||
TestParser.TestSpec(markdown, expected);
|
||||
|
||||
// Make the link text unbalanced
|
||||
foreach (var bracketIndex in linkText
|
||||
.Select((c, i) => new Tuple<char, int>(c, i))
|
||||
.Where(t => t.Item1 == '[' || t.Item1 == ']')
|
||||
.Select(t => t.Item2))
|
||||
{
|
||||
string brokenLinkText = linkText.Remove(bracketIndex, 1);
|
||||
|
||||
markdown = $"[{brokenLinkText}](/uri)";
|
||||
expected = $@"<p><a href=""/uri"">{brokenLinkText}</a></p>";
|
||||
|
||||
string actual = Markdown.ToHtml(markdown);
|
||||
Assert.AreNotEqual(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsIssue356Corrected()
|
||||
{
|
||||
string input = @"https://foo.bar/path/\#m4mv5W0GYKZpGvfA.97";
|
||||
string expected = @"<p><a href=""https://foo.bar/path/%5C#m4mv5W0GYKZpGvfA.97"">https://foo.bar/path/\#m4mv5W0GYKZpGvfA.97</a></p>";
|
||||
|
||||
TestParser.TestSpec($"<{input}>", expected);
|
||||
TestParser.TestSpec(input, expected, "autolinks|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsIssue365Corrected()
|
||||
{
|
||||
// The scheme must be escaped too...
|
||||
string input = "";
|
||||
string expected = "<p><img src=\"%22onclick=%22alert&#40;%27click%27&#41;%22://\" alt=\"image\" /></p>";
|
||||
|
||||
TestParser.TestSpec(input, expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAltTextIsCorrectlyEscaped()
|
||||
{
|
||||
TestParser.TestSpec(
|
||||
@"",
|
||||
@"<p><img src=""girl.png"" alt=""This is image alt text with quotation ' and double quotation "hello" world"" /></p>");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestChangelogPRLinksMatchDescription()
|
||||
{
|
||||
string solutionFolder = Path.GetFullPath(Path.Combine(TestParser.TestsDirectory, "../.."));
|
||||
string changelogPath = Path.Combine(solutionFolder, "changelog.md");
|
||||
string changelog = File.ReadAllText(changelogPath);
|
||||
var matches = Regex.Matches(changelog, @"\(\[\(PR #(\d+)\)\]\(.*?pull\/(\d+)\)\)");
|
||||
Assert.Greater(matches.Count, 0);
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
Assert.True(int.TryParse(match.Groups[1].Value, out int textNr));
|
||||
Assert.True(int.TryParse(match.Groups[2].Value, out int linkNr));
|
||||
Assert.AreEqual(textNr, linkNr);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFixHang()
|
||||
{
|
||||
var input = File.ReadAllText(Path.Combine(TestParser.TestsDirectory, "hang.md"));
|
||||
_ = Markdown.ToHtml(input);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInvalidHtmlEntity()
|
||||
{
|
||||
var input = "9&ddr;&*&ddr;&de<64><65>__";
|
||||
TestParser.TestSpec(input, "<p>9&ddr;&*&ddr;&de<64><65>__</p>");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInvalidCharacterHandling()
|
||||
{
|
||||
var input = File.ReadAllText(Path.Combine(TestParser.TestsDirectory, "ArgumentOutOfRangeException.md"));
|
||||
_ = Markdown.ToHtml(input);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInvalidCodeEscape()
|
||||
{
|
||||
var input = "```**Header** ";
|
||||
_ = Markdown.ToHtml(input);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmphasisAndHtmlEntity()
|
||||
{
|
||||
var markdownText = "*Unlimited-Fun®*®";
|
||||
TestParser.TestSpec(markdownText, "<p><em>Unlimited-Fun®</em>®</p>");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestThematicInsideCodeBlockInsideList()
|
||||
{
|
||||
var input = @"1. In the :
|
||||
|
||||
```
|
||||
Id DisplayName Description
|
||||
-- ----------- -----------
|
||||
62375ab9-6b52-47ed-826b-58e47e0e304b Group.Unified ...
|
||||
```";
|
||||
TestParser.TestSpec(input, @"<ol>
|
||||
<li><p>In the :</p>
|
||||
<pre><code>Id DisplayName Description
|
||||
-- ----------- -----------
|
||||
62375ab9-6b52-47ed-826b-58e47e0e304b Group.Unified ...
|
||||
</code></pre></li>
|
||||
</ol>");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VisualizeMathExpressions()
|
||||
{
|
||||
string math = @"Math expressions
|
||||
|
||||
$\frac{n!}{k!(n-k)!} = \binom{n}{k}$
|
||||
|
||||
$$\frac{n!}{k!(n-k)!} = \binom{n}{k}$$
|
||||
|
||||
$$
|
||||
\frac{n!}{k!(n-k)!} = \binom{n}{k}
|
||||
$$
|
||||
|
||||
<div class=""math"">
|
||||
\begin{align}
|
||||
\sqrt{37} & = \sqrt{\frac{73^2-1}{12^2}} \\
|
||||
& = \sqrt{\frac{73^2}{12^2}\cdot\frac{73^2-1}{73^2}} \\
|
||||
& = \sqrt{\frac{73^2}{12^2}}\sqrt{\frac{73^2-1}{73^2}} \\
|
||||
& = \frac{73}{12}\sqrt{1 - \frac{1}{73^2}} \\
|
||||
& \approx \frac{73}{12}\left(1 - \frac{1}{2\cdot73^2}\right)
|
||||
\end{align}
|
||||
</div>
|
||||
";
|
||||
Console.WriteLine("Math Expressions:\n");
|
||||
|
||||
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
|
||||
|
||||
|
||||
var html = Markdown.ToHtml(math, pl);
|
||||
Console.WriteLine(html);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InlineMathExpression()
|
||||
{
|
||||
string math = @"Math expressions
|
||||
|
||||
$\frac{n!}{k!(n-k)!} = \binom{n}{k}$
|
||||
";
|
||||
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
|
||||
|
||||
var html = Markdown.ToHtml(math, pl);
|
||||
Console.WriteLine(html);
|
||||
|
||||
Assert.IsTrue(html.Contains("<p><span class=\"math\">\\("), "Leading bracket missing");
|
||||
Assert.IsTrue(html.Contains("\\)</span></p>"), "Trailing bracket missing");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BlockMathExpression()
|
||||
{
|
||||
string math = @"Math expressions
|
||||
|
||||
$$
|
||||
\frac{n!}{k!(n-k)!} = \binom{n}{k}
|
||||
$$
|
||||
";
|
||||
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
|
||||
|
||||
var html = Markdown.ToHtml(math, pl);
|
||||
Console.WriteLine(html);
|
||||
|
||||
Assert.IsTrue(html.Contains("<div class=\"math\">\n\\["), "Leading bracket missing");
|
||||
Assert.IsTrue(html.Contains("\\]</div>"), "Trailing bracket missing");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanDisableParsingHeadings()
|
||||
{
|
||||
var noHeadingsPipeline = new MarkdownPipelineBuilder().DisableHeadings().Build();
|
||||
|
||||
TestParser.TestSpec("Foo\n===", "<h1>Foo</h1>");
|
||||
TestParser.TestSpec("Foo\n===", "<p>Foo\n===</p>", noHeadingsPipeline);
|
||||
|
||||
TestParser.TestSpec("# Heading 1", "<h1>Heading 1</h1>");
|
||||
TestParser.TestSpec("# Heading 1", "<p># Heading 1</p>", noHeadingsPipeline);
|
||||
|
||||
// Does not also disable link reference definitions
|
||||
TestParser.TestSpec("[Foo]\n\n[Foo]: bar", "<p><a href=\"bar\">Foo</a></p>");
|
||||
TestParser.TestSpec("[Foo]\n\n[Foo]: bar", "<p><a href=\"bar\">Foo</a></p>", noHeadingsPipeline);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanOpenAutoLinksInNewWindow()
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder().UseAutoLinks().Build();
|
||||
var newWindowPipeline = new MarkdownPipelineBuilder().UseAutoLinks(new AutoLinkOptions() { OpenInNewWindow = true }).Build();
|
||||
|
||||
TestParser.TestSpec("www.foo.bar", "<p><a href=\"http://www.foo.bar\">www.foo.bar</a></p>", pipeline);
|
||||
TestParser.TestSpec("www.foo.bar", "<p><a href=\"http://www.foo.bar\" target=\"blank\">www.foo.bar</a></p>", newWindowPipeline);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanUseHttpsPrefixForWWWAutoLinks()
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder().UseAutoLinks().Build();
|
||||
var httpsPipeline = new MarkdownPipelineBuilder().UseAutoLinks(new AutoLinkOptions() { UseHttpsForWWWLinks = true }).Build();
|
||||
|
||||
TestParser.TestSpec("www.foo.bar", "<p><a href=\"http://www.foo.bar\">www.foo.bar</a></p>", pipeline);
|
||||
TestParser.TestSpec("www.foo.bar", "<p><a href=\"https://www.foo.bar\">www.foo.bar</a></p>", httpsPipeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
93
src/Markdig.Tests/NormalizeSpecs/Headings.generated.cs
Normal file
93
src/Markdig.Tests/NormalizeSpecs/Headings.generated.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Headings
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Normalize.Headings
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestHeadings
|
||||
{
|
||||
// # Headings
|
||||
[Test]
|
||||
public void Headings_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Headings
|
||||
//
|
||||
// The following Markdown:
|
||||
// # Heading 1
|
||||
//
|
||||
// ## Heading 2
|
||||
//
|
||||
// ### Heading 3
|
||||
//
|
||||
// #### Heading 4
|
||||
//
|
||||
// ##### Heading 5
|
||||
//
|
||||
// ###### Heading 6
|
||||
//
|
||||
// Should be rendered as:
|
||||
// # Heading 1
|
||||
//
|
||||
// ## Heading 2
|
||||
//
|
||||
// ### Heading 3
|
||||
//
|
||||
// #### Heading 4
|
||||
//
|
||||
// ##### Heading 5
|
||||
//
|
||||
// ###### Heading 6
|
||||
|
||||
Console.WriteLine("Example 1\nSection Headings\n");
|
||||
TestNormalize.TestSpec("# Heading 1\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6", "# Heading 1\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6", "");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Headings_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Headings
|
||||
//
|
||||
// The following Markdown:
|
||||
// ###### Heading
|
||||
//
|
||||
// Text after two newlines
|
||||
//
|
||||
// Should be rendered as:
|
||||
// ###### Heading
|
||||
//
|
||||
// Text after two newlines
|
||||
|
||||
Console.WriteLine("Example 2\nSection Headings\n");
|
||||
TestNormalize.TestSpec("###### Heading\n\nText after two newlines", "###### Heading\n\nText after two newlines", "");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Headings_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Headings
|
||||
//
|
||||
// The following Markdown:
|
||||
// Heading
|
||||
// =======
|
||||
//
|
||||
// Text after two newlines
|
||||
//
|
||||
// Should be rendered as:
|
||||
// # Heading
|
||||
//
|
||||
// Text after two newlines
|
||||
|
||||
Console.WriteLine("Example 3\nSection Headings\n");
|
||||
TestNormalize.TestSpec("Heading\n=======\n\nText after two newlines", "# Heading\n\nText after two newlines", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/Markdig.Tests/NormalizeSpecs/Headings.md
Normal file
48
src/Markdig.Tests/NormalizeSpecs/Headings.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Headings
|
||||
|
||||
```````````````````````````````` example
|
||||
# Heading 1
|
||||
|
||||
## Heading 2
|
||||
|
||||
### Heading 3
|
||||
|
||||
#### Heading 4
|
||||
|
||||
##### Heading 5
|
||||
|
||||
###### Heading 6
|
||||
.
|
||||
# Heading 1
|
||||
|
||||
## Heading 2
|
||||
|
||||
### Heading 3
|
||||
|
||||
#### Heading 4
|
||||
|
||||
##### Heading 5
|
||||
|
||||
###### Heading 6
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
###### Heading
|
||||
|
||||
Text after two newlines
|
||||
.
|
||||
###### Heading
|
||||
|
||||
Text after two newlines
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
Heading
|
||||
=======
|
||||
|
||||
Text after two newlines
|
||||
.
|
||||
# Heading
|
||||
|
||||
Text after two newlines
|
||||
````````````````````````````````
|
||||
@@ -0,0 +1,35 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Sample
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.PlainText.Sample
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSamplePlainTextSpec
|
||||
{
|
||||
// # Sample plain text spec
|
||||
//
|
||||
// Emphasis and anchors are stripped. A newline is ensured.
|
||||
[Test]
|
||||
public void SamplePlainTextSpec_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Sample plain text spec
|
||||
//
|
||||
// The following Markdown:
|
||||
// *Hello*, [world](http://example.com)!
|
||||
//
|
||||
// Should be rendered as:
|
||||
// Hello, world!
|
||||
//
|
||||
|
||||
Console.WriteLine("Example 1\nSection Sample plain text spec\n");
|
||||
TestPlainText.TestSpec("*Hello*, [world](http://example.com)!", "Hello, world!\n", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/Markdig.Tests/PlainTextSpecs/SamplePlainText.md
Normal file
10
src/Markdig.Tests/PlainTextSpecs/SamplePlainText.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Sample plain text spec
|
||||
|
||||
Emphasis and anchors are stripped. A newline is ensured.
|
||||
|
||||
```````````````````````````````` example
|
||||
*Hello*, [world](http://example.com)!
|
||||
.
|
||||
Hello, world!
|
||||
|
||||
````````````````````````````````
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
new TestPlayParser().TestSimple();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Textamin.Tests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Textamin.Tests")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("a0c5cb5f-5568-40ab-b945-d6d2664d51b0")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
236
src/Markdig.Tests/Specs/AbbreviationSpecs.generated.cs
Normal file
236
src/Markdig.Tests/Specs/AbbreviationSpecs.generated.cs
Normal file
@@ -0,0 +1,236 @@
|
||||
// Generated: 2019-05-15 02:46:55
|
||||
|
||||
// --------------------------------
|
||||
// Abbreviations
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Abbreviations
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsAbbreviation
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the different extensions supported:
|
||||
//
|
||||
// ## Abbreviation
|
||||
//
|
||||
// Abbreviation can be declared by using the `*[Abbreviation Label]: Abbreviation description`
|
||||
//
|
||||
// Abbreviation definition will be removed from the original document. Any Abbreviation label found in literals will be replaced by the abbreviation description:
|
||||
[Test]
|
||||
public void ExtensionsAbbreviation_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Abbreviation
|
||||
//
|
||||
// The following Markdown:
|
||||
// *[HTML]: Hypertext Markup Language
|
||||
//
|
||||
// Later in a text we are using HTML and it becomes an abbr tag HTML
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>Later in a text we are using <abbr title="Hypertext Markup Language">HTML</abbr> and it becomes an abbr tag <abbr title="Hypertext Markup Language">HTML</abbr></p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Abbreviation\n");
|
||||
TestParser.TestSpec("*[HTML]: Hypertext Markup Language\n\nLater in a text we are using HTML and it becomes an abbr tag HTML", "<p>Later in a text we are using <abbr title=\"Hypertext Markup Language\">HTML</abbr> and it becomes an abbr tag <abbr title=\"Hypertext Markup Language\">HTML</abbr></p>", "abbreviations|advanced");
|
||||
}
|
||||
|
||||
// An abbreviation definition can be indented at most 3 spaces
|
||||
[Test]
|
||||
public void ExtensionsAbbreviation_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Abbreviation
|
||||
//
|
||||
// The following Markdown:
|
||||
// *[HTML]: Hypertext Markup Language
|
||||
// *[This]: is not an abbreviation
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <pre><code>*[This]: is not an abbreviation
|
||||
// </code></pre>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Abbreviation\n");
|
||||
TestParser.TestSpec("*[HTML]: Hypertext Markup Language\n *[This]: is not an abbreviation", "<pre><code>*[This]: is not an abbreviation\n</code></pre>", "abbreviations|advanced");
|
||||
}
|
||||
|
||||
// An abbreviation may contain spaces:
|
||||
[Test]
|
||||
public void ExtensionsAbbreviation_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Abbreviation
|
||||
//
|
||||
// The following Markdown:
|
||||
// *[SUPER HTML]: Super Hypertext Markup Language
|
||||
//
|
||||
// This is a SUPER HTML document
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <abbr title="Super Hypertext Markup Language">SUPER HTML</abbr> document</p>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Abbreviation\n");
|
||||
TestParser.TestSpec("*[SUPER HTML]: Super Hypertext Markup Language\n\nThis is a SUPER HTML document ", "<p>This is a <abbr title=\"Super Hypertext Markup Language\">SUPER HTML</abbr> document</p>", "abbreviations|advanced");
|
||||
}
|
||||
|
||||
// Abbreviation may contain any unicode characters:
|
||||
[Test]
|
||||
public void ExtensionsAbbreviation_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Abbreviation
|
||||
//
|
||||
// The following Markdown:
|
||||
// *[😃 HTML]: Hypertext Markup Language
|
||||
//
|
||||
// This is a 😃 HTML document
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <abbr title="Hypertext Markup Language">😃 HTML</abbr> document</p>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Abbreviation\n");
|
||||
TestParser.TestSpec("*[😃 HTML]: Hypertext Markup Language\n\nThis is a 😃 HTML document ", "<p>This is a <abbr title=\"Hypertext Markup Language\">😃 HTML</abbr> document</p>", "abbreviations|advanced");
|
||||
}
|
||||
|
||||
// Abbreviations may be similar:
|
||||
[Test]
|
||||
public void ExtensionsAbbreviation_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / Abbreviation
|
||||
//
|
||||
// The following Markdown:
|
||||
// *[1A]: First
|
||||
// *[1A1]: Second
|
||||
// *[1A2]: Third
|
||||
//
|
||||
// We can abbreviate 1A, 1A1 and 1A2!
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>We can abbreviate <abbr title="First">1A</abbr>, <abbr title="Second">1A1</abbr> and <abbr title="Third">1A2</abbr>!</p>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / Abbreviation\n");
|
||||
TestParser.TestSpec("*[1A]: First\n*[1A1]: Second\n*[1A2]: Third\n\nWe can abbreviate 1A, 1A1 and 1A2!", "<p>We can abbreviate <abbr title=\"First\">1A</abbr>, <abbr title=\"Second\">1A1</abbr> and <abbr title=\"Third\">1A2</abbr>!</p>", "abbreviations|advanced");
|
||||
}
|
||||
|
||||
// Abbreviations should match whole word only:
|
||||
[Test]
|
||||
public void ExtensionsAbbreviation_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / Abbreviation
|
||||
//
|
||||
// The following Markdown:
|
||||
// *[1A]: First
|
||||
//
|
||||
// We should not abbreviate 1.1A or 11A!
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>We should not abbreviate 1.1A or 11A!</p>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / Abbreviation\n");
|
||||
TestParser.TestSpec("*[1A]: First\n\nWe should not abbreviate 1.1A or 11A!", "<p>We should not abbreviate 1.1A or 11A!</p>", "abbreviations|advanced");
|
||||
}
|
||||
|
||||
// Abbreviations should match whole word only, even if the word is the entire content:
|
||||
[Test]
|
||||
public void ExtensionsAbbreviation_Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Extensions / Abbreviation
|
||||
//
|
||||
// The following Markdown:
|
||||
// *[1A]: First
|
||||
//
|
||||
// 1.1A
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>1.1A</p>
|
||||
|
||||
Console.WriteLine("Example 7\nSection Extensions / Abbreviation\n");
|
||||
TestParser.TestSpec("*[1A]: First\n\n1.1A", "<p>1.1A</p>", "abbreviations|advanced");
|
||||
}
|
||||
|
||||
// Abbreviations should match whole word only, even if there is another glossary term:
|
||||
[Test]
|
||||
public void ExtensionsAbbreviation_Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Extensions / Abbreviation
|
||||
//
|
||||
// The following Markdown:
|
||||
// *[SCO]: First
|
||||
// *[SCOM]: Second
|
||||
//
|
||||
// SCOM
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><abbr title="Second">SCOM</abbr></p>
|
||||
|
||||
Console.WriteLine("Example 8\nSection Extensions / Abbreviation\n");
|
||||
TestParser.TestSpec("*[SCO]: First\n*[SCOM]: Second\n\nSCOM", "<p><abbr title=\"Second\">SCOM</abbr></p>", "abbreviations|advanced");
|
||||
}
|
||||
|
||||
// Abbreviations should only match when surrounded by whitespace:
|
||||
[Test]
|
||||
public void ExtensionsAbbreviation_Example009()
|
||||
{
|
||||
// Example 9
|
||||
// Section: Extensions / Abbreviation
|
||||
//
|
||||
// The following Markdown:
|
||||
// *[PR]: Pull Request
|
||||
//
|
||||
// PRAA
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>PRAA</p>
|
||||
|
||||
Console.WriteLine("Example 9\nSection Extensions / Abbreviation\n");
|
||||
TestParser.TestSpec("*[PR]: Pull Request\n\nPRAA", "<p>PRAA</p>", "abbreviations|advanced");
|
||||
}
|
||||
|
||||
// Single character abbreviations should be matched
|
||||
[Test]
|
||||
public void ExtensionsAbbreviation_Example010()
|
||||
{
|
||||
// Example 10
|
||||
// Section: Extensions / Abbreviation
|
||||
//
|
||||
// The following Markdown:
|
||||
// *[A]: Foo
|
||||
//
|
||||
// A
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><abbr title="Foo">A</abbr></p>
|
||||
|
||||
Console.WriteLine("Example 10\nSection Extensions / Abbreviation\n");
|
||||
TestParser.TestSpec("*[A]: Foo\n\nA", "<p><abbr title=\"Foo\">A</abbr></p>", "abbreviations|advanced");
|
||||
}
|
||||
|
||||
// The longest matching abbreviation should be used
|
||||
[Test]
|
||||
public void ExtensionsAbbreviation_Example011()
|
||||
{
|
||||
// Example 11
|
||||
// Section: Extensions / Abbreviation
|
||||
//
|
||||
// The following Markdown:
|
||||
// *[Foo]: foo
|
||||
// *[Foo Bar]: foobar
|
||||
//
|
||||
// Foo B
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><abbr title="foo">Foo</abbr> B</p>
|
||||
|
||||
Console.WriteLine("Example 11\nSection Extensions / Abbreviation\n");
|
||||
TestParser.TestSpec("*[Foo]: foo\n*[Foo Bar]: foobar\n\nFoo B", "<p><abbr title=\"foo\">Foo</abbr> B</p>", "abbreviations|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,3 +45,77 @@ This is a 😃 HTML document
|
||||
.
|
||||
<p>This is a <abbr title="Hypertext Markup Language">😃 HTML</abbr> document</p>
|
||||
````````````````````````````````
|
||||
|
||||
Abbreviations may be similar:
|
||||
|
||||
```````````````````````````````` example
|
||||
*[1A]: First
|
||||
*[1A1]: Second
|
||||
*[1A2]: Third
|
||||
|
||||
We can abbreviate 1A, 1A1 and 1A2!
|
||||
.
|
||||
<p>We can abbreviate <abbr title="First">1A</abbr>, <abbr title="Second">1A1</abbr> and <abbr title="Third">1A2</abbr>!</p>
|
||||
````````````````````````````````
|
||||
|
||||
Abbreviations should match whole word only:
|
||||
|
||||
```````````````````````````````` example
|
||||
*[1A]: First
|
||||
|
||||
We should not abbreviate 1.1A or 11A!
|
||||
.
|
||||
<p>We should not abbreviate 1.1A or 11A!</p>
|
||||
````````````````````````````````
|
||||
|
||||
Abbreviations should match whole word only, even if the word is the entire content:
|
||||
|
||||
```````````````````````````````` example
|
||||
*[1A]: First
|
||||
|
||||
1.1A
|
||||
.
|
||||
<p>1.1A</p>
|
||||
````````````````````````````````
|
||||
|
||||
Abbreviations should match whole word only, even if there is another glossary term:
|
||||
|
||||
```````````````````````````````` example
|
||||
*[SCO]: First
|
||||
*[SCOM]: Second
|
||||
|
||||
SCOM
|
||||
.
|
||||
<p><abbr title="Second">SCOM</abbr></p>
|
||||
````````````````````````````````
|
||||
|
||||
Abbreviations should only match when surrounded by whitespace:
|
||||
|
||||
```````````````````````````````` example
|
||||
*[PR]: Pull Request
|
||||
|
||||
PRAA
|
||||
.
|
||||
<p>PRAA</p>
|
||||
````````````````````````````````
|
||||
|
||||
Single character abbreviations should be matched
|
||||
|
||||
```````````````````````````````` example
|
||||
*[A]: Foo
|
||||
|
||||
A
|
||||
.
|
||||
<p><abbr title="Foo">A</abbr></p>
|
||||
````````````````````````````````
|
||||
|
||||
The longest matching abbreviation should be used
|
||||
|
||||
```````````````````````````````` example
|
||||
*[Foo]: foo
|
||||
*[Foo Bar]: foobar
|
||||
|
||||
Foo B
|
||||
.
|
||||
<p><abbr title="foo">Foo</abbr> B</p>
|
||||
````````````````````````````````
|
||||
224
src/Markdig.Tests/Specs/AutoIdentifierSpecs.generated.cs
Normal file
224
src/Markdig.Tests/Specs/AutoIdentifierSpecs.generated.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Auto Identifiers
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.AutoIdentifiers
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsHeadingAutoIdentifiers
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the auto identifier extension
|
||||
//
|
||||
// ## Heading Auto Identifiers
|
||||
//
|
||||
// Allows to automatically creates an identifier for a heading:
|
||||
[Test]
|
||||
public void ExtensionsHeadingAutoIdentifiers_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Heading Auto Identifiers
|
||||
//
|
||||
// The following Markdown:
|
||||
// # This is a heading
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <h1 id="this-is-a-heading">This is a heading</h1>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Heading Auto Identifiers\n");
|
||||
TestParser.TestSpec("# This is a heading", "<h1 id=\"this-is-a-heading\">This is a heading</h1>", "autoidentifiers|advanced");
|
||||
}
|
||||
|
||||
// Only punctuation `-`, `_` and `.` is kept, all other non letter characters are discarded.
|
||||
// Consecutive same character `-`, `_` or `.` are rendered into a single one
|
||||
// Characters `-`, `_` and `.` at the end of the string are also discarded.
|
||||
[Test]
|
||||
public void ExtensionsHeadingAutoIdentifiers_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Heading Auto Identifiers
|
||||
//
|
||||
// The following Markdown:
|
||||
// # This - is a &@! heading _ with . and ! -
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <h1 id="this-is-a-heading_with.and">This - is a &@! heading _ with . and ! -</h1>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Heading Auto Identifiers\n");
|
||||
TestParser.TestSpec("# This - is a &@! heading _ with . and ! -", "<h1 id=\"this-is-a-heading_with.and\">This - is a &@! heading _ with . and ! -</h1>", "autoidentifiers|advanced");
|
||||
}
|
||||
|
||||
// Formatting (emphasis) are also discarded:
|
||||
[Test]
|
||||
public void ExtensionsHeadingAutoIdentifiers_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Heading Auto Identifiers
|
||||
//
|
||||
// The following Markdown:
|
||||
// # This is a *heading*
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <h1 id="this-is-a-heading">This is a <em>heading</em></h1>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Heading Auto Identifiers\n");
|
||||
TestParser.TestSpec("# This is a *heading*", "<h1 id=\"this-is-a-heading\">This is a <em>heading</em></h1>", "autoidentifiers|advanced");
|
||||
}
|
||||
|
||||
// Links are also removed:
|
||||
[Test]
|
||||
public void ExtensionsHeadingAutoIdentifiers_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Heading Auto Identifiers
|
||||
//
|
||||
// The following Markdown:
|
||||
// # This is a [heading](/url)
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <h1 id="this-is-a-heading">This is a <a href="/url">heading</a></h1>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Heading Auto Identifiers\n");
|
||||
TestParser.TestSpec("# This is a [heading](/url)", "<h1 id=\"this-is-a-heading\">This is a <a href=\"/url\">heading</a></h1>", "autoidentifiers|advanced");
|
||||
}
|
||||
|
||||
// If multiple heading have the same text, -1, -2...-n will be postfix to the header id.
|
||||
[Test]
|
||||
public void ExtensionsHeadingAutoIdentifiers_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / Heading Auto Identifiers
|
||||
//
|
||||
// The following Markdown:
|
||||
// # This is a heading
|
||||
// # This is a heading
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <h1 id="this-is-a-heading">This is a heading</h1>
|
||||
// <h1 id="this-is-a-heading-1">This is a heading</h1>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / Heading Auto Identifiers\n");
|
||||
TestParser.TestSpec("# This is a heading\n# This is a heading", "<h1 id=\"this-is-a-heading\">This is a heading</h1>\n<h1 id=\"this-is-a-heading-1\">This is a heading</h1>", "autoidentifiers|advanced");
|
||||
}
|
||||
|
||||
// The heading Id will start on the first letter character of the heading, all previous characters will be discarded:
|
||||
[Test]
|
||||
public void ExtensionsHeadingAutoIdentifiers_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / Heading Auto Identifiers
|
||||
//
|
||||
// The following Markdown:
|
||||
// # 1.0 This is a heading
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <h1 id="this-is-a-heading">1.0 This is a heading</h1>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / Heading Auto Identifiers\n");
|
||||
TestParser.TestSpec("# 1.0 This is a heading", "<h1 id=\"this-is-a-heading\">1.0 This is a heading</h1>", "autoidentifiers|advanced");
|
||||
}
|
||||
|
||||
// If the heading is all stripped by the previous rules, the id `section` will be used instead:
|
||||
[Test]
|
||||
public void ExtensionsHeadingAutoIdentifiers_Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Extensions / Heading Auto Identifiers
|
||||
//
|
||||
// The following Markdown:
|
||||
// # 1.0 & ^ % *
|
||||
// # 1.0 & ^ % *
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <h1 id="section">1.0 & ^ % *</h1>
|
||||
// <h1 id="section-1">1.0 & ^ % *</h1>
|
||||
|
||||
Console.WriteLine("Example 7\nSection Extensions / Heading Auto Identifiers\n");
|
||||
TestParser.TestSpec("# 1.0 & ^ % *\n# 1.0 & ^ % *", "<h1 id=\"section\">1.0 & ^ % *</h1>\n<h1 id=\"section-1\">1.0 & ^ % *</h1>", "autoidentifiers|advanced");
|
||||
}
|
||||
|
||||
// When the options "AutoLink" is setup, it is possible to link to an existing heading by using the
|
||||
// exact same Label text as the heading:
|
||||
[Test]
|
||||
public void ExtensionsHeadingAutoIdentifiers_Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Extensions / Heading Auto Identifiers
|
||||
//
|
||||
// The following Markdown:
|
||||
// # This is a heading
|
||||
// [This is a heading]
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <h1 id="this-is-a-heading">This is a heading</h1>
|
||||
// <p><a href="#this-is-a-heading">This is a heading</a></p>
|
||||
|
||||
Console.WriteLine("Example 8\nSection Extensions / Heading Auto Identifiers\n");
|
||||
TestParser.TestSpec("# This is a heading\n[This is a heading]", "<h1 id=\"this-is-a-heading\">This is a heading</h1>\n<p><a href=\"#this-is-a-heading\">This is a heading</a></p>", "autoidentifiers|advanced");
|
||||
}
|
||||
|
||||
// Links before the heading are also working:
|
||||
[Test]
|
||||
public void ExtensionsHeadingAutoIdentifiers_Example009()
|
||||
{
|
||||
// Example 9
|
||||
// Section: Extensions / Heading Auto Identifiers
|
||||
//
|
||||
// The following Markdown:
|
||||
// [This is a heading]
|
||||
// # This is a heading
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="#this-is-a-heading">This is a heading</a></p>
|
||||
// <h1 id="this-is-a-heading">This is a heading</h1>
|
||||
|
||||
Console.WriteLine("Example 9\nSection Extensions / Heading Auto Identifiers\n");
|
||||
TestParser.TestSpec("[This is a heading]\n# This is a heading", "<p><a href=\"#this-is-a-heading\">This is a heading</a></p>\n<h1 id=\"this-is-a-heading\">This is a heading</h1>", "autoidentifiers|advanced");
|
||||
}
|
||||
|
||||
// The text of the link can be changed:
|
||||
[Test]
|
||||
public void ExtensionsHeadingAutoIdentifiers_Example010()
|
||||
{
|
||||
// Example 10
|
||||
// Section: Extensions / Heading Auto Identifiers
|
||||
//
|
||||
// The following Markdown:
|
||||
// [With a new text][This is a heading]
|
||||
// # This is a heading
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="#this-is-a-heading">With a new text</a></p>
|
||||
// <h1 id="this-is-a-heading">This is a heading</h1>
|
||||
|
||||
Console.WriteLine("Example 10\nSection Extensions / Heading Auto Identifiers\n");
|
||||
TestParser.TestSpec("[With a new text][This is a heading]\n# This is a heading", "<p><a href=\"#this-is-a-heading\">With a new text</a></p>\n<h1 id=\"this-is-a-heading\">This is a heading</h1>", "autoidentifiers|advanced");
|
||||
}
|
||||
|
||||
// An autoidentifier should not conflict with an existing link:
|
||||
[Test]
|
||||
public void ExtensionsHeadingAutoIdentifiers_Example011()
|
||||
{
|
||||
// Example 11
|
||||
// Section: Extensions / Heading Auto Identifiers
|
||||
//
|
||||
// The following Markdown:
|
||||
// ![scenario image][scenario]
|
||||
// ## Scenario
|
||||
// [scenario]: ./scenario.png
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><img src="./scenario.png" alt="scenario image" /></p>
|
||||
// <h2 id="scenario">Scenario</h2>
|
||||
|
||||
Console.WriteLine("Example 11\nSection Extensions / Heading Auto Identifiers\n");
|
||||
TestParser.TestSpec("![scenario image][scenario]\n## Scenario\n[scenario]: ./scenario.png", "<p><img src=\"./scenario.png\" alt=\"scenario image\" /></p>\n<h2 id=\"scenario\">Scenario</h2>", "autoidentifiers|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ Allows to automatically creates an identifier for a heading:
|
||||
<h1 id="this-is-a-heading">This is a heading</h1>
|
||||
````````````````````````````````
|
||||
|
||||
Only punctuation `-`, `_` and `.` is kept, all over non letter characters are discarded.
|
||||
Only punctuation `-`, `_` and `.` is kept, all other non letter characters are discarded.
|
||||
Consecutive same character `-`, `_` or `.` are rendered into a single one
|
||||
Characters `-`, `_` and `.` at the end of the string are also discarded.
|
||||
|
||||
@@ -96,3 +96,14 @@ The text of the link can be changed:
|
||||
<p><a href="#this-is-a-heading">With a new text</a></p>
|
||||
<h1 id="this-is-a-heading">This is a heading</h1>
|
||||
````````````````````````````````
|
||||
|
||||
An autoidentifier should not conflict with an existing link:
|
||||
|
||||
```````````````````````````````` example
|
||||
![scenario image][scenario]
|
||||
## Scenario
|
||||
[scenario]: ./scenario.png
|
||||
.
|
||||
<p><img src="./scenario.png" alt="scenario image" /></p>
|
||||
<h2 id="scenario">Scenario</h2>
|
||||
````````````````````````````````
|
||||
|
||||
561
src/Markdig.Tests/Specs/AutoLinks.generated.cs
Normal file
561
src/Markdig.Tests/Specs/AutoLinks.generated.cs
Normal file
@@ -0,0 +1,561 @@
|
||||
// Generated: 2020-07-21 22:02:10
|
||||
|
||||
// --------------------------------
|
||||
// Auto Links
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.AutoLinks
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsAutoLinks
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the different extensions supported:
|
||||
//
|
||||
// ## AutoLinks
|
||||
//
|
||||
// Autolinks will format as a HTML link any string that starts by:
|
||||
//
|
||||
// - `http://` or `https://`
|
||||
// - `ftp://`
|
||||
// - `mailto:`
|
||||
// - `tel:`
|
||||
// - `www.`
|
||||
[Test]
|
||||
public void ExtensionsAutoLinks_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / AutoLinks
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a http://www.google.com URL and https://www.google.com
|
||||
// This is a ftp://test.com
|
||||
// And a mailto:email@toto.com
|
||||
// And a tel:+1555123456
|
||||
// And a plain www.google.com
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <a href="http://www.google.com">http://www.google.com</a> URL and <a href="https://www.google.com">https://www.google.com</a>
|
||||
// This is a <a href="ftp://test.com">ftp://test.com</a>
|
||||
// And a <a href="mailto:email@toto.com">email@toto.com</a>
|
||||
// And a <a href="tel:+1555123456">+1555123456</a>
|
||||
// And a plain <a href="http://www.google.com">www.google.com</a></p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / AutoLinks\n");
|
||||
TestParser.TestSpec("This is a http://www.google.com URL and https://www.google.com\nThis is a ftp://test.com\nAnd a mailto:email@toto.com\nAnd a tel:+1555123456\nAnd a plain www.google.com", "<p>This is a <a href=\"http://www.google.com\">http://www.google.com</a> URL and <a href=\"https://www.google.com\">https://www.google.com</a>\nThis is a <a href=\"ftp://test.com\">ftp://test.com</a>\nAnd a <a href=\"mailto:email@toto.com\">email@toto.com</a>\nAnd a <a href=\"tel:+1555123456\">+1555123456</a>\nAnd a plain <a href=\"http://www.google.com\">www.google.com</a></p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// But incomplete links will not be matched:
|
||||
[Test]
|
||||
public void ExtensionsAutoLinks_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / AutoLinks
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is not a http:/www.google.com URL and https:/www.google.com
|
||||
// This is not a ftp:/test.com
|
||||
// And not a mailto:emailtoto.com
|
||||
// And not a plain www. or a www.x
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is not a http:/www.google.com URL and https:/www.google.com
|
||||
// This is not a ftp:/test.com
|
||||
// And not a mailto:emailtoto.com
|
||||
// And not a plain www. or a www.x</p>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / AutoLinks\n");
|
||||
TestParser.TestSpec("This is not a http:/www.google.com URL and https:/www.google.com\nThis is not a ftp:/test.com\nAnd not a mailto:emailtoto.com\nAnd not a plain www. or a www.x ", "<p>This is not a http:/www.google.com URL and https:/www.google.com\nThis is not a ftp:/test.com\nAnd not a mailto:emailtoto.com\nAnd not a plain www. or a www.x</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// Previous character must be a punctuation or a valid space (tab, space, new line):
|
||||
[Test]
|
||||
public void ExtensionsAutoLinks_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / AutoLinks
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is not a nhttp://www.google.com URL but this is (https://www.google.com)
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is not a nhttp://www.google.com URL but this is (<a href="https://www.google.com">https://www.google.com</a>)</p>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / AutoLinks\n");
|
||||
TestParser.TestSpec("This is not a nhttp://www.google.com URL but this is (https://www.google.com)", "<p>This is not a nhttp://www.google.com URL but this is (<a href=\"https://www.google.com\">https://www.google.com</a>)</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// An autolink should not interfere with an `<a>` HTML inline:
|
||||
[Test]
|
||||
public void ExtensionsAutoLinks_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / AutoLinks
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is an HTML <a href="http://www.google.com">http://www.google.com</a> link
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is an HTML <a href="http://www.google.com">http://www.google.com</a> link</p>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / AutoLinks\n");
|
||||
TestParser.TestSpec("This is an HTML <a href=\"http://www.google.com\">http://www.google.com</a> link", "<p>This is an HTML <a href=\"http://www.google.com\">http://www.google.com</a> link</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// or even within emphasis:
|
||||
[Test]
|
||||
public void ExtensionsAutoLinks_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / AutoLinks
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is an HTML <a href="http://www.google.com"> **http://www.google.com** </a> link
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is an HTML <a href="http://www.google.com"> <strong>http://www.google.com</strong> </a> link</p>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / AutoLinks\n");
|
||||
TestParser.TestSpec("This is an HTML <a href=\"http://www.google.com\"> **http://www.google.com** </a> link", "<p>This is an HTML <a href=\"http://www.google.com\"> <strong>http://www.google.com</strong> </a> link</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// An autolink should not interfere with a markdown link:
|
||||
[Test]
|
||||
public void ExtensionsAutoLinks_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / AutoLinks
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is an HTML [http://www.google.com](http://www.google.com) link
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is an HTML <a href="http://www.google.com">http://www.google.com</a> link</p>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / AutoLinks\n");
|
||||
TestParser.TestSpec("This is an HTML [http://www.google.com](http://www.google.com) link", "<p>This is an HTML <a href=\"http://www.google.com\">http://www.google.com</a> link</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// A link embraced by pending emphasis should let the emphasis takes precedence if characters are placed at the end of the matched link:
|
||||
[Test]
|
||||
public void ExtensionsAutoLinks_Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Extensions / AutoLinks
|
||||
//
|
||||
// The following Markdown:
|
||||
// Check **http://www.a.com** or __http://www.b.com__
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>Check <strong><a href="http://www.a.com">http://www.a.com</a></strong> or <strong><a href="http://www.b.com">http://www.b.com</a></strong></p>
|
||||
|
||||
Console.WriteLine("Example 7\nSection Extensions / AutoLinks\n");
|
||||
TestParser.TestSpec("Check **http://www.a.com** or __http://www.b.com__", "<p>Check <strong><a href=\"http://www.a.com\">http://www.a.com</a></strong> or <strong><a href=\"http://www.b.com\">http://www.b.com</a></strong></p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// It is not mentioned by the spec, but empty emails won't be matched (only a subset of [RFC2368](https://tools.ietf.org/html/rfc2368) is supported by auto links):
|
||||
[Test]
|
||||
public void ExtensionsAutoLinks_Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Extensions / AutoLinks
|
||||
//
|
||||
// The following Markdown:
|
||||
// mailto:email@test.com is okay, but mailto:@test.com is not
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="mailto:email@test.com">email@test.com</a> is okay, but mailto:@test.com is not</p>
|
||||
|
||||
Console.WriteLine("Example 8\nSection Extensions / AutoLinks\n");
|
||||
TestParser.TestSpec("mailto:email@test.com is okay, but mailto:@test.com is not", "<p><a href=\"mailto:email@test.com\">email@test.com</a> is okay, but mailto:@test.com is not</p>", "autolinks|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsAutoLinksGFMSupport
|
||||
{
|
||||
// ### GFM Support
|
||||
//
|
||||
// Extract from [GFM Autolinks extensions specs](https://github.github.com/gfm/#autolinks-extension-)
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksGFMSupport_Example009()
|
||||
{
|
||||
// Example 9
|
||||
// Section: Extensions / AutoLinks / GFM Support
|
||||
//
|
||||
// The following Markdown:
|
||||
// www.commonmark.org
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://www.commonmark.org">www.commonmark.org</a></p>
|
||||
|
||||
Console.WriteLine("Example 9\nSection Extensions / AutoLinks / GFM Support\n");
|
||||
TestParser.TestSpec("www.commonmark.org", "<p><a href=\"http://www.commonmark.org\">www.commonmark.org</a></p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksGFMSupport_Example010()
|
||||
{
|
||||
// Example 10
|
||||
// Section: Extensions / AutoLinks / GFM Support
|
||||
//
|
||||
// The following Markdown:
|
||||
// Visit www.commonmark.org/help for more information.
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>Visit <a href="http://www.commonmark.org/help">www.commonmark.org/help</a> for more information.</p>
|
||||
|
||||
Console.WriteLine("Example 10\nSection Extensions / AutoLinks / GFM Support\n");
|
||||
TestParser.TestSpec("Visit www.commonmark.org/help for more information.", "<p>Visit <a href=\"http://www.commonmark.org/help\">www.commonmark.org/help</a> for more information.</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksGFMSupport_Example011()
|
||||
{
|
||||
// Example 11
|
||||
// Section: Extensions / AutoLinks / GFM Support
|
||||
//
|
||||
// The following Markdown:
|
||||
// Visit www.commonmark.org.
|
||||
//
|
||||
// Visit www.commonmark.org/a.b.
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>Visit <a href="http://www.commonmark.org">www.commonmark.org</a>.</p>
|
||||
// <p>Visit <a href="http://www.commonmark.org/a.b">www.commonmark.org/a.b</a>.</p>
|
||||
|
||||
Console.WriteLine("Example 11\nSection Extensions / AutoLinks / GFM Support\n");
|
||||
TestParser.TestSpec("Visit www.commonmark.org.\n\nVisit www.commonmark.org/a.b.", "<p>Visit <a href=\"http://www.commonmark.org\">www.commonmark.org</a>.</p>\n<p>Visit <a href=\"http://www.commonmark.org/a.b\">www.commonmark.org/a.b</a>.</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksGFMSupport_Example012()
|
||||
{
|
||||
// Example 12
|
||||
// Section: Extensions / AutoLinks / GFM Support
|
||||
//
|
||||
// The following Markdown:
|
||||
// www.google.com/search?q=Markup+(business)
|
||||
//
|
||||
// (www.google.com/search?q=Markup+(business))
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
|
||||
// <p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>)</p>
|
||||
|
||||
Console.WriteLine("Example 12\nSection Extensions / AutoLinks / GFM Support\n");
|
||||
TestParser.TestSpec("www.google.com/search?q=Markup+(business)\n\n(www.google.com/search?q=Markup+(business))", "<p><a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a></p>\n<p>(<a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a>)</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksGFMSupport_Example013()
|
||||
{
|
||||
// Example 13
|
||||
// Section: Extensions / AutoLinks / GFM Support
|
||||
//
|
||||
// The following Markdown:
|
||||
// www.google.com/search?q=commonmark&hl=en
|
||||
//
|
||||
// www.google.com/search?q=commonmark&hl;
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://www.google.com/search?q=commonmark&hl=en">www.google.com/search?q=commonmark&hl=en</a></p>
|
||||
// <p><a href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&hl;</p>
|
||||
|
||||
Console.WriteLine("Example 13\nSection Extensions / AutoLinks / GFM Support\n");
|
||||
TestParser.TestSpec("www.google.com/search?q=commonmark&hl=en\n\nwww.google.com/search?q=commonmark&hl;", "<p><a href=\"http://www.google.com/search?q=commonmark&hl=en\">www.google.com/search?q=commonmark&hl=en</a></p>\n<p><a href=\"http://www.google.com/search?q=commonmark\">www.google.com/search?q=commonmark</a>&hl;</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksGFMSupport_Example014()
|
||||
{
|
||||
// Example 14
|
||||
// Section: Extensions / AutoLinks / GFM Support
|
||||
//
|
||||
// The following Markdown:
|
||||
// www.commonmark.org/he<lp
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://www.commonmark.org/he">www.commonmark.org/he</a><lp</p>
|
||||
|
||||
Console.WriteLine("Example 14\nSection Extensions / AutoLinks / GFM Support\n");
|
||||
TestParser.TestSpec("www.commonmark.org/he<lp", "<p><a href=\"http://www.commonmark.org/he\">www.commonmark.org/he</a><lp</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksGFMSupport_Example015()
|
||||
{
|
||||
// Example 15
|
||||
// Section: Extensions / AutoLinks / GFM Support
|
||||
//
|
||||
// The following Markdown:
|
||||
// http://commonmark.org
|
||||
//
|
||||
// (Visit https://encrypted.google.com/search?q=Markup+(business))
|
||||
//
|
||||
// Anonymous FTP is available at ftp://foo.bar.baz.
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://commonmark.org">http://commonmark.org</a></p>
|
||||
// <p>(Visit <a href="https://encrypted.google.com/search?q=Markup+(business)">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>
|
||||
// <p>Anonymous FTP is available at <a href="ftp://foo.bar.baz">ftp://foo.bar.baz</a>.</p>
|
||||
|
||||
Console.WriteLine("Example 15\nSection Extensions / AutoLinks / GFM Support\n");
|
||||
TestParser.TestSpec("http://commonmark.org\n\n(Visit https://encrypted.google.com/search?q=Markup+(business))\n\nAnonymous FTP is available at ftp://foo.bar.baz.", "<p><a href=\"http://commonmark.org\">http://commonmark.org</a></p>\n<p>(Visit <a href=\"https://encrypted.google.com/search?q=Markup+(business)\">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>\n<p>Anonymous FTP is available at <a href=\"ftp://foo.bar.baz\">ftp://foo.bar.baz</a>.</p>", "autolinks|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsAutoLinksValidDomainTests
|
||||
{
|
||||
// ### Valid Domain Tests
|
||||
//
|
||||
// Domain names that have empty segments won't be matched
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksValidDomainTests_Example016()
|
||||
{
|
||||
// Example 16
|
||||
// Section: Extensions / AutoLinks / Valid Domain Tests
|
||||
//
|
||||
// The following Markdown:
|
||||
// www..
|
||||
// www..com
|
||||
// http://test.
|
||||
// http://.test
|
||||
// http://.
|
||||
// http://..
|
||||
// ftp://test.
|
||||
// ftp://.test
|
||||
// mailto:email@test.
|
||||
// mailto:email@.test
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>www..
|
||||
// www..com
|
||||
// http://test.
|
||||
// http://.test
|
||||
// http://.
|
||||
// http://..
|
||||
// ftp://test.
|
||||
// ftp://.test
|
||||
// mailto:email@test.
|
||||
// mailto:email@.test</p>
|
||||
|
||||
Console.WriteLine("Example 16\nSection Extensions / AutoLinks / Valid Domain Tests\n");
|
||||
TestParser.TestSpec("www..\nwww..com\nhttp://test.\nhttp://.test\nhttp://.\nhttp://..\nftp://test.\nftp://.test\nmailto:email@test.\nmailto:email@.test", "<p>www..\nwww..com\nhttp://test.\nhttp://.test\nhttp://.\nhttp://..\nftp://test.\nftp://.test\nmailto:email@test.\nmailto:email@.test</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// Domain names with too few segments won't be matched
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksValidDomainTests_Example017()
|
||||
{
|
||||
// Example 17
|
||||
// Section: Extensions / AutoLinks / Valid Domain Tests
|
||||
//
|
||||
// The following Markdown:
|
||||
// www
|
||||
// www.com
|
||||
// http://test
|
||||
// ftp://test
|
||||
// mailto:email@test
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>www
|
||||
// www.com
|
||||
// http://test
|
||||
// ftp://test
|
||||
// mailto:email@test</p>
|
||||
|
||||
Console.WriteLine("Example 17\nSection Extensions / AutoLinks / Valid Domain Tests\n");
|
||||
TestParser.TestSpec("www\nwww.com\nhttp://test\nftp://test\nmailto:email@test", "<p>www\nwww.com\nhttp://test\nftp://test\nmailto:email@test</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// Domain names that contain an underscores in the last two segments won't be matched
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksValidDomainTests_Example018()
|
||||
{
|
||||
// Example 18
|
||||
// Section: Extensions / AutoLinks / Valid Domain Tests
|
||||
//
|
||||
// The following Markdown:
|
||||
// www._test.foo.bar is okay, but www._test.foo is not
|
||||
//
|
||||
// http://te_st.foo.bar is okay, as is http://test.foo_.bar.foo
|
||||
//
|
||||
// But http://te_st.foo, http://test.foo_.bar and http://test._foo are not
|
||||
//
|
||||
// ftp://test_.foo.bar is okay, but ftp://test.fo_o is not
|
||||
//
|
||||
// mailto:email@_test.foo.bar is okay, but mailto:email@_test.foo is not
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://www._test.foo.bar">www._test.foo.bar</a> is okay, but www._test.foo is not</p>
|
||||
// <p><a href="http://te_st.foo.bar">http://te_st.foo.bar</a> is okay, as is <a href="http://test.foo_.bar.foo">http://test.foo_.bar.foo</a></p>
|
||||
// <p>But http://te_st.foo, http://test.foo_.bar and http://test._foo are not</p>
|
||||
// <p><a href="ftp://test_.foo.bar">ftp://test_.foo.bar</a> is okay, but ftp://test.fo_o is not</p>
|
||||
// <p><a href="mailto:email@_test.foo.bar">email@_test.foo.bar</a> is okay, but mailto:email@_test.foo is not</p>
|
||||
|
||||
Console.WriteLine("Example 18\nSection Extensions / AutoLinks / Valid Domain Tests\n");
|
||||
TestParser.TestSpec("www._test.foo.bar is okay, but www._test.foo is not\n\nhttp://te_st.foo.bar is okay, as is http://test.foo_.bar.foo\n\nBut http://te_st.foo, http://test.foo_.bar and http://test._foo are not\n\nftp://test_.foo.bar is okay, but ftp://test.fo_o is not\n\nmailto:email@_test.foo.bar is okay, but mailto:email@_test.foo is not", "<p><a href=\"http://www._test.foo.bar\">www._test.foo.bar</a> is okay, but www._test.foo is not</p>\n<p><a href=\"http://te_st.foo.bar\">http://te_st.foo.bar</a> is okay, as is <a href=\"http://test.foo_.bar.foo\">http://test.foo_.bar.foo</a></p>\n<p>But http://te_st.foo, http://test.foo_.bar and http://test._foo are not</p>\n<p><a href=\"ftp://test_.foo.bar\">ftp://test_.foo.bar</a> is okay, but ftp://test.fo_o is not</p>\n<p><a href=\"mailto:email@_test.foo.bar\">email@_test.foo.bar</a> is okay, but mailto:email@_test.foo is not</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// Domain names that contain invalid characters (not AlphaNumberic, -, _ or .) won't be matched
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksValidDomainTests_Example019()
|
||||
{
|
||||
// Example 19
|
||||
// Section: Extensions / AutoLinks / Valid Domain Tests
|
||||
//
|
||||
// The following Markdown:
|
||||
// https://[your-domain]/api
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>https://[your-domain]/api</p>
|
||||
|
||||
Console.WriteLine("Example 19\nSection Extensions / AutoLinks / Valid Domain Tests\n");
|
||||
TestParser.TestSpec("https://[your-domain]/api", "<p>https://[your-domain]/api</p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// Domain names followed by ?, : or # instead of / are matched
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksValidDomainTests_Example020()
|
||||
{
|
||||
// Example 20
|
||||
// Section: Extensions / AutoLinks / Valid Domain Tests
|
||||
//
|
||||
// The following Markdown:
|
||||
// https://github.com?
|
||||
//
|
||||
// https://github.com?a
|
||||
//
|
||||
// https://github.com#a
|
||||
//
|
||||
// https://github.com:
|
||||
//
|
||||
// https://github.com:443
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="https://github.com">https://github.com</a>?</p>
|
||||
// <p><a href="https://github.com?a">https://github.com?a</a></p>
|
||||
// <p><a href="https://github.com#a">https://github.com#a</a></p>
|
||||
// <p><a href="https://github.com">https://github.com</a>:</p>
|
||||
// <p><a href="https://github.com:443">https://github.com:443</a></p>
|
||||
|
||||
Console.WriteLine("Example 20\nSection Extensions / AutoLinks / Valid Domain Tests\n");
|
||||
TestParser.TestSpec("https://github.com?\n\nhttps://github.com?a\n\nhttps://github.com#a\n\nhttps://github.com:\n\nhttps://github.com:443", "<p><a href=\"https://github.com\">https://github.com</a>?</p>\n<p><a href=\"https://github.com?a\">https://github.com?a</a></p>\n<p><a href=\"https://github.com#a\">https://github.com#a</a></p>\n<p><a href=\"https://github.com\">https://github.com</a>:</p>\n<p><a href=\"https://github.com:443\">https://github.com:443</a></p>", "autolinks|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsAutoLinksUnicodeSupport
|
||||
{
|
||||
// ### Unicode support
|
||||
//
|
||||
// Links with unicode characters in the path / query / fragment are matched and url encoded
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksUnicodeSupport_Example021()
|
||||
{
|
||||
// Example 21
|
||||
// Section: Extensions / AutoLinks / Unicode support
|
||||
//
|
||||
// The following Markdown:
|
||||
// http://abc.net/☃
|
||||
//
|
||||
// http://abc.net?☃
|
||||
//
|
||||
// http://abc.net#☃
|
||||
//
|
||||
// http://abc.net/foo#☃
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://abc.net/%E2%98%83">http://abc.net/☃</a></p>
|
||||
// <p><a href="http://abc.net?%E2%98%83">http://abc.net?☃</a></p>
|
||||
// <p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
|
||||
// <p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
|
||||
|
||||
Console.WriteLine("Example 21\nSection Extensions / AutoLinks / Unicode support\n");
|
||||
TestParser.TestSpec("http://abc.net/☃\n\nhttp://abc.net?☃\n\nhttp://abc.net#☃\n\nhttp://abc.net/foo#☃", "<p><a href=\"http://abc.net/%E2%98%83\">http://abc.net/☃</a></p>\n<p><a href=\"http://abc.net?%E2%98%83\">http://abc.net?☃</a></p>\n<p><a href=\"http://abc.net#%E2%98%83\">http://abc.net#☃</a></p>\n<p><a href=\"http://abc.net/foo#%E2%98%83\">http://abc.net/foo#☃</a></p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// Unicode characters in the FQDN are matched and IDNA encoded
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksUnicodeSupport_Example022()
|
||||
{
|
||||
// Example 22
|
||||
// Section: Extensions / AutoLinks / Unicode support
|
||||
//
|
||||
// The following Markdown:
|
||||
// http://☃.net?☃
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
|
||||
|
||||
Console.WriteLine("Example 22\nSection Extensions / AutoLinks / Unicode support\n");
|
||||
TestParser.TestSpec("http://☃.net?☃", "<p><a href=\"http://xn--n3h.net?%E2%98%83\">http://☃.net?☃</a></p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// Same goes for regular autolinks
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksUnicodeSupport_Example023()
|
||||
{
|
||||
// Example 23
|
||||
// Section: Extensions / AutoLinks / Unicode support
|
||||
//
|
||||
// The following Markdown:
|
||||
// <http://abc.net/☃>
|
||||
//
|
||||
// <http://abc.net?☃>
|
||||
//
|
||||
// <http://abc.net#☃>
|
||||
//
|
||||
// <http://abc.net/foo#☃>
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://abc.net/%E2%98%83">http://abc.net/☃</a></p>
|
||||
// <p><a href="http://abc.net?%E2%98%83">http://abc.net?☃</a></p>
|
||||
// <p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
|
||||
// <p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
|
||||
|
||||
Console.WriteLine("Example 23\nSection Extensions / AutoLinks / Unicode support\n");
|
||||
TestParser.TestSpec("<http://abc.net/☃>\n\n<http://abc.net?☃>\n\n<http://abc.net#☃>\n\n<http://abc.net/foo#☃>", "<p><a href=\"http://abc.net/%E2%98%83\">http://abc.net/☃</a></p>\n<p><a href=\"http://abc.net?%E2%98%83\">http://abc.net?☃</a></p>\n<p><a href=\"http://abc.net#%E2%98%83\">http://abc.net#☃</a></p>\n<p><a href=\"http://abc.net/foo#%E2%98%83\">http://abc.net/foo#☃</a></p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksUnicodeSupport_Example024()
|
||||
{
|
||||
// Example 24
|
||||
// Section: Extensions / AutoLinks / Unicode support
|
||||
//
|
||||
// The following Markdown:
|
||||
// <http://☃.net?☃>
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
|
||||
|
||||
Console.WriteLine("Example 24\nSection Extensions / AutoLinks / Unicode support\n");
|
||||
TestParser.TestSpec("<http://☃.net?☃>", "<p><a href=\"http://xn--n3h.net?%E2%98%83\">http://☃.net?☃</a></p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// It also complies with CommonMark's vision of priority.
|
||||
// This will therefore be seen as an autolink and not as code inline.
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksUnicodeSupport_Example025()
|
||||
{
|
||||
// Example 25
|
||||
// Section: Extensions / AutoLinks / Unicode support
|
||||
//
|
||||
// The following Markdown:
|
||||
// <http://foö.bar.`baz>`
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://xn--fo-gka.bar.%60baz">http://foö.bar.`baz</a>`</p>
|
||||
|
||||
Console.WriteLine("Example 25\nSection Extensions / AutoLinks / Unicode support\n");
|
||||
TestParser.TestSpec("<http://foö.bar.`baz>`", "<p><a href=\"http://xn--fo-gka.bar.%60baz\">http://foö.bar.`baz</a>`</p>", "autolinks|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
304
src/Markdig.Tests/Specs/AutoLinks.md
Normal file
304
src/Markdig.Tests/Specs/AutoLinks.md
Normal file
@@ -0,0 +1,304 @@
|
||||
# Extensions
|
||||
|
||||
This section describes the different extensions supported:
|
||||
|
||||
## AutoLinks
|
||||
|
||||
Autolinks will format as a HTML link any string that starts by:
|
||||
|
||||
- `http://` or `https://`
|
||||
- `ftp://`
|
||||
- `mailto:`
|
||||
- `tel:`
|
||||
- `www.`
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a http://www.google.com URL and https://www.google.com
|
||||
This is a ftp://test.com
|
||||
And a mailto:email@toto.com
|
||||
And a tel:+1555123456
|
||||
And a plain www.google.com
|
||||
.
|
||||
<p>This is a <a href="http://www.google.com">http://www.google.com</a> URL and <a href="https://www.google.com">https://www.google.com</a>
|
||||
This is a <a href="ftp://test.com">ftp://test.com</a>
|
||||
And a <a href="mailto:email@toto.com">email@toto.com</a>
|
||||
And a <a href="tel:+1555123456">+1555123456</a>
|
||||
And a plain <a href="http://www.google.com">www.google.com</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
But incomplete links will not be matched:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is not a http:/www.google.com URL and https:/www.google.com
|
||||
This is not a ftp:/test.com
|
||||
And not a mailto:emailtoto.com
|
||||
And not a plain www. or a www.x
|
||||
.
|
||||
<p>This is not a http:/www.google.com URL and https:/www.google.com
|
||||
This is not a ftp:/test.com
|
||||
And not a mailto:emailtoto.com
|
||||
And not a plain www. or a www.x</p>
|
||||
````````````````````````````````
|
||||
|
||||
Previous character must be a punctuation or a valid space (tab, space, new line):
|
||||
|
||||
```````````````````````````````` example
|
||||
This is not a nhttp://www.google.com URL but this is (https://www.google.com)
|
||||
.
|
||||
<p>This is not a nhttp://www.google.com URL but this is (<a href="https://www.google.com">https://www.google.com</a>)</p>
|
||||
````````````````````````````````
|
||||
|
||||
An autolink should not interfere with an `<a>` HTML inline:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is an HTML <a href="http://www.google.com">http://www.google.com</a> link
|
||||
.
|
||||
<p>This is an HTML <a href="http://www.google.com">http://www.google.com</a> link</p>
|
||||
````````````````````````````````
|
||||
or even within emphasis:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is an HTML <a href="http://www.google.com"> **http://www.google.com** </a> link
|
||||
.
|
||||
<p>This is an HTML <a href="http://www.google.com"> <strong>http://www.google.com</strong> </a> link</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
An autolink should not interfere with a markdown link:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is an HTML [http://www.google.com](http://www.google.com) link
|
||||
.
|
||||
<p>This is an HTML <a href="http://www.google.com">http://www.google.com</a> link</p>
|
||||
````````````````````````````````
|
||||
|
||||
A link embraced by pending emphasis should let the emphasis takes precedence if characters are placed at the end of the matched link:
|
||||
|
||||
```````````````````````````````` example
|
||||
Check **http://www.a.com** or __http://www.b.com__
|
||||
.
|
||||
<p>Check <strong><a href="http://www.a.com">http://www.a.com</a></strong> or <strong><a href="http://www.b.com">http://www.b.com</a></strong></p>
|
||||
````````````````````````````````
|
||||
|
||||
It is not mentioned by the spec, but empty emails won't be matched (only a subset of [RFC2368](https://tools.ietf.org/html/rfc2368) is supported by auto links):
|
||||
|
||||
```````````````````````````````` example
|
||||
mailto:email@test.com is okay, but mailto:@test.com is not
|
||||
.
|
||||
<p><a href="mailto:email@test.com">email@test.com</a> is okay, but mailto:@test.com is not</p>
|
||||
````````````````````````````````
|
||||
|
||||
### GFM Support
|
||||
|
||||
Extract from [GFM Autolinks extensions specs](https://github.github.com/gfm/#autolinks-extension-)
|
||||
|
||||
```````````````````````````````` example
|
||||
www.commonmark.org
|
||||
.
|
||||
<p><a href="http://www.commonmark.org">www.commonmark.org</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
Visit www.commonmark.org/help for more information.
|
||||
.
|
||||
<p>Visit <a href="http://www.commonmark.org/help">www.commonmark.org/help</a> for more information.</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
Visit www.commonmark.org.
|
||||
|
||||
Visit www.commonmark.org/a.b.
|
||||
.
|
||||
<p>Visit <a href="http://www.commonmark.org">www.commonmark.org</a>.</p>
|
||||
<p>Visit <a href="http://www.commonmark.org/a.b">www.commonmark.org/a.b</a>.</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
```````````````````````````````` example
|
||||
www.google.com/search?q=Markup+(business)
|
||||
|
||||
(www.google.com/search?q=Markup+(business))
|
||||
.
|
||||
<p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
|
||||
<p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>)</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
```````````````````````````````` example
|
||||
www.google.com/search?q=commonmark&hl=en
|
||||
|
||||
www.google.com/search?q=commonmark&hl;
|
||||
.
|
||||
<p><a href="http://www.google.com/search?q=commonmark&hl=en">www.google.com/search?q=commonmark&hl=en</a></p>
|
||||
<p><a href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&hl;</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
```````````````````````````````` example
|
||||
www.commonmark.org/he<lp
|
||||
.
|
||||
<p><a href="http://www.commonmark.org/he">www.commonmark.org/he</a><lp</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
http://commonmark.org
|
||||
|
||||
(Visit https://encrypted.google.com/search?q=Markup+(business))
|
||||
|
||||
Anonymous FTP is available at ftp://foo.bar.baz.
|
||||
.
|
||||
<p><a href="http://commonmark.org">http://commonmark.org</a></p>
|
||||
<p>(Visit <a href="https://encrypted.google.com/search?q=Markup+(business)">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>
|
||||
<p>Anonymous FTP is available at <a href="ftp://foo.bar.baz">ftp://foo.bar.baz</a>.</p>
|
||||
````````````````````````````````
|
||||
|
||||
### Valid Domain Tests
|
||||
|
||||
Domain names that have empty segments won't be matched
|
||||
|
||||
```````````````````````````````` example
|
||||
www..
|
||||
www..com
|
||||
http://test.
|
||||
http://.test
|
||||
http://.
|
||||
http://..
|
||||
ftp://test.
|
||||
ftp://.test
|
||||
mailto:email@test.
|
||||
mailto:email@.test
|
||||
.
|
||||
<p>www..
|
||||
www..com
|
||||
http://test.
|
||||
http://.test
|
||||
http://.
|
||||
http://..
|
||||
ftp://test.
|
||||
ftp://.test
|
||||
mailto:email@test.
|
||||
mailto:email@.test</p>
|
||||
````````````````````````````````
|
||||
|
||||
Domain names with too few segments won't be matched
|
||||
|
||||
```````````````````````````````` example
|
||||
www
|
||||
www.com
|
||||
http://test
|
||||
ftp://test
|
||||
mailto:email@test
|
||||
.
|
||||
<p>www
|
||||
www.com
|
||||
http://test
|
||||
ftp://test
|
||||
mailto:email@test</p>
|
||||
````````````````````````````````
|
||||
|
||||
Domain names that contain an underscores in the last two segments won't be matched
|
||||
|
||||
```````````````````````````````` example
|
||||
www._test.foo.bar is okay, but www._test.foo is not
|
||||
|
||||
http://te_st.foo.bar is okay, as is http://test.foo_.bar.foo
|
||||
|
||||
But http://te_st.foo, http://test.foo_.bar and http://test._foo are not
|
||||
|
||||
ftp://test_.foo.bar is okay, but ftp://test.fo_o is not
|
||||
|
||||
mailto:email@_test.foo.bar is okay, but mailto:email@_test.foo is not
|
||||
.
|
||||
<p><a href="http://www._test.foo.bar">www._test.foo.bar</a> is okay, but www._test.foo is not</p>
|
||||
<p><a href="http://te_st.foo.bar">http://te_st.foo.bar</a> is okay, as is <a href="http://test.foo_.bar.foo">http://test.foo_.bar.foo</a></p>
|
||||
<p>But http://te_st.foo, http://test.foo_.bar and http://test._foo are not</p>
|
||||
<p><a href="ftp://test_.foo.bar">ftp://test_.foo.bar</a> is okay, but ftp://test.fo_o is not</p>
|
||||
<p><a href="mailto:email@_test.foo.bar">email@_test.foo.bar</a> is okay, but mailto:email@_test.foo is not</p>
|
||||
````````````````````````````````
|
||||
|
||||
Domain names that contain invalid characters (not AlphaNumberic, -, _ or .) won't be matched
|
||||
|
||||
```````````````````````````````` example
|
||||
https://[your-domain]/api
|
||||
.
|
||||
<p>https://[your-domain]/api</p>
|
||||
````````````````````````````````
|
||||
|
||||
Domain names followed by ?, : or # instead of / are matched
|
||||
|
||||
```````````````````````````````` example
|
||||
https://github.com?
|
||||
|
||||
https://github.com?a
|
||||
|
||||
https://github.com#a
|
||||
|
||||
https://github.com:
|
||||
|
||||
https://github.com:443
|
||||
.
|
||||
<p><a href="https://github.com">https://github.com</a>?</p>
|
||||
<p><a href="https://github.com?a">https://github.com?a</a></p>
|
||||
<p><a href="https://github.com#a">https://github.com#a</a></p>
|
||||
<p><a href="https://github.com">https://github.com</a>:</p>
|
||||
<p><a href="https://github.com:443">https://github.com:443</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
### Unicode support
|
||||
|
||||
Links with unicode characters in the path / query / fragment are matched and url encoded
|
||||
|
||||
```````````````````````````````` example
|
||||
http://abc.net/☃
|
||||
|
||||
http://abc.net?☃
|
||||
|
||||
http://abc.net#☃
|
||||
|
||||
http://abc.net/foo#☃
|
||||
.
|
||||
<p><a href="http://abc.net/%E2%98%83">http://abc.net/☃</a></p>
|
||||
<p><a href="http://abc.net?%E2%98%83">http://abc.net?☃</a></p>
|
||||
<p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
|
||||
<p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
Unicode characters in the FQDN are matched and IDNA encoded
|
||||
|
||||
```````````````````````````````` example
|
||||
http://☃.net?☃
|
||||
.
|
||||
<p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
Same goes for regular autolinks
|
||||
|
||||
```````````````````````````````` example
|
||||
<http://abc.net/☃>
|
||||
|
||||
<http://abc.net?☃>
|
||||
|
||||
<http://abc.net#☃>
|
||||
|
||||
<http://abc.net/foo#☃>
|
||||
.
|
||||
<p><a href="http://abc.net/%E2%98%83">http://abc.net/☃</a></p>
|
||||
<p><a href="http://abc.net?%E2%98%83">http://abc.net?☃</a></p>
|
||||
<p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
|
||||
<p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
<http://☃.net?☃>
|
||||
.
|
||||
<p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
It also complies with CommonMark's vision of priority.
|
||||
This will therefore be seen as an autolink and not as code inline.
|
||||
|
||||
```````````````````````````````` example
|
||||
<http://foö.bar.`baz>`
|
||||
.
|
||||
<p><a href="http://xn--fo-gka.bar.%60baz">http://foö.bar.`baz</a>`</p>
|
||||
````````````````````````````````
|
||||
111
src/Markdig.Tests/Specs/BootstrapSpecs.generated.cs
Normal file
111
src/Markdig.Tests/Specs/BootstrapSpecs.generated.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
// Generated: 2019-04-15 05:23:49
|
||||
|
||||
// --------------------------------
|
||||
// Bootstrap
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Bootstrap
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsBootstrap
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// Adds support for outputting bootstrap ready tags:
|
||||
//
|
||||
// ## Bootstrap
|
||||
//
|
||||
// Adds bootstrap `.table` class to `<table>`:
|
||||
[Test]
|
||||
public void ExtensionsBootstrap_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Bootstrap
|
||||
//
|
||||
// The following Markdown:
|
||||
// Name | Value
|
||||
// -----| -----
|
||||
// Abc | 16
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table class="table">
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>Name</th>
|
||||
// <th>Value</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>Abc</td>
|
||||
// <td>16</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Bootstrap\n");
|
||||
TestParser.TestSpec("Name | Value\n-----| -----\nAbc | 16", "<table class=\"table\">\n<thead>\n<tr>\n<th>Name</th>\n<th>Value</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Abc</td>\n<td>16</td>\n</tr>\n</tbody>\n</table>", "bootstrap+pipetables+figures+attributes");
|
||||
}
|
||||
|
||||
// Adds bootstrap `.blockquote` class to `<blockquote>`:
|
||||
[Test]
|
||||
public void ExtensionsBootstrap_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Bootstrap
|
||||
//
|
||||
// The following Markdown:
|
||||
// > This is a blockquote
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <blockquote class="blockquote">
|
||||
// <p>This is a blockquote</p>
|
||||
// </blockquote>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Bootstrap\n");
|
||||
TestParser.TestSpec("> This is a blockquote", "<blockquote class=\"blockquote\">\n<p>This is a blockquote</p>\n</blockquote>", "bootstrap+pipetables+figures+attributes");
|
||||
}
|
||||
|
||||
// Adds bootstrap `.figure` class to `<figure>` and `.figure-caption` to `<figcaption>`
|
||||
[Test]
|
||||
public void ExtensionsBootstrap_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Bootstrap
|
||||
//
|
||||
// The following Markdown:
|
||||
// ^^^
|
||||
// This is a text in a caption
|
||||
// ^^^ This is the caption
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <figure class="figure">
|
||||
// <p>This is a text in a caption</p>
|
||||
// <figcaption class="figure-caption">This is the caption</figcaption>
|
||||
// </figure>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Bootstrap\n");
|
||||
TestParser.TestSpec("^^^\nThis is a text in a caption\n^^^ This is the caption", "<figure class=\"figure\">\n<p>This is a text in a caption</p>\n<figcaption class=\"figure-caption\">This is the caption</figcaption>\n</figure>", "bootstrap+pipetables+figures+attributes");
|
||||
}
|
||||
|
||||
// Adds the `.img-fluid` class to all image links `<img>`
|
||||
[Test]
|
||||
public void ExtensionsBootstrap_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Bootstrap
|
||||
//
|
||||
// The following Markdown:
|
||||
// 
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><img src="/url" class="img-fluid" alt="Image Link" /></p>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Bootstrap\n");
|
||||
TestParser.TestSpec("", "<p><img src=\"/url\" class=\"img-fluid\" alt=\"Image Link\" /></p>", "bootstrap+pipetables+figures+attributes");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# Extensions
|
||||
|
||||
Adds support for outputing bootstrap ready tags:
|
||||
Adds support for outputting bootstrap ready tags:
|
||||
|
||||
## Bootstrap
|
||||
|
||||
|
||||
15267
src/Markdig.Tests/Specs/CommonMark.generated.cs
Normal file
15267
src/Markdig.Tests/Specs/CommonMark.generated.cs
Normal file
File diff suppressed because it is too large
Load Diff
9710
src/Markdig.Tests/Specs/CommonMark.md
Normal file
9710
src/Markdig.Tests/Specs/CommonMark.md
Normal file
File diff suppressed because it is too large
Load Diff
211
src/Markdig.Tests/Specs/CustomContainerSpecs.generated.cs
Normal file
211
src/Markdig.Tests/Specs/CustomContainerSpecs.generated.cs
Normal file
@@ -0,0 +1,211 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Custom Containers
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.CustomContainers
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsCustomContainer
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the different extensions supported:
|
||||
//
|
||||
// ## Custom Container
|
||||
//
|
||||
// A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</div>` block.
|
||||
[Test]
|
||||
public void ExtensionsCustomContainer_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Custom Container
|
||||
//
|
||||
// The following Markdown:
|
||||
// :::spoiler
|
||||
// This is a *spoiler*
|
||||
// :::
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <div class="spoiler"><p>This is a <em>spoiler</em></p>
|
||||
// </div>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Custom Container\n");
|
||||
TestParser.TestSpec(":::spoiler\nThis is a *spoiler*\n:::", "<div class=\"spoiler\"><p>This is a <em>spoiler</em></p>\n</div>", "customcontainers+attributes|advanced");
|
||||
}
|
||||
|
||||
// The text following the opened custom container is optional:
|
||||
[Test]
|
||||
public void ExtensionsCustomContainer_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Custom Container
|
||||
//
|
||||
// The following Markdown:
|
||||
// :::
|
||||
// This is a regular div
|
||||
// :::
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <div><p>This is a regular div</p>
|
||||
// </div>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Custom Container\n");
|
||||
TestParser.TestSpec(":::\nThis is a regular div\n:::", "<div><p>This is a regular div</p>\n</div>", "customcontainers+attributes|advanced");
|
||||
}
|
||||
|
||||
// Like for fenced code block, you can use more than 3 `:` characters as long as the closing has the same number of characters:
|
||||
[Test]
|
||||
public void ExtensionsCustomContainer_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Custom Container
|
||||
//
|
||||
// The following Markdown:
|
||||
// ::::::::::::spoiler
|
||||
// This is a spoiler
|
||||
// ::::::::::::
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <div class="spoiler"><p>This is a spoiler</p>
|
||||
// </div>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Custom Container\n");
|
||||
TestParser.TestSpec("::::::::::::spoiler\nThis is a spoiler\n::::::::::::", "<div class=\"spoiler\"><p>This is a spoiler</p>\n</div>", "customcontainers+attributes|advanced");
|
||||
}
|
||||
|
||||
// Like for fenced code block, a custom container can span over multiple empty lines in a list block:
|
||||
[Test]
|
||||
public void ExtensionsCustomContainer_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Custom Container
|
||||
//
|
||||
// The following Markdown:
|
||||
// - This is a list
|
||||
// :::spoiler
|
||||
// This is a spoiler
|
||||
// - item1
|
||||
// - item2
|
||||
// :::
|
||||
// - A second item in the list
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ul>
|
||||
// <li>This is a list
|
||||
// <div class="spoiler">This is a spoiler
|
||||
// <ul>
|
||||
// <li>item1</li>
|
||||
// <li>item2</li>
|
||||
// </ul>
|
||||
// </div>
|
||||
// </li>
|
||||
// <li>A second item in the list</li>
|
||||
// </ul>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Custom Container\n");
|
||||
TestParser.TestSpec("- This is a list\n :::spoiler\n This is a spoiler\n - item1\n - item2\n :::\n- A second item in the list", "<ul>\n<li>This is a list\n<div class=\"spoiler\">This is a spoiler\n<ul>\n<li>item1</li>\n<li>item2</li>\n</ul>\n</div>\n</li>\n<li>A second item in the list</li>\n</ul>", "customcontainers+attributes|advanced");
|
||||
}
|
||||
|
||||
// Attributes extension is also supported for Custom Container, as long as the Attributes extension is activated after the CustomContainer extension (`.UseCustomContainer().UseAttributes()`)
|
||||
[Test]
|
||||
public void ExtensionsCustomContainer_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / Custom Container
|
||||
//
|
||||
// The following Markdown:
|
||||
// :::spoiler {#myspoiler myprop=yes}
|
||||
// This is a spoiler
|
||||
// :::
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <div id="myspoiler" class="spoiler" myprop="yes"><p>This is a spoiler</p>
|
||||
// </div>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / Custom Container\n");
|
||||
TestParser.TestSpec(":::spoiler {#myspoiler myprop=yes}\nThis is a spoiler\n:::", "<div id=\"myspoiler\" class=\"spoiler\" myprop=\"yes\"><p>This is a spoiler</p>\n</div>", "customcontainers+attributes|advanced");
|
||||
}
|
||||
|
||||
// The content of a custom container can contain any blocks:
|
||||
[Test]
|
||||
public void ExtensionsCustomContainer_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / Custom Container
|
||||
//
|
||||
// The following Markdown:
|
||||
// :::mycontainer
|
||||
// <p>This is a raw spoiler</p>
|
||||
// :::
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <div class="mycontainer"><p>This is a raw spoiler</p>
|
||||
// </div>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / Custom Container\n");
|
||||
TestParser.TestSpec(":::mycontainer\n<p>This is a raw spoiler</p>\n:::", "<div class=\"mycontainer\"><p>This is a raw spoiler</p>\n</div>", "customcontainers+attributes|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsInlineCustomContainer
|
||||
{
|
||||
// ## Inline Custom Container
|
||||
//
|
||||
// A custom container can also be used within an inline container (e.g: paragraph, heading...) by enclosing a text by a new emphasis `::`
|
||||
[Test]
|
||||
public void ExtensionsInlineCustomContainer_Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Extensions / Inline Custom Container
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a text ::with special emphasis::
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a text <span>with special emphasis</span></p>
|
||||
|
||||
Console.WriteLine("Example 7\nSection Extensions / Inline Custom Container \n");
|
||||
TestParser.TestSpec("This is a text ::with special emphasis::", "<p>This is a text <span>with special emphasis</span></p>", "customcontainers+attributes|advanced");
|
||||
}
|
||||
|
||||
// Any other emphasis inline can be used within this emphasis inline container:
|
||||
[Test]
|
||||
public void ExtensionsInlineCustomContainer_Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Extensions / Inline Custom Container
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a text ::with special *emphasis*::
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a text <span>with special <em>emphasis</em></span></p>
|
||||
|
||||
Console.WriteLine("Example 8\nSection Extensions / Inline Custom Container \n");
|
||||
TestParser.TestSpec("This is a text ::with special *emphasis*::", "<p>This is a text <span>with special <em>emphasis</em></span></p>", "customcontainers+attributes|advanced");
|
||||
}
|
||||
|
||||
// Attributes can be attached to a inline custom container:
|
||||
[Test]
|
||||
public void ExtensionsInlineCustomContainer_Example009()
|
||||
{
|
||||
// Example 9
|
||||
// Section: Extensions / Inline Custom Container
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a text ::with special emphasis::{#myId .myemphasis}
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a text <span id="myId" class="myemphasis">with special emphasis</span></p>
|
||||
|
||||
Console.WriteLine("Example 9\nSection Extensions / Inline Custom Container \n");
|
||||
TestParser.TestSpec("This is a text ::with special emphasis::{#myId .myemphasis}", "<p>This is a text <span id=\"myId\" class=\"myemphasis\">with special emphasis</span></p>", "customcontainers+attributes|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ This section describes the different extensions supported:
|
||||
|
||||
## Custom Container
|
||||
|
||||
A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</dib>` block.
|
||||
A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</div>` block.
|
||||
|
||||
```````````````````````````````` example
|
||||
:::spoiler
|
||||
@@ -109,4 +109,4 @@ Attributes can be attached to a inline custom container:
|
||||
This is a text ::with special emphasis::{#myId .myemphasis}
|
||||
.
|
||||
<p>This is a text <span id="myId" class="myemphasis">with special emphasis</span></p>
|
||||
````````````````````````````````
|
||||
````````````````````````````````
|
||||
|
||||
202
src/Markdig.Tests/Specs/DefinitionListSpecs.generated.cs
Normal file
202
src/Markdig.Tests/Specs/DefinitionListSpecs.generated.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
// Generated: 2019-04-15 05:06:35
|
||||
|
||||
// --------------------------------
|
||||
// Definition Lists
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.DefinitionLists
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsDefinitionLists
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the different extensions supported:
|
||||
//
|
||||
// ## Definition lists
|
||||
//
|
||||
// A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</div>` block.
|
||||
[Test]
|
||||
public void ExtensionsDefinitionLists_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Definition lists
|
||||
//
|
||||
// The following Markdown:
|
||||
//
|
||||
// Term 1
|
||||
// : This is a definition item
|
||||
// With a paragraph
|
||||
// > This is a block quote
|
||||
//
|
||||
// - This is a list
|
||||
// - with an item2
|
||||
//
|
||||
// ```java
|
||||
// Test
|
||||
//
|
||||
//
|
||||
// ```
|
||||
//
|
||||
// And a last line
|
||||
// : This ia another definition item
|
||||
//
|
||||
// Term2
|
||||
// Term3 *with some inline*
|
||||
// : This is another definition for term2
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <dl>
|
||||
// <dt>Term 1</dt>
|
||||
// <dd><p>This is a definition item
|
||||
// With a paragraph</p>
|
||||
// <blockquote>
|
||||
// <p>This is a block quote</p>
|
||||
// </blockquote>
|
||||
// <ul>
|
||||
// <li>This is a list</li>
|
||||
// <li>with an item2</li>
|
||||
// </ul>
|
||||
// <pre><code class="language-java">Test
|
||||
//
|
||||
//
|
||||
// </code></pre>
|
||||
// <p>And a last line</p>
|
||||
// </dd>
|
||||
// <dd>This ia another definition item</dd>
|
||||
// <dt>Term2</dt>
|
||||
// <dt>Term3 <em>with some inline</em></dt>
|
||||
// <dd>This is another definition for term2</dd>
|
||||
// </dl>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Definition lists\n");
|
||||
TestParser.TestSpec("\nTerm 1\n: This is a definition item\n With a paragraph\n > This is a block quote\n\n - This is a list\n - with an item2\n\n ```java\n Test\n\n\n ```\n\n And a last line\n: This ia another definition item\n\nTerm2\nTerm3 *with some inline*\n: This is another definition for term2", "<dl>\n<dt>Term 1</dt>\n<dd><p>This is a definition item\nWith a paragraph</p>\n<blockquote>\n<p>This is a block quote</p>\n</blockquote>\n<ul>\n<li>This is a list</li>\n<li>with an item2</li>\n</ul>\n<pre><code class=\"language-java\">Test\n\n\n</code></pre>\n<p>And a last line</p>\n</dd>\n<dd>This ia another definition item</dd>\n<dt>Term2</dt>\n<dt>Term3 <em>with some inline</em></dt>\n<dd>This is another definition for term2</dd>\n</dl>", "definitionlists+attributes|advanced");
|
||||
}
|
||||
|
||||
// A definition term can be followed at most by one blank line. Lazy continuations are supported for definitions:
|
||||
[Test]
|
||||
public void ExtensionsDefinitionLists_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Definition lists
|
||||
//
|
||||
// The following Markdown:
|
||||
// Term 1
|
||||
//
|
||||
// : Definition
|
||||
// with lazy continuation.
|
||||
//
|
||||
// Second paragraph of the definition.
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <dl>
|
||||
// <dt>Term 1</dt>
|
||||
// <dd><p>Definition
|
||||
// with lazy continuation.</p>
|
||||
// <p>Second paragraph of the definition.</p>
|
||||
// </dd>
|
||||
// </dl>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Definition lists\n");
|
||||
TestParser.TestSpec("Term 1\n\n: Definition\nwith lazy continuation.\n\n Second paragraph of the definition.", "<dl>\n<dt>Term 1</dt>\n<dd><p>Definition\nwith lazy continuation.</p>\n<p>Second paragraph of the definition.</p>\n</dd>\n</dl>", "definitionlists+attributes|advanced");
|
||||
}
|
||||
|
||||
// The definition must be indented to 4 characters including the `:`.
|
||||
[Test]
|
||||
public void ExtensionsDefinitionLists_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Definition lists
|
||||
//
|
||||
// The following Markdown:
|
||||
// Term 1
|
||||
// : Invalid with less than 3 characters
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>Term 1
|
||||
// : Invalid with less than 3 characters</p>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Definition lists\n");
|
||||
TestParser.TestSpec("Term 1\n: Invalid with less than 3 characters", "<p>Term 1\n: Invalid with less than 3 characters</p>", "definitionlists+attributes|advanced");
|
||||
}
|
||||
|
||||
// The `:` can be indented up to 3 spaces:
|
||||
[Test]
|
||||
public void ExtensionsDefinitionLists_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Definition lists
|
||||
//
|
||||
// The following Markdown:
|
||||
// Term 1
|
||||
// : Valid even if `:` starts at most 3 spaces
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <dl>
|
||||
// <dt>Term 1</dt>
|
||||
// <dd>Valid even if <code>:</code> starts at most 3 spaces</dd>
|
||||
// </dl>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Definition lists\n");
|
||||
TestParser.TestSpec("Term 1\n : Valid even if `:` starts at most 3 spaces", "<dl>\n<dt>Term 1</dt>\n<dd>Valid even if <code>:</code> starts at most 3 spaces</dd>\n</dl>", "definitionlists+attributes|advanced");
|
||||
}
|
||||
|
||||
// But more than 3 spaces before `:` will trigger an indented code block:
|
||||
[Test]
|
||||
public void ExtensionsDefinitionLists_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / Definition lists
|
||||
//
|
||||
// The following Markdown:
|
||||
// Term 1
|
||||
//
|
||||
// : Not valid
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>Term 1</p>
|
||||
// <pre><code>: Not valid
|
||||
// </code></pre>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / Definition lists\n");
|
||||
TestParser.TestSpec("Term 1\n\n : Not valid", "<p>Term 1</p>\n<pre><code>: Not valid\n</code></pre>", "definitionlists+attributes|advanced");
|
||||
}
|
||||
|
||||
// Definition lists can be nested inside list items
|
||||
[Test]
|
||||
public void ExtensionsDefinitionLists_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / Definition lists
|
||||
//
|
||||
// The following Markdown:
|
||||
// 1. First
|
||||
//
|
||||
// 2. Second
|
||||
//
|
||||
// Term 1
|
||||
// : Definition
|
||||
//
|
||||
// Term 2
|
||||
// : Second Definition
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ol>
|
||||
// <li><p>First</p></li>
|
||||
// <li><p>Second</p>
|
||||
// <dl>
|
||||
// <dt>Term 1</dt>
|
||||
// <dd>Definition</dd>
|
||||
// <dt>Term 2</dt>
|
||||
// <dd>Second Definition</dd>
|
||||
// </dl></li>
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / Definition lists\n");
|
||||
TestParser.TestSpec("1. First\n \n2. Second\n \n Term 1\n : Definition\n \n Term 2\n : Second Definition", "<ol>\n<li><p>First</p></li>\n<li><p>Second</p>\n<dl>\n<dt>Term 1</dt>\n<dd>Definition</dd>\n<dt>Term 2</dt>\n<dd>Second Definition</dd>\n</dl></li>\n</ol>", "definitionlists+attributes|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ This section describes the different extensions supported:
|
||||
|
||||
## Definition lists
|
||||
|
||||
A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</dib>` block.
|
||||
A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</div>` block.
|
||||
|
||||
```````````````````````````````` example
|
||||
|
||||
@@ -105,3 +105,28 @@ Term 1
|
||||
<pre><code>: Not valid
|
||||
</code></pre>
|
||||
````````````````````````````````
|
||||
|
||||
Definition lists can be nested inside list items
|
||||
|
||||
```````````````````````````````` example
|
||||
1. First
|
||||
|
||||
2. Second
|
||||
|
||||
Term 1
|
||||
: Definition
|
||||
|
||||
Term 2
|
||||
: Second Definition
|
||||
.
|
||||
<ol>
|
||||
<li><p>First</p></li>
|
||||
<li><p>Second</p>
|
||||
<dl>
|
||||
<dt>Term 1</dt>
|
||||
<dd>Definition</dd>
|
||||
<dt>Term 2</dt>
|
||||
<dd>Second Definition</dd>
|
||||
</dl></li>
|
||||
</ol>
|
||||
````````````````````````````````
|
||||
|
||||
94
src/Markdig.Tests/Specs/DiagramsSpecs.generated.cs
Normal file
94
src/Markdig.Tests/Specs/DiagramsSpecs.generated.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Diagrams
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Diagrams
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsMermaidDiagrams
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// Adds support for diagrams extension:
|
||||
//
|
||||
// ## Mermaid diagrams
|
||||
//
|
||||
// Using a fenced code block with the `mermaid` language info will output a `<div class='mermaid'>` instead of a `pre/code` block:
|
||||
[Test]
|
||||
public void ExtensionsMermaidDiagrams_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Mermaid diagrams
|
||||
//
|
||||
// The following Markdown:
|
||||
// ```mermaid
|
||||
// graph TD;
|
||||
// A-->B;
|
||||
// A-->C;
|
||||
// B-->D;
|
||||
// C-->D;
|
||||
// ```
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <div class="mermaid">graph TD;
|
||||
// A-->B;
|
||||
// A-->C;
|
||||
// B-->D;
|
||||
// C-->D;
|
||||
// </div>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Mermaid diagrams\n");
|
||||
TestParser.TestSpec("```mermaid\ngraph TD;\n A-->B;\n A-->C;\n B-->D;\n C-->D;\n```", "<div class=\"mermaid\">graph TD;\n A-->B;\n A-->C;\n B-->D;\n C-->D;\n</div>", "diagrams|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsNomnomlDiagrams
|
||||
{
|
||||
// ## nomnoml diagrams
|
||||
//
|
||||
// Using a fenced code block with the `nomnoml` language info will output a `<div class='nomnoml'>` instead of a `pre/code` block:
|
||||
[Test]
|
||||
public void ExtensionsNomnomlDiagrams_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / nomnoml diagrams
|
||||
//
|
||||
// The following Markdown:
|
||||
// ```nomnoml
|
||||
// [example|
|
||||
// propertyA: Int
|
||||
// propertyB: string
|
||||
// |
|
||||
// methodA()
|
||||
// methodB()
|
||||
// |
|
||||
// [subA]--[subB]
|
||||
// [subA]-:>[sub C]
|
||||
// ]
|
||||
// ```
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <div class="nomnoml">[example|
|
||||
// propertyA: Int
|
||||
// propertyB: string
|
||||
// |
|
||||
// methodA()
|
||||
// methodB()
|
||||
// |
|
||||
// [subA]--[subB]
|
||||
// [subA]-:>[sub C]
|
||||
// ]
|
||||
// </div>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / nomnoml diagrams\n");
|
||||
TestParser.TestSpec("```nomnoml\n[example|\n propertyA: Int\n propertyB: string\n|\n methodA()\n methodB()\n|\n [subA]--[subB]\n [subA]-:>[sub C]\n]\n```", "<div class=\"nomnoml\">[example|\n propertyA: Int\n propertyB: string\n|\n methodA()\n methodB()\n|\n [subA]--[subB]\n [subA]-:>[sub C]\n]\n</div>", "diagrams|advanced");
|
||||
}
|
||||
// TODO: Add other text diagram languages
|
||||
}
|
||||
}
|
||||
57
src/Markdig.Tests/Specs/DiagramsSpecs.md
Normal file
57
src/Markdig.Tests/Specs/DiagramsSpecs.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Extensions
|
||||
|
||||
Adds support for diagrams extension:
|
||||
|
||||
## Mermaid diagrams
|
||||
|
||||
Using a fenced code block with the `mermaid` language info will output a `<div class='mermaid'>` instead of a `pre/code` block:
|
||||
|
||||
```````````````````````````````` example
|
||||
```mermaid
|
||||
graph TD;
|
||||
A-->B;
|
||||
A-->C;
|
||||
B-->D;
|
||||
C-->D;
|
||||
```
|
||||
.
|
||||
<div class="mermaid">graph TD;
|
||||
A-->B;
|
||||
A-->C;
|
||||
B-->D;
|
||||
C-->D;
|
||||
</div>
|
||||
````````````````````````````````
|
||||
|
||||
## nomnoml diagrams
|
||||
|
||||
Using a fenced code block with the `nomnoml` language info will output a `<div class='nomnoml'>` instead of a `pre/code` block:
|
||||
|
||||
```````````````````````````````` example
|
||||
```nomnoml
|
||||
[example|
|
||||
propertyA: Int
|
||||
propertyB: string
|
||||
|
|
||||
methodA()
|
||||
methodB()
|
||||
|
|
||||
[subA]--[subB]
|
||||
[subA]-:>[sub C]
|
||||
]
|
||||
```
|
||||
.
|
||||
<div class="nomnoml">[example|
|
||||
propertyA: Int
|
||||
propertyB: string
|
||||
|
|
||||
methodA()
|
||||
methodB()
|
||||
|
|
||||
[subA]--[subB]
|
||||
[subA]-:>[sub C]
|
||||
]
|
||||
</div>
|
||||
````````````````````````````````
|
||||
|
||||
TODO: Add other text diagram languages
|
||||
91
src/Markdig.Tests/Specs/EmojiSpecs.generated.cs
Normal file
91
src/Markdig.Tests/Specs/EmojiSpecs.generated.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
// Generated: 2020-01-13 21:08:58
|
||||
|
||||
// --------------------------------
|
||||
// Emoji
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Emoji
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsEmoji
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the different extensions supported:
|
||||
//
|
||||
// ## Emoji
|
||||
//
|
||||
// Emoji shortcodes and smileys can be converted to their respective unicode characters:
|
||||
[Test]
|
||||
public void ExtensionsEmoji_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Emoji
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a test with a :) and a :angry: smiley
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a test with a 😃 and a 😠 smiley</p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Emoji\n");
|
||||
TestParser.TestSpec("This is a test with a :) and a :angry: smiley", "<p>This is a test with a 😃 and a 😠 smiley</p>", "emojis|advanced+emojis");
|
||||
}
|
||||
|
||||
// An emoji needs to be preceded by a space:
|
||||
[Test]
|
||||
public void ExtensionsEmoji_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Emoji
|
||||
//
|
||||
// The following Markdown:
|
||||
// These are not:) an emoji with a:) x:angry:x
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>These are not:) an emoji with a:) x:angry:x</p>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Emoji\n");
|
||||
TestParser.TestSpec("These are not:) an emoji with a:) x:angry:x", "<p>These are not:) an emoji with a:) x:angry:x</p>", "emojis|advanced+emojis");
|
||||
}
|
||||
|
||||
// Emojis can be followed by close punctuation (or any other characters):
|
||||
[Test]
|
||||
public void ExtensionsEmoji_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Emoji
|
||||
//
|
||||
// The following Markdown:
|
||||
// We all need :), it makes us :muscle:. (and :ok_hand:).
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>We all need 😃, it makes us 💪. (and 👌).</p>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Emoji\n");
|
||||
TestParser.TestSpec("We all need :), it makes us :muscle:. (and :ok_hand:).", "<p>We all need 😃, it makes us 💪. (and 👌).</p>", "emojis|advanced+emojis");
|
||||
}
|
||||
|
||||
// Sentences can end with emojis:
|
||||
[Test]
|
||||
public void ExtensionsEmoji_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Emoji
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a sentence :ok_hand:
|
||||
// and keeps going to the next line :)
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a sentence 👌
|
||||
// and keeps going to the next line 😃</p>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Emoji\n");
|
||||
TestParser.TestSpec("This is a sentence :ok_hand:\nand keeps going to the next line :)", "<p>This is a sentence 👌\nand keeps going to the next line 😃</p>", "emojis|advanced+emojis");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,36 @@ This section describes the different extensions supported:
|
||||
|
||||
## Emoji
|
||||
|
||||
Emoji and smiley can be converted to their respective unicode characters:
|
||||
Emoji shortcodes and smileys can be converted to their respective unicode characters:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a test with a :) and a :angry: smiley
|
||||
.
|
||||
<p>This is a test with a 😃 and a 😠 smiley</p>
|
||||
````````````````````````````````
|
||||
|
||||
An emoji needs to be preceded by a space:
|
||||
|
||||
```````````````````````````````` example
|
||||
These are not:) an emoji with a:) x:angry:x
|
||||
.
|
||||
<p>These are not:) an emoji with a:) x:angry:x</p>
|
||||
````````````````````````````````
|
||||
|
||||
Emojis can be followed by close punctuation (or any other characters):
|
||||
|
||||
```````````````````````````````` example
|
||||
We all need :), it makes us :muscle:. (and :ok_hand:).
|
||||
.
|
||||
<p>We all need 😃, it makes us 💪. (and 👌).</p>
|
||||
````````````````````````````````
|
||||
|
||||
Sentences can end with emojis:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a sentence :ok_hand:
|
||||
and keeps going to the next line :)
|
||||
.
|
||||
<p>This is a sentence 👌
|
||||
and keeps going to the next line 😃</p>
|
||||
````````````````````````````````
|
||||
|
||||
152
src/Markdig.Tests/Specs/EmphasisExtraSpecs.generated.cs
Normal file
152
src/Markdig.Tests/Specs/EmphasisExtraSpecs.generated.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Emphasis Extra
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.EmphasisExtra
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsStrikethrough
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// The following additional emphasis are supported:
|
||||
//
|
||||
// ## Strikethrough
|
||||
//
|
||||
// Allows to strikethrough a span of text by surrounding it by `~~`. The semantic used for the generated HTML is the tag `<del>`.
|
||||
[Test]
|
||||
public void ExtensionsStrikethrough_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Strikethrough
|
||||
//
|
||||
// The following Markdown:
|
||||
// The following text ~~is deleted~~
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>The following text <del>is deleted</del></p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Strikethrough\n");
|
||||
TestParser.TestSpec("The following text ~~is deleted~~", "<p>The following text <del>is deleted</del></p>", "emphasisextras|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsSuperscriptAndSubscript
|
||||
{
|
||||
// ## Superscript and Subscript
|
||||
//
|
||||
// Superscripts can be written by surrounding a text by ^ characters; subscripts can be written by surrounding the subscripted text by ~ characters
|
||||
[Test]
|
||||
public void ExtensionsSuperscriptAndSubscript_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Superscript and Subscript
|
||||
//
|
||||
// The following Markdown:
|
||||
// H~2~O is a liquid. 2^10^ is 1024
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>H<sub>2</sub>O is a liquid. 2<sup>10</sup> is 1024</p>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Superscript and Subscript\n");
|
||||
TestParser.TestSpec("H~2~O is a liquid. 2^10^ is 1024", "<p>H<sub>2</sub>O is a liquid. 2<sup>10</sup> is 1024</p>", "emphasisextras|advanced");
|
||||
}
|
||||
|
||||
// Certain punctuation characters are exempted from the rule forbidding them within inline delimiters
|
||||
[Test]
|
||||
public void ExtensionsSuperscriptAndSubscript_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Superscript and Subscript
|
||||
//
|
||||
// The following Markdown:
|
||||
// One quintillionth can be expressed as 10^-18^
|
||||
//
|
||||
// Daggers^†^ and double-daggers^‡^ can be used to denote notes.
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>One quintillionth can be expressed as 10<sup>-18</sup></p>
|
||||
// <p>Daggers<sup>†</sup> and double-daggers<sup>‡</sup> can be used to denote notes.</p>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Superscript and Subscript\n");
|
||||
TestParser.TestSpec("One quintillionth can be expressed as 10^-18^\n\nDaggers^†^ and double-daggers^‡^ can be used to denote notes.", "<p>One quintillionth can be expressed as 10<sup>-18</sup></p>\n<p>Daggers<sup>†</sup> and double-daggers<sup>‡</sup> can be used to denote notes.</p>", "emphasisextras|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsInserted
|
||||
{
|
||||
// ## Inserted
|
||||
//
|
||||
// Inserted text can be used to specify that a text has been added to a document. The semantic used for the generated HTML is the tag `<ins>`.
|
||||
[Test]
|
||||
public void ExtensionsInserted_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Inserted
|
||||
//
|
||||
// The following Markdown:
|
||||
// ++Inserted text++
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><ins>Inserted text</ins></p>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Inserted\n");
|
||||
TestParser.TestSpec("++Inserted text++", "<p><ins>Inserted text</ins></p>", "emphasisextras|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsMarked
|
||||
{
|
||||
// ## Marked
|
||||
//
|
||||
// Marked text can be used to specify that a text has been marked in a document. The semantic used for the generated HTML is the tag `<mark>`.
|
||||
[Test]
|
||||
public void ExtensionsMarked_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / Marked
|
||||
//
|
||||
// The following Markdown:
|
||||
// ==Marked text==
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><mark>Marked text</mark></p>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / Marked\n");
|
||||
TestParser.TestSpec("==Marked text==", "<p><mark>Marked text</mark></p>", "emphasisextras|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsEmphasisOnHtmlEntities
|
||||
{
|
||||
// ## Emphasis on Html Entities
|
||||
[Test]
|
||||
public void ExtensionsEmphasisOnHtmlEntities_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / Emphasis on Html Entities
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is text MyBrand ^®^ and MyTrademark ^™^
|
||||
// This is text MyBrand^®^ and MyTrademark^™^
|
||||
// This is text MyBrand~®~ and MyCopyright^©^
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is text MyBrand <sup>®</sup> and MyTrademark <sup>TM</sup>
|
||||
// This is text MyBrand<sup>®</sup> and MyTrademark<sup>TM</sup>
|
||||
// This is text MyBrand<sub>®</sub> and MyCopyright<sup>©</sup></p>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / Emphasis on Html Entities\n");
|
||||
TestParser.TestSpec("This is text MyBrand ^®^ and MyTrademark ^™^\nThis is text MyBrand^®^ and MyTrademark^™^\nThis is text MyBrand~®~ and MyCopyright^©^", "<p>This is text MyBrand <sup>®</sup> and MyTrademark <sup>TM</sup>\nThis is text MyBrand<sup>®</sup> and MyTrademark<sup>TM</sup>\nThis is text MyBrand<sub>®</sub> and MyCopyright<sup>©</sup></p>", "emphasisextras|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,17 @@ H~2~O is a liquid. 2^10^ is 1024
|
||||
.
|
||||
<p>H<sub>2</sub>O is a liquid. 2<sup>10</sup> is 1024</p>
|
||||
````````````````````````````````
|
||||
|
||||
Certain punctuation characters are exempted from the rule forbidding them within inline delimiters
|
||||
|
||||
```````````````````````````````` example
|
||||
One quintillionth can be expressed as 10^-18^
|
||||
|
||||
Daggers^†^ and double-daggers^‡^ can be used to denote notes.
|
||||
.
|
||||
<p>One quintillionth can be expressed as 10<sup>-18</sup></p>
|
||||
<p>Daggers<sup>†</sup> and double-daggers<sup>‡</sup> can be used to denote notes.</p>
|
||||
````````````````````````````````
|
||||
|
||||
## Inserted
|
||||
|
||||
@@ -41,3 +52,16 @@ Marked text can be used to specify that a text has been marked in a document. T
|
||||
.
|
||||
<p><mark>Marked text</mark></p>
|
||||
````````````````````````````````
|
||||
## Emphasis on Html Entities
|
||||
|
||||
|
||||
```````````````````````````````` example
|
||||
This is text MyBrand ^®^ and MyTrademark ^™^
|
||||
This is text MyBrand^®^ and MyTrademark^™^
|
||||
This is text MyBrand~®~ and MyCopyright^©^
|
||||
.
|
||||
<p>This is text MyBrand <sup>®</sup> and MyTrademark <sup>TM</sup>
|
||||
This is text MyBrand<sup>®</sup> and MyTrademark<sup>TM</sup>
|
||||
This is text MyBrand<sub>®</sub> and MyCopyright<sup>©</sup></p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Figures, Footers and Cites
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.FiguresFootersAndCites
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsFigures
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// The following the figure extension:
|
||||
//
|
||||
// ## Figures
|
||||
//
|
||||
// A figure can be defined by using a pattern equivalent to a fenced code block but with the character `^`
|
||||
[Test]
|
||||
public void ExtensionsFigures_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Figures
|
||||
//
|
||||
// The following Markdown:
|
||||
// ^^^
|
||||
// This is a figure
|
||||
// ^^^ This is a *caption*
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <figure>
|
||||
// <p>This is a figure</p>
|
||||
// <figcaption>This is a <em>caption</em></figcaption>
|
||||
// </figure>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Figures\n");
|
||||
TestParser.TestSpec("^^^\nThis is a figure\n^^^ This is a *caption*", "<figure>\n<p>This is a figure</p>\n<figcaption>This is a <em>caption</em></figcaption>\n</figure>", "figures+footers+citations|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsFooters
|
||||
{
|
||||
// ## Footers
|
||||
//
|
||||
// A footer equivalent to a block quote parsing but starts with double character ^^
|
||||
[Test]
|
||||
public void ExtensionsFooters_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Footers
|
||||
//
|
||||
// The following Markdown:
|
||||
// ^^ This is a footer
|
||||
// ^^ multi-line
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <footer>This is a footer
|
||||
// multi-line</footer>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Footers\n");
|
||||
TestParser.TestSpec("^^ This is a footer\n^^ multi-line", "<footer>This is a footer\nmulti-line</footer>", "figures+footers+citations|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsCite
|
||||
{
|
||||
// ## Cite
|
||||
//
|
||||
// A cite is working like an emphasis but using the double character ""
|
||||
[Test]
|
||||
public void ExtensionsCite_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Cite
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a ""citation of someone""
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <cite>citation of someone</cite></p>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Cite\n");
|
||||
TestParser.TestSpec("This is a \"\"citation of someone\"\"", "<p>This is a <cite>citation of someone</cite></p>", "figures+footers+citations|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
193
src/Markdig.Tests/Specs/FootnotesSpecs.generated.cs
Normal file
193
src/Markdig.Tests/Specs/FootnotesSpecs.generated.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
// Generated: 2019-04-15 05:33:49
|
||||
|
||||
// --------------------------------
|
||||
// Footnotes
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Footnotes
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsFootnotes
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the different extensions supported:
|
||||
//
|
||||
// ## Footnotes
|
||||
//
|
||||
// Allows footnotes using the following syntax (taken from pandoc example):
|
||||
[Test]
|
||||
public void ExtensionsFootnotes_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Footnotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// Here is a footnote reference,[^1] and another.[^longnote]
|
||||
//
|
||||
// This is another reference to [^1]
|
||||
//
|
||||
// [^1]: Here is the footnote.
|
||||
//
|
||||
// And another reference to [^longnote]
|
||||
//
|
||||
// [^longnote]: Here's one with multiple blocks.
|
||||
//
|
||||
// Subsequent paragraphs are indented to show that they
|
||||
// belong to the previous footnote.
|
||||
//
|
||||
// > This is a block quote
|
||||
// > Inside a footnote
|
||||
//
|
||||
// { some.code }
|
||||
//
|
||||
// The whole paragraph can be indented, or just the first
|
||||
// line. In this way, multi-paragraph footnotes work like
|
||||
// multi-paragraph list items.
|
||||
//
|
||||
// This paragraph won't be part of the note, because it
|
||||
// isn't indented.
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>Here is a footnote reference,<a id="fnref:1" href="#fn:1" class="footnote-ref"><sup>1</sup></a> and another.<a id="fnref:3" href="#fn:2" class="footnote-ref"><sup>2</sup></a></p>
|
||||
// <p>This is another reference to <a id="fnref:2" href="#fn:1" class="footnote-ref"><sup>1</sup></a></p>
|
||||
// <p>And another reference to <a id="fnref:4" href="#fn:2" class="footnote-ref"><sup>2</sup></a></p>
|
||||
// <p>This paragraph won't be part of the note, because it
|
||||
// isn't indented.</p>
|
||||
// <div class="footnotes">
|
||||
// <hr />
|
||||
// <ol>
|
||||
// <li id="fn:1">
|
||||
// <p>Here is the footnote.<a href="#fnref:1" class="footnote-back-ref">↩</a><a href="#fnref:2" class="footnote-back-ref">↩</a></p>
|
||||
// </li>
|
||||
// <li id="fn:2">
|
||||
// <p>Here's one with multiple blocks.</p>
|
||||
// <p>Subsequent paragraphs are indented to show that they
|
||||
// belong to the previous footnote.</p>
|
||||
// <blockquote>
|
||||
// <p>This is a block quote
|
||||
// Inside a footnote</p>
|
||||
// </blockquote>
|
||||
// <pre><code>{ some.code }
|
||||
// </code></pre>
|
||||
// <p>The whole paragraph can be indented, or just the first
|
||||
// line. In this way, multi-paragraph footnotes work like
|
||||
// multi-paragraph list items.<a href="#fnref:3" class="footnote-back-ref">↩</a><a href="#fnref:4" class="footnote-back-ref">↩</a></p>
|
||||
// </li>
|
||||
// </ol>
|
||||
// </div>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Footnotes\n");
|
||||
TestParser.TestSpec("Here is a footnote reference,[^1] and another.[^longnote]\n\nThis is another reference to [^1]\n\n[^1]: Here is the footnote.\n\nAnd another reference to [^longnote]\n\n[^longnote]: Here's one with multiple blocks.\n\n Subsequent paragraphs are indented to show that they\nbelong to the previous footnote.\n\n > This is a block quote\n > Inside a footnote\n\n { some.code }\n\n The whole paragraph can be indented, or just the first\n line. In this way, multi-paragraph footnotes work like\n multi-paragraph list items.\n\nThis paragraph won't be part of the note, because it\nisn't indented.", "<p>Here is a footnote reference,<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a> and another.<a id=\"fnref:3\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a></p>\n<p>This is another reference to <a id=\"fnref:2\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a></p>\n<p>And another reference to <a id=\"fnref:4\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a></p>\n<p>This paragraph won't be part of the note, because it\nisn't indented.</p>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Here is the footnote.<a href=\"#fnref:1\" class=\"footnote-back-ref\">↩</a><a href=\"#fnref:2\" class=\"footnote-back-ref\">↩</a></p>\n</li>\n<li id=\"fn:2\">\n<p>Here's one with multiple blocks.</p>\n<p>Subsequent paragraphs are indented to show that they\nbelong to the previous footnote.</p>\n<blockquote>\n<p>This is a block quote\nInside a footnote</p>\n</blockquote>\n<pre><code>{ some.code }\n</code></pre>\n<p>The whole paragraph can be indented, or just the first\nline. In this way, multi-paragraph footnotes work like\nmulti-paragraph list items.<a href=\"#fnref:3\" class=\"footnote-back-ref\">↩</a><a href=\"#fnref:4\" class=\"footnote-back-ref\">↩</a></p>\n</li>\n</ol>\n</div>", "footnotes|advanced");
|
||||
}
|
||||
|
||||
// Check with multiple consecutive footnotes:
|
||||
[Test]
|
||||
public void ExtensionsFootnotes_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Footnotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4].
|
||||
//
|
||||
// [^1]: Footnote 1 text
|
||||
//
|
||||
// [^2]: Footnote 2 text
|
||||
//
|
||||
// a
|
||||
//
|
||||
// [^3]: Footnote 3 text
|
||||
//
|
||||
// [^4]: Footnote 4 text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>Here is a footnote<a id="fnref:1" href="#fn:1" class="footnote-ref"><sup>1</sup></a>. And another one<a id="fnref:2" href="#fn:2" class="footnote-ref"><sup>2</sup></a>. And a third one<a id="fnref:3" href="#fn:3" class="footnote-ref"><sup>3</sup></a>. And a fourth<a id="fnref:4" href="#fn:4" class="footnote-ref"><sup>4</sup></a>.</p>
|
||||
// <p>a</p>
|
||||
// <div class="footnotes">
|
||||
// <hr />
|
||||
// <ol>
|
||||
// <li id="fn:1">
|
||||
// <p>Footnote 1 text<a href="#fnref:1" class="footnote-back-ref">↩</a></p></li>
|
||||
// <li id="fn:2">
|
||||
// <p>Footnote 2 text<a href="#fnref:2" class="footnote-back-ref">↩</a></p></li>
|
||||
// <li id="fn:3">
|
||||
// <p>Footnote 3 text<a href="#fnref:3" class="footnote-back-ref">↩</a></p></li>
|
||||
// <li id="fn:4">
|
||||
// <p>Footnote 4 text<a href="#fnref:4" class="footnote-back-ref">↩</a></p></li>
|
||||
// </ol>
|
||||
// </div>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Footnotes\n");
|
||||
TestParser.TestSpec("Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4].\n\n[^1]: Footnote 1 text\n\n[^2]: Footnote 2 text\n\na\n\n[^3]: Footnote 3 text\n\n[^4]: Footnote 4 text", "<p>Here is a footnote<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a>. And another one<a id=\"fnref:2\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a>. And a third one<a id=\"fnref:3\" href=\"#fn:3\" class=\"footnote-ref\"><sup>3</sup></a>. And a fourth<a id=\"fnref:4\" href=\"#fn:4\" class=\"footnote-ref\"><sup>4</sup></a>.</p>\n<p>a</p>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Footnote 1 text<a href=\"#fnref:1\" class=\"footnote-back-ref\">↩</a></p></li>\n<li id=\"fn:2\">\n<p>Footnote 2 text<a href=\"#fnref:2\" class=\"footnote-back-ref\">↩</a></p></li>\n<li id=\"fn:3\">\n<p>Footnote 3 text<a href=\"#fnref:3\" class=\"footnote-back-ref\">↩</a></p></li>\n<li id=\"fn:4\">\n<p>Footnote 4 text<a href=\"#fnref:4\" class=\"footnote-back-ref\">↩</a></p></li>\n</ol>\n</div>", "footnotes|advanced");
|
||||
}
|
||||
|
||||
// Another test with consecutive footnotes without a blank line separator:
|
||||
[Test]
|
||||
public void ExtensionsFootnotes_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Footnotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4].
|
||||
//
|
||||
// [^1]: Footnote 1 text
|
||||
// [^2]: Footnote 2 text
|
||||
// [^3]: Footnote 3 text
|
||||
// [^4]: Footnote 4 text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>Here is a footnote<a id="fnref:1" href="#fn:1" class="footnote-ref"><sup>1</sup></a>. And another one<a id="fnref:2" href="#fn:2" class="footnote-ref"><sup>2</sup></a>. And a third one<a id="fnref:3" href="#fn:3" class="footnote-ref"><sup>3</sup></a>. And a fourth<a id="fnref:4" href="#fn:4" class="footnote-ref"><sup>4</sup></a>.</p>
|
||||
// <div class="footnotes">
|
||||
// <hr />
|
||||
// <ol>
|
||||
// <li id="fn:1">
|
||||
// <p>Footnote 1 text<a href="#fnref:1" class="footnote-back-ref">↩</a></p></li>
|
||||
// <li id="fn:2">
|
||||
// <p>Footnote 2 text<a href="#fnref:2" class="footnote-back-ref">↩</a></p></li>
|
||||
// <li id="fn:3">
|
||||
// <p>Footnote 3 text<a href="#fnref:3" class="footnote-back-ref">↩</a></p></li>
|
||||
// <li id="fn:4">
|
||||
// <p>Footnote 4 text<a href="#fnref:4" class="footnote-back-ref">↩</a></p></li>
|
||||
// </ol>
|
||||
// </div>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Footnotes\n");
|
||||
TestParser.TestSpec("Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4].\n\n[^1]: Footnote 1 text\n[^2]: Footnote 2 text\n[^3]: Footnote 3 text\n[^4]: Footnote 4 text", "<p>Here is a footnote<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a>. And another one<a id=\"fnref:2\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a>. And a third one<a id=\"fnref:3\" href=\"#fn:3\" class=\"footnote-ref\"><sup>3</sup></a>. And a fourth<a id=\"fnref:4\" href=\"#fn:4\" class=\"footnote-ref\"><sup>4</sup></a>.</p>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Footnote 1 text<a href=\"#fnref:1\" class=\"footnote-back-ref\">↩</a></p></li>\n<li id=\"fn:2\">\n<p>Footnote 2 text<a href=\"#fnref:2\" class=\"footnote-back-ref\">↩</a></p></li>\n<li id=\"fn:3\">\n<p>Footnote 3 text<a href=\"#fnref:3\" class=\"footnote-back-ref\">↩</a></p></li>\n<li id=\"fn:4\">\n<p>Footnote 4 text<a href=\"#fnref:4\" class=\"footnote-back-ref\">↩</a></p></li>\n</ol>\n</div>", "footnotes|advanced");
|
||||
}
|
||||
|
||||
// A footnote link inside a list should work as well:
|
||||
[Test]
|
||||
public void ExtensionsFootnotes_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Footnotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// - abc
|
||||
// - def[^1]
|
||||
//
|
||||
// [^1]: Here is the footnote.
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ul>
|
||||
// <li>abc</li>
|
||||
// <li>def<a id="fnref:1" href="#fn:1" class="footnote-ref"><sup>1</sup></a></li>
|
||||
// </ul>
|
||||
// <div class="footnotes">
|
||||
// <hr />
|
||||
// <ol>
|
||||
// <li id="fn:1">
|
||||
// <p>Here is the footnote.<a href="#fnref:1" class="footnote-back-ref">↩</a></p></li>
|
||||
// </ol>
|
||||
// </div>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Footnotes\n");
|
||||
TestParser.TestSpec("- abc\n- def[^1]\n\n[^1]: Here is the footnote.", "<ul>\n<li>abc</li>\n<li>def<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a></li>\n</ul>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Here is the footnote.<a href=\"#fnref:1\" class=\"footnote-back-ref\">↩</a></p></li>\n</ol>\n</div>", "footnotes|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This section describes the different extensions supported:
|
||||
|
||||
## Footontes
|
||||
## Footnotes
|
||||
|
||||
Allows footnotes using the following syntax (taken from pandoc example):
|
||||
|
||||
@@ -61,3 +61,81 @@ multi-paragraph list items.<a href="#fnref:3" class="footnote-back-ref">↩<
|
||||
</div>
|
||||
````````````````````````````````
|
||||
|
||||
Check with multiple consecutive footnotes:
|
||||
|
||||
```````````````````````````````` example
|
||||
Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4].
|
||||
|
||||
[^1]: Footnote 1 text
|
||||
|
||||
[^2]: Footnote 2 text
|
||||
|
||||
a
|
||||
|
||||
[^3]: Footnote 3 text
|
||||
|
||||
[^4]: Footnote 4 text
|
||||
.
|
||||
<p>Here is a footnote<a id="fnref:1" href="#fn:1" class="footnote-ref"><sup>1</sup></a>. And another one<a id="fnref:2" href="#fn:2" class="footnote-ref"><sup>2</sup></a>. And a third one<a id="fnref:3" href="#fn:3" class="footnote-ref"><sup>3</sup></a>. And a fourth<a id="fnref:4" href="#fn:4" class="footnote-ref"><sup>4</sup></a>.</p>
|
||||
<p>a</p>
|
||||
<div class="footnotes">
|
||||
<hr />
|
||||
<ol>
|
||||
<li id="fn:1">
|
||||
<p>Footnote 1 text<a href="#fnref:1" class="footnote-back-ref">↩</a></p></li>
|
||||
<li id="fn:2">
|
||||
<p>Footnote 2 text<a href="#fnref:2" class="footnote-back-ref">↩</a></p></li>
|
||||
<li id="fn:3">
|
||||
<p>Footnote 3 text<a href="#fnref:3" class="footnote-back-ref">↩</a></p></li>
|
||||
<li id="fn:4">
|
||||
<p>Footnote 4 text<a href="#fnref:4" class="footnote-back-ref">↩</a></p></li>
|
||||
</ol>
|
||||
</div>
|
||||
````````````````````````````````
|
||||
|
||||
Another test with consecutive footnotes without a blank line separator:
|
||||
|
||||
```````````````````````````````` example
|
||||
Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4].
|
||||
|
||||
[^1]: Footnote 1 text
|
||||
[^2]: Footnote 2 text
|
||||
[^3]: Footnote 3 text
|
||||
[^4]: Footnote 4 text
|
||||
.
|
||||
<p>Here is a footnote<a id="fnref:1" href="#fn:1" class="footnote-ref"><sup>1</sup></a>. And another one<a id="fnref:2" href="#fn:2" class="footnote-ref"><sup>2</sup></a>. And a third one<a id="fnref:3" href="#fn:3" class="footnote-ref"><sup>3</sup></a>. And a fourth<a id="fnref:4" href="#fn:4" class="footnote-ref"><sup>4</sup></a>.</p>
|
||||
<div class="footnotes">
|
||||
<hr />
|
||||
<ol>
|
||||
<li id="fn:1">
|
||||
<p>Footnote 1 text<a href="#fnref:1" class="footnote-back-ref">↩</a></p></li>
|
||||
<li id="fn:2">
|
||||
<p>Footnote 2 text<a href="#fnref:2" class="footnote-back-ref">↩</a></p></li>
|
||||
<li id="fn:3">
|
||||
<p>Footnote 3 text<a href="#fnref:3" class="footnote-back-ref">↩</a></p></li>
|
||||
<li id="fn:4">
|
||||
<p>Footnote 4 text<a href="#fnref:4" class="footnote-back-ref">↩</a></p></li>
|
||||
</ol>
|
||||
</div>
|
||||
````````````````````````````````
|
||||
|
||||
A footnote link inside a list should work as well:
|
||||
|
||||
```````````````````````````````` example
|
||||
- abc
|
||||
- def[^1]
|
||||
|
||||
[^1]: Here is the footnote.
|
||||
.
|
||||
<ul>
|
||||
<li>abc</li>
|
||||
<li>def<a id="fnref:1" href="#fn:1" class="footnote-ref"><sup>1</sup></a></li>
|
||||
</ul>
|
||||
<div class="footnotes">
|
||||
<hr />
|
||||
<ol>
|
||||
<li id="fn:1">
|
||||
<p>Here is the footnote.<a href="#fnref:1" class="footnote-back-ref">↩</a></p></li>
|
||||
</ol>
|
||||
</div>
|
||||
````````````````````````````````
|
||||
|
||||
106
src/Markdig.Tests/Specs/GenericAttributesSpecs.generated.cs
Normal file
106
src/Markdig.Tests/Specs/GenericAttributesSpecs.generated.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
// Generated: 2019-08-01 13:57:17
|
||||
|
||||
// --------------------------------
|
||||
// Generic Attributes
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.GenericAttributes
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsGenericAttributes
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the different extensions supported:
|
||||
//
|
||||
// ## Generic Attributes
|
||||
//
|
||||
// Attributes can be attached to:
|
||||
// - The previous inline element if the previous element is not a literal
|
||||
// - The next block if the current block is a paragraph and the attributes is the only inline present in the paragraph
|
||||
// - Or the current block
|
||||
//
|
||||
// Attributes can be of 3 kinds:
|
||||
//
|
||||
// - An id element, starting by `#` that will be used to set the `id` property of the HTML element
|
||||
// - A class element, starting by `.` that will be appended to the CSS class property of the HTML element
|
||||
// - a `name=value` or `name="value"` that will be appended as an attribute of the HTML element
|
||||
//
|
||||
// The following shows that attributes is attached to the current block or the previous inline:
|
||||
[Test]
|
||||
public void ExtensionsGenericAttributes_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Generic Attributes
|
||||
//
|
||||
// The following Markdown:
|
||||
// # This is a heading with an an attribute{#heading-link}
|
||||
//
|
||||
// # This is a heading # {#heading-link2}
|
||||
//
|
||||
// [This is a link](http://google.com){#a-link .myclass data-lang=fr data-value="This is a value"}
|
||||
//
|
||||
// This is a heading{#heading-link2}
|
||||
// -----------------
|
||||
//
|
||||
// This is a paragraph with an attached attributes {#myparagraph attached-bool-property attached-bool-property2}
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <h1 id="heading-link">This is a heading with an an attribute</h1>
|
||||
// <h1 id="heading-link2">This is a heading</h1>
|
||||
// <p><a href="http://google.com" id="a-link" class="myclass" data-lang="fr" data-value="This is a value">This is a link</a></p>
|
||||
// <h2 id="heading-link2">This is a heading</h2>
|
||||
// <p id="myparagraph" attached-bool-property="" attached-bool-property2="">This is a paragraph with an attached attributes </p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Generic Attributes\n");
|
||||
TestParser.TestSpec("# This is a heading with an an attribute{#heading-link}\n\n# This is a heading # {#heading-link2}\n\n[This is a link](http://google.com){#a-link .myclass data-lang=fr data-value=\"This is a value\"}\n\nThis is a heading{#heading-link2}\n-----------------\n\nThis is a paragraph with an attached attributes {#myparagraph attached-bool-property attached-bool-property2}", "<h1 id=\"heading-link\">This is a heading with an an attribute</h1>\n<h1 id=\"heading-link2\">This is a heading</h1>\n<p><a href=\"http://google.com\" id=\"a-link\" class=\"myclass\" data-lang=\"fr\" data-value=\"This is a value\">This is a link</a></p>\n<h2 id=\"heading-link2\">This is a heading</h2>\n<p id=\"myparagraph\" attached-bool-property=\"\" attached-bool-property2=\"\">This is a paragraph with an attached attributes </p>", "attributes|advanced");
|
||||
}
|
||||
|
||||
// The following shows that attributes can be attached to the next block if they are used inside a single line just preceding the block (and preceded by a blank line or beginning of a block container):
|
||||
[Test]
|
||||
public void ExtensionsGenericAttributes_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Generic Attributes
|
||||
//
|
||||
// The following Markdown:
|
||||
// {#fenced-id .fenced-class}
|
||||
// ~~~
|
||||
// This is a fenced with attached attributes
|
||||
// ~~~
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <pre><code id="fenced-id" class="fenced-class">This is a fenced with attached attributes
|
||||
// </code></pre>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Generic Attributes\n");
|
||||
TestParser.TestSpec("{#fenced-id .fenced-class}\n~~~\nThis is a fenced with attached attributes\n~~~ ", "<pre><code id=\"fenced-id\" class=\"fenced-class\">This is a fenced with attached attributes\n</code></pre>", "attributes|advanced");
|
||||
}
|
||||
|
||||
// Attribute values can be one character long
|
||||
[Test]
|
||||
public void ExtensionsGenericAttributes_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Generic Attributes
|
||||
//
|
||||
// The following Markdown:
|
||||
// [Foo](url){data-x=1}
|
||||
//
|
||||
// [Foo](url){data-x='1'}
|
||||
//
|
||||
// [Foo](url){data-x=11}
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="url" data-x="1">Foo</a></p>
|
||||
// <p><a href="url" data-x="1">Foo</a></p>
|
||||
// <p><a href="url" data-x="11">Foo</a></p>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Generic Attributes\n");
|
||||
TestParser.TestSpec("[Foo](url){data-x=1}\n\n[Foo](url){data-x='1'}\n\n[Foo](url){data-x=11}", "<p><a href=\"url\" data-x=\"1\">Foo</a></p>\n<p><a href=\"url\" data-x=\"1\">Foo</a></p>\n<p><a href=\"url\" data-x=\"11\">Foo</a></p>", "attributes|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,13 +27,13 @@ The following shows that attributes is attached to the current block or the prev
|
||||
This is a heading{#heading-link2}
|
||||
-----------------
|
||||
|
||||
This is a paragraph with an attached attributes {#myparagraph attached-bool-property}
|
||||
This is a paragraph with an attached attributes {#myparagraph attached-bool-property attached-bool-property2}
|
||||
.
|
||||
<h1 id="heading-link">This is a heading with an an attribute</h1>
|
||||
<h1 id="heading-link2">This is a heading</h1>
|
||||
<p><a href="http://google.com" id="a-link" class="myclass" data-lang="fr" data-value="This is a value">This is a link</a></p>
|
||||
<h2 id="heading-link2">This is a heading</h2>
|
||||
<p id="myparagraph" attached-bool-property>This is a paragraph with an attached attributes </p>
|
||||
<p id="myparagraph" attached-bool-property="" attached-bool-property2="">This is a paragraph with an attached attributes </p>
|
||||
````````````````````````````````
|
||||
|
||||
The following shows that attributes can be attached to the next block if they are used inside a single line just preceding the block (and preceded by a blank line or beginning of a block container):
|
||||
@@ -47,3 +47,17 @@ This is a fenced with attached attributes
|
||||
<pre><code id="fenced-id" class="fenced-class">This is a fenced with attached attributes
|
||||
</code></pre>
|
||||
````````````````````````````````
|
||||
|
||||
Attribute values can be one character long
|
||||
|
||||
```````````````````````````````` example
|
||||
[Foo](url){data-x=1}
|
||||
|
||||
[Foo](url){data-x='1'}
|
||||
|
||||
[Foo](url){data-x=11}
|
||||
.
|
||||
<p><a href="url" data-x="1">Foo</a></p>
|
||||
<p><a href="url" data-x="1">Foo</a></p>
|
||||
<p><a href="url" data-x="11">Foo</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
234
src/Markdig.Tests/Specs/GlobalizationSpecs.generated.cs
Normal file
234
src/Markdig.Tests/Specs/GlobalizationSpecs.generated.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
// Generated: 2019-04-15 05:25:26
|
||||
|
||||
// --------------------------------
|
||||
// Globalization
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Globalization
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsGlobalization
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the different extensions supported:
|
||||
//
|
||||
// ## Globalization
|
||||
// Adds support for RTL content by adding `dir="rtl"` and `align="right` attributes to the appropriate html elements. Left to right text is not affected by this extension.
|
||||
//
|
||||
// Whether a markdown block is marked as RTL or not is determined by the [first strong character](https://en.wikipedia.org/wiki/Bi-directional_text#Strong_characters) of the block.
|
||||
//
|
||||
// **Note**: You might need to add `<meta charset="UTF-8">` to the head of the html file to be able to see the result correctly.
|
||||
//
|
||||
// Headings and block quotes:
|
||||
[Test]
|
||||
public void ExtensionsGlobalization_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Globalization
|
||||
//
|
||||
// The following Markdown:
|
||||
// # Fruits
|
||||
// In botany, a [fruit](https://en.wikipedia.org/wiki/Fruit) is the seed-bearing structure in flowering plants (also known as angiosperms) formed from the ovary after flowering.
|
||||
//
|
||||
// > Fruits are good for health
|
||||
// -- Anonymous
|
||||
//
|
||||
// # میوە
|
||||
// [میوە](https://ckb.wikipedia.org/wiki/%D9%85%DB%8C%D9%88%DB%95) یان مێوە بەروبوومی ڕوەکیە کە ڕوەکەکان ھەڵیان ئەگرن وەک بەرگێک بۆ تۆوەکانیان، بە زۆری جیادەکرێتەوە بە شیرینی یان ترشی لە تامدا و بە بوونی بڕێکی زۆر ئاو
|
||||
//
|
||||
// > میوە بۆ تەندروستی باشە
|
||||
// -- نەزانراو
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <h1 id="fruits">Fruits</h1>
|
||||
// <p>In botany, a <a href="https://en.wikipedia.org/wiki/Fruit">fruit</a> is the seed-bearing structure in flowering plants (also known as angiosperms) formed from the ovary after flowering.</p>
|
||||
// <blockquote>
|
||||
// <p>Fruits are good for health
|
||||
// -- Anonymous</p>
|
||||
// </blockquote>
|
||||
// <h1 id="section" dir="rtl">میوە</h1>
|
||||
// <p dir="rtl"><a href="https://ckb.wikipedia.org/wiki/%D9%85%DB%8C%D9%88%DB%95" dir="rtl">میوە</a> یان مێوە بەروبوومی ڕوەکیە کە ڕوەکەکان ھەڵیان ئەگرن وەک بەرگێک بۆ تۆوەکانیان، بە زۆری جیادەکرێتەوە بە شیرینی یان ترشی لە تامدا و بە بوونی بڕێکی زۆر ئاو</p>
|
||||
// <blockquote dir="rtl">
|
||||
// <p dir="rtl">میوە بۆ تەندروستی باشە
|
||||
// -- نەزانراو</p>
|
||||
// </blockquote>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Globalization\n");
|
||||
TestParser.TestSpec("# Fruits\nIn botany, a [fruit](https://en.wikipedia.org/wiki/Fruit) is the seed-bearing structure in flowering plants (also known as angiosperms) formed from the ovary after flowering.\n\n> Fruits are good for health\n-- Anonymous\n\n# میوە\n[میوە](https://ckb.wikipedia.org/wiki/%D9%85%DB%8C%D9%88%DB%95) یان مێوە بەروبوومی ڕوەکیە کە ڕوەکەکان ھەڵیان ئەگرن وەک بەرگێک بۆ تۆوەکانیان، بە زۆری جیادەکرێتەوە بە شیرینی یان ترشی لە تامدا و بە بوونی بڕێکی زۆر ئاو\n\n> میوە بۆ تەندروستی باشە\n-- نەزانراو", "<h1 id=\"fruits\">Fruits</h1>\n<p>In botany, a <a href=\"https://en.wikipedia.org/wiki/Fruit\">fruit</a> is the seed-bearing structure in flowering plants (also known as angiosperms) formed from the ovary after flowering.</p>\n<blockquote>\n<p>Fruits are good for health\n-- Anonymous</p>\n</blockquote>\n<h1 id=\"section\" dir=\"rtl\">میوە</h1>\n<p dir=\"rtl\"><a href=\"https://ckb.wikipedia.org/wiki/%D9%85%DB%8C%D9%88%DB%95\" dir=\"rtl\">میوە</a> یان مێوە بەروبوومی ڕوەکیە کە ڕوەکەکان ھەڵیان ئەگرن وەک بەرگێک بۆ تۆوەکانیان، بە زۆری جیادەکرێتەوە بە شیرینی یان ترشی لە تامدا و بە بوونی بڕێکی زۆر ئاو</p>\n<blockquote dir=\"rtl\">\n<p dir=\"rtl\">میوە بۆ تەندروستی باشە\n-- نەزانراو</p>\n</blockquote>", "globalization+advanced+emojis");
|
||||
}
|
||||
|
||||
// Lists:
|
||||
[Test]
|
||||
public void ExtensionsGlobalization_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Globalization
|
||||
//
|
||||
// The following Markdown:
|
||||
// ## Types of fruits
|
||||
// - Berries
|
||||
// - Strawberry
|
||||
// - kiwifruit
|
||||
// - Citrus
|
||||
// - Orange
|
||||
// - Lemon
|
||||
//
|
||||
// ## Examples of fruits :yum:
|
||||
// 1. Apple
|
||||
// 2. Banana
|
||||
// 3. Orange
|
||||
//
|
||||
// ## Grocery List
|
||||
// - [X] Watermelon
|
||||
// - [X] Apricot
|
||||
// - [ ] Fig
|
||||
//
|
||||
// ## نموونەی میوە :yum:
|
||||
// 1. ? سێو
|
||||
// 2. 5 مۆز
|
||||
// 3. پرتەقاڵ
|
||||
//
|
||||
// ## جۆرەکانی میوە
|
||||
// - توو
|
||||
// - فڕاولە
|
||||
// - کیوی
|
||||
// - مزرەمەنی
|
||||
// - پڕتەقاڵ
|
||||
// - لیمۆ
|
||||
//
|
||||
// ## لیستی کڕین
|
||||
// - [X] شووتی
|
||||
// - [X] قەیسی
|
||||
// - [ ] هەنجیر
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <h2 id="types-of-fruits">Types of fruits</h2>
|
||||
// <ul>
|
||||
// <li>Berries
|
||||
// <ul>
|
||||
// <li>Strawberry</li>
|
||||
// <li>kiwifruit</li>
|
||||
// </ul>
|
||||
// </li>
|
||||
// <li>Citrus
|
||||
// <ul>
|
||||
// <li>Orange</li>
|
||||
// <li>Lemon</li>
|
||||
// </ul>
|
||||
// </li>
|
||||
// </ul>
|
||||
// <h2 id="examples-of-fruits">Examples of fruits 😋</h2>
|
||||
// <ol>
|
||||
// <li>Apple</li>
|
||||
// <li>Banana</li>
|
||||
// <li>Orange</li>
|
||||
// </ol>
|
||||
// <h2 id="grocery-list">Grocery List</h2>
|
||||
// <ul class="contains-task-list">
|
||||
// <li class="task-list-item"><input disabled="disabled" type="checkbox" checked="checked" /> Watermelon</li>
|
||||
// <li class="task-list-item"><input disabled="disabled" type="checkbox" checked="checked" /> Apricot</li>
|
||||
// <li class="task-list-item"><input disabled="disabled" type="checkbox" /> Fig</li>
|
||||
// </ul>
|
||||
// <h2 id="section" dir="rtl">نموونەی میوە 😋</h2>
|
||||
// <ol dir="rtl">
|
||||
// <li>? سێو</li>
|
||||
// <li>5 مۆز</li>
|
||||
// <li> پرتەقاڵ</li>
|
||||
// </ol>
|
||||
// <h2 id="section-1" dir="rtl">جۆرەکانی میوە</h2>
|
||||
// <ul dir="rtl">
|
||||
// <li>توو
|
||||
// <ul dir="rtl">
|
||||
// <li>فڕاولە</li>
|
||||
// <li>کیوی</li>
|
||||
// </ul>
|
||||
// </li>
|
||||
// <li>مزرەمەنی
|
||||
// <ul dir="rtl">
|
||||
// <li>پڕتەقاڵ</li>
|
||||
// <li>لیمۆ</li>
|
||||
// </ul>
|
||||
// </li>
|
||||
// </ul>
|
||||
// <h2 id="section-2" dir="rtl">لیستی کڕین</h2>
|
||||
// <ul class="contains-task-list" dir="rtl">
|
||||
// <li class="task-list-item"><input disabled="disabled" type="checkbox" checked="checked" /> شووتی</li>
|
||||
// <li class="task-list-item"><input disabled="disabled" type="checkbox" checked="checked" /> قەیسی</li>
|
||||
// <li class="task-list-item"><input disabled="disabled" type="checkbox" /> هەنجیر</li>
|
||||
// </ul>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Globalization\n");
|
||||
TestParser.TestSpec("## Types of fruits\n- Berries\n - Strawberry\n - kiwifruit\n- Citrus\n - Orange\n - Lemon\n\n## Examples of fruits :yum:\n1. Apple\n2. Banana\n3. Orange\n\n## Grocery List\n- [X] Watermelon\n- [X] Apricot\n- [ ] Fig \n\n## نموونەی میوە :yum:\n1. ? سێو\n2. 5 مۆز \n3. پرتەقاڵ\n\n## جۆرەکانی میوە\n- توو\n - فڕاولە\n - کیوی\n- مزرەمەنی\n - پڕتەقاڵ\n - لیمۆ\n\n## لیستی کڕین\n- [X] شووتی\n- [X] قەیسی\n- [ ] هەنجیر", "<h2 id=\"types-of-fruits\">Types of fruits</h2>\n<ul>\n<li>Berries\n<ul>\n<li>Strawberry</li>\n<li>kiwifruit</li>\n</ul>\n</li>\n<li>Citrus\n<ul>\n<li>Orange</li>\n<li>Lemon</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"examples-of-fruits\">Examples of fruits 😋</h2>\n<ol>\n<li>Apple</li>\n<li>Banana</li>\n<li>Orange</li>\n</ol>\n<h2 id=\"grocery-list\">Grocery List</h2>\n<ul class=\"contains-task-list\">\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> Watermelon</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> Apricot</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" /> Fig</li>\n</ul>\n<h2 id=\"section\" dir=\"rtl\">نموونەی میوە 😋</h2>\n<ol dir=\"rtl\">\n<li>? سێو</li>\n<li>5 مۆز</li>\n<li> پرتەقاڵ</li>\n</ol>\n<h2 id=\"section-1\" dir=\"rtl\">جۆرەکانی میوە</h2>\n<ul dir=\"rtl\">\n<li>توو\n<ul dir=\"rtl\">\n<li>فڕاولە</li>\n<li>کیوی</li>\n</ul>\n</li>\n<li>مزرەمەنی\n<ul dir=\"rtl\">\n<li>پڕتەقاڵ</li>\n<li>لیمۆ</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"section-2\" dir=\"rtl\">لیستی کڕین</h2>\n<ul class=\"contains-task-list\" dir=\"rtl\">\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> شووتی</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> قەیسی</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" /> هەنجیر</li>\n</ul>", "globalization+advanced+emojis");
|
||||
}
|
||||
|
||||
// Tables:
|
||||
[Test]
|
||||
public void ExtensionsGlobalization_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Globalization
|
||||
//
|
||||
// The following Markdown:
|
||||
// Nutrition |Apple | Oranges
|
||||
// --|-- | --
|
||||
// Calories|52|47
|
||||
// Sugar|10g|9g
|
||||
//
|
||||
// پێکهاتە |سێو | پڕتەقاڵ
|
||||
// --|-- | --
|
||||
// کالۆری|٥٢|٤٧
|
||||
// شەکر| ١٠گ|٩گ
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>Nutrition</th>
|
||||
// <th>Apple</th>
|
||||
// <th>Oranges</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>Calories</td>
|
||||
// <td>52</td>
|
||||
// <td>47</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>Sugar</td>
|
||||
// <td>10g</td>
|
||||
// <td>9g</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
// <table dir="rtl" align="right">
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>پێکهاتە</th>
|
||||
// <th>سێو</th>
|
||||
// <th>پڕتەقاڵ</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>کالۆری</td>
|
||||
// <td>٥٢</td>
|
||||
// <td>٤٧</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>شەکر</td>
|
||||
// <td>١٠گ</td>
|
||||
// <td>٩گ</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Globalization\n");
|
||||
TestParser.TestSpec("Nutrition |Apple | Oranges\n--|-- | --\nCalories|52|47\nSugar|10g|9g\n\n پێکهاتە |سێو | پڕتەقاڵ\n--|-- | --\nکالۆری|٥٢|٤٧\nشەکر| ١٠گ|٩گ", "<table>\n<thead>\n<tr>\n<th>Nutrition</th>\n<th>Apple</th>\n<th>Oranges</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Calories</td>\n<td>52</td>\n<td>47</td>\n</tr>\n<tr>\n<td>Sugar</td>\n<td>10g</td>\n<td>9g</td>\n</tr>\n</tbody>\n</table>\n<table dir=\"rtl\" align=\"right\">\n<thead>\n<tr>\n<th>پێکهاتە</th>\n<th>سێو</th>\n<th>پڕتەقاڵ</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>کالۆری</td>\n<td>٥٢</td>\n<td>٤٧</td>\n</tr>\n<tr>\n<td>شەکر</td>\n<td>١٠گ</td>\n<td>٩گ</td>\n</tr>\n</tbody>\n</table>", "globalization+advanced+emojis");
|
||||
}
|
||||
}
|
||||
}
|
||||
189
src/Markdig.Tests/Specs/GlobalizationSpecs.md
Normal file
189
src/Markdig.Tests/Specs/GlobalizationSpecs.md
Normal file
@@ -0,0 +1,189 @@
|
||||
# Extensions
|
||||
|
||||
This section describes the different extensions supported:
|
||||
|
||||
## Globalization
|
||||
Adds support for RTL content by adding `dir="rtl"` and `align="right` attributes to the appropriate html elements. Left to right text is not affected by this extension.
|
||||
|
||||
Whether a markdown block is marked as RTL or not is determined by the [first strong character](https://en.wikipedia.org/wiki/Bi-directional_text#Strong_characters) of the block.
|
||||
|
||||
**Note**: You might need to add `<meta charset="UTF-8">` to the head of the html file to be able to see the result correctly.
|
||||
|
||||
Headings and block quotes:
|
||||
```````````````````````````````` example
|
||||
# Fruits
|
||||
In botany, a [fruit](https://en.wikipedia.org/wiki/Fruit) is the seed-bearing structure in flowering plants (also known as angiosperms) formed from the ovary after flowering.
|
||||
|
||||
> Fruits are good for health
|
||||
-- Anonymous
|
||||
|
||||
# میوە
|
||||
[میوە](https://ckb.wikipedia.org/wiki/%D9%85%DB%8C%D9%88%DB%95) یان مێوە بەروبوومی ڕوەکیە کە ڕوەکەکان ھەڵیان ئەگرن وەک بەرگێک بۆ تۆوەکانیان، بە زۆری جیادەکرێتەوە بە شیرینی یان ترشی لە تامدا و بە بوونی بڕێکی زۆر ئاو
|
||||
|
||||
> میوە بۆ تەندروستی باشە
|
||||
-- نەزانراو
|
||||
.
|
||||
<h1 id="fruits">Fruits</h1>
|
||||
<p>In botany, a <a href="https://en.wikipedia.org/wiki/Fruit">fruit</a> is the seed-bearing structure in flowering plants (also known as angiosperms) formed from the ovary after flowering.</p>
|
||||
<blockquote>
|
||||
<p>Fruits are good for health
|
||||
-- Anonymous</p>
|
||||
</blockquote>
|
||||
<h1 id="section" dir="rtl">میوە</h1>
|
||||
<p dir="rtl"><a href="https://ckb.wikipedia.org/wiki/%D9%85%DB%8C%D9%88%DB%95" dir="rtl">میوە</a> یان مێوە بەروبوومی ڕوەکیە کە ڕوەکەکان ھەڵیان ئەگرن وەک بەرگێک بۆ تۆوەکانیان، بە زۆری جیادەکرێتەوە بە شیرینی یان ترشی لە تامدا و بە بوونی بڕێکی زۆر ئاو</p>
|
||||
<blockquote dir="rtl">
|
||||
<p dir="rtl">میوە بۆ تەندروستی باشە
|
||||
-- نەزانراو</p>
|
||||
</blockquote>
|
||||
````````````````````````````````
|
||||
|
||||
Lists:
|
||||
```````````````````````````````` example
|
||||
## Types of fruits
|
||||
- Berries
|
||||
- Strawberry
|
||||
- kiwifruit
|
||||
- Citrus
|
||||
- Orange
|
||||
- Lemon
|
||||
|
||||
## Examples of fruits :yum:
|
||||
1. Apple
|
||||
2. Banana
|
||||
3. Orange
|
||||
|
||||
## Grocery List
|
||||
- [X] Watermelon
|
||||
- [X] Apricot
|
||||
- [ ] Fig
|
||||
|
||||
## نموونەی میوە :yum:
|
||||
1. ? سێو
|
||||
2. 5 مۆز
|
||||
3. پرتەقاڵ
|
||||
|
||||
## جۆرەکانی میوە
|
||||
- توو
|
||||
- فڕاولە
|
||||
- کیوی
|
||||
- مزرەمەنی
|
||||
- پڕتەقاڵ
|
||||
- لیمۆ
|
||||
|
||||
## لیستی کڕین
|
||||
- [X] شووتی
|
||||
- [X] قەیسی
|
||||
- [ ] هەنجیر
|
||||
.
|
||||
<h2 id="types-of-fruits">Types of fruits</h2>
|
||||
<ul>
|
||||
<li>Berries
|
||||
<ul>
|
||||
<li>Strawberry</li>
|
||||
<li>kiwifruit</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Citrus
|
||||
<ul>
|
||||
<li>Orange</li>
|
||||
<li>Lemon</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="examples-of-fruits">Examples of fruits 😋</h2>
|
||||
<ol>
|
||||
<li>Apple</li>
|
||||
<li>Banana</li>
|
||||
<li>Orange</li>
|
||||
</ol>
|
||||
<h2 id="grocery-list">Grocery List</h2>
|
||||
<ul class="contains-task-list">
|
||||
<li class="task-list-item"><input disabled="disabled" type="checkbox" checked="checked" /> Watermelon</li>
|
||||
<li class="task-list-item"><input disabled="disabled" type="checkbox" checked="checked" /> Apricot</li>
|
||||
<li class="task-list-item"><input disabled="disabled" type="checkbox" /> Fig</li>
|
||||
</ul>
|
||||
<h2 id="section" dir="rtl">نموونەی میوە 😋</h2>
|
||||
<ol dir="rtl">
|
||||
<li>? سێو</li>
|
||||
<li>5 مۆز</li>
|
||||
<li> پرتەقاڵ</li>
|
||||
</ol>
|
||||
<h2 id="section-1" dir="rtl">جۆرەکانی میوە</h2>
|
||||
<ul dir="rtl">
|
||||
<li>توو
|
||||
<ul dir="rtl">
|
||||
<li>فڕاولە</li>
|
||||
<li>کیوی</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>مزرەمەنی
|
||||
<ul dir="rtl">
|
||||
<li>پڕتەقاڵ</li>
|
||||
<li>لیمۆ</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="section-2" dir="rtl">لیستی کڕین</h2>
|
||||
<ul class="contains-task-list" dir="rtl">
|
||||
<li class="task-list-item"><input disabled="disabled" type="checkbox" checked="checked" /> شووتی</li>
|
||||
<li class="task-list-item"><input disabled="disabled" type="checkbox" checked="checked" /> قەیسی</li>
|
||||
<li class="task-list-item"><input disabled="disabled" type="checkbox" /> هەنجیر</li>
|
||||
</ul>
|
||||
````````````````````````````````
|
||||
|
||||
Tables:
|
||||
|
||||
```````````````````````````````` example
|
||||
Nutrition |Apple | Oranges
|
||||
--|-- | --
|
||||
Calories|52|47
|
||||
Sugar|10g|9g
|
||||
|
||||
پێکهاتە |سێو | پڕتەقاڵ
|
||||
--|-- | --
|
||||
کالۆری|٥٢|٤٧
|
||||
شەکر| ١٠گ|٩گ
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nutrition</th>
|
||||
<th>Apple</th>
|
||||
<th>Oranges</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Calories</td>
|
||||
<td>52</td>
|
||||
<td>47</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sugar</td>
|
||||
<td>10g</td>
|
||||
<td>9g</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table dir="rtl" align="right">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>پێکهاتە</th>
|
||||
<th>سێو</th>
|
||||
<th>پڕتەقاڵ</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>کالۆری</td>
|
||||
<td>٥٢</td>
|
||||
<td>٤٧</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>شەکر</td>
|
||||
<td>١٠گ</td>
|
||||
<td>٩گ</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
399
src/Markdig.Tests/Specs/GridTableSpecs.generated.cs
Normal file
399
src/Markdig.Tests/Specs/GridTableSpecs.generated.cs
Normal file
@@ -0,0 +1,399 @@
|
||||
// Generated: 2020-04-20 07:21:20
|
||||
|
||||
// --------------------------------
|
||||
// Grid Tables
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.GridTables
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsGridTable
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the different extensions supported:
|
||||
//
|
||||
// ## Grid Table
|
||||
//
|
||||
// A grid table allows to have multiple lines per cells and allows to span cells over multiple columns. The following shows a simple grid table
|
||||
//
|
||||
// ```
|
||||
// +---------+---------+
|
||||
// | Header | Header |
|
||||
// | Column1 | Column2 |
|
||||
// +=========+=========+
|
||||
// | 1. ab | > This is a quote
|
||||
// | 2. cde | > For the second column
|
||||
// | 3. f |
|
||||
// +---------+---------+
|
||||
// | Second row spanning
|
||||
// | on two columns
|
||||
// +---------+---------+
|
||||
// | Back | |
|
||||
// | to | |
|
||||
// | one | |
|
||||
// | column | |
|
||||
// ```
|
||||
//
|
||||
// **Rule #1**
|
||||
// The first line of a grid table must a **row separator**. It must start with the column separator character `+` used to separate columns in a row separator. Each column separator is:
|
||||
// - starting by optional spaces
|
||||
// - followed by an optional `:` to specify left align, followed by optional spaces
|
||||
// - followed by a sequence of at least one `-` character, followed by optional spaces
|
||||
// - followed by an optional `:` to specify right align (or center align if left align is also defined)
|
||||
// - ending by optional spaces
|
||||
//
|
||||
// The first row separator must be followed by a *regular row*. A regular row must start with the character `|` that is starting at the same position than the column separator `+` of the first row separator.
|
||||
//
|
||||
//
|
||||
// The following is a valid row separator
|
||||
[Test]
|
||||
public void ExtensionsGridTable_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Grid Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// +---------+---------+
|
||||
// | This is | a table |
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <col style="width:50%" />
|
||||
// <col style="width:50%" />
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>This is</td>
|
||||
// <td>a table</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Grid Table\n");
|
||||
TestParser.TestSpec("+---------+---------+\n| This is | a table |", "<table>\n<col style=\"width:50%\" />\n<col style=\"width:50%\" />\n<tbody>\n<tr>\n<td>This is</td>\n<td>a table</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
|
||||
}
|
||||
|
||||
// The following is not a valid row separator
|
||||
[Test]
|
||||
public void ExtensionsGridTable_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Grid Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// |-----xxx----+---------+
|
||||
// | This is | not a table
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>|-----xxx----+---------+
|
||||
// | This is | not a table</p>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Grid Table\n");
|
||||
TestParser.TestSpec("|-----xxx----+---------+\n| This is | not a table", "<p>|-----xxx----+---------+\n| This is | not a table</p>", "gridtables|advanced");
|
||||
}
|
||||
|
||||
// **Rule #2**
|
||||
// A regular row can continue a previous regular row when column separator `|` are positioned at the same position than the previous line. If they are positioned at the same location, the column may span over multiple columns:
|
||||
[Test]
|
||||
public void ExtensionsGridTable_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Grid Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// +---------+---------+---------+
|
||||
// | Col1 | Col2 | Col3 |
|
||||
// | Col1a | Col2a | Col3a |
|
||||
// | Col1b | Col3b |
|
||||
// | Col1c |
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <col style="width:33.33%" />
|
||||
// <col style="width:33.33%" />
|
||||
// <col style="width:33.33%" />
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>Col1
|
||||
// Col1a</td>
|
||||
// <td>Col2
|
||||
// Col2a</td>
|
||||
// <td>Col3
|
||||
// Col3a</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td colspan="2">Col1b</td>
|
||||
// <td>Col3b</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td colspan="3">Col1c</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Grid Table\n");
|
||||
TestParser.TestSpec("+---------+---------+---------+\n| Col1 | Col2 | Col3 |\n| Col1a | Col2a | Col3a |\n| Col1b | Col3b |\n| Col1c |", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td>Col1\nCol1a</td>\n<td>Col2\nCol2a</td>\n<td>Col3\nCol3a</td>\n</tr>\n<tr>\n<td colspan=\"2\">Col1b</td>\n<td>Col3b</td>\n</tr>\n<tr>\n<td colspan=\"3\">Col1c</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
|
||||
}
|
||||
|
||||
// A row header is separated using `+========+` instead of `+---------+`:
|
||||
[Test]
|
||||
public void ExtensionsGridTable_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Grid Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// +---------+---------+
|
||||
// | This is | a table |
|
||||
// +=========+=========+
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <col style="width:50%" />
|
||||
// <col style="width:50%" />
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>This is</th>
|
||||
// <th>a table</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Grid Table\n");
|
||||
TestParser.TestSpec("+---------+---------+\n| This is | a table |\n+=========+=========+", "<table>\n<col style=\"width:50%\" />\n<col style=\"width:50%\" />\n<thead>\n<tr>\n<th>This is</th>\n<th>a table</th>\n</tr>\n</thead>\n</table>", "gridtables|advanced");
|
||||
}
|
||||
|
||||
// The last column separator `|` may be omitted:
|
||||
[Test]
|
||||
public void ExtensionsGridTable_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / Grid Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// +---------+---------+
|
||||
// | This is | a table with a longer text in the second column
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <col style="width:50%" />
|
||||
// <col style="width:50%" />
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>This is</td>
|
||||
// <td>a table with a longer text in the second column</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / Grid Table\n");
|
||||
TestParser.TestSpec("+---------+---------+\n| This is | a table with a longer text in the second column", "<table>\n<col style=\"width:50%\" />\n<col style=\"width:50%\" />\n<tbody>\n<tr>\n<td>This is</td>\n<td>a table with a longer text in the second column</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
|
||||
}
|
||||
|
||||
// The respective width of the columns are calculated from the ratio between the total size of the first table row without counting the `+`: `+----+--------+----+` would be divided between:
|
||||
//
|
||||
// Total size is : 16
|
||||
//
|
||||
// - `----` -> 4
|
||||
// - `--------` -> 8
|
||||
// - `----` -> 4
|
||||
//
|
||||
// So the width would be 4/16 = 25%, 8/16 = 50%, 4/16 = 25%
|
||||
[Test]
|
||||
public void ExtensionsGridTable_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / Grid Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// +----+--------+----+
|
||||
// | A | B C D | E |
|
||||
// +----+--------+----+
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <col style="width:25%" />
|
||||
// <col style="width:50%" />
|
||||
// <col style="width:25%" />
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>A</td>
|
||||
// <td>B C D</td>
|
||||
// <td>E</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / Grid Table\n");
|
||||
TestParser.TestSpec("+----+--------+----+\n| A | B C D | E |\n+----+--------+----+", "<table>\n<col style=\"width:25%\" />\n<col style=\"width:50%\" />\n<col style=\"width:25%\" />\n<tbody>\n<tr>\n<td>A</td>\n<td>B C D</td>\n<td>E</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
|
||||
}
|
||||
|
||||
// Alignment might be specified on the first row using the character `:`:
|
||||
[Test]
|
||||
public void ExtensionsGridTable_Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Extensions / Grid Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// +-----+:---:+-----+
|
||||
// | A | B | C |
|
||||
// +-----+-----+-----+
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <col style="width:33.33%" />
|
||||
// <col style="width:33.33%" />
|
||||
// <col style="width:33.33%" />
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>A</td>
|
||||
// <td style="text-align: center;">B</td>
|
||||
// <td>C</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 7\nSection Extensions / Grid Table\n");
|
||||
TestParser.TestSpec("+-----+:---:+-----+\n| A | B | C |\n+-----+-----+-----+", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td>A</td>\n<td style=\"text-align: center;\">B</td>\n<td>C</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
|
||||
}
|
||||
|
||||
// A grid table may have cells spanning both columns and rows:
|
||||
[Test]
|
||||
public void ExtensionsGridTable_Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Extensions / Grid Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// +---+---+---+
|
||||
// | AAAAA | B |
|
||||
// +---+---+ B +
|
||||
// | D | E | B |
|
||||
// + D +---+---+
|
||||
// | D | CCCCC |
|
||||
// +---+---+---+
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <col style="width:33.33%" />
|
||||
// <col style="width:33.33%" />
|
||||
// <col style="width:33.33%" />
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td colspan="2">AAAAA</td>
|
||||
// <td rowspan="2">B
|
||||
// B
|
||||
// B</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td rowspan="2">D
|
||||
// D
|
||||
// D</td>
|
||||
// <td>E</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td colspan="2">CCCCC</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 8\nSection Extensions / Grid Table\n");
|
||||
TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+---+---+ B +\n| D | E | B |\n+ D +---+---+\n| D | CCCCC |\n+---+---+---+", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td colspan=\"2\">AAAAA</td>\n<td rowspan=\"2\">B\nB\nB</td>\n</tr>\n<tr>\n<td rowspan=\"2\">D\nD\nD</td>\n<td>E</td>\n</tr>\n<tr>\n<td colspan=\"2\">CCCCC</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
|
||||
}
|
||||
|
||||
// A grid table may have cells with both colspan and rowspan:
|
||||
[Test]
|
||||
public void ExtensionsGridTable_Example009()
|
||||
{
|
||||
// Example 9
|
||||
// Section: Extensions / Grid Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// +---+---+---+
|
||||
// | AAAAA | B |
|
||||
// + AAAAA +---+
|
||||
// | AAAAA | C |
|
||||
// +---+---+---+
|
||||
// | D | E | F |
|
||||
// +---+---+---+
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <col style="width:33.33%" />
|
||||
// <col style="width:33.33%" />
|
||||
// <col style="width:33.33%" />
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td colspan="2" rowspan="2">AAAAA
|
||||
// AAAAA
|
||||
// AAAAA</td>
|
||||
// <td>B</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>C</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>D</td>
|
||||
// <td>E</td>
|
||||
// <td>F</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 9\nSection Extensions / Grid Table\n");
|
||||
TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+ AAAAA +---+\n| AAAAA | C |\n+---+---+---+\n| D | E | F |\n+---+---+---+", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td colspan=\"2\" rowspan=\"2\">AAAAA\nAAAAA\nAAAAA</td>\n<td>B</td>\n</tr>\n<tr>\n<td>C</td>\n</tr>\n<tr>\n<td>D</td>\n<td>E</td>\n<td>F</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
|
||||
}
|
||||
|
||||
// A grid table may not have irregularly shaped cells:
|
||||
[Test]
|
||||
public void ExtensionsGridTable_Example010()
|
||||
{
|
||||
// Example 10
|
||||
// Section: Extensions / Grid Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// +---+---+---+
|
||||
// | AAAAA | B |
|
||||
// + A +---+ B +
|
||||
// | A | C | B |
|
||||
// +---+---+---+
|
||||
// | DDDDD | E |
|
||||
// +---+---+---+
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>+---+---+---+
|
||||
// | AAAAA | B |
|
||||
// + A +---+ B +
|
||||
// | A | C | B |
|
||||
// +---+---+---+
|
||||
// | DDDDD | E |
|
||||
// +---+---+---+</p>
|
||||
|
||||
Console.WriteLine("Example 10\nSection Extensions / Grid Table\n");
|
||||
TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+ A +---+ B +\n| A | C | B |\n+---+---+---+\n| DDDDD | E |\n+---+---+---+", "<p>+---+---+---+\n| AAAAA | B |\n+ A +---+ B +\n| A | C | B |\n+---+---+---+\n| DDDDD | E |\n+---+---+---+</p>", "gridtables|advanced");
|
||||
}
|
||||
|
||||
// An empty `+` on a line should result in a simple empty list output:
|
||||
[Test]
|
||||
public void ExtensionsGridTable_Example011()
|
||||
{
|
||||
// Example 11
|
||||
// Section: Extensions / Grid Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// +
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ul>
|
||||
// <li></li>
|
||||
// </ul>
|
||||
|
||||
Console.WriteLine("Example 11\nSection Extensions / Grid Table\n");
|
||||
TestParser.TestSpec("+", "<ul>\n<li></li>\n</ul>", "gridtables|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,8 @@ The following is a valid row separator
|
||||
| This is | a table |
|
||||
.
|
||||
<table>
|
||||
<col style="width:50%">
|
||||
<col style="width:50%">
|
||||
<col style="width:50%" />
|
||||
<col style="width:50%" />
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>This is</td>
|
||||
@@ -70,13 +70,13 @@ A regular row can continue a previous regular row when column separator `|` are
|
||||
+---------+---------+---------+
|
||||
| Col1 | Col2 | Col3 |
|
||||
| Col1a | Col2a | Col3a |
|
||||
| Col12 | Col3b |
|
||||
| Col123 |
|
||||
| Col1b | Col3b |
|
||||
| Col1c |
|
||||
.
|
||||
<table>
|
||||
<col style="width:33.33%">
|
||||
<col style="width:33.33%">
|
||||
<col style="width:33.33%">
|
||||
<col style="width:33.33%" />
|
||||
<col style="width:33.33%" />
|
||||
<col style="width:33.33%" />
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Col1
|
||||
@@ -87,11 +87,11 @@ Col2a</td>
|
||||
Col3a</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">Col12</td>
|
||||
<td></td>
|
||||
<td colspan="2">Col1b</td>
|
||||
<td>Col3b</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">Col123</td>
|
||||
<td colspan="3">Col1c</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -105,8 +105,8 @@ A row header is separated using `+========+` instead of `+---------+`:
|
||||
+=========+=========+
|
||||
.
|
||||
<table>
|
||||
<col style="width:50%">
|
||||
<col style="width:50%">
|
||||
<col style="width:50%" />
|
||||
<col style="width:50%" />
|
||||
<thead>
|
||||
<tr>
|
||||
<th>This is</th>
|
||||
@@ -123,8 +123,8 @@ The last column separator `|` may be omitted:
|
||||
| This is | a table with a longer text in the second column
|
||||
.
|
||||
<table>
|
||||
<col style="width:50%">
|
||||
<col style="width:50%">
|
||||
<col style="width:50%" />
|
||||
<col style="width:50%" />
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>This is</td>
|
||||
@@ -150,9 +150,9 @@ So the width would be 4/16 = 25%, 8/16 = 50%, 4/16 = 25%
|
||||
+----+--------+----+
|
||||
.
|
||||
<table>
|
||||
<col style="width:25%">
|
||||
<col style="width:50%">
|
||||
<col style="width:25%">
|
||||
<col style="width:25%" />
|
||||
<col style="width:50%" />
|
||||
<col style="width:25%" />
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>A</td>
|
||||
@@ -172,9 +172,9 @@ Alignment might be specified on the first row using the character `:`:
|
||||
+-----+-----+-----+
|
||||
.
|
||||
<table>
|
||||
<col style="width:33.33%">
|
||||
<col style="width:33.33%">
|
||||
<col style="width:33.33%">
|
||||
<col style="width:33.33%" />
|
||||
<col style="width:33.33%" />
|
||||
<col style="width:33.33%" />
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>A</td>
|
||||
@@ -184,3 +184,103 @@ Alignment might be specified on the first row using the character `:`:
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
A grid table may have cells spanning both columns and rows:
|
||||
|
||||
```````````````````````````````` example
|
||||
+---+---+---+
|
||||
| AAAAA | B |
|
||||
+---+---+ B +
|
||||
| D | E | B |
|
||||
+ D +---+---+
|
||||
| D | CCCCC |
|
||||
+---+---+---+
|
||||
.
|
||||
<table>
|
||||
<col style="width:33.33%" />
|
||||
<col style="width:33.33%" />
|
||||
<col style="width:33.33%" />
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="2">AAAAA</td>
|
||||
<td rowspan="2">B
|
||||
B
|
||||
B</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="2">D
|
||||
D
|
||||
D</td>
|
||||
<td>E</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">CCCCC</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
A grid table may have cells with both colspan and rowspan:
|
||||
|
||||
```````````````````````````````` example
|
||||
+---+---+---+
|
||||
| AAAAA | B |
|
||||
+ AAAAA +---+
|
||||
| AAAAA | C |
|
||||
+---+---+---+
|
||||
| D | E | F |
|
||||
+---+---+---+
|
||||
.
|
||||
<table>
|
||||
<col style="width:33.33%" />
|
||||
<col style="width:33.33%" />
|
||||
<col style="width:33.33%" />
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="2" rowspan="2">AAAAA
|
||||
AAAAA
|
||||
AAAAA</td>
|
||||
<td>B</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>C</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>D</td>
|
||||
<td>E</td>
|
||||
<td>F</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
A grid table may not have irregularly shaped cells:
|
||||
|
||||
```````````````````````````````` example
|
||||
+---+---+---+
|
||||
| AAAAA | B |
|
||||
+ A +---+ B +
|
||||
| A | C | B |
|
||||
+---+---+---+
|
||||
| DDDDD | E |
|
||||
+---+---+---+
|
||||
.
|
||||
<p>+---+---+---+
|
||||
| AAAAA | B |
|
||||
+ A +---+ B +
|
||||
| A | C | B |
|
||||
+---+---+---+
|
||||
| DDDDD | E |
|
||||
+---+---+---+</p>
|
||||
````````````````````````````````
|
||||
|
||||
An empty `+` on a line should result in a simple empty list output:
|
||||
|
||||
|
||||
```````````````````````````````` example
|
||||
+
|
||||
.
|
||||
<ul>
|
||||
<li></li>
|
||||
</ul>
|
||||
````````````````````````````````
|
||||
|
||||
40
src/Markdig.Tests/Specs/HardlineBreakSpecs.generated.cs
Normal file
40
src/Markdig.Tests/Specs/HardlineBreakSpecs.generated.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Hardline Breaks
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.HardlineBreaks
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsHardlineBreak
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the different extensions supported:
|
||||
//
|
||||
// ## Hardline break
|
||||
//
|
||||
// When this extension is used, a new line in a paragraph block will result in a hardline break `<br>`:
|
||||
[Test]
|
||||
public void ExtensionsHardlineBreak_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Hardline break
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a paragraph
|
||||
// with a break inside
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a paragraph<br />
|
||||
// with a break inside</p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Hardline break\n");
|
||||
TestParser.TestSpec("This is a paragraph\nwith a break inside", "<p>This is a paragraph<br />\nwith a break inside</p>", "hardlinebreak|advanced+hardlinebreak");
|
||||
}
|
||||
}
|
||||
}
|
||||
180
src/Markdig.Tests/Specs/JiraLinks.generated.cs
Normal file
180
src/Markdig.Tests/Specs/JiraLinks.generated.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
// Generated: 2019-04-15 05:30:00
|
||||
|
||||
// --------------------------------
|
||||
// Jira Links
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.JiraLinks
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestJiraLinks
|
||||
{
|
||||
// ## Jira Links
|
||||
//
|
||||
// The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g.
|
||||
//
|
||||
// ```
|
||||
// var pipeline = new MarkdownPipelineBuilder()
|
||||
// .UseJiraLinks(new JiraLinkOptions("http://your.company.abc"))
|
||||
// .Build();
|
||||
// ```
|
||||
//
|
||||
// The rules for detecting a link are:
|
||||
//
|
||||
// - The project key must be composed of one or more capitalized ASCII letter `[A-Z]+`
|
||||
// - A single hyphen `-` must separate the project key and issue number.
|
||||
// - The issue number is composed of 1 or more digits `[0, 9]+`
|
||||
// - The reference must be preceded by either `(` or whitespace or EOF.
|
||||
// - The reference must be followed by either `)` or whitespace or EOF.
|
||||
//
|
||||
// The following are valid examples:
|
||||
[Test]
|
||||
public void JiraLinks_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Jira Links
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a ABCD-123 issue
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</a> issue</p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Jira Links\n");
|
||||
TestParser.TestSpec("This is a ABCD-123 issue", "<p>This is a <a href=\"http://your.company.abc/browse/ABCD-123\" target=\"blank\">ABCD-123</a> issue</p>", "jiralinks");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JiraLinks_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Jira Links
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a KIRA-1 issue
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a> issue</p>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Jira Links\n");
|
||||
TestParser.TestSpec("This is a KIRA-1 issue", "<p>This is a <a href=\"http://your.company.abc/browse/KIRA-1\" target=\"blank\">KIRA-1</a> issue</p>", "jiralinks");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JiraLinks_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Jira Links
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a Z-1 issue
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <a href="http://your.company.abc/browse/Z-1" target="blank">Z-1</a> issue</p>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Jira Links\n");
|
||||
TestParser.TestSpec("This is a Z-1 issue", "<p>This is a <a href=\"http://your.company.abc/browse/Z-1\" target=\"blank\">Z-1</a> issue</p>", "jiralinks");
|
||||
}
|
||||
|
||||
// These are also valid links with `(` and `)`:
|
||||
[Test]
|
||||
public void JiraLinks_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Jira Links
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a (ABCD-123) issue
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a (<a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</a>) issue</p>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Jira Links\n");
|
||||
TestParser.TestSpec("This is a (ABCD-123) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/ABCD-123\" target=\"blank\">ABCD-123</a>) issue</p>", "jiralinks");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JiraLinks_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Jira Links
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a (KIRA-1) issue
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a (<a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a>) issue</p>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Jira Links\n");
|
||||
TestParser.TestSpec("This is a (KIRA-1) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/KIRA-1\" target=\"blank\">KIRA-1</a>) issue</p>", "jiralinks");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JiraLinks_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Jira Links
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a (Z-1) issue
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a (<a href="http://your.company.abc/browse/Z-1" target="blank">Z-1</a>) issue</p>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Jira Links\n");
|
||||
TestParser.TestSpec("This is a (Z-1) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/Z-1\" target=\"blank\">Z-1</a>) issue</p>", "jiralinks");
|
||||
}
|
||||
|
||||
// These are not valid links:
|
||||
[Test]
|
||||
public void JiraLinks_Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Jira Links
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is not aJIRA-123 issue
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is not aJIRA-123 issue</p>
|
||||
|
||||
Console.WriteLine("Example 7\nSection Jira Links\n");
|
||||
TestParser.TestSpec("This is not aJIRA-123 issue", "<p>This is not aJIRA-123 issue</p>", "jiralinks");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JiraLinks_Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Jira Links
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is not JIRA-123a issue
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is not JIRA-123a issue</p>
|
||||
|
||||
Console.WriteLine("Example 8\nSection Jira Links\n");
|
||||
TestParser.TestSpec("This is not JIRA-123a issue", "<p>This is not JIRA-123a issue</p>", "jiralinks");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JiraLinks_Example009()
|
||||
{
|
||||
// Example 9
|
||||
// Section: Jira Links
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is not JIRA- issue
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is not JIRA- issue</p>
|
||||
|
||||
Console.WriteLine("Example 9\nSection Jira Links\n");
|
||||
TestParser.TestSpec("This is not JIRA- issue", "<p>This is not JIRA- issue</p>", "jiralinks");
|
||||
}
|
||||
}
|
||||
}
|
||||
77
src/Markdig.Tests/Specs/JiraLinks.md
Normal file
77
src/Markdig.Tests/Specs/JiraLinks.md
Normal file
@@ -0,0 +1,77 @@
|
||||
## Jira Links
|
||||
|
||||
The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g.
|
||||
|
||||
```
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
.UseJiraLinks(new JiraLinkOptions("http://your.company.abc"))
|
||||
.Build();
|
||||
```
|
||||
|
||||
The rules for detecting a link are:
|
||||
|
||||
- The project key must be composed of one or more capitalized ASCII letter `[A-Z]+`
|
||||
- A single hyphen `-` must separate the project key and issue number.
|
||||
- The issue number is composed of 1 or more digits `[0, 9]+`
|
||||
- The reference must be preceded by either `(` or whitespace or EOF.
|
||||
- The reference must be followed by either `)` or whitespace or EOF.
|
||||
|
||||
The following are valid examples:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a ABCD-123 issue
|
||||
.
|
||||
<p>This is a <a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</a> issue</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a KIRA-1 issue
|
||||
.
|
||||
<p>This is a <a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a> issue</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a Z-1 issue
|
||||
.
|
||||
<p>This is a <a href="http://your.company.abc/browse/Z-1" target="blank">Z-1</a> issue</p>
|
||||
````````````````````````````````
|
||||
|
||||
These are also valid links with `(` and `)`:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a (ABCD-123) issue
|
||||
.
|
||||
<p>This is a (<a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</a>) issue</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a (KIRA-1) issue
|
||||
.
|
||||
<p>This is a (<a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a>) issue</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a (Z-1) issue
|
||||
.
|
||||
<p>This is a (<a href="http://your.company.abc/browse/Z-1" target="blank">Z-1</a>) issue</p>
|
||||
````````````````````````````````
|
||||
|
||||
These are not valid links:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is not aJIRA-123 issue
|
||||
.
|
||||
<p>This is not aJIRA-123 issue</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is not JIRA-123a issue
|
||||
.
|
||||
<p>This is not JIRA-123a issue</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is not JIRA- issue
|
||||
.
|
||||
<p>This is not JIRA- issue</p>
|
||||
````````````````````````````````
|
||||
217
src/Markdig.Tests/Specs/ListExtraSpecs.generated.cs
Normal file
217
src/Markdig.Tests/Specs/ListExtraSpecs.generated.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// List Extras
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.ListExtras
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsOrderedListWithAlphaLetter
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// The following additional list items are supported:
|
||||
//
|
||||
// ## Ordered list with alpha letter
|
||||
//
|
||||
// Allows to use a list using an alpha letter instead of a number
|
||||
[Test]
|
||||
public void ExtensionsOrderedListWithAlphaLetter_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Ordered list with alpha letter
|
||||
//
|
||||
// The following Markdown:
|
||||
// a. First item
|
||||
// b. Second item
|
||||
// c. Last item
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ol type="a">
|
||||
// <li>First item</li>
|
||||
// <li>Second item</li>
|
||||
// <li>Last item</li>
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Ordered list with alpha letter\n");
|
||||
TestParser.TestSpec("a. First item\nb. Second item\nc. Last item", "<ol type=\"a\">\n<li>First item</li>\n<li>Second item</li>\n<li>Last item</li>\n</ol>", "listextras|advanced");
|
||||
}
|
||||
|
||||
// It works also for uppercase alpha:
|
||||
[Test]
|
||||
public void ExtensionsOrderedListWithAlphaLetter_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Ordered list with alpha letter
|
||||
//
|
||||
// The following Markdown:
|
||||
// A. First item
|
||||
// B. Second item
|
||||
// C. Last item
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ol type="A">
|
||||
// <li>First item</li>
|
||||
// <li>Second item</li>
|
||||
// <li>Last item</li>
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Ordered list with alpha letter\n");
|
||||
TestParser.TestSpec("A. First item\nB. Second item\nC. Last item", "<ol type=\"A\">\n<li>First item</li>\n<li>Second item</li>\n<li>Last item</li>\n</ol>", "listextras|advanced");
|
||||
}
|
||||
|
||||
// Like for numbered list, a list can start with a different letter
|
||||
[Test]
|
||||
public void ExtensionsOrderedListWithAlphaLetter_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Ordered list with alpha letter
|
||||
//
|
||||
// The following Markdown:
|
||||
// b. First item
|
||||
// c. Second item
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ol type="a" start="2">
|
||||
// <li>First item</li>
|
||||
// <li>Second item</li>
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Ordered list with alpha letter\n");
|
||||
TestParser.TestSpec("b. First item\nc. Second item", "<ol type=\"a\" start=\"2\">\n<li>First item</li>\n<li>Second item</li>\n</ol>", "listextras|advanced");
|
||||
}
|
||||
|
||||
// A different type of list will break the existing list:
|
||||
[Test]
|
||||
public void ExtensionsOrderedListWithAlphaLetter_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Ordered list with alpha letter
|
||||
//
|
||||
// The following Markdown:
|
||||
// a. First item1
|
||||
// b. Second item
|
||||
// A. First item2
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ol type="a">
|
||||
// <li>First item1</li>
|
||||
// <li>Second item</li>
|
||||
// </ol>
|
||||
// <ol type="A">
|
||||
// <li>First item2</li>
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Ordered list with alpha letter\n");
|
||||
TestParser.TestSpec("a. First item1\nb. Second item\nA. First item2", "<ol type=\"a\">\n<li>First item1</li>\n<li>Second item</li>\n</ol>\n<ol type=\"A\">\n<li>First item2</li>\n</ol>", "listextras|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsOrderedListWithRomanLetter
|
||||
{
|
||||
// ## Ordered list with roman letter
|
||||
//
|
||||
// Allows to use a list using a roman number instead of a number.
|
||||
[Test]
|
||||
public void ExtensionsOrderedListWithRomanLetter_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / Ordered list with roman letter
|
||||
//
|
||||
// The following Markdown:
|
||||
// i. First item
|
||||
// ii. Second item
|
||||
// iii. Third item
|
||||
// iv. Last item
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ol type="i">
|
||||
// <li>First item</li>
|
||||
// <li>Second item</li>
|
||||
// <li>Third item</li>
|
||||
// <li>Last item</li>
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / Ordered list with roman letter\n");
|
||||
TestParser.TestSpec("i. First item\nii. Second item\niii. Third item\niv. Last item", "<ol type=\"i\">\n<li>First item</li>\n<li>Second item</li>\n<li>Third item</li>\n<li>Last item</li>\n</ol>", "listextras|advanced");
|
||||
}
|
||||
|
||||
// It works also for uppercase alpha:
|
||||
[Test]
|
||||
public void ExtensionsOrderedListWithRomanLetter_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / Ordered list with roman letter
|
||||
//
|
||||
// The following Markdown:
|
||||
// I. First item
|
||||
// II. Second item
|
||||
// III. Third item
|
||||
// IV. Last item
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ol type="I">
|
||||
// <li>First item</li>
|
||||
// <li>Second item</li>
|
||||
// <li>Third item</li>
|
||||
// <li>Last item</li>
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / Ordered list with roman letter\n");
|
||||
TestParser.TestSpec("I. First item\nII. Second item\nIII. Third item\nIV. Last item", "<ol type=\"I\">\n<li>First item</li>\n<li>Second item</li>\n<li>Third item</li>\n<li>Last item</li>\n</ol>", "listextras|advanced");
|
||||
}
|
||||
|
||||
// Like for numbered list, a list can start with a different letter
|
||||
[Test]
|
||||
public void ExtensionsOrderedListWithRomanLetter_Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Extensions / Ordered list with roman letter
|
||||
//
|
||||
// The following Markdown:
|
||||
// ii. First item
|
||||
// iii. Second item
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ol type="i" start="2">
|
||||
// <li>First item</li>
|
||||
// <li>Second item</li>
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example 7\nSection Extensions / Ordered list with roman letter\n");
|
||||
TestParser.TestSpec("ii. First item\niii. Second item", "<ol type=\"i\" start=\"2\">\n<li>First item</li>\n<li>Second item</li>\n</ol>", "listextras|advanced");
|
||||
}
|
||||
|
||||
// Lists can be restarted, specifying the start point.
|
||||
[Test]
|
||||
public void ExtensionsOrderedListWithRomanLetter_Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Extensions / Ordered list with roman letter
|
||||
//
|
||||
// The following Markdown:
|
||||
// 1. First item
|
||||
//
|
||||
// Some text
|
||||
//
|
||||
// 2. Second item
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ol>
|
||||
// <li>First item</li>
|
||||
// </ol>
|
||||
// <p>Some text</p>
|
||||
// <ol start="2">
|
||||
// <li>Second item</li>
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example 8\nSection Extensions / Ordered list with roman letter\n");
|
||||
TestParser.TestSpec("1. First item\n\nSome text\n\n2. Second item", "<ol>\n<li>First item</li>\n</ol>\n<p>Some text</p>\n<ol start=\"2\">\n<li>Second item</li>\n</ol>", "listextras|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ Like for numbered list, a list can start with a different letter
|
||||
b. First item
|
||||
c. Second item
|
||||
.
|
||||
<ol type="a" start="b">
|
||||
<ol type="a" start="2">
|
||||
<li>First item</li>
|
||||
<li>Second item</li>
|
||||
</ol>
|
||||
@@ -100,8 +100,26 @@ Like for numbered list, a list can start with a different letter
|
||||
ii. First item
|
||||
iii. Second item
|
||||
.
|
||||
<ol type="i" start="ii">
|
||||
<ol type="i" start="2">
|
||||
<li>First item</li>
|
||||
<li>Second item</li>
|
||||
</ol>
|
||||
````````````````````````````````
|
||||
|
||||
Lists can be restarted, specifying the start point.
|
||||
|
||||
```````````````````````````````` example
|
||||
1. First item
|
||||
|
||||
Some text
|
||||
|
||||
2. Second item
|
||||
.
|
||||
<ol>
|
||||
<li>First item</li>
|
||||
</ol>
|
||||
<p>Some text</p>
|
||||
<ol start="2">
|
||||
<li>Second item</li>
|
||||
</ol>
|
||||
````````````````````````````````
|
||||
|
||||
328
src/Markdig.Tests/Specs/MathSpecs.generated.cs
Normal file
328
src/Markdig.Tests/Specs/MathSpecs.generated.cs
Normal file
@@ -0,0 +1,328 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Math
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Math
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsMathInline
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// Adds support for mathematics spans:
|
||||
//
|
||||
// ## Math Inline
|
||||
//
|
||||
// Allows to define a mathematic block embraced by `$...$`
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a $math block$
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <span class="math">\(math block\)</span></p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is a $math block$", "<p>This is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
// Or by `$$...$$` embracing it by:
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a $$math block$$
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <span class="math">\(math block\)</span></p>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is a $$math block$$", "<p>This is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
// Newlines inside an inline math are not allowed:
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is not a $$math
|
||||
// block$$ and? this is a $$math block$$
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is not a $$math
|
||||
// block$$ and? this is a <span class="math">\(math block\)</span></p>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is not a $$math \nblock$$ and? this is a $$math block$$", "<p>This is not a $$math\nblock$$ and? this is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is not a $math
|
||||
// block$ and? this is a $math block$
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is not a $math
|
||||
// block$ and? this is a <span class="math">\(math block\)</span></p>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is not a $math \nblock$ and? this is a $math block$", "<p>This is not a $math\nblock$ and? this is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
// An opening `$` can be followed by a space if the closing is also preceded by a space `$`:
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a $ math block $
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <span class="math">\(math block\)</span></p>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is a $ math block $", "<p>This is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a $ math block $ after
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <span class="math">\(math block\)</span> after</p>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is a $ math block $ after", "<p>This is a <span class=\"math\">\\(math block\\)</span> after</p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a $$ math block $$ after
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <span class="math">\(math block\)</span> after</p>
|
||||
|
||||
Console.WriteLine("Example 7\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is a $$ math block $$ after", "<p>This is a <span class=\"math\">\\(math block\\)</span> after</p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a not $ math block$ because there is not a whitespace before the closing
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a not $ math block$ because there is not a whitespace before the closing</p>
|
||||
|
||||
Console.WriteLine("Example 8\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is a not $ math block$ because there is not a whitespace before the closing", "<p>This is a not $ math block$ because there is not a whitespace before the closing</p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
// For the opening `$` it requires a space or a punctuation before (but cannot be used within a word):
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example009()
|
||||
{
|
||||
// Example 9
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is not a m$ath block$
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is not a m$ath block$</p>
|
||||
|
||||
Console.WriteLine("Example 9\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is not a m$ath block$", "<p>This is not a m$ath block$</p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
// For the closing `$` it requires a space after or a punctuation (but cannot be preceded by a space and cannot be used within a word):
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example010()
|
||||
{
|
||||
// Example 10
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is not a $math bloc$k
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is not a $math bloc$k</p>
|
||||
|
||||
Console.WriteLine("Example 10\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is not a $math bloc$k", "<p>This is not a $math bloc$k</p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
// For the closing `$` it requires a space after or a punctuation (but cannot be preceded by a space and cannot be used within a word):
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example011()
|
||||
{
|
||||
// Example 11
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is should not match a 16$ or a $15
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is should not match a 16$ or a $15</p>
|
||||
|
||||
Console.WriteLine("Example 11\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is should not match a 16$ or a $15", "<p>This is should not match a 16$ or a $15</p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
// A `$` can be escaped between a math inline block by using the escape `\\`
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example012()
|
||||
{
|
||||
// Example 12
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a $math \$ block$
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <span class="math">\(math \$ block\)</span></p>
|
||||
|
||||
Console.WriteLine("Example 12\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is a $math \\$ block$", "<p>This is a <span class=\"math\">\\(math \\$ block\\)</span></p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
// At most, two `$` will be matched for the opening and closing:
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example013()
|
||||
{
|
||||
// Example 13
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a $$$math block$$$
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <span class="math">\($math block$\)</span></p>
|
||||
|
||||
Console.WriteLine("Example 13\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is a $$$math block$$$", "<p>This is a <span class=\"math\">\\($math block$\\)</span></p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
// Regular text can come both before and after the math inline
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example014()
|
||||
{
|
||||
// Example 14
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a $math block$ with text on both sides.
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <span class="math">\(math block\)</span> with text on both sides.</p>
|
||||
|
||||
Console.WriteLine("Example 14\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is a $math block$ with text on both sides.", "<p>This is a <span class=\"math\">\\(math block\\)</span> with text on both sides.</p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
// A mathematic block takes precedence over standard emphasis `*` `_`:
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example015()
|
||||
{
|
||||
// Example 15
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is *a $math* block$
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is *a <span class="math">\(math* block\)</span></p>
|
||||
|
||||
Console.WriteLine("Example 15\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("This is *a $math* block$", "<p>This is *a <span class=\"math\">\\(math* block\\)</span></p>", "mathematics|advanced");
|
||||
}
|
||||
|
||||
// An opening $$ at the beginning of a line should not be interpreted as a Math block:
|
||||
[Test]
|
||||
public void ExtensionsMathInline_Example016()
|
||||
{
|
||||
// Example 16
|
||||
// Section: Extensions / Math Inline
|
||||
//
|
||||
// The following Markdown:
|
||||
// $$ math $$ starting at a line
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><span class="math">\(math\)</span> starting at a line</p>
|
||||
|
||||
Console.WriteLine("Example 16\nSection Extensions / Math Inline\n");
|
||||
TestParser.TestSpec("$$ math $$ starting at a line", "<p><span class=\"math\">\\(math\\)</span> starting at a line</p>", "mathematics|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsMathBlock
|
||||
{
|
||||
// ## Math Block
|
||||
//
|
||||
// The match block can spawn on multiple lines by having a $$ starting on a line.
|
||||
// It is working as a fenced code block.
|
||||
[Test]
|
||||
public void ExtensionsMathBlock_Example017()
|
||||
{
|
||||
// Example 17
|
||||
// Section: Extensions / Math Block
|
||||
//
|
||||
// The following Markdown:
|
||||
// $$
|
||||
// \begin{equation}
|
||||
// \int_0^\infty \frac{x^3}{e^x-1}\,dx = \frac{\pi^4}{15}
|
||||
// \label{eq:sample}
|
||||
// \end{equation}
|
||||
// $$
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <div class="math">
|
||||
// \[
|
||||
// \begin{equation}
|
||||
// \int_0^\infty \frac{x^3}{e^x-1}\,dx = \frac{\pi^4}{15}
|
||||
// \label{eq:sample}
|
||||
// \end{equation}
|
||||
// \]</div>
|
||||
|
||||
Console.WriteLine("Example 17\nSection Extensions / Math Block\n");
|
||||
TestParser.TestSpec("$$\n\\begin{equation}\n \\int_0^\\infty \\frac{x^3}{e^x-1}\\,dx = \\frac{\\pi^4}{15}\n \\label{eq:sample}\n\\end{equation}\n$$", "<div class=\"math\">\n\\[\n\\begin{equation}\n \\int_0^\\infty \\frac{x^3}{e^x-1}\\,dx = \\frac{\\pi^4}{15}\n \\label{eq:sample}\n\\end{equation}\n\\]</div>", "mathematics|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ Allows to define a mathematic block embraced by `$...$`
|
||||
```````````````````````````````` example
|
||||
This is a $math block$
|
||||
.
|
||||
<p>This is a <span class="math">math block</span></p>
|
||||
<p>This is a <span class="math">\(math block\)</span></p>
|
||||
````````````````````````````````
|
||||
|
||||
Or by `$$...$$` embracing it by:
|
||||
@@ -17,15 +17,50 @@ Or by `$$...$$` embracing it by:
|
||||
```````````````````````````````` example
|
||||
This is a $$math block$$
|
||||
.
|
||||
<p>This is a <span class="math">math block</span></p>
|
||||
<p>This is a <span class="math">\(math block\)</span></p>
|
||||
````````````````````````````````
|
||||
|
||||
The opening `$` and closing `$` is following the rules of the emphasis delimiter `_`:
|
||||
Newlines inside an inline math are not allowed:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is not a $ math block $
|
||||
This is not a $$math
|
||||
block$$ and? this is a $$math block$$
|
||||
.
|
||||
<p>This is not a $ math block $</p>
|
||||
<p>This is not a $$math
|
||||
block$$ and? this is a <span class="math">\(math block\)</span></p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is not a $math
|
||||
block$ and? this is a $math block$
|
||||
.
|
||||
<p>This is not a $math
|
||||
block$ and? this is a <span class="math">\(math block\)</span></p>
|
||||
````````````````````````````````
|
||||
An opening `$` can be followed by a space if the closing is also preceded by a space `$`:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a $ math block $
|
||||
.
|
||||
<p>This is a <span class="math">\(math block\)</span></p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a $ math block $ after
|
||||
.
|
||||
<p>This is a <span class="math">\(math block\)</span> after</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a $$ math block $$ after
|
||||
.
|
||||
<p>This is a <span class="math">\(math block\)</span> after</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a not $ math block$ because there is not a whitespace before the closing
|
||||
.
|
||||
<p>This is a not $ math block$ because there is not a whitespace before the closing</p>
|
||||
````````````````````````````````
|
||||
|
||||
For the opening `$` it requires a space or a punctuation before (but cannot be used within a word):
|
||||
@@ -57,7 +92,7 @@ A `$` can be escaped between a math inline block by using the escape `\\`
|
||||
```````````````````````````````` example
|
||||
This is a $math \$ block$
|
||||
.
|
||||
<p>This is a <span class="math">math \$ block</span></p>
|
||||
<p>This is a <span class="math">\(math \$ block\)</span></p>
|
||||
````````````````````````````````
|
||||
|
||||
At most, two `$` will be matched for the opening and closing:
|
||||
@@ -65,15 +100,29 @@ At most, two `$` will be matched for the opening and closing:
|
||||
```````````````````````````````` example
|
||||
This is a $$$math block$$$
|
||||
.
|
||||
<p>This is a <span class="math">$math block$</span></p>
|
||||
<p>This is a <span class="math">\($math block$\)</span></p>
|
||||
````````````````````````````````
|
||||
|
||||
Regular text can come both before and after the math inline
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a $math block$ with text on both sides.
|
||||
.
|
||||
<p>This is a <span class="math">\(math block\)</span> with text on both sides.</p>
|
||||
````````````````````````````````
|
||||
A mathematic block takes precedence over standard emphasis `*` `_`:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is *a $math* block$
|
||||
.
|
||||
<p>This is *a <span class="math">math* block</span></p>
|
||||
<p>This is *a <span class="math">\(math* block\)</span></p>
|
||||
````````````````````````````````
|
||||
An opening $$ at the beginning of a line should not be interpreted as a Math block:
|
||||
|
||||
```````````````````````````````` example
|
||||
$$ math $$ starting at a line
|
||||
.
|
||||
<p><span class="math">\(math\)</span> starting at a line</p>
|
||||
````````````````````````````````
|
||||
|
||||
## Math Block
|
||||
@@ -89,9 +138,11 @@ $$
|
||||
\end{equation}
|
||||
$$
|
||||
.
|
||||
<div class="math">\begin{equation}
|
||||
<div class="math">
|
||||
\[
|
||||
\begin{equation}
|
||||
\int_0^\infty \frac{x^3}{e^x-1}\,dx = \frac{\pi^4}{15}
|
||||
\label{eq:sample}
|
||||
\end{equation}
|
||||
</div>
|
||||
\]</div>
|
||||
````````````````````````````````
|
||||
|
||||
65
src/Markdig.Tests/Specs/MediaSpecs.generated.cs
Normal file
65
src/Markdig.Tests/Specs/MediaSpecs.generated.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
// Generated: 2020-05-12 19:59:34
|
||||
|
||||
// --------------------------------
|
||||
// Media
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Media
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsMediaLinks
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// Adds support for media links:
|
||||
//
|
||||
// ## Media links
|
||||
//
|
||||
// Allows to embed audio/video links to popular website:
|
||||
[Test]
|
||||
public void ExtensionsMediaLinks_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Media links
|
||||
//
|
||||
// The following Markdown:
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://player.vimeo.com/video/8607834" class="vimeo" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><video width="500" height="281" controls=""><source type="video/mp4" src="https://sample.com/video.mp4"></source></video></p>
|
||||
// <p><iframe src="https://music.yandex.ru/iframe/#track/4402274/411845/" class="yandex" width="500" height="281" frameborder="0"></iframe></p>
|
||||
// <p><iframe src="https://ok.ru/videoembed/26870090463" class="odnoklassniki" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Media links\n");
|
||||
TestParser.TestSpec("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://player.vimeo.com/video/8607834\" class=\"vimeo\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"https://sample.com/video.mp4\"></source></video></p>\n<p><iframe src=\"https://music.yandex.ru/iframe/#track/4402274/411845/\" class=\"yandex\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n<p><iframe src=\"https://ok.ru/videoembed/26870090463\" class=\"odnoklassniki\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>", "medialinks|advanced+medialinks");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,38 @@
|
||||
Adds support for media links:
|
||||
|
||||
## Media links
|
||||
|
||||
|
||||
Allows to embed audio/video links to popular website:
|
||||
|
||||
```````````````````````````````` example
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
.
|
||||
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" frameborder="0" allowfullscreen></iframe></p>
|
||||
<p><iframe src="https://player.vimeo.com/video/8607834" width="500" height="281" frameborder="0" allowfullscreen></iframe></p>
|
||||
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><iframe src="https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><iframe src="https://player.vimeo.com/video/8607834" class="vimeo" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><video width="500" height="281" controls=""><source type="video/mp4" src="https://sample.com/video.mp4"></source></video></p>
|
||||
<p><iframe src="https://music.yandex.ru/iframe/#track/4402274/411845/" class="yandex" width="500" height="281" frameborder="0"></iframe></p>
|
||||
<p><iframe src="https://ok.ru/videoembed/26870090463" class="odnoklassniki" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
````````````````````````````````
|
||||
59
src/Markdig.Tests/Specs/NoHtmlSpecs.generated.cs
Normal file
59
src/Markdig.Tests/Specs/NoHtmlSpecs.generated.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// No Html
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.NoHtml
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsNoHTML
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// ## NoHTML
|
||||
//
|
||||
// The extension DisableHtml allows to disable the parsing of HTML:
|
||||
//
|
||||
// For inline HTML:
|
||||
[Test]
|
||||
public void ExtensionsNoHTML_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / NoHTML
|
||||
//
|
||||
// The following Markdown:
|
||||
// this is some text</td></tr>
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>this is some text</td></tr></p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / NoHTML\n");
|
||||
TestParser.TestSpec("this is some text</td></tr>", "<p>this is some text</td></tr></p>", "nohtml");
|
||||
}
|
||||
|
||||
// For Block HTML:
|
||||
[Test]
|
||||
public void ExtensionsNoHTML_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / NoHTML
|
||||
//
|
||||
// The following Markdown:
|
||||
// <div>
|
||||
// this is some text
|
||||
// </div>
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><div>
|
||||
// this is some text
|
||||
// </div></p>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / NoHTML\n");
|
||||
TestParser.TestSpec("<div>\nthis is some text\n</div>", "<p><div>\nthis is some text\n</div></p>", "nohtml");
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/Markdig.Tests/Specs/NoHtmlSpecs.md
Normal file
27
src/Markdig.Tests/Specs/NoHtmlSpecs.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Extensions
|
||||
|
||||
## NoHTML
|
||||
|
||||
The extension DisableHtml allows to disable the parsing of HTML:
|
||||
|
||||
For inline HTML:
|
||||
|
||||
```````````````````````````````` example
|
||||
this is some text</td></tr>
|
||||
.
|
||||
<p>this is some text</td></tr></p>
|
||||
````````````````````````````````
|
||||
|
||||
For Block HTML:
|
||||
|
||||
```````````````````````````````` example
|
||||
<div>
|
||||
this is some text
|
||||
</div>
|
||||
.
|
||||
<p><div>
|
||||
this is some text
|
||||
</div></p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
857
src/Markdig.Tests/Specs/PipeTableGfmSpecs.generated.cs
Normal file
857
src/Markdig.Tests/Specs/PipeTableGfmSpecs.generated.cs
Normal file
@@ -0,0 +1,857 @@
|
||||
// Generated: 2020-07-30 15:47:38
|
||||
|
||||
// --------------------------------
|
||||
// GFM Pipe Tables
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.GFMPipeTables
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsGfmPipeTable
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the different extensions supported:
|
||||
//
|
||||
// ## Gfm Pipe Table
|
||||
//
|
||||
// This groups a certain set of behaviors that makes pipe tables adhere more strictly to the GitHub-flavored Markdown specification.
|
||||
//
|
||||
// A pipe table is detected when:
|
||||
//
|
||||
// **Rule #1**
|
||||
// - Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backtick \`) or a HTML inline.
|
||||
// - The second row must separate the first header row from sub-sequent rows by containing a **header column separator** for each column separated by a column delimiter. A header column separator is:
|
||||
// - starting by optional spaces
|
||||
// - followed by an optional `:` to specify left align
|
||||
// - followed by a sequence of at least one `-` character
|
||||
// - followed by an optional `:` to specify right align (or center align if left align is also defined)
|
||||
// - ending by optional spaces
|
||||
//
|
||||
// Because a list has a higher precedence than a pipe table, a table header row separator requires at least 2 dashes `--` to start a header row:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | -
|
||||
// 0 | 1
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n-- | -\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// The following is also considered as a table, even if the second line starts like a list:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// - | -
|
||||
// 0 | 1
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n- | -\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// A pipe table with only one header row is allowed:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | --
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// After a row separator header, they will be interpreted as plain column:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | --
|
||||
// -- | --
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>--</td>
|
||||
// <td>--</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n-- | --\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>--</td>\n<td>--</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// But if a table doesn't start with a column delimiter, it is not interpreted as a table, even if following lines have a column delimiter
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a b
|
||||
// c | d
|
||||
// e | f
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>a b
|
||||
// c | d
|
||||
// e | f</p>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a b\nc | d\ne | f", "<p>a b\nc | d\ne | f</p>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// If a line doesn't have a column delimiter `|` the table is not detected
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// c no d
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>a | b
|
||||
// c no d</p>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\nc no d", "<p>a | b\nc no d</p>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// If a row contains more columns than the header row, the extra columns will be ignored:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | --
|
||||
// 0 | 1 | 2
|
||||
// 3 | 4
|
||||
// 5 |
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>3</td>
|
||||
// <td>4</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>5</td>
|
||||
// <td></td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 7\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a | b \n-- | --\n0 | 1 | 2\n3 | 4\n5 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>3</td>\n<td>4</td>\n</tr>\n<tr>\n<td>5</td>\n<td></td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// **Rule #2**
|
||||
// A pipe table ends after a blank line or the end of the file.
|
||||
//
|
||||
// **Rule #3**
|
||||
// A cell content is trimmed (start and end) from white-spaces.
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b |
|
||||
// -- | --
|
||||
// 0 | 1 |
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 8\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a | b |\n-- | --\n0 | 1 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// **Rule #4**
|
||||
// Column delimiters `|` at the very beginning of a line or just before a line ending with only spaces and/or terminated by a newline can be omitted
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example009()
|
||||
{
|
||||
// Example 9
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b |
|
||||
// -- | --
|
||||
// | 0 | 1
|
||||
// | 2 | 3 |
|
||||
// 4 | 5
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>2</td>
|
||||
// <td>3</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>4</td>
|
||||
// <td>5</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 9\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec(" a | b |\n-- | --\n| 0 | 1\n| 2 | 3 |\n 4 | 5 ", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>2</td>\n<td>3</td>\n</tr>\n<tr>\n<td>4</td>\n<td>5</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// A pipe may be present at both the beginning/ending of each line:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example010()
|
||||
{
|
||||
// Example 10
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// |a|b|
|
||||
// |-|-|
|
||||
// |0|1|
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 10\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("|a|b|\n|-|-|\n|0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// Or may be omitted on one side:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example011()
|
||||
{
|
||||
// Example 11
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a|b|
|
||||
// -|-|
|
||||
// 0|1|
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 11\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a|b|\n-|-|\n0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example012()
|
||||
{
|
||||
// Example 12
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// |a|b
|
||||
// |-|-
|
||||
// |0|1
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 12\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("|a|b\n|-|-\n|0|1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// Single column table can be declared with lines starting only by a column delimiter:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example013()
|
||||
{
|
||||
// Example 13
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// | a
|
||||
// | --
|
||||
// | b
|
||||
// | c
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>b</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>c</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 13\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("| a\n| --\n| b\n| c ", "<table>\n<thead>\n<tr>\n<th>a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b</td>\n</tr>\n<tr>\n<td>c</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// **Rule #5**
|
||||
//
|
||||
// The first row is considered as a **header row** if it is separated from the regular rows by a row containing a **header column separator** for each column. A header column separator is:
|
||||
//
|
||||
// - starting by optional spaces
|
||||
// - followed by an optional `:` to specify left align
|
||||
// - followed by a sequence of at least one `-` character
|
||||
// - followed by an optional `:` to specify right align (or center align if left align is also defined)
|
||||
// - ending by optional spaces
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example014()
|
||||
{
|
||||
// Example 14
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -------|-------
|
||||
// 0 | 1
|
||||
// 2 | 3
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>2</td>
|
||||
// <td>3</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 14\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec(" a | b \n-------|-------\n 0 | 1 \n 2 | 3 ", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>2</td>\n<td>3</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// The text alignment is defined by default to be center for header and left for cells. If the left alignment is applied, it will force the column heading to be left aligned.
|
||||
// There is no way to define a different alignment for heading and cells (apart from the default).
|
||||
// The text alignment can be changed by using the character `:` with the header column separator:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example015()
|
||||
{
|
||||
// Example 15
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b | c
|
||||
// :------|:-------:| ----:
|
||||
// 0 | 1 | 2
|
||||
// 3 | 4 | 5
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th style="text-align: left;">a</th>
|
||||
// <th style="text-align: center;">b</th>
|
||||
// <th style="text-align: right;">c</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td style="text-align: left;">0</td>
|
||||
// <td style="text-align: center;">1</td>
|
||||
// <td style="text-align: right;">2</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style="text-align: left;">3</td>
|
||||
// <td style="text-align: center;">4</td>
|
||||
// <td style="text-align: right;">5</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 15\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec(" a | b | c \n:------|:-------:| ----:\n 0 | 1 | 2 \n 3 | 4 | 5 ", "<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">a</th>\n<th style=\"text-align: center;\">b</th>\n<th style=\"text-align: right;\">c</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\">0</td>\n<td style=\"text-align: center;\">1</td>\n<td style=\"text-align: right;\">2</td>\n</tr>\n<tr>\n<td style=\"text-align: left;\">3</td>\n<td style=\"text-align: center;\">4</td>\n<td style=\"text-align: right;\">5</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// Test alignment with starting and ending pipes:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example016()
|
||||
{
|
||||
// Example 16
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// | abc | def | ghi |
|
||||
// |:---:|-----|----:|
|
||||
// | 1 | 2 | 3 |
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th style="text-align: center;">abc</th>
|
||||
// <th>def</th>
|
||||
// <th style="text-align: right;">ghi</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td style="text-align: center;">1</td>
|
||||
// <td>2</td>
|
||||
// <td style="text-align: right;">3</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 16\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("| abc | def | ghi |\n|:---:|-----|----:|\n| 1 | 2 | 3 |", "<table>\n<thead>\n<tr>\n<th style=\"text-align: center;\">abc</th>\n<th>def</th>\n<th style=\"text-align: right;\">ghi</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: center;\">1</td>\n<td>2</td>\n<td style=\"text-align: right;\">3</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// The following example shows a non matching header column separator:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example017()
|
||||
{
|
||||
// Example 17
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -------|---x---
|
||||
// 0 | 1
|
||||
// 2 | 3
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>a | b
|
||||
// -------|---x---
|
||||
// 0 | 1
|
||||
// 2 | 3</p>
|
||||
|
||||
Console.WriteLine("Example 17\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec(" a | b\n-------|---x---\n 0 | 1\n 2 | 3 ", "<p>a | b\n-------|---x---\n0 | 1\n2 | 3</p> ", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// **Rule #6**
|
||||
//
|
||||
// A column delimiter has a higher priority than emphasis delimiter
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example018()
|
||||
{
|
||||
// Example 18
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// *a* | b
|
||||
// ----- |-----
|
||||
// 0 | _1_
|
||||
// _2 | 3*
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th><em>a</em></th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td><em>1</em></td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>_2</td>
|
||||
// <td>3*</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 18\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec(" *a* | b\n----- |-----\n 0 | _1_\n _2 | 3* ", "<table>\n<thead>\n<tr>\n<th><em>a</em></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td><em>1</em></td>\n</tr>\n<tr>\n<td>_2</td>\n<td>3*</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// **Rule #7**
|
||||
//
|
||||
// A backtick/code delimiter has a higher precedence than a column delimiter `|`:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example019()
|
||||
{
|
||||
// Example 19
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b `
|
||||
// 0 | `
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>a | b <code>0 |</code></p>
|
||||
|
||||
Console.WriteLine("Example 19\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a | b `\n0 | ` ", "<p>a | b <code>0 |</code></p> ", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// **Rule #8**
|
||||
//
|
||||
// A HTML inline has a higher precedence than a column delimiter `|`:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example020()
|
||||
{
|
||||
// Example 20
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a <a href="" title="|"></a> | b
|
||||
// -- | --
|
||||
// 0 | 1
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a <a href="" title="|"></a></th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 20\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a <a href=\"\" title=\"|\"></a> | b\n-- | --\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a <a href=\"\" title=\"|\"></a></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// **Rule #9**
|
||||
//
|
||||
// Links have a higher precedence than the column delimiter character `|`:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example021()
|
||||
{
|
||||
// Example 21
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | --
|
||||
// [This is a link with a | inside the label](http://google.com) | 1
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td><a href="http://google.com">This is a link with a | inside the label</a></td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 21\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n-- | --\n[This is a link with a | inside the label](http://google.com) | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><a href=\"http://google.com\">This is a link with a | inside the label</a></td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// **Rule #10**
|
||||
//
|
||||
// It is possible to have a single row header only:
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example022()
|
||||
{
|
||||
// Example 22
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | --
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 22\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example023()
|
||||
{
|
||||
// Example 23
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// |a|b|c
|
||||
// |---|---|---|
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// <th>c</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 23\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("|a|b|c\n|---|---|---|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n</tr>\n</thead>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// **Tests**
|
||||
//
|
||||
// Tests trailing spaces after pipes
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example024()
|
||||
{
|
||||
// Example 24
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// | abc | def |
|
||||
// |---|---|
|
||||
// | cde| ddd|
|
||||
// | eee| fff|
|
||||
// | fff | fffff |
|
||||
// |gggg | ffff |
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>abc</th>
|
||||
// <th>def</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>cde</td>
|
||||
// <td>ddd</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>eee</td>
|
||||
// <td>fff</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>fff</td>
|
||||
// <td>fffff</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>gggg</td>
|
||||
// <td>ffff</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 24\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("| abc | def | \n|---|---|\n| cde| ddd| \n| eee| fff|\n| fff | fffff | \n|gggg | ffff | ", "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>cde</td>\n<td>ddd</td>\n</tr>\n<tr>\n<td>eee</td>\n<td>fff</td>\n</tr>\n<tr>\n<td>fff</td>\n<td>fffff</td>\n</tr>\n<tr>\n<td>gggg</td>\n<td>ffff</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
|
||||
// **Normalized columns count**
|
||||
//
|
||||
// The tables are normalized to the number of columns found in the table header.
|
||||
// Extra columns will be ignored, missing columns will be inserted.
|
||||
[Test]
|
||||
public void ExtensionsGfmPipeTable_Example025()
|
||||
{
|
||||
// Example 25
|
||||
// Section: Extensions / Gfm Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | -
|
||||
// 0 | 1 | 2
|
||||
// 3 |
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>3</td>
|
||||
// <td></td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 25\nSection Extensions / Gfm Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n-- | - \n0 | 1 | 2\n3 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>3</td>\n<td></td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
|
||||
}
|
||||
}
|
||||
}
|
||||
617
src/Markdig.Tests/Specs/PipeTableGfmSpecs.md
Normal file
617
src/Markdig.Tests/Specs/PipeTableGfmSpecs.md
Normal file
@@ -0,0 +1,617 @@
|
||||
# Extensions
|
||||
|
||||
This section describes the different extensions supported:
|
||||
|
||||
## Gfm Pipe Table
|
||||
|
||||
This groups a certain set of behaviors that makes pipe tables adhere more strictly to the GitHub-flavored Markdown specification.
|
||||
|
||||
A pipe table is detected when:
|
||||
|
||||
**Rule #1**
|
||||
- Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backtick \`) or a HTML inline.
|
||||
- The second row must separate the first header row from sub-sequent rows by containing a **header column separator** for each column separated by a column delimiter. A header column separator is:
|
||||
- starting by optional spaces
|
||||
- followed by an optional `:` to specify left align
|
||||
- followed by a sequence of at least one `-` character
|
||||
- followed by an optional `:` to specify right align (or center align if left align is also defined)
|
||||
- ending by optional spaces
|
||||
|
||||
Because a list has a higher precedence than a pipe table, a table header row separator requires at least 2 dashes `--` to start a header row:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-- | -
|
||||
0 | 1
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
The following is also considered as a table, even if the second line starts like a list:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
- | -
|
||||
0 | 1
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
A pipe table with only one header row is allowed:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-- | --
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
After a row separator header, they will be interpreted as plain column:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-- | --
|
||||
-- | --
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>--</td>
|
||||
<td>--</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
But if a table doesn't start with a column delimiter, it is not interpreted as a table, even if following lines have a column delimiter
|
||||
|
||||
```````````````````````````````` example
|
||||
a b
|
||||
c | d
|
||||
e | f
|
||||
.
|
||||
<p>a b
|
||||
c | d
|
||||
e | f</p>
|
||||
````````````````````````````````
|
||||
|
||||
If a line doesn't have a column delimiter `|` the table is not detected
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
c no d
|
||||
.
|
||||
<p>a | b
|
||||
c no d</p>
|
||||
````````````````````````````````
|
||||
|
||||
If a row contains more columns than the header row, the extra columns will be ignored:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-- | --
|
||||
0 | 1 | 2
|
||||
3 | 4
|
||||
5 |
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>4</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>5</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Rule #2**
|
||||
A pipe table ends after a blank line or the end of the file.
|
||||
|
||||
**Rule #3**
|
||||
A cell content is trimmed (start and end) from white-spaces.
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b |
|
||||
-- | --
|
||||
0 | 1 |
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Rule #4**
|
||||
Column delimiters `|` at the very beginning of a line or just before a line ending with only spaces and/or terminated by a newline can be omitted
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b |
|
||||
-- | --
|
||||
| 0 | 1
|
||||
| 2 | 3 |
|
||||
4 | 5
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>4</td>
|
||||
<td>5</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
A pipe may be present at both the beginning/ending of each line:
|
||||
|
||||
```````````````````````````````` example
|
||||
|a|b|
|
||||
|-|-|
|
||||
|0|1|
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
Or may be omitted on one side:
|
||||
|
||||
```````````````````````````````` example
|
||||
a|b|
|
||||
-|-|
|
||||
0|1|
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
|a|b
|
||||
|-|-
|
||||
|0|1
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
|
||||
Single column table can be declared with lines starting only by a column delimiter:
|
||||
|
||||
```````````````````````````````` example
|
||||
| a
|
||||
| --
|
||||
| b
|
||||
| c
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>b</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>c</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Rule #5**
|
||||
|
||||
The first row is considered as a **header row** if it is separated from the regular rows by a row containing a **header column separator** for each column. A header column separator is:
|
||||
|
||||
- starting by optional spaces
|
||||
- followed by an optional `:` to specify left align
|
||||
- followed by a sequence of at least one `-` character
|
||||
- followed by an optional `:` to specify right align (or center align if left align is also defined)
|
||||
- ending by optional spaces
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-------|-------
|
||||
0 | 1
|
||||
2 | 3
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
The text alignment is defined by default to be center for header and left for cells. If the left alignment is applied, it will force the column heading to be left aligned.
|
||||
There is no way to define a different alignment for heading and cells (apart from the default).
|
||||
The text alignment can be changed by using the character `:` with the header column separator:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b | c
|
||||
:------|:-------:| ----:
|
||||
0 | 1 | 2
|
||||
3 | 4 | 5
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align: left;">a</th>
|
||||
<th style="text-align: center;">b</th>
|
||||
<th style="text-align: right;">c</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align: left;">0</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: right;">2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: left;">3</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: right;">5</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
Test alignment with starting and ending pipes:
|
||||
|
||||
```````````````````````````````` example
|
||||
| abc | def | ghi |
|
||||
|:---:|-----|----:|
|
||||
| 1 | 2 | 3 |
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align: center;">abc</th>
|
||||
<th>def</th>
|
||||
<th style="text-align: right;">ghi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td>2</td>
|
||||
<td style="text-align: right;">3</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
The following example shows a non matching header column separator:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-------|---x---
|
||||
0 | 1
|
||||
2 | 3
|
||||
.
|
||||
<p>a | b
|
||||
-------|---x---
|
||||
0 | 1
|
||||
2 | 3</p>
|
||||
````````````````````````````````
|
||||
|
||||
**Rule #6**
|
||||
|
||||
A column delimiter has a higher priority than emphasis delimiter
|
||||
|
||||
```````````````````````````````` example
|
||||
*a* | b
|
||||
----- |-----
|
||||
0 | _1_
|
||||
_2 | 3*
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><em>a</em></th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td><em>1</em></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>_2</td>
|
||||
<td>3*</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Rule #7**
|
||||
|
||||
A backtick/code delimiter has a higher precedence than a column delimiter `|`:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b `
|
||||
0 | `
|
||||
.
|
||||
<p>a | b <code>0 |</code></p>
|
||||
````````````````````````````````
|
||||
|
||||
**Rule #8**
|
||||
|
||||
A HTML inline has a higher precedence than a column delimiter `|`:
|
||||
|
||||
```````````````````````````````` example
|
||||
a <a href="" title="|"></a> | b
|
||||
-- | --
|
||||
0 | 1
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a <a href="" title="|"></a></th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Rule #9**
|
||||
|
||||
Links have a higher precedence than the column delimiter character `|`:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-- | --
|
||||
[This is a link with a | inside the label](http://google.com) | 1
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="http://google.com">This is a link with a | inside the label</a></td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Rule #10**
|
||||
|
||||
It is possible to have a single row header only:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-- | --
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
|a|b|c
|
||||
|---|---|---|
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
<th>c</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Tests**
|
||||
|
||||
Tests trailing spaces after pipes
|
||||
|
||||
```````````````````````````````` example
|
||||
| abc | def |
|
||||
|---|---|
|
||||
| cde| ddd|
|
||||
| eee| fff|
|
||||
| fff | fffff |
|
||||
|gggg | ffff |
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>abc</th>
|
||||
<th>def</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>cde</td>
|
||||
<td>ddd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>eee</td>
|
||||
<td>fff</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>fff</td>
|
||||
<td>fffff</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>gggg</td>
|
||||
<td>ffff</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Normalized columns count**
|
||||
|
||||
The tables are normalized to the number of columns found in the table header.
|
||||
Extra columns will be ignored, missing columns will be inserted.
|
||||
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-- | -
|
||||
0 | 1 | 2
|
||||
3 |
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
855
src/Markdig.Tests/Specs/PipeTableSpecs.generated.cs
Normal file
855
src/Markdig.Tests/Specs/PipeTableSpecs.generated.cs
Normal file
@@ -0,0 +1,855 @@
|
||||
// Generated: 2020-07-30 15:32:13
|
||||
|
||||
// --------------------------------
|
||||
// Pipe Tables
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.PipeTables
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsPipeTable
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// This section describes the different extensions supported:
|
||||
//
|
||||
// ## Pipe Table
|
||||
//
|
||||
// A pipe table is detected when:
|
||||
//
|
||||
// **Rule #1**
|
||||
// - Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backtick \`) or a HTML inline.
|
||||
// - The second row must separate the first header row from sub-sequent rows by containing a **header column separator** for each column separated by a column delimiter. A header column separator is:
|
||||
// - starting by optional spaces
|
||||
// - followed by an optional `:` to specify left align
|
||||
// - followed by a sequence of at least one `-` character
|
||||
// - followed by an optional `:` to specify right align (or center align if left align is also defined)
|
||||
// - ending by optional spaces
|
||||
//
|
||||
// Because a list has a higher precedence than a pipe table, a table header row separator requires at least 2 dashes `--` to start a header row:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | -
|
||||
// 0 | 1
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n-- | -\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// The following is also considered as a table, even if the second line starts like a list:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// - | -
|
||||
// 0 | 1
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n- | -\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// A pipe table with only one header row is allowed:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | --
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// After a row separator header, they will be interpreted as plain column:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | --
|
||||
// -- | --
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>--</td>
|
||||
// <td>--</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n-- | --\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>--</td>\n<td>--</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// But if a table doesn't start with a column delimiter, it is not interpreted as a table, even if following lines have a column delimiter
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a b
|
||||
// c | d
|
||||
// e | f
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>a b
|
||||
// c | d
|
||||
// e | f</p>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a b\nc | d\ne | f", "<p>a b\nc | d\ne | f</p>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// If a line doesn't have a column delimiter `|` the table is not detected
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// c no d
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>a | b
|
||||
// c no d</p>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\nc no d", "<p>a | b\nc no d</p>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// If a row contains more column than the header row, it will still be added as a column:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | --
|
||||
// 0 | 1 | 2
|
||||
// 3 | 4
|
||||
// 5 |
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// <th></th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// <td>2</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>3</td>
|
||||
// <td>4</td>
|
||||
// <td></td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>5</td>
|
||||
// <td></td>
|
||||
// <td></td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 7\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a | b \n-- | --\n0 | 1 | 2\n3 | 4\n5 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n<td>2</td>\n</tr>\n<tr>\n<td>3</td>\n<td>4</td>\n<td></td>\n</tr>\n<tr>\n<td>5</td>\n<td></td>\n<td></td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// **Rule #2**
|
||||
// A pipe table ends after a blank line or the end of the file.
|
||||
//
|
||||
// **Rule #3**
|
||||
// A cell content is trimmed (start and end) from white-spaces.
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b |
|
||||
// -- | --
|
||||
// 0 | 1 |
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 8\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a | b |\n-- | --\n0 | 1 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// **Rule #4**
|
||||
// Column delimiters `|` at the very beginning of a line or just before a line ending with only spaces and/or terminated by a newline can be omitted
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example009()
|
||||
{
|
||||
// Example 9
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b |
|
||||
// -- | --
|
||||
// | 0 | 1
|
||||
// | 2 | 3 |
|
||||
// 4 | 5
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>2</td>
|
||||
// <td>3</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>4</td>
|
||||
// <td>5</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 9\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec(" a | b |\n-- | --\n| 0 | 1\n| 2 | 3 |\n 4 | 5 ", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>2</td>\n<td>3</td>\n</tr>\n<tr>\n<td>4</td>\n<td>5</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// A pipe may be present at both the beginning/ending of each line:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example010()
|
||||
{
|
||||
// Example 10
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// |a|b|
|
||||
// |-|-|
|
||||
// |0|1|
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 10\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("|a|b|\n|-|-|\n|0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// Or may be omitted on one side:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example011()
|
||||
{
|
||||
// Example 11
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a|b|
|
||||
// -|-|
|
||||
// 0|1|
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 11\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a|b|\n-|-|\n0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example012()
|
||||
{
|
||||
// Example 12
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// |a|b
|
||||
// |-|-
|
||||
// |0|1
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 12\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("|a|b\n|-|-\n|0|1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// Single column table can be declared with lines starting only by a column delimiter:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example013()
|
||||
{
|
||||
// Example 13
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// | a
|
||||
// | --
|
||||
// | b
|
||||
// | c
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>b</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>c</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 13\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("| a\n| --\n| b\n| c ", "<table>\n<thead>\n<tr>\n<th>a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b</td>\n</tr>\n<tr>\n<td>c</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// **Rule #5**
|
||||
//
|
||||
// The first row is considered as a **header row** if it is separated from the regular rows by a row containing a **header column separator** for each column. A header column separator is:
|
||||
//
|
||||
// - starting by optional spaces
|
||||
// - followed by an optional `:` to specify left align
|
||||
// - followed by a sequence of at least one `-` character
|
||||
// - followed by an optional `:` to specify right align (or center align if left align is also defined)
|
||||
// - ending by optional spaces
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example014()
|
||||
{
|
||||
// Example 14
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -------|-------
|
||||
// 0 | 1
|
||||
// 2 | 3
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>2</td>
|
||||
// <td>3</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 14\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec(" a | b \n-------|-------\n 0 | 1 \n 2 | 3 ", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>2</td>\n<td>3</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// The text alignment is defined by default to be center for header and left for cells. If the left alignment is applied, it will force the column heading to be left aligned.
|
||||
// There is no way to define a different alignment for heading and cells (apart from the default).
|
||||
// The text alignment can be changed by using the character `:` with the header column separator:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example015()
|
||||
{
|
||||
// Example 15
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b | c
|
||||
// :------|:-------:| ----:
|
||||
// 0 | 1 | 2
|
||||
// 3 | 4 | 5
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th style="text-align: left;">a</th>
|
||||
// <th style="text-align: center;">b</th>
|
||||
// <th style="text-align: right;">c</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td style="text-align: left;">0</td>
|
||||
// <td style="text-align: center;">1</td>
|
||||
// <td style="text-align: right;">2</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td style="text-align: left;">3</td>
|
||||
// <td style="text-align: center;">4</td>
|
||||
// <td style="text-align: right;">5</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 15\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec(" a | b | c \n:------|:-------:| ----:\n 0 | 1 | 2 \n 3 | 4 | 5 ", "<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">a</th>\n<th style=\"text-align: center;\">b</th>\n<th style=\"text-align: right;\">c</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\">0</td>\n<td style=\"text-align: center;\">1</td>\n<td style=\"text-align: right;\">2</td>\n</tr>\n<tr>\n<td style=\"text-align: left;\">3</td>\n<td style=\"text-align: center;\">4</td>\n<td style=\"text-align: right;\">5</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// Test alignment with starting and ending pipes:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example016()
|
||||
{
|
||||
// Example 16
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// | abc | def | ghi |
|
||||
// |:---:|-----|----:|
|
||||
// | 1 | 2 | 3 |
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th style="text-align: center;">abc</th>
|
||||
// <th>def</th>
|
||||
// <th style="text-align: right;">ghi</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td style="text-align: center;">1</td>
|
||||
// <td>2</td>
|
||||
// <td style="text-align: right;">3</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 16\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("| abc | def | ghi |\n|:---:|-----|----:|\n| 1 | 2 | 3 |", "<table>\n<thead>\n<tr>\n<th style=\"text-align: center;\">abc</th>\n<th>def</th>\n<th style=\"text-align: right;\">ghi</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: center;\">1</td>\n<td>2</td>\n<td style=\"text-align: right;\">3</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// The following example shows a non matching header column separator:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example017()
|
||||
{
|
||||
// Example 17
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -------|---x---
|
||||
// 0 | 1
|
||||
// 2 | 3
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>a | b
|
||||
// -------|---x---
|
||||
// 0 | 1
|
||||
// 2 | 3</p>
|
||||
|
||||
Console.WriteLine("Example 17\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec(" a | b\n-------|---x---\n 0 | 1\n 2 | 3 ", "<p>a | b\n-------|---x---\n0 | 1\n2 | 3</p> ", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// **Rule #6**
|
||||
//
|
||||
// A column delimiter has a higher priority than emphasis delimiter
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example018()
|
||||
{
|
||||
// Example 18
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// *a* | b
|
||||
// ----- |-----
|
||||
// 0 | _1_
|
||||
// _2 | 3*
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th><em>a</em></th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td><em>1</em></td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>_2</td>
|
||||
// <td>3*</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 18\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec(" *a* | b\n----- |-----\n 0 | _1_\n _2 | 3* ", "<table>\n<thead>\n<tr>\n<th><em>a</em></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td><em>1</em></td>\n</tr>\n<tr>\n<td>_2</td>\n<td>3*</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// **Rule #7**
|
||||
//
|
||||
// A backtick/code delimiter has a higher precedence than a column delimiter `|`:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example019()
|
||||
{
|
||||
// Example 19
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b `
|
||||
// 0 | `
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>a | b <code>0 |</code></p>
|
||||
|
||||
Console.WriteLine("Example 19\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a | b `\n0 | ` ", "<p>a | b <code>0 |</code></p> ", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// **Rule #8**
|
||||
//
|
||||
// A HTML inline has a higher precedence than a column delimiter `|`:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example020()
|
||||
{
|
||||
// Example 20
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a <a href="" title="|"></a> | b
|
||||
// -- | --
|
||||
// 0 | 1
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a <a href="" title="|"></a></th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 20\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a <a href=\"\" title=\"|\"></a> | b\n-- | --\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a <a href=\"\" title=\"|\"></a></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// **Rule #9**
|
||||
//
|
||||
// Links have a higher precedence than the column delimiter character `|`:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example021()
|
||||
{
|
||||
// Example 21
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | --
|
||||
// [This is a link with a | inside the label](http://google.com) | 1
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td><a href="http://google.com">This is a link with a | inside the label</a></td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 21\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n-- | --\n[This is a link with a | inside the label](http://google.com) | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><a href=\"http://google.com\">This is a link with a | inside the label</a></td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// **Rule #10**
|
||||
//
|
||||
// It is possible to have a single row header only:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example022()
|
||||
{
|
||||
// Example 22
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | --
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 22\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example023()
|
||||
{
|
||||
// Example 23
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// |a|b|c
|
||||
// |---|---|---|
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// <th>c</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 23\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("|a|b|c\n|---|---|---|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n</tr>\n</thead>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// **Tests**
|
||||
//
|
||||
// Tests trailing spaces after pipes
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example024()
|
||||
{
|
||||
// Example 24
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// | abc | def |
|
||||
// |---|---|
|
||||
// | cde| ddd|
|
||||
// | eee| fff|
|
||||
// | fff | fffff |
|
||||
// |gggg | ffff |
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>abc</th>
|
||||
// <th>def</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>cde</td>
|
||||
// <td>ddd</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>eee</td>
|
||||
// <td>fff</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>fff</td>
|
||||
// <td>fffff</td>
|
||||
// </tr>
|
||||
// <tr>
|
||||
// <td>gggg</td>
|
||||
// <td>ffff</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 24\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("| abc | def | \n|---|---|\n| cde| ddd| \n| eee| fff|\n| fff | fffff | \n|gggg | ffff | ", "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>cde</td>\n<td>ddd</td>\n</tr>\n<tr>\n<td>eee</td>\n<td>fff</td>\n</tr>\n<tr>\n<td>fff</td>\n<td>fffff</td>\n</tr>\n<tr>\n<td>gggg</td>\n<td>ffff</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// **Normalized columns count**
|
||||
//
|
||||
// The tables are normalized to the maximum number of columns found in a table
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example025()
|
||||
{
|
||||
// Example 25
|
||||
// Section: Extensions / Pipe Table
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | -
|
||||
// 0 | 1 | 2
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// <th></th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// <td>2</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 25\nSection Extensions / Pipe Table\n");
|
||||
TestParser.TestSpec("a | b\n-- | - \n0 | 1 | 2", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n<td>2</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ This section describes the different extensions supported:
|
||||
A pipe table is detected when:
|
||||
|
||||
**Rule #1**
|
||||
- Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backstick \`) or a HTML inline.
|
||||
- Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backtick \`) or a HTML inline.
|
||||
- The second row must separate the first header row from sub-sequent rows by containing a **header column separator** for each column separated by a column delimiter. A header column separator is:
|
||||
- starting by optional spaces
|
||||
- followed by an optional `:` to specify left align
|
||||
@@ -122,7 +122,7 @@ c no d
|
||||
c no d</p>
|
||||
````````````````````````````````
|
||||
|
||||
The number of columns in the first row determine the number of columns for the whole table. Any extra columns delimiter `|` for sub-sequent lines are converted to literal strings instead:
|
||||
If a row contains more column than the header row, it will still be added as a column:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
@@ -136,19 +136,24 @@ a | b
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1 | 2</td>
|
||||
<td>1</td>
|
||||
<td>2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>4</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>5</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -214,6 +219,76 @@ Column delimiters `|` at the very beginning of a line or just before a line endi
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
A pipe may be present at both the beginning/ending of each line:
|
||||
|
||||
```````````````````````````````` example
|
||||
|a|b|
|
||||
|-|-|
|
||||
|0|1|
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
Or may be omitted on one side:
|
||||
|
||||
```````````````````````````````` example
|
||||
a|b|
|
||||
-|-|
|
||||
0|1|
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
|a|b
|
||||
|-|-
|
||||
|0|1
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
|
||||
Single column table can be declared with lines starting only by a column delimiter:
|
||||
|
||||
```````````````````````````````` example
|
||||
@@ -275,7 +350,8 @@ The first row is considered as a **header row** if it is separated from the regu
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
The text alignment is defined by default to be left.
|
||||
The text alignment is defined by default to be center for header and left for cells. If the left alignment is applied, it will force the column heading to be left aligned.
|
||||
There is no way to define a different alignment for heading and cells (apart from the default).
|
||||
The text alignment can be changed by using the character `:` with the header column separator:
|
||||
|
||||
```````````````````````````````` example
|
||||
@@ -287,19 +363,19 @@ The text alignment can be changed by using the character `:` with the header col
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th style="text-align: left;">a</th>
|
||||
<th style="text-align: center;">b</th>
|
||||
<th style="text-align: right;">c</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td style="text-align: left;">0</td>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td style="text-align: right;">2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td style="text-align: left;">3</td>
|
||||
<td style="text-align: center;">4</td>
|
||||
<td style="text-align: right;">5</td>
|
||||
</tr>
|
||||
@@ -307,6 +383,31 @@ The text alignment can be changed by using the character `:` with the header col
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
Test alignment with starting and ending pipes:
|
||||
|
||||
```````````````````````````````` example
|
||||
| abc | def | ghi |
|
||||
|:---:|-----|----:|
|
||||
| 1 | 2 | 3 |
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align: center;">abc</th>
|
||||
<th>def</th>
|
||||
<th style="text-align: right;">ghi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align: center;">1</td>
|
||||
<td>2</td>
|
||||
<td style="text-align: right;">3</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
The following example shows a non matching header column separator:
|
||||
|
||||
```````````````````````````````` example
|
||||
@@ -353,7 +454,7 @@ A column delimiter has a higher priority than emphasis delimiter
|
||||
|
||||
**Rule #7**
|
||||
|
||||
A backstick/code delimiter has a higher precedence than a column delimiter `|`:
|
||||
A backtick/code delimiter has a higher precedence than a column delimiter `|`:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b `
|
||||
@@ -362,7 +463,7 @@ a | b `
|
||||
<p>a | b <code>0 |</code></p>
|
||||
````````````````````````````````
|
||||
|
||||
**Rule #7**
|
||||
**Rule #8**
|
||||
|
||||
A HTML inline has a higher precedence than a column delimiter `|`:
|
||||
|
||||
@@ -387,7 +488,7 @@ a <a href="" title="|"></a> | b
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Rule #8**
|
||||
**Rule #9**
|
||||
|
||||
Links have a higher precedence than the column delimiter character `|`:
|
||||
|
||||
@@ -412,3 +513,103 @@ a | b
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Rule #10**
|
||||
|
||||
It is possible to have a single row header only:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-- | --
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
|a|b|c
|
||||
|---|---|---|
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
<th>c</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Tests**
|
||||
|
||||
Tests trailing spaces after pipes
|
||||
|
||||
```````````````````````````````` example
|
||||
| abc | def |
|
||||
|---|---|
|
||||
| cde| ddd|
|
||||
| eee| fff|
|
||||
| fff | fffff |
|
||||
|gggg | ffff |
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>abc</th>
|
||||
<th>def</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>cde</td>
|
||||
<td>ddd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>eee</td>
|
||||
<td>fff</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>fff</td>
|
||||
<td>fffff</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>gggg</td>
|
||||
<td>ffff</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
**Normalized columns count**
|
||||
|
||||
The tables are normalized to the maximum number of columns found in a table
|
||||
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-- | -
|
||||
0 | 1 | 2
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>2</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
369
src/Markdig.Tests/Specs/SmartyPantsSpecs.generated.cs
Normal file
369
src/Markdig.Tests/Specs/SmartyPantsSpecs.generated.cs
Normal file
@@ -0,0 +1,369 @@
|
||||
// Generated: 2019-08-01 12:33:23
|
||||
|
||||
// --------------------------------
|
||||
// Smarty Pants
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.SmartyPants
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// Adds support for smarty pants:
|
||||
//
|
||||
// ## SmartyPants Quotes
|
||||
//
|
||||
// Converts the following character to smarty pants:
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a "text"
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a “text”</p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("This is a \"text\"", "<p>This is a “text”</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a 'text'
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a ‘text’</p>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("This is a 'text'", "<p>This is a ‘text’</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a <<text>>
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a «text»</p>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("This is a <<text>>", "<p>This is a «text»</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
// Unbalanced quotes are not changed:
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a "text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a "text</p>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("This is a \"text", "<p>This is a "text</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a 'text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a 'text</p>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("This is a 'text", "<p>This is a 'text</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a <<text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <<text</p>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("This is a <<text", "<p>This is a <<text</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
// Unbalanced quotes inside other quotes are not changed:
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a "text 'with" a another text'
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a “text 'with” a another text'</p>
|
||||
|
||||
Console.WriteLine("Example 7\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("This is a \"text 'with\" a another text'", "<p>This is a “text 'with” a another text'</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is 'a "text 'with" a another text'
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is ‘a “text 'with” a another text’</p>
|
||||
|
||||
Console.WriteLine("Example 8\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("This is 'a \"text 'with\" a another text'", "<p>This is ‘a “text 'with” a another text’</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example009()
|
||||
{
|
||||
// Example 9
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a 'text <<with' a another text>>
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a ‘text <<with’ a another text>></p>
|
||||
|
||||
Console.WriteLine("Example 9\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("This is a 'text <<with' a another text>>", "<p>This is a ‘text <<with’ a another text>></p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example010()
|
||||
{
|
||||
// Example 10
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a <<text 'with>> a another text'
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a «text 'with» a another text'</p>
|
||||
|
||||
Console.WriteLine("Example 10\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("This is a <<text 'with>> a another text'", "<p>This is a «text 'with» a another text'</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
// Quotes requires to have the same rules than emphasis `_` regarding left/right frankling rules:
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example011()
|
||||
{
|
||||
// Example 11
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// It's not quotes'
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>It's not quotes'</p>
|
||||
|
||||
Console.WriteLine("Example 11\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("It's not quotes'", "<p>It's not quotes'</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example012()
|
||||
{
|
||||
// Example 12
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// They are ' not matching quotes '
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>They are ' not matching quotes '</p>
|
||||
|
||||
Console.WriteLine("Example 12\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("They are ' not matching quotes '", "<p>They are ' not matching quotes '</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example013()
|
||||
{
|
||||
// Example 13
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// They are' not matching 'quotes
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>They are' not matching 'quotes</p>
|
||||
|
||||
Console.WriteLine("Example 13\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("They are' not matching 'quotes", "<p>They are' not matching 'quotes</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
// An emphasis starting inside left/right quotes will span over the right quote:
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example014()
|
||||
{
|
||||
// Example 14
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is "a *text" with an emphasis*
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is “a <em>text” with an emphasis</em></p>
|
||||
|
||||
Console.WriteLine("Example 14\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("This is \"a *text\" with an emphasis*", "<p>This is “a <em>text” with an emphasis</em></p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
// Multiple sets of quotes can be used
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsQuotes_Example015()
|
||||
{
|
||||
// Example 15
|
||||
// Section: Extensions / SmartyPants Quotes
|
||||
//
|
||||
// The following Markdown:
|
||||
// "aaa" "bbb" "ccc" "ddd"
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>“aaa” “bbb” “ccc” “ddd”</p>
|
||||
|
||||
Console.WriteLine("Example 15\nSection Extensions / SmartyPants Quotes\n");
|
||||
TestParser.TestSpec("\"aaa\" \"bbb\" \"ccc\" \"ddd\"", "<p>“aaa” “bbb” “ccc” “ddd”</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsSmartyPantsSeparators
|
||||
{
|
||||
// ## SmartyPants Separators
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsSeparators_Example016()
|
||||
{
|
||||
// Example 16
|
||||
// Section: Extensions / SmartyPants Separators
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a -- text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a – text</p>
|
||||
|
||||
Console.WriteLine("Example 16\nSection Extensions / SmartyPants Separators\n");
|
||||
TestParser.TestSpec("This is a -- text", "<p>This is a – text</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsSeparators_Example017()
|
||||
{
|
||||
// Example 17
|
||||
// Section: Extensions / SmartyPants Separators
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a --- text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a — text</p>
|
||||
|
||||
Console.WriteLine("Example 17\nSection Extensions / SmartyPants Separators\n");
|
||||
TestParser.TestSpec("This is a --- text", "<p>This is a — text</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsSeparators_Example018()
|
||||
{
|
||||
// Example 18
|
||||
// Section: Extensions / SmartyPants Separators
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a en ellipsis...
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a en ellipsis…</p>
|
||||
|
||||
Console.WriteLine("Example 18\nSection Extensions / SmartyPants Separators\n");
|
||||
TestParser.TestSpec("This is a en ellipsis...", "<p>This is a en ellipsis…</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
// Check that a smartypants are not breaking pipetable parsing:
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsSeparators_Example019()
|
||||
{
|
||||
// Example 19
|
||||
// Section: Extensions / SmartyPants Separators
|
||||
//
|
||||
// The following Markdown:
|
||||
// a | b
|
||||
// -- | --
|
||||
// 0 | 1
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>a</th>
|
||||
// <th>b</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// <tr>
|
||||
// <td>0</td>
|
||||
// <td>1</td>
|
||||
// </tr>
|
||||
// </tbody>
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 19\nSection Extensions / SmartyPants Separators\n");
|
||||
TestParser.TestSpec("a | b\n-- | --\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
|
||||
// Check quotes and dash:
|
||||
[Test]
|
||||
public void ExtensionsSmartyPantsSeparators_Example020()
|
||||
{
|
||||
// Example 20
|
||||
// Section: Extensions / SmartyPants Separators
|
||||
//
|
||||
// The following Markdown:
|
||||
// A "quote" with a ---
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>A “quote” with a —</p>
|
||||
|
||||
Console.WriteLine("Example 20\nSection Extensions / SmartyPants Separators\n");
|
||||
TestParser.TestSpec("A \"quote\" with a ---", "<p>A “quote” with a —</p>", "pipetables+smartypants|advanced+smartypants");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,12 @@ This is a "text 'with" a another text'
|
||||
<p>This is a “text 'with” a another text'</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is 'a "text 'with" a another text'
|
||||
.
|
||||
<p>This is ‘a “text 'with” a another text’</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a 'text <<with' a another text>>
|
||||
.
|
||||
@@ -83,29 +89,6 @@ They are' not matching 'quotes
|
||||
.
|
||||
<p>They are' not matching 'quotes</p>
|
||||
````````````````````````````````
|
||||
|
||||
Double quotes using ``` `` ``` are working if they match another `''` pair, and there is no other double quotes on the line (otherwise they would be parsed as a code span):
|
||||
|
||||
```````````````````````````````` example
|
||||
This is ``a double quote''
|
||||
.
|
||||
<p>This is “a double quote”</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is ``a code span''``
|
||||
.
|
||||
<p>This is <code>a code span''</code></p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
hello ``there```
|
||||
test
|
||||
.
|
||||
<p>hello “there”`
|
||||
test</p>
|
||||
````````````````````````````````
|
||||
|
||||
An emphasis starting inside left/right quotes will span over the right quote:
|
||||
|
||||
```````````````````````````````` example
|
||||
@@ -114,6 +97,14 @@ This is "a *text" with an emphasis*
|
||||
<p>This is “a <em>text” with an emphasis</em></p>
|
||||
````````````````````````````````
|
||||
|
||||
Multiple sets of quotes can be used
|
||||
|
||||
```````````````````````````````` example
|
||||
"aaa" "bbb" "ccc" "ddd"
|
||||
.
|
||||
<p>“aaa” “bbb” “ccc” “ddd”</p>
|
||||
````````````````````````````````
|
||||
|
||||
## SmartyPants Separators
|
||||
|
||||
```````````````````````````````` example
|
||||
@@ -133,3 +124,36 @@ This is a en ellipsis...
|
||||
.
|
||||
<p>This is a en ellipsis…</p>
|
||||
````````````````````````````````
|
||||
|
||||
Check that a smartypants are not breaking pipetable parsing:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b
|
||||
-- | --
|
||||
0 | 1
|
||||
.
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
Check quotes and dash:
|
||||
|
||||
```````````````````````````````` example
|
||||
A "quote" with a ---
|
||||
.
|
||||
<p>A “quote” with a —</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,334 +0,0 @@
|
||||
<#/*
|
||||
Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
This file is licensed under the BSD-Clause 2 license.
|
||||
See the license.txt file in the project root for more information.The MIT License (MIT)
|
||||
|
||||
This is a modified version of code released previously with the following license:
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2014 Morten Houston Ludvigsen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/#>
|
||||
<#@ template debug="false" hostspecific="true" language="C#" #>
|
||||
<#@ assembly name="System.Core" #>
|
||||
<#@ import namespace="System.Globalization" #>
|
||||
<#@ import namespace="System.IO" #>
|
||||
<#@ import namespace="System.Linq" #>
|
||||
<#@ import namespace="System.Text" #>
|
||||
<#@ import namespace="System.Text.RegularExpressions" #>
|
||||
<#@ import namespace="System.Collections.Generic" #>
|
||||
<#@ import namespace="System.CodeDom" #>
|
||||
<#@ import namespace="System.CodeDom.Compiler" #>
|
||||
<#@ output extension=".cs" #><#
|
||||
var specFiles = new KeyValuePair<string, string>[] {
|
||||
new KeyValuePair<string, string>("https://raw.githubusercontent.com/jgm/CommonMark/master/spec.txt", string.Empty),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("PipeTableSpecs.md"), "pipetables"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("FootnotesSpecs.md"), "footnotes"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("GenericAttributesSpecs.md"), "attributes"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("EmphasisExtraSpecs.md"), "emphasisextras"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("HardlineBreakSpecs.md"), "hardlinebreak"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("GridTableSpecs.md"), "gridtables"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("CustomContainerSpecs.md"), "customcontainers+attributes"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("DefinitionListSpecs.md"), "definitionlists+attributes"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("EmojiSpecs.md"), "emojis"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("AbbreviationSpecs.md"), "abbreviations"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("ListExtraSpecs.md"), "listextras"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("FigureFooterAndCiteSpecs.md"), "figures+footers+citations"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("MathSpecs.md"), "mathematics"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("BootstrapSpecs.md"), "bootstrap+pipetables+figures+attributes"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("MediaSpecs.md"), "medialinks"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("SmartyPantsSpecs.md"), "smartypants"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("AutoIdentifierSpecs.md"), "autoidentifiers"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("TaskListSpecs.md"), "tasklists"),
|
||||
};
|
||||
var emptyLines = false;
|
||||
var displayEmptyLines = false;
|
||||
#>
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
<#
|
||||
foreach (var specFileItem in specFiles)
|
||||
{
|
||||
var specFile = specFileItem.Key;
|
||||
foreach (var item in ReadSpecs(specFile))
|
||||
{
|
||||
if (item is string)
|
||||
{
|
||||
var line = (string)item;
|
||||
if (line == "")
|
||||
{
|
||||
emptyLines = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (emptyLines && displayEmptyLines)
|
||||
{
|
||||
#>
|
||||
//
|
||||
<#
|
||||
}
|
||||
#>
|
||||
// <#= line #>
|
||||
<#
|
||||
displayEmptyLines = true;
|
||||
emptyLines = false;
|
||||
}
|
||||
}
|
||||
if (item is Spec)
|
||||
{
|
||||
var spec = (Spec)item;
|
||||
emptyLines = false;
|
||||
displayEmptyLines = false;
|
||||
#>
|
||||
[TestFixture]
|
||||
public partial class Test<#= spec.SecHeadingCompact #>
|
||||
{
|
||||
[Test]
|
||||
public void <#= spec.Name #>()
|
||||
{
|
||||
// Example <#= spec.Example #>
|
||||
// Section: <#= spec.SecHeading #>
|
||||
//
|
||||
// The following CommonMark:
|
||||
<#= string.Join(Environment.NewLine, spec.CommonMark.Split('\n').Select(s => string.Format(" // {0}", s))) #>
|
||||
//
|
||||
// Should be rendered as:
|
||||
<#= string.Join(Environment.NewLine, spec.Html.Split('\n').Select(s => string.Format(" // {0}", s))) #>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, <#= spec.Example #>, "<#= Escape(spec.SecHeading) #>");
|
||||
TestParser.TestSpec("<#= Escape(spec.CommonMark) #>", "<#= Escape(spec.Html) #>", "<#= Escape(specFileItem.Value) #>");
|
||||
}
|
||||
}
|
||||
<#
|
||||
}
|
||||
}
|
||||
}
|
||||
#>
|
||||
}
|
||||
<#+
|
||||
private class Item
|
||||
{
|
||||
}
|
||||
|
||||
private class Spec
|
||||
{
|
||||
public int Example { get; set; }
|
||||
public int Number { get; set; }
|
||||
public string SecHeading { get; set; }
|
||||
public string SecHeadingCompact {get; set;}
|
||||
public string SectionId { get; set; }
|
||||
public string CommonMark { get; set; }
|
||||
public string Html { get; set; }
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return string.Format("Example{0:000}", Example); }
|
||||
}
|
||||
}
|
||||
|
||||
private bool Match(string value, string pattern, out string[] groups)
|
||||
{
|
||||
var match = Regex.Match(value, pattern);
|
||||
if (match.Success)
|
||||
{
|
||||
groups = match.Groups.Cast<Group>().Select(g => g.Value).ToArray();
|
||||
return true;
|
||||
}
|
||||
groups = new string[] { };
|
||||
return false;
|
||||
}
|
||||
|
||||
private string GetSectionId(IEnumerable<string> sectionHeadings)
|
||||
{
|
||||
var name = string.Join("", sectionHeadings.Select(s => CultureInfo.InvariantCulture.TextInfo.ToTitleCase(s)));
|
||||
name = Regex.Replace(name, @"\s+", "");
|
||||
return name;
|
||||
}
|
||||
|
||||
private IEnumerable<object> ReadSpecs(string fileName)
|
||||
{
|
||||
var stage = 0;
|
||||
var commonMark = "";
|
||||
var html = "";
|
||||
var example = 0;
|
||||
var lineNum = 0;
|
||||
var exampleLine = 0;
|
||||
var sectionNums = new List<int>();
|
||||
var sectionHeadings = new Stack<string>();
|
||||
var sectionHeading = "";
|
||||
var groups = new string[] { };
|
||||
var line = "";
|
||||
var sectionSpecNumbers = new Dictionary<string, int>();
|
||||
var endOfTests = false;
|
||||
|
||||
string content;
|
||||
if (fileName.StartsWith("http"))
|
||||
{
|
||||
using (var client = new System.Net.WebClient() { Encoding = Encoding.UTF8 })
|
||||
content = client.DownloadString(fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
content = File.ReadAllText(fileName);
|
||||
}
|
||||
|
||||
using (var reader = new StringReader(content))
|
||||
{
|
||||
while (!endOfTests && (line = reader.ReadLine()) != null)
|
||||
{
|
||||
lineNum += 1;
|
||||
|
||||
if (stage == 0 && line == "```````````````````````````````` example")
|
||||
{
|
||||
stage = 1; // parse markdown
|
||||
exampleLine = lineNum;
|
||||
}
|
||||
else if (stage == 1 && line == ".")
|
||||
{
|
||||
stage = 2;
|
||||
}
|
||||
else if (stage == 2 && line == "````````````````````````````````")
|
||||
{
|
||||
stage = 0;
|
||||
|
||||
var sectionId = GetSectionId(sectionHeadings.Reverse());
|
||||
if (sectionSpecNumbers.ContainsKey(sectionId))
|
||||
{
|
||||
sectionSpecNumbers[sectionId] += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sectionSpecNumbers[sectionId] = 1;
|
||||
}
|
||||
|
||||
var heading = string.Join(" ", sectionHeadings.Reverse()).Replace("\\","\\\\");
|
||||
var headingCompact = Regex.Replace(heading, "[^A-Za-z0-9]+", string.Empty);
|
||||
example++;
|
||||
yield return new Spec
|
||||
{
|
||||
Example = example,
|
||||
Number = sectionSpecNumbers[sectionId],
|
||||
SecHeading = heading,
|
||||
SecHeadingCompact = headingCompact,
|
||||
SectionId = sectionId,
|
||||
CommonMark = commonMark,
|
||||
Html = html
|
||||
};
|
||||
commonMark = "";
|
||||
html = "";
|
||||
}
|
||||
else if (stage == 0 && line == "<!-- END TESTS -->")
|
||||
{
|
||||
endOfTests = true;
|
||||
}
|
||||
else if (stage == 0 && Match(line, "^(#+) +(.*)", out groups))
|
||||
{
|
||||
var sectionLevel = groups[1].Length;
|
||||
sectionHeading = groups[2];
|
||||
|
||||
while (sectionHeadings.Count() < sectionLevel)
|
||||
{
|
||||
sectionHeadings.Push("");
|
||||
}
|
||||
while (sectionHeadings.Count() >= sectionLevel)
|
||||
{
|
||||
sectionHeadings.Pop();
|
||||
}
|
||||
sectionHeadings.Push(sectionHeading);
|
||||
|
||||
if (sectionNums.Count > 0 && sectionNums.Count == sectionLevel - 1)
|
||||
{
|
||||
sectionNums[sectionNums.Count - 1]++;
|
||||
}
|
||||
else if (sectionNums.Count > sectionLevel - 1)
|
||||
{
|
||||
sectionNums = Enumerable.Range(0, sectionLevel).ToList();
|
||||
sectionNums[sectionNums.Count - 1]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (sectionNums.Count < sectionLevel - 1)
|
||||
{
|
||||
sectionNums.Add(1);
|
||||
}
|
||||
}
|
||||
|
||||
yield return line.Trim();
|
||||
}
|
||||
else if (stage == 1)
|
||||
{
|
||||
if (commonMark.Length > 0)
|
||||
{
|
||||
commonMark += '\n';
|
||||
}
|
||||
commonMark += line;
|
||||
}
|
||||
else if (stage == 2)
|
||||
{
|
||||
if (html.Length > 0)
|
||||
{
|
||||
html += '\n';
|
||||
}
|
||||
html += line;
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return line.Trim();
|
||||
}
|
||||
}
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
yield return line.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string Escape(string input)
|
||||
{
|
||||
return input
|
||||
.Replace("→", "\t")
|
||||
.Replace("\\", "\\\\")
|
||||
.Replace("\"", "\\\"")
|
||||
.Replace("\0", "\\0")
|
||||
.Replace("\a", "\\a")
|
||||
.Replace("\b", "\\b")
|
||||
.Replace("\f", "\\f")
|
||||
.Replace("\n", "\\n")
|
||||
.Replace("\r", "\\r")
|
||||
.Replace("\t", "\\t")
|
||||
.Replace("\v", "\\v")
|
||||
;
|
||||
}
|
||||
|
||||
private static string ToLiteral(string input)
|
||||
{
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
using (var provider = CodeDomProvider.CreateProvider("CSharp"))
|
||||
{
|
||||
provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
|
||||
return writer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
#>
|
||||
63
src/Markdig.Tests/Specs/TaskListSpecs.generated.cs
Normal file
63
src/Markdig.Tests/Specs/TaskListSpecs.generated.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Task Lists
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.TaskLists
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsTaskLists
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// Adds support for task lists:
|
||||
//
|
||||
// ## TaskLists
|
||||
//
|
||||
// A task list item consist of `[ ]` or `[x]` or `[X]` inside a list item (ordered or unordered)
|
||||
[Test]
|
||||
public void ExtensionsTaskLists_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / TaskLists
|
||||
//
|
||||
// The following Markdown:
|
||||
// - [ ] Item1
|
||||
// - [x] Item2
|
||||
// - [ ] Item3
|
||||
// - Item4
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <ul class="contains-task-list">
|
||||
// <li class="task-list-item"><input disabled="disabled" type="checkbox" /> Item1</li>
|
||||
// <li class="task-list-item"><input disabled="disabled" type="checkbox" checked="checked" /> Item2</li>
|
||||
// <li class="task-list-item"><input disabled="disabled" type="checkbox" /> Item3</li>
|
||||
// <li>Item4</li>
|
||||
// </ul>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / TaskLists\n");
|
||||
TestParser.TestSpec("- [ ] Item1\n- [x] Item2\n- [ ] Item3\n- Item4", "<ul class=\"contains-task-list\">\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" /> Item1</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> Item2</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" /> Item3</li>\n<li>Item4</li>\n</ul>", "tasklists|advanced");
|
||||
}
|
||||
|
||||
// A task is not recognized outside a list item:
|
||||
[Test]
|
||||
public void ExtensionsTaskLists_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / TaskLists
|
||||
//
|
||||
// The following Markdown:
|
||||
// [ ] This is not a task list
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>[ ] This is not a task list</p>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / TaskLists\n");
|
||||
TestParser.TestSpec("[ ] This is not a task list", "<p>[ ] This is not a task list</p>", "tasklists|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,10 @@ A task list item consist of `[ ]` or `[x]` or `[X]` inside a list item (ordered
|
||||
- [ ] Item3
|
||||
- Item4
|
||||
.
|
||||
<ul>
|
||||
<li><input disabled="disabled" type="checkbox" /> Item1</li>
|
||||
<li><input disabled="disabled" type="checkbox" checked="checked" /> Item2</li>
|
||||
<li><input disabled="disabled" type="checkbox" /> Item3</li>
|
||||
<ul class="contains-task-list">
|
||||
<li class="task-list-item"><input disabled="disabled" type="checkbox" /> Item1</li>
|
||||
<li class="task-list-item"><input disabled="disabled" type="checkbox" checked="checked" /> Item2</li>
|
||||
<li class="task-list-item"><input disabled="disabled" type="checkbox" /> Item3</li>
|
||||
<li>Item4</li>
|
||||
</ul>
|
||||
````````````````````````````````
|
||||
|
||||
214
src/Markdig.Tests/Specs/YamlSpecs.generated.cs
Normal file
214
src/Markdig.Tests/Specs/YamlSpecs.generated.cs
Normal file
@@ -0,0 +1,214 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Yaml
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Yaml
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsYAMLFrontmatterDiscard
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// Adds support for YAML frontmatter parsing:
|
||||
//
|
||||
// ## YAML frontmatter discard
|
||||
//
|
||||
// If a frontmatter is present, it will not be rendered:
|
||||
[Test]
|
||||
public void ExtensionsYAMLFrontmatterDiscard_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / YAML frontmatter discard
|
||||
//
|
||||
// The following Markdown:
|
||||
// ---
|
||||
// this: is a frontmatter
|
||||
// ---
|
||||
// This is a text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a text</p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / YAML frontmatter discard\n");
|
||||
TestParser.TestSpec("---\nthis: is a frontmatter\n---\nThis is a text", "<p>This is a text</p>", "yaml");
|
||||
}
|
||||
|
||||
// But if a frontmatter doesn't happen on the first line, it will be parse as regular Markdown content
|
||||
[Test]
|
||||
public void ExtensionsYAMLFrontmatterDiscard_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions / YAML frontmatter discard
|
||||
//
|
||||
// The following Markdown:
|
||||
// This is a text1
|
||||
// ---
|
||||
// this: is a frontmatter
|
||||
// ---
|
||||
// This is a text2
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <h2>This is a text1</h2>
|
||||
// <h2>this: is a frontmatter</h2>
|
||||
// <p>This is a text2</p>
|
||||
|
||||
Console.WriteLine("Example 2\nSection Extensions / YAML frontmatter discard\n");
|
||||
TestParser.TestSpec("This is a text1\n---\nthis: is a frontmatter\n---\nThis is a text2", "<h2>This is a text1</h2>\n<h2>this: is a frontmatter</h2>\n<p>This is a text2</p>", "yaml");
|
||||
}
|
||||
|
||||
// It expects an exact 3 dashes `---`:
|
||||
[Test]
|
||||
public void ExtensionsYAMLFrontmatterDiscard_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions / YAML frontmatter discard
|
||||
//
|
||||
// The following Markdown:
|
||||
// ----
|
||||
// this: is a frontmatter
|
||||
// ----
|
||||
// This is a text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <hr />
|
||||
// <h2>this: is a frontmatter</h2>
|
||||
// <p>This is a text</p>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / YAML frontmatter discard\n");
|
||||
TestParser.TestSpec("----\nthis: is a frontmatter\n----\nThis is a text", "<hr />\n<h2>this: is a frontmatter</h2>\n<p>This is a text</p>", "yaml");
|
||||
}
|
||||
|
||||
// It can end with three dots `...`:
|
||||
[Test]
|
||||
public void ExtensionsYAMLFrontmatterDiscard_Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions / YAML frontmatter discard
|
||||
//
|
||||
// The following Markdown:
|
||||
// ---
|
||||
// this: is a frontmatter
|
||||
//
|
||||
// ...
|
||||
// This is a text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a text</p>
|
||||
|
||||
Console.WriteLine("Example 4\nSection Extensions / YAML frontmatter discard\n");
|
||||
TestParser.TestSpec("---\nthis: is a frontmatter\n\n...\nThis is a text", "<p>This is a text</p>", "yaml");
|
||||
}
|
||||
|
||||
// If the end front matter marker (`...` or `---`) is not present, it will render the `---` has a `<hr>`:
|
||||
[Test]
|
||||
public void ExtensionsYAMLFrontmatterDiscard_Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions / YAML frontmatter discard
|
||||
//
|
||||
// The following Markdown:
|
||||
// ---
|
||||
// this: is a frontmatter
|
||||
// This is a text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <hr />
|
||||
// <p>this: is a frontmatter
|
||||
// This is a text</p>
|
||||
|
||||
Console.WriteLine("Example 5\nSection Extensions / YAML frontmatter discard\n");
|
||||
TestParser.TestSpec("---\nthis: is a frontmatter\nThis is a text", "<hr />\n<p>this: is a frontmatter\nThis is a text</p>", "yaml");
|
||||
}
|
||||
|
||||
// It expects exactly three dots `...`:
|
||||
[Test]
|
||||
public void ExtensionsYAMLFrontmatterDiscard_Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions / YAML frontmatter discard
|
||||
//
|
||||
// The following Markdown:
|
||||
// ---
|
||||
// this: is a frontmatter
|
||||
// ....
|
||||
// This is a text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <hr />
|
||||
// <p>this: is a frontmatter
|
||||
// ....
|
||||
// This is a text</p>
|
||||
|
||||
Console.WriteLine("Example 6\nSection Extensions / YAML frontmatter discard\n");
|
||||
TestParser.TestSpec("---\nthis: is a frontmatter\n....\nThis is a text", "<hr />\n<p>this: is a frontmatter\n....\nThis is a text</p>", "yaml");
|
||||
}
|
||||
|
||||
// Front matter ends with the first line containing three dots `...` or three dashes `---`:
|
||||
[Test]
|
||||
public void ExtensionsYAMLFrontmatterDiscard_Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Extensions / YAML frontmatter discard
|
||||
//
|
||||
// The following Markdown:
|
||||
// ---
|
||||
// this: is a frontmatter
|
||||
// ....
|
||||
//
|
||||
// Hello
|
||||
// ---
|
||||
// This is a text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a text</p>
|
||||
|
||||
Console.WriteLine("Example 7\nSection Extensions / YAML frontmatter discard\n");
|
||||
TestParser.TestSpec("---\nthis: is a frontmatter\n....\n\nHello\n---\nThis is a text", "<p>This is a text</p>", "yaml");
|
||||
}
|
||||
|
||||
// It expects whitespace can exist after the leading characters
|
||||
[Test]
|
||||
public void ExtensionsYAMLFrontmatterDiscard_Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Extensions / YAML frontmatter discard
|
||||
//
|
||||
// The following Markdown:
|
||||
// ---
|
||||
// this: is a frontmatter
|
||||
// ...
|
||||
// This is a text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a text</p>
|
||||
|
||||
Console.WriteLine("Example 8\nSection Extensions / YAML frontmatter discard\n");
|
||||
TestParser.TestSpec("--- \nthis: is a frontmatter\n...\nThis is a text", "<p>This is a text</p>", "yaml");
|
||||
}
|
||||
|
||||
// It expects whitespace can exist after the trailing characters
|
||||
[Test]
|
||||
public void ExtensionsYAMLFrontmatterDiscard_Example009()
|
||||
{
|
||||
// Example 9
|
||||
// Section: Extensions / YAML frontmatter discard
|
||||
//
|
||||
// The following Markdown:
|
||||
// ---
|
||||
// this: is a frontmatter
|
||||
// ...
|
||||
// This is a text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a text</p>
|
||||
|
||||
Console.WriteLine("Example 9\nSection Extensions / YAML frontmatter discard\n");
|
||||
TestParser.TestSpec("---\nthis: is a frontmatter\n... \nThis is a text", "<p>This is a text</p>", "yaml");
|
||||
}
|
||||
}
|
||||
}
|
||||
120
src/Markdig.Tests/Specs/YamlSpecs.md
Normal file
120
src/Markdig.Tests/Specs/YamlSpecs.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Extensions
|
||||
|
||||
Adds support for YAML frontmatter parsing:
|
||||
|
||||
## YAML frontmatter discard
|
||||
|
||||
If a frontmatter is present, it will not be rendered:
|
||||
|
||||
```````````````````````````````` example
|
||||
---
|
||||
this: is a frontmatter
|
||||
---
|
||||
This is a text
|
||||
.
|
||||
<p>This is a text</p>
|
||||
````````````````````````````````
|
||||
|
||||
But if a frontmatter doesn't happen on the first line, it will be parse as regular Markdown content
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a text1
|
||||
---
|
||||
this: is a frontmatter
|
||||
---
|
||||
This is a text2
|
||||
.
|
||||
<h2>This is a text1</h2>
|
||||
<h2>this: is a frontmatter</h2>
|
||||
<p>This is a text2</p>
|
||||
````````````````````````````````
|
||||
|
||||
It expects an exact 3 dashes `---`:
|
||||
|
||||
```````````````````````````````` example
|
||||
----
|
||||
this: is a frontmatter
|
||||
----
|
||||
This is a text
|
||||
.
|
||||
<hr />
|
||||
<h2>this: is a frontmatter</h2>
|
||||
<p>This is a text</p>
|
||||
````````````````````````````````
|
||||
|
||||
It can end with three dots `...`:
|
||||
|
||||
```````````````````````````````` example
|
||||
---
|
||||
this: is a frontmatter
|
||||
|
||||
...
|
||||
This is a text
|
||||
.
|
||||
<p>This is a text</p>
|
||||
````````````````````````````````
|
||||
|
||||
If the end front matter marker (`...` or `---`) is not present, it will render the `---` has a `<hr>`:
|
||||
|
||||
```````````````````````````````` example
|
||||
---
|
||||
this: is a frontmatter
|
||||
This is a text
|
||||
.
|
||||
<hr />
|
||||
<p>this: is a frontmatter
|
||||
This is a text</p>
|
||||
````````````````````````````````
|
||||
|
||||
It expects exactly three dots `...`:
|
||||
|
||||
```````````````````````````````` example
|
||||
---
|
||||
this: is a frontmatter
|
||||
....
|
||||
This is a text
|
||||
.
|
||||
<hr />
|
||||
<p>this: is a frontmatter
|
||||
....
|
||||
This is a text</p>
|
||||
````````````````````````````````
|
||||
|
||||
Front matter ends with the first line containing three dots `...` or three dashes `---`:
|
||||
|
||||
```````````````````````````````` example
|
||||
---
|
||||
this: is a frontmatter
|
||||
....
|
||||
|
||||
Hello
|
||||
---
|
||||
This is a text
|
||||
.
|
||||
<p>This is a text</p>
|
||||
````````````````````````````````
|
||||
|
||||
It expects whitespace can exist after the leading characters
|
||||
|
||||
```````````````````````````````` example
|
||||
---
|
||||
this: is a frontmatter
|
||||
...
|
||||
This is a text
|
||||
.
|
||||
<p>This is a text</p>
|
||||
````````````````````````````````
|
||||
|
||||
It expects whitespace can exist after the trailing characters
|
||||
|
||||
```````````````````````````````` example
|
||||
---
|
||||
this: is a frontmatter
|
||||
...
|
||||
This is a text
|
||||
.
|
||||
<p>This is a text</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
|
||||
36
src/Markdig.Tests/Specs/readme.md
Normal file
36
src/Markdig.Tests/Specs/readme.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Documentation Tests/Specs
|
||||
|
||||
You will find from the following links the supported extensions in markdig and their usage:
|
||||
|
||||
- 2 kind of tables:
|
||||
- [**Pipe tables**](PipeTableSpecs.md)
|
||||
- [**Grid tables**](GridTableSpecs.md)
|
||||
- [**Extra emphasis**](EmphasisExtraSpecs.md)
|
||||
- strike through `~~`,
|
||||
- Subscript `~`
|
||||
- Superscript `^`
|
||||
- Inserted `++`
|
||||
- Marked `==`
|
||||
- [**Special attributes**](GenericAttributesSpecs.md)
|
||||
- [**Definition lists**](DefinitionListSpecs.md)
|
||||
- [**Footnotes**](FootnotesSpecs.md)
|
||||
- [**Auto-identifiers**](AutoIdentifierSpecs.md)
|
||||
- [**Auto-links**](AutoLinks.md)
|
||||
- [**Task Lists**](TaskListSpecs.md)
|
||||
- [**Extra bullet lists**](ListExtraSpecs.md)
|
||||
- [**Media support**](MediaSpecs.md)
|
||||
- [**Abbreviations**](AbbreviationSpecs.md)
|
||||
- [**Citation**](FigureFooterAndCiteSpecs.md)
|
||||
- [**Custom containers**](CustomContainerSpecs.md)
|
||||
- [**Figures**](FigureFooterAndCiteSpecs.md)
|
||||
- [**Footers**](FigureFooterAndCiteSpecs.md)
|
||||
- [**Mathematics**](MathSpecs.md)/Latex extension by enclosing `$$` for block and `$` for inline math (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/mathematics-extension/457/31))
|
||||
- [**Soft lines as hard lines**](HardlineBreakSpecs.md)
|
||||
- [**Emoji**](EmojiSpecs.md)
|
||||
- [**SmartyPants**](SmartyPantsSpecs.md)
|
||||
- [**Bootstrap**](BootstrapSpecs.md)
|
||||
- [**Diagrams**](DiagramsSpecs.md)
|
||||
- [**YAML frontmatter**](YamlSpecs.md)
|
||||
- [**JIRA links**](JiraLinks.md)
|
||||
|
||||
> Notice that the links above are not yet the final documentation but are "specification" files used for testing the correctness of markdig for each extension
|
||||
42
src/Markdig.Tests/TestConfigureNewLine.cs
Normal file
42
src/Markdig.Tests/TestConfigureNewLine.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestConfigureNewLine
|
||||
{
|
||||
[Test]
|
||||
[TestCase(/* newLineForWriting: */ "\n", /* markdownText: */ "*1*\n*2*\n", /* expected: */ "<p><em>1</em>\n<em>2</em></p>\n")]
|
||||
[TestCase(/* newLineForWriting: */ "\n", /* markdownText: */ "*1*\r\n*2*\r\n", /* expected: */ "<p><em>1</em>\n<em>2</em></p>\n")]
|
||||
[TestCase(/* newLineForWriting: */ "\r\n", /* markdownText: */ "*1*\n*2*\n", /* expected: */ "<p><em>1</em>\r\n<em>2</em></p>\r\n")]
|
||||
[TestCase(/* newLineForWriting: */ "\r\n", /* markdownText: */ "*1*\r\n*2*\r\n", /* expected: */ "<p><em>1</em>\r\n<em>2</em></p>\r\n")]
|
||||
[TestCase(/* newLineForWriting: */ "!!!" , /* markdownText: */ "*1*\n*2*\n", /* expected: */ "<p><em>1</em>!!!<em>2</em></p>!!!")]
|
||||
[TestCase(/* newLineForWriting: */ "!!!" , /* markdownText: */ "*1*\r\n*2*\r\n", /* expected: */ "<p><em>1</em>!!!<em>2</em></p>!!!")]
|
||||
public void TestHtmlOutputWhenConfiguringNewLine(string newLineForWriting, string markdownText, string expected)
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
.ConfigureNewLine(newLineForWriting)
|
||||
.Build();
|
||||
|
||||
var actual = Markdown.ToHtml(markdownText, pipeline);
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(/* newLineForWriting: */ "\n", /* markdownText: */ "*1*\n*2*\n", /* expected: */ "1\n2\n")]
|
||||
[TestCase(/* newLineForWriting: */ "\n", /* markdownText: */ "*1*\r\n*2*\r\n", /* expected: */ "1\n2\n")]
|
||||
[TestCase(/* newLineForWriting: */ "\r\n", /* markdownText: */ "*1*\n*2*\n", /* expected: */ "1\r\n2\r\n")]
|
||||
[TestCase(/* newLineForWriting: */ "\r\n", /* markdownText: */ "*1*\r\n*2*\r\n", /* expected: */ "1\r\n2\r\n")]
|
||||
[TestCase(/* newLineForWriting: */ "!!!", /* markdownText: */ "*1*\n*2*\n", /* expected: */ "1!!!2!!!")]
|
||||
[TestCase(/* newLineForWriting: */ "!!!", /* markdownText: */ "*1*\r\n*2*\r\n", /* expected: */ "1!!!2!!!")]
|
||||
public void TestPlainOutputWhenConfiguringNewLine(string newLineForWriting, string markdownText, string expected)
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
.ConfigureNewLine(newLineForWriting)
|
||||
.Build();
|
||||
|
||||
var actual = Markdown.ToPlainText(markdownText, pipeline);
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
70
src/Markdig.Tests/TestContainerBlocks.cs
Normal file
70
src/Markdig.Tests/TestContainerBlocks.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using Markdig.Syntax;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
public class TestContainerBlocks
|
||||
{
|
||||
private class MockContainerBlock : ContainerBlock
|
||||
{
|
||||
public MockContainerBlock()
|
||||
: base(null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanBeCleared()
|
||||
{
|
||||
ContainerBlock container = new MockContainerBlock();
|
||||
Assert.AreEqual(0, container.Count);
|
||||
Assert.Null(container.LastChild);
|
||||
|
||||
var paragraph = new ParagraphBlock();
|
||||
Assert.Null(paragraph.Parent);
|
||||
|
||||
container.Add(paragraph);
|
||||
|
||||
Assert.AreEqual(1, container.Count);
|
||||
Assert.AreSame(container, paragraph.Parent);
|
||||
Assert.AreSame(paragraph, container.LastChild);
|
||||
|
||||
container.Clear();
|
||||
|
||||
Assert.AreEqual(0, container.Count);
|
||||
Assert.Null(container.LastChild);
|
||||
Assert.Null(paragraph.Parent);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanBeInsertedInto()
|
||||
{
|
||||
ContainerBlock container = new MockContainerBlock();
|
||||
|
||||
var one = new ParagraphBlock();
|
||||
container.Insert(0, one);
|
||||
Assert.AreEqual(1, container.Count);
|
||||
Assert.AreSame(container[0], one);
|
||||
|
||||
var two = new ParagraphBlock();
|
||||
container.Insert(1, two);
|
||||
Assert.AreEqual(2, container.Count);
|
||||
Assert.AreSame(container[0], one);
|
||||
Assert.AreSame(container[1], two);
|
||||
|
||||
var three = new ParagraphBlock();
|
||||
container.Insert(0, three);
|
||||
Assert.AreEqual(3, container.Count);
|
||||
Assert.AreSame(container[0], three);
|
||||
Assert.AreSame(container[1], one);
|
||||
Assert.AreSame(container[2], two);
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => container.Insert(0, null));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => container.Insert(4, new ParagraphBlock()));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => container.Insert(-1, new ParagraphBlock()));
|
||||
Assert.Throws<ArgumentException>(() => container.Insert(0, one)); // one already has a parent
|
||||
}
|
||||
}
|
||||
}
|
||||
128
src/Markdig.Tests/TestCustomEmojis.cs
Normal file
128
src/Markdig.Tests/TestCustomEmojis.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Markdig.Extensions.Emoji;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestCustomEmojis
|
||||
{
|
||||
[Test]
|
||||
[TestCase(":smiley:", "<p>♥</p>\n")]
|
||||
[TestCase(":confused:", "<p>:confused:</p>\n")] // default emoji does not work
|
||||
[TestCase(":/", "<p>:/</p>\n")] // default smiley does not work
|
||||
public void TestCustomEmoji(string input, string expected)
|
||||
{
|
||||
var emojiToUnicode = new Dictionary<string, string>();
|
||||
var smileyToEmoji = new Dictionary<string, string>();
|
||||
|
||||
emojiToUnicode[":smiley:"] = "♥";
|
||||
|
||||
var customMapping = new EmojiMapping(emojiToUnicode, smileyToEmoji);
|
||||
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
.UseEmojiAndSmiley(customEmojiMapping: customMapping)
|
||||
.Build();
|
||||
|
||||
var actual = Markdown.ToHtml(input, pipeline);
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(":testheart:", "<p>♥</p>\n")]
|
||||
[TestCase("hello", "<p>♥</p>\n")]
|
||||
[TestCase(":confused:", "<p>:confused:</p>\n")] // default emoji does not work
|
||||
[TestCase(":/", "<p>:/</p>\n")] // default smiley does not work
|
||||
public void TestCustomSmiley(string input, string expected)
|
||||
{
|
||||
var emojiToUnicode = new Dictionary<string, string>();
|
||||
var smileyToEmoji = new Dictionary<string, string>();
|
||||
|
||||
emojiToUnicode[":testheart:"] = "♥";
|
||||
smileyToEmoji["hello"] = ":testheart:";
|
||||
|
||||
var customMapping = new EmojiMapping(emojiToUnicode, smileyToEmoji);
|
||||
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
.UseEmojiAndSmiley(customEmojiMapping: customMapping)
|
||||
.Build();
|
||||
|
||||
var actual = Markdown.ToHtml(input, pipeline);
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(":smiley:", "<p>♥</p>\n")]
|
||||
[TestCase(":)", "<p>♥</p>\n")]
|
||||
[TestCase(":confused:", "<p>😕</p>\n")] // default emoji still works
|
||||
[TestCase(":/", "<p>😕</p>\n")] // default smiley still works
|
||||
public void TestOverrideDefaultWithCustomEmoji(string input, string expected)
|
||||
{
|
||||
var emojiToUnicode = EmojiMapping.GetDefaultEmojiShortcodeToUnicode();
|
||||
var smileyToEmoji = EmojiMapping.GetDefaultSmileyToEmojiShortcode();
|
||||
|
||||
emojiToUnicode[":smiley:"] = "♥";
|
||||
|
||||
var customMapping = new EmojiMapping(emojiToUnicode, smileyToEmoji);
|
||||
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
.UseEmojiAndSmiley(customEmojiMapping: customMapping)
|
||||
.Build();
|
||||
|
||||
var actual = Markdown.ToHtml(input, pipeline);
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(":testheart:", "<p>♥</p>\n")]
|
||||
[TestCase("hello", "<p>♥</p>\n")]
|
||||
[TestCase(":confused:", "<p>😕</p>\n")] // default emoji still works
|
||||
[TestCase(":/", "<p>😕</p>\n")] // default smiley still works
|
||||
public void TestOverrideDefaultWithCustomSmiley(string input, string expected)
|
||||
{
|
||||
var emojiToUnicode = EmojiMapping.GetDefaultEmojiShortcodeToUnicode();
|
||||
var smileyToEmoji = EmojiMapping.GetDefaultSmileyToEmojiShortcode();
|
||||
|
||||
emojiToUnicode[":testheart:"] = "♥";
|
||||
smileyToEmoji["hello"] = ":testheart:";
|
||||
|
||||
var customMapping = new EmojiMapping(emojiToUnicode, smileyToEmoji);
|
||||
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
.UseEmojiAndSmiley(customEmojiMapping: customMapping)
|
||||
.Build();
|
||||
|
||||
var actual = Markdown.ToHtml(input, pipeline);
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCustomEmojiValidation()
|
||||
{
|
||||
var emojiToUnicode = new Dictionary<string, string>();
|
||||
var smileyToEmoji = new Dictionary<string, string>();
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => new EmojiMapping(null, smileyToEmoji));
|
||||
Assert.Throws<ArgumentNullException>(() => new EmojiMapping(emojiToUnicode, null));
|
||||
|
||||
emojiToUnicode.Add("null-value", null);
|
||||
Assert.Throws<ArgumentException>(() => new EmojiMapping(emojiToUnicode, smileyToEmoji));
|
||||
emojiToUnicode.Clear();
|
||||
|
||||
smileyToEmoji.Add("null-value", null);
|
||||
Assert.Throws<ArgumentException>(() => new EmojiMapping(emojiToUnicode, smileyToEmoji));
|
||||
smileyToEmoji.Clear();
|
||||
|
||||
smileyToEmoji.Add("foo", "something-that-does-not-exist-in-emojiToUnicode");
|
||||
Assert.Throws<ArgumentException>(() => new EmojiMapping(emojiToUnicode, smileyToEmoji));
|
||||
smileyToEmoji.Clear();
|
||||
|
||||
emojiToUnicode.Add("a", "aaa");
|
||||
emojiToUnicode.Add("b", "bbb");
|
||||
emojiToUnicode.Add("c", "ccc");
|
||||
smileyToEmoji.Add("a", "c"); // "a" already exists in emojiToUnicode
|
||||
Assert.Throws<ArgumentException>(() => new EmojiMapping(emojiToUnicode, smileyToEmoji));
|
||||
}
|
||||
}
|
||||
}
|
||||
153
src/Markdig.Tests/TestDescendantsOrder.cs
Normal file
153
src/Markdig.Tests/TestDescendantsOrder.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using NUnit.Framework;
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestDescendantsOrder
|
||||
{
|
||||
[Test]
|
||||
public void TestSchemas()
|
||||
{
|
||||
foreach (var syntaxTree in TestParser.SpecsSyntaxTrees)
|
||||
{
|
||||
AssertIEnumerablesAreEqual(
|
||||
Descendants_Legacy(syntaxTree),
|
||||
syntaxTree.Descendants());
|
||||
|
||||
AssertIEnumerablesAreEqual(
|
||||
syntaxTree.Descendants().OfType<ParagraphBlock>(),
|
||||
syntaxTree.Descendants<ParagraphBlock>());
|
||||
|
||||
AssertIEnumerablesAreEqual(
|
||||
syntaxTree.Descendants().OfType<ParagraphBlock>(),
|
||||
(syntaxTree as ContainerBlock).Descendants<ParagraphBlock>());
|
||||
|
||||
AssertIEnumerablesAreEqual(
|
||||
syntaxTree.Descendants().OfType<LiteralInline>(),
|
||||
syntaxTree.Descendants<LiteralInline>());
|
||||
|
||||
foreach (LiteralInline literalInline in syntaxTree.Descendants<LiteralInline>())
|
||||
{
|
||||
Assert.AreSame(ArrayHelper.Empty<ListBlock>(), literalInline.Descendants<ListBlock>());
|
||||
Assert.AreSame(ArrayHelper.Empty<ParagraphBlock>(), literalInline.Descendants<ParagraphBlock>());
|
||||
Assert.AreSame(ArrayHelper.Empty<ContainerInline>(), literalInline.Descendants<ContainerInline>());
|
||||
}
|
||||
|
||||
foreach (ContainerInline containerInline in syntaxTree.Descendants<ContainerInline>())
|
||||
{
|
||||
AssertIEnumerablesAreEqual(
|
||||
containerInline.FindDescendants<LiteralInline>(),
|
||||
containerInline.Descendants<LiteralInline>());
|
||||
|
||||
AssertIEnumerablesAreEqual(
|
||||
containerInline.FindDescendants<LiteralInline>(),
|
||||
(containerInline as MarkdownObject).Descendants<LiteralInline>());
|
||||
|
||||
if (containerInline.FirstChild is null)
|
||||
{
|
||||
Assert.AreSame(ArrayHelper.Empty<LiteralInline>(), containerInline.Descendants<LiteralInline>());
|
||||
Assert.AreSame(ArrayHelper.Empty<LiteralInline>(), containerInline.FindDescendants<LiteralInline>());
|
||||
Assert.AreSame(ArrayHelper.Empty<LiteralInline>(), (containerInline as MarkdownObject).Descendants<LiteralInline>());
|
||||
}
|
||||
|
||||
Assert.AreSame(ArrayHelper.Empty<ListBlock>(), containerInline.Descendants<ListBlock>());
|
||||
Assert.AreSame(ArrayHelper.Empty<ParagraphBlock>(), containerInline.Descendants<ParagraphBlock>());
|
||||
}
|
||||
|
||||
foreach (ParagraphBlock paragraphBlock in syntaxTree.Descendants<ParagraphBlock>())
|
||||
{
|
||||
AssertIEnumerablesAreEqual(
|
||||
(paragraphBlock as MarkdownObject).Descendants<LiteralInline>(),
|
||||
paragraphBlock.Descendants<LiteralInline>());
|
||||
|
||||
Assert.AreSame(ArrayHelper.Empty<ParagraphBlock>(), paragraphBlock.Descendants<ParagraphBlock>());
|
||||
}
|
||||
|
||||
foreach (ContainerBlock containerBlock in syntaxTree.Descendants<ContainerBlock>())
|
||||
{
|
||||
AssertIEnumerablesAreEqual(
|
||||
containerBlock.Descendants<LiteralInline>(),
|
||||
(containerBlock as MarkdownObject).Descendants<LiteralInline>());
|
||||
|
||||
AssertIEnumerablesAreEqual(
|
||||
containerBlock.Descendants<ParagraphBlock>(),
|
||||
(containerBlock as MarkdownObject).Descendants<ParagraphBlock>());
|
||||
|
||||
if (containerBlock.Count == 0)
|
||||
{
|
||||
Assert.AreSame(ArrayHelper.Empty<LiteralInline>(), containerBlock.Descendants<LiteralInline>());
|
||||
Assert.AreSame(ArrayHelper.Empty<LiteralInline>(), (containerBlock as Block).Descendants<LiteralInline>());
|
||||
Assert.AreSame(ArrayHelper.Empty<LiteralInline>(), (containerBlock as MarkdownObject).Descendants<LiteralInline>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssertIEnumerablesAreEqual<T>(IEnumerable<T> first, IEnumerable<T> second)
|
||||
{
|
||||
var firstList = new List<T>(first);
|
||||
var secondList = new List<T>(second);
|
||||
|
||||
Assert.AreEqual(firstList.Count, secondList.Count);
|
||||
|
||||
for (int i = 0; i < firstList.Count; i++)
|
||||
{
|
||||
Assert.AreSame(firstList[i], secondList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<MarkdownObject> Descendants_Legacy(MarkdownObject markdownObject)
|
||||
{
|
||||
// TODO: implement a recursiveless method
|
||||
|
||||
var block = markdownObject as ContainerBlock;
|
||||
if (block != null)
|
||||
{
|
||||
foreach (var subBlock in block)
|
||||
{
|
||||
yield return subBlock;
|
||||
|
||||
foreach (var sub in Descendants_Legacy(subBlock))
|
||||
{
|
||||
yield return sub;
|
||||
}
|
||||
|
||||
// Visit leaf block that have inlines
|
||||
var leafBlock = subBlock as LeafBlock;
|
||||
if (leafBlock?.Inline != null)
|
||||
{
|
||||
foreach (var subInline in Descendants_Legacy(leafBlock.Inline))
|
||||
{
|
||||
yield return subInline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var inline = markdownObject as ContainerInline;
|
||||
if (inline != null)
|
||||
{
|
||||
var child = inline.FirstChild;
|
||||
while (child != null)
|
||||
{
|
||||
var next = child.NextSibling;
|
||||
yield return child;
|
||||
|
||||
foreach (var sub in Descendants_Legacy(child))
|
||||
{
|
||||
yield return sub;
|
||||
}
|
||||
|
||||
child = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
168
src/Markdig.Tests/TestEmphasisExtended.cs
Normal file
168
src/Markdig.Tests/TestEmphasisExtended.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using Markdig.Parsers.Inlines;
|
||||
using Markdig.Renderers;
|
||||
using Markdig.Renderers.Html;
|
||||
using Markdig.Syntax.Inlines;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestEmphasisExtended
|
||||
{
|
||||
class EmphasisTestExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
var emphasisParser = pipeline.InlineParsers.Find<EmphasisInlineParser>();
|
||||
Debug.Assert(emphasisParser != null);
|
||||
|
||||
foreach (var emphasis in EmphasisTestDescriptors)
|
||||
{
|
||||
emphasisParser.EmphasisDescriptors.Add(
|
||||
new EmphasisDescriptor(emphasis.Character, emphasis.Minimum, emphasis.Maximum, true));
|
||||
}
|
||||
emphasisParser.TryCreateEmphasisInlineList.Add((delimiterChar, delimiterCount) =>
|
||||
{
|
||||
return delimiterChar == '*' || delimiterChar == '_'
|
||||
? null
|
||||
: new CustomEmphasisInline() { DelimiterChar = delimiterChar, DelimiterCount = delimiterCount };
|
||||
});
|
||||
}
|
||||
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
renderer.ObjectRenderers.Insert(0, new EmphasisRenderer());
|
||||
}
|
||||
|
||||
class EmphasisRenderer : HtmlObjectRenderer<CustomEmphasisInline>
|
||||
{
|
||||
protected override void Write(HtmlRenderer renderer, CustomEmphasisInline obj)
|
||||
{
|
||||
var tag = EmphasisTestDescriptors.First(test => test.Character == obj.DelimiterChar).Tags[obj.DelimiterCount];
|
||||
|
||||
renderer.Write(tag.OpeningTag);
|
||||
renderer.WriteChildren(obj);
|
||||
renderer.Write(tag.ClosingTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
class Tag
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public int Level;
|
||||
#pragma warning restore CS0649
|
||||
public string RawTag;
|
||||
public string OpeningTag;
|
||||
public string ClosingTag;
|
||||
|
||||
public Tag(string tag)
|
||||
{
|
||||
RawTag = tag;
|
||||
OpeningTag = "<" + tag + ">";
|
||||
ClosingTag = "</" + tag + ">";
|
||||
}
|
||||
|
||||
public static implicit operator Tag(string tag)
|
||||
=> new Tag(tag);
|
||||
}
|
||||
class EmphasisTestDescriptor
|
||||
{
|
||||
public char Character;
|
||||
public int Minimum;
|
||||
public int Maximum;
|
||||
public Dictionary<int, Tag> Tags = new Dictionary<int, Tag>();
|
||||
|
||||
private EmphasisTestDescriptor(char character, int min, int max)
|
||||
{
|
||||
Character = character;
|
||||
Minimum = min;
|
||||
Maximum = max;
|
||||
}
|
||||
public EmphasisTestDescriptor(char character, int min, int max, params Tag[] tags)
|
||||
: this(character, min, max)
|
||||
{
|
||||
Debug.Assert(tags.Length == max - min + 1);
|
||||
foreach (var tag in tags)
|
||||
{
|
||||
Tags.Add(min++, tag);
|
||||
}
|
||||
}
|
||||
public EmphasisTestDescriptor(char character, int min, int max, string tag)
|
||||
: this(character, min, max, new Tag(tag)) { }
|
||||
}
|
||||
class CustomEmphasisInline : EmphasisInline { }
|
||||
static readonly EmphasisTestDescriptor[] EmphasisTestDescriptors = new[]
|
||||
{
|
||||
// Min Max
|
||||
new EmphasisTestDescriptor('"', 1, 1, "quotation"),
|
||||
new EmphasisTestDescriptor(',', 1, 2, "comma", "extra-comma"),
|
||||
new EmphasisTestDescriptor('!', 2, 3, "warning", "error"),
|
||||
new EmphasisTestDescriptor('=', 1, 3, "equal", "really-equal", "congruent"),
|
||||
new EmphasisTestDescriptor('1', 1, 1, "one-only"),
|
||||
new EmphasisTestDescriptor('2', 2, 2, "two-only"),
|
||||
new EmphasisTestDescriptor('3', 3, 3, "three-only"),
|
||||
};
|
||||
|
||||
static readonly MarkdownPipeline Pipeline = new MarkdownPipelineBuilder().Use<EmphasisTestExtension>().Build();
|
||||
|
||||
[Test]
|
||||
[TestCase("*foo**", "<em>foo</em>*")]
|
||||
[TestCase("**foo*", "*<em>foo</em>")]
|
||||
[TestCase("***foo***", "<em><strong>foo</strong></em>")]
|
||||
[TestCase("**_foo_**", "<strong><em>foo</em></strong>")]
|
||||
[TestCase("_**foo**_", "<em><strong>foo</strong></em>")]
|
||||
[TestCase("\"foo\"", "<quotation>foo</quotation>")]
|
||||
[TestCase("\"\"foo\"\"", "<quotation><quotation>foo</quotation></quotation>")]
|
||||
[TestCase("\"foo\"\"", "<quotation>foo</quotation>"")]
|
||||
[TestCase("\"\"foo\"", ""<quotation>foo</quotation>")]
|
||||
[TestCase(", foo", ", foo")]
|
||||
[TestCase(", foo,", ", foo,")]
|
||||
[TestCase(",some, foo,", "<comma>some</comma> foo,")]
|
||||
[TestCase(",,foo,,", "<extra-comma>foo</extra-comma>")]
|
||||
[TestCase(",foo,,", "<comma>foo</comma>,")]
|
||||
[TestCase(",,,foo,,,", "<comma><extra-comma>foo</extra-comma></comma>")]
|
||||
[TestCase("!1!", "!1!")]
|
||||
[TestCase("!!2!!", "<warning>2</warning>")]
|
||||
[TestCase("!!!3!!!", "<error>3</error>")]
|
||||
[TestCase("!!!34!!!!", "<error>34</error>!")]
|
||||
[TestCase("!!!!43!!!", "!<error>43</error>")]
|
||||
[TestCase("!!!!44!!!!", "!<error>44!</error>")] // This is a new case - should the second ! be before or after </error>?
|
||||
[TestCase("!!!!!5!!!!!", "<warning><error>5</error></warning>")]
|
||||
[TestCase("!!!!!!6!!!!!!", "<error><error>6</error></error>")]
|
||||
[TestCase("!! !mixed!!!", "!! !mixed!!!")] // can't open the delimiter because of the whitespace
|
||||
[TestCase("=", "=")]
|
||||
[TestCase("==", "==")]
|
||||
[TestCase("====", "====")]
|
||||
[TestCase("=a", "=a")]
|
||||
[TestCase("=a=", "<equal>a</equal>")]
|
||||
[TestCase("==a=", "=<equal>a</equal>")]
|
||||
[TestCase("==a==", "<really-equal>a</really-equal>")]
|
||||
[TestCase("==a===", "<really-equal>a</really-equal>=")]
|
||||
[TestCase("===a===", "<congruent>a</congruent>")]
|
||||
[TestCase("====a====", "<equal><congruent>a</congruent></equal>")]
|
||||
[TestCase("=====a=====", "<really-equal><congruent>a</congruent></really-equal>")]
|
||||
[TestCase("1", "1")]
|
||||
[TestCase("1 1", "1 1")]
|
||||
[TestCase("1Foo1", "<one-only>Foo</one-only>")]
|
||||
[TestCase("1121", "1<one-only>2</one-only>")]
|
||||
[TestCase("22322", "<two-only>3</two-only>")]
|
||||
[TestCase("2232", "2232")]
|
||||
[TestCase("333", "333")]
|
||||
[TestCase("3334333", "<three-only>4</three-only>")]
|
||||
[TestCase("33334333", "3<three-only>4</three-only>")]
|
||||
[TestCase("33343333", "<three-only>4</three-only>3")]
|
||||
[TestCase("122122", "<one-only>22</one-only>22")]
|
||||
[TestCase("221221", "<two-only>1</two-only>1")]
|
||||
[TestCase("122foo221", "<one-only><two-only>foo</two-only></one-only>")]
|
||||
[TestCase("122foo122", "<one-only>22foo</one-only>22")]
|
||||
[TestCase("!!!!!Attention:!! \"==1+1== 2\",but ===333 and 222===, mod 111!!!",
|
||||
"<error><warning>Attention:</warning> <quotation><really-equal><one-only>+</one-only></really-equal> 2</quotation><comma>but <congruent>333 and 222</congruent></comma> mod 111</error>")]
|
||||
public void TestEmphasis(string markdown, string expectedHtml)
|
||||
{
|
||||
TestParser.TestSpec(markdown, "<p>" + expectedHtml + "</p>", Pipeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
45
src/Markdig.Tests/TestEmphasisExtraOptions.cs
Normal file
45
src/Markdig.Tests/TestEmphasisExtraOptions.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using NUnit.Framework;
|
||||
using Markdig.Extensions.EmphasisExtras;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestEmphasisExtraOptions
|
||||
{
|
||||
[Test]
|
||||
public void OnlyStrikethrough_Single()
|
||||
{
|
||||
TestParser.TestSpec("~foo~", "<p>~foo~</p>", new MarkdownPipelineBuilder().UseEmphasisExtras(EmphasisExtraOptions.Strikethrough).Build());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OnlyStrikethrough_Double()
|
||||
{
|
||||
TestParser.TestSpec("~~foo~~", "<p><del>foo</del></p>", new MarkdownPipelineBuilder().UseEmphasisExtras(EmphasisExtraOptions.Strikethrough).Build());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OnlySubscript_Single()
|
||||
{
|
||||
TestParser.TestSpec("~foo~", "<p><sub>foo</sub></p>", new MarkdownPipelineBuilder().UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OnlySubscript_Double()
|
||||
{
|
||||
TestParser.TestSpec("~~foo~~", "<p><sub><sub>foo</sub></sub></p>", new MarkdownPipelineBuilder().UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SubscriptAndStrikethrough_Single()
|
||||
{
|
||||
TestParser.TestSpec("~foo~", "<p><sub>foo</sub></p>", new MarkdownPipelineBuilder().UseEmphasisExtras(EmphasisExtraOptions.Strikethrough | EmphasisExtraOptions.Subscript).Build());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SubscriptAndStrikethrough_Double()
|
||||
{
|
||||
TestParser.TestSpec("~~foo~~", "<p><del>foo</del></p>", new MarkdownPipelineBuilder().UseEmphasisExtras(EmphasisExtraOptions.Strikethrough | EmphasisExtraOptions.Subscript).Build());
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/Markdig.Tests/TestEmphasisPlus.cs
Normal file
23
src/Markdig.Tests/TestEmphasisPlus.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public partial class TestEmphasisPlus
|
||||
{
|
||||
[Test]
|
||||
public void StrongNormal()
|
||||
{
|
||||
TestParser.TestSpec("***Strong emphasis*** normal", "<p><em><strong>Strong emphasis</strong></em> normal</p>", "");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NormalStrongNormal()
|
||||
{
|
||||
TestParser.TestSpec("normal ***Strong emphasis*** normal", "<p>normal <em><strong>Strong emphasis</strong></em> normal</p>", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/Markdig.Tests/TestExceptionNotThrown.cs
Normal file
48
src/Markdig.Tests/TestExceptionNotThrown.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExceptionNotThrown
|
||||
{
|
||||
[Test]
|
||||
public void DoesNotThrowIndexOutOfRangeException1()
|
||||
{
|
||||
Assert.DoesNotThrow(() =>
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
|
||||
Markdown.ToHtml("+-\n|\n+", pipeline);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesNotThrowIndexOutOfRangeException2()
|
||||
{
|
||||
Assert.DoesNotThrow(() =>
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
|
||||
Markdown.ToHtml("+--\n|\n+0", pipeline);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesNotThrowIndexOutOfRangeException3()
|
||||
{
|
||||
Assert.DoesNotThrow(() =>
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
|
||||
Markdown.ToHtml("+-\n|\n+\n0", pipeline);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesNotThrowIndexOutOfRangeException4()
|
||||
{
|
||||
Assert.DoesNotThrow(() =>
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
|
||||
Markdown.ToHtml("+-\n|\n+0", pipeline);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
96
src/Markdig.Tests/TestHtmlAttributes.cs
Normal file
96
src/Markdig.Tests/TestHtmlAttributes.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using Markdig.Renderers.Html;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
[TestFixture()]
|
||||
public class TestHtmlAttributes
|
||||
{
|
||||
[Test]
|
||||
public void TestAddClass()
|
||||
{
|
||||
var attributes = new HtmlAttributes();
|
||||
attributes.AddClass("test");
|
||||
Assert.NotNull(attributes.Classes);
|
||||
Assert.AreEqual(new List<string>() { "test" }, attributes.Classes);
|
||||
|
||||
attributes.AddClass("test");
|
||||
Assert.AreEqual(1, attributes.Classes.Count);
|
||||
|
||||
attributes.AddClass("test1");
|
||||
Assert.AreEqual(new List<string>() { "test", "test1" }, attributes.Classes);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddProperty()
|
||||
{
|
||||
var attributes = new HtmlAttributes();
|
||||
attributes.AddProperty("key1", "1");
|
||||
Assert.NotNull(attributes.Properties);
|
||||
Assert.AreEqual(new List<KeyValuePair<string, string>>() { new KeyValuePair<string, string>("key1", "1") }, attributes.Properties);
|
||||
|
||||
attributes.AddPropertyIfNotExist("key1", "1");
|
||||
Assert.NotNull(attributes.Properties);
|
||||
Assert.AreEqual(new List<KeyValuePair<string, string>>() { new KeyValuePair<string, string>("key1", "1") }, attributes.Properties);
|
||||
|
||||
attributes.AddPropertyIfNotExist("key2", "2");
|
||||
Assert.AreEqual(new List<KeyValuePair<string, string>>() { new KeyValuePair<string, string>("key1", "1"), new KeyValuePair<string, string>("key2", "2") }, attributes.Properties);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCopyTo()
|
||||
{
|
||||
var from = new HtmlAttributes();
|
||||
from.AddClass("test");
|
||||
from.AddProperty("key1", "1");
|
||||
|
||||
var to = new HtmlAttributes();
|
||||
from.CopyTo(to);
|
||||
|
||||
Assert.True(ReferenceEquals(from.Classes, to.Classes));
|
||||
Assert.True(ReferenceEquals(from.Properties, to.Properties));
|
||||
|
||||
// From: Classes From: Properties To: Classes To: Properties
|
||||
// test1: null null null null
|
||||
from = new HtmlAttributes();
|
||||
to = new HtmlAttributes();
|
||||
from.CopyTo(to, false, false);
|
||||
Assert.Null(to.Classes);
|
||||
Assert.Null(to.Properties);
|
||||
|
||||
// test2: ["test"] ["key1", "1"] null null
|
||||
from = new HtmlAttributes();
|
||||
to = new HtmlAttributes();
|
||||
from.AddClass("test");
|
||||
from.AddProperty("key1", "1");
|
||||
from.CopyTo(to, false, false);
|
||||
Assert.AreEqual(new List<string>() { "test" }, to.Classes);
|
||||
Assert.AreEqual(new List<KeyValuePair<string, string>>() { new KeyValuePair<string, string>("key1", "1")}, to.Properties);
|
||||
|
||||
// test3: null null ["test"] ["key1", "1"]
|
||||
from = new HtmlAttributes();
|
||||
to = new HtmlAttributes();
|
||||
to.AddClass("test");
|
||||
to.AddProperty("key1", "1");
|
||||
from.CopyTo(to, false, false);
|
||||
Assert.AreEqual(new List<string>() { "test" }, to.Classes);
|
||||
Assert.AreEqual(new List<KeyValuePair<string, string>>() { new KeyValuePair<string, string>("key1", "1") }, to.Properties);
|
||||
|
||||
// test4: ["test1"] ["key2", "2"] ["test"] ["key1", "1"]
|
||||
from = new HtmlAttributes();
|
||||
to = new HtmlAttributes();
|
||||
from.AddClass("test1");
|
||||
from.AddProperty("key2", "2");
|
||||
to.AddClass("test");
|
||||
to.AddProperty("key1", "1");
|
||||
from.CopyTo(to, false, false);
|
||||
Assert.AreEqual(new List<string>() { "test", "test1" }, to.Classes);
|
||||
Assert.AreEqual(new List<KeyValuePair<string, string>>() { new KeyValuePair<string, string>("key1", "1"), new KeyValuePair<string, string>("key2", "2") }, to.Properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using NUnit.Framework;
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Syntax;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
@@ -15,8 +14,7 @@ namespace Markdig.Tests
|
||||
{
|
||||
var inputTag = "<a>";
|
||||
var text = new StringSlice(inputTag);
|
||||
string outputTag;
|
||||
Assert.True(HtmlHelper.TryParseHtmlTag(text, out outputTag));
|
||||
Assert.True(HtmlHelper.TryParseHtmlTag(text, out string outputTag));
|
||||
Assert.AreEqual(inputTag, outputTag);
|
||||
}
|
||||
|
||||
@@ -25,8 +23,7 @@ namespace Markdig.Tests
|
||||
{
|
||||
var inputTag = "<a href='http://google.com'>";
|
||||
var text = new StringSlice(inputTag);
|
||||
string outputTag;
|
||||
Assert.True(HtmlHelper.TryParseHtmlTag(text, out outputTag));
|
||||
Assert.True(HtmlHelper.TryParseHtmlTag(text, out string outputTag));
|
||||
Assert.AreEqual(inputTag, outputTag);
|
||||
}
|
||||
}
|
||||
|
||||
25
src/Markdig.Tests/TestImageAltText.cs
Normal file
25
src/Markdig.Tests/TestImageAltText.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using NUnit.Framework;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestImageAltText
|
||||
{
|
||||
[Test]
|
||||
[TestCase("", "")]
|
||||
[TestCase("", "foo")]
|
||||
[TestCase("![][1]\n\n[1]: image.jpg", "")]
|
||||
[TestCase("![bar][1]\n\n[1]: image.jpg", "bar")]
|
||||
[TestCase("", "")]
|
||||
[TestCase("", "foo")]
|
||||
[TestCase("![][1]\n\n[1]: image.jpg 'title'", "")]
|
||||
[TestCase("![bar][1]\n\n[1]: image.jpg 'title'", "bar")]
|
||||
public void TestImageHtmlAltText(string markdown, string expectedAltText)
|
||||
{
|
||||
string html = Markdown.ToHtml(markdown);
|
||||
string actualAltText = Regex.Match(html, "alt=\"(.*?)\"").Groups[1].Value;
|
||||
Assert.AreEqual(expectedAltText, actualAltText);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using Markdig.Helpers;
|
||||
|
||||
@@ -18,60 +17,60 @@ namespace Markdig.Tests
|
||||
public void TestEmpty()
|
||||
{
|
||||
var lineReader = new LineReader("");
|
||||
Assert.Null(lineReader.ReadLine()?.ToString());
|
||||
Assert.Null(lineReader.ReadLine().Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLinesOnlyLf()
|
||||
{
|
||||
var lineReader = new LineReader("\n\n\n");
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
|
||||
Assert.AreEqual(1, lineReader.SourcePosition);
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
|
||||
Assert.AreEqual(2, lineReader.SourcePosition);
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
|
||||
Assert.Null(lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
|
||||
Assert.Null(lineReader.ReadLine().Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLinesOnlyCr()
|
||||
{
|
||||
var lineReader = new LineReader("\r\r\r");
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
|
||||
Assert.AreEqual(1, lineReader.SourcePosition);
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
|
||||
Assert.AreEqual(2, lineReader.SourcePosition);
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
|
||||
Assert.Null(lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
|
||||
Assert.Null(lineReader.ReadLine().Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLinesOnlyCrLf()
|
||||
{
|
||||
var lineReader = new LineReader("\r\n\r\n\r\n");
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
|
||||
Assert.AreEqual(2, lineReader.SourcePosition);
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
|
||||
Assert.AreEqual(4, lineReader.SourcePosition);
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine()?.ToString());
|
||||
Assert.Null(lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual(string.Empty, lineReader.ReadLine().ToString());
|
||||
Assert.Null(lineReader.ReadLine().Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoEndOfLine()
|
||||
{
|
||||
var lineReader = new LineReader("123");
|
||||
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
|
||||
Assert.Null(lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual("123", lineReader.ReadLine().ToString());
|
||||
Assert.Null(lineReader.ReadLine().Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLf()
|
||||
{
|
||||
var lineReader = new LineReader("123\n");
|
||||
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual("123", lineReader.ReadLine().ToString());
|
||||
Assert.AreEqual(4, lineReader.SourcePosition);
|
||||
Assert.Null(lineReader.ReadLine()?.ToString());
|
||||
Assert.Null(lineReader.ReadLine().Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -79,29 +78,29 @@ namespace Markdig.Tests
|
||||
{
|
||||
// When limited == true, we limit the internal buffer exactly after the first new line char '\n'
|
||||
var lineReader = new LineReader("123\n456");
|
||||
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual("123", lineReader.ReadLine().ToString());
|
||||
Assert.AreEqual(4, lineReader.SourcePosition);
|
||||
Assert.AreEqual("456", lineReader.ReadLine()?.ToString());
|
||||
Assert.Null(lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual("456", lineReader.ReadLine().ToString());
|
||||
Assert.Null(lineReader.ReadLine().Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCr()
|
||||
{
|
||||
var lineReader = new LineReader("123\r");
|
||||
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual("123", lineReader.ReadLine().ToString());
|
||||
Assert.AreEqual(4, lineReader.SourcePosition);
|
||||
Assert.Null(lineReader.ReadLine()?.ToString());
|
||||
Assert.Null(lineReader.ReadLine().Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCr2()
|
||||
{
|
||||
var lineReader = new LineReader("123\r456");
|
||||
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual("123", lineReader.ReadLine().ToString());
|
||||
Assert.AreEqual(4, lineReader.SourcePosition);
|
||||
Assert.AreEqual("456", lineReader.ReadLine()?.ToString());
|
||||
Assert.Null(lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual("456", lineReader.ReadLine().ToString());
|
||||
Assert.Null(lineReader.ReadLine().Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -110,19 +109,19 @@ namespace Markdig.Tests
|
||||
// When limited == true, we limit the internal buffer exactly after the first new line char '\r'
|
||||
// and we check that we don't get a new line for `\n`
|
||||
var lineReader = new LineReader("123\r\n");
|
||||
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual("123", lineReader.ReadLine().ToString());
|
||||
Assert.AreEqual(5, lineReader.SourcePosition);
|
||||
Assert.Null(lineReader.ReadLine()?.ToString());
|
||||
Assert.Null(lineReader.ReadLine().Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCrLf2()
|
||||
{
|
||||
var lineReader = new LineReader("123\r\n456");
|
||||
Assert.AreEqual("123", lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual("123", lineReader.ReadLine().ToString());
|
||||
Assert.AreEqual(5, lineReader.SourcePosition);
|
||||
Assert.AreEqual("456", lineReader.ReadLine()?.ToString());
|
||||
Assert.Null(lineReader.ReadLine()?.ToString());
|
||||
Assert.AreEqual("456", lineReader.ReadLine().ToString());
|
||||
Assert.Null(lineReader.ReadLine().Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using NUnit.Framework;
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Syntax;
|
||||
@@ -14,8 +15,7 @@ namespace Markdig.Tests
|
||||
public void TestUrlSimple()
|
||||
{
|
||||
var text = new StringSlice("toto tutu");
|
||||
string link;
|
||||
Assert.True(LinkHelper.TryParseUrl(ref text, out link));
|
||||
Assert.True(LinkHelper.TryParseUrl(ref text, out string link));
|
||||
Assert.AreEqual("toto", link);
|
||||
Assert.AreEqual(' ', text.CurrentChar);
|
||||
}
|
||||
@@ -24,18 +24,27 @@ namespace Markdig.Tests
|
||||
public void TestUrlUrl()
|
||||
{
|
||||
var text = new StringSlice("http://google.com)");
|
||||
string link;
|
||||
Assert.True(LinkHelper.TryParseUrl(ref text, out link));
|
||||
Assert.True(LinkHelper.TryParseUrl(ref text, out string link));
|
||||
Assert.AreEqual("http://google.com", link);
|
||||
Assert.AreEqual(')', text.CurrentChar);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("http://google.com.")]
|
||||
[TestCase("http://google.com. ")]
|
||||
public void TestUrlTrailingFullStop(string uri)
|
||||
{
|
||||
var text = new StringSlice(uri);
|
||||
Assert.True(LinkHelper.TryParseUrl(ref text, out string link, true));
|
||||
Assert.AreEqual("http://google.com", link);
|
||||
Assert.AreEqual('.', text.CurrentChar);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUrlNestedParenthesis()
|
||||
{
|
||||
var text = new StringSlice("(toto)tutu(tata) nooo");
|
||||
string link;
|
||||
Assert.True(LinkHelper.TryParseUrl(ref text, out link));
|
||||
Assert.True(LinkHelper.TryParseUrl(ref text, out string link));
|
||||
Assert.AreEqual("(toto)tutu(tata)", link);
|
||||
Assert.AreEqual(' ', text.CurrentChar);
|
||||
}
|
||||
@@ -44,8 +53,7 @@ namespace Markdig.Tests
|
||||
public void TestUrlAlternate()
|
||||
{
|
||||
var text = new StringSlice("<toto_tata_tutu> nooo");
|
||||
string link;
|
||||
Assert.True(LinkHelper.TryParseUrl(ref text, out link));
|
||||
Assert.True(LinkHelper.TryParseUrl(ref text, out string link));
|
||||
Assert.AreEqual("toto_tata_tutu", link);
|
||||
Assert.AreEqual(' ', text.CurrentChar);
|
||||
}
|
||||
@@ -54,16 +62,14 @@ namespace Markdig.Tests
|
||||
public void TestUrlAlternateInvalid()
|
||||
{
|
||||
var text = new StringSlice("<toto_tata_tutu");
|
||||
string link;
|
||||
Assert.False(LinkHelper.TryParseUrl(ref text, out link));
|
||||
Assert.False(LinkHelper.TryParseUrl(ref text, out string link));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTitleSimple()
|
||||
{
|
||||
var text = new StringSlice(@"'tata\tutu\''");
|
||||
string title;
|
||||
Assert.True(LinkHelper.TryParseTitle(ref text, out title));
|
||||
Assert.True(LinkHelper.TryParseTitle(ref text, out string title));
|
||||
Assert.AreEqual(@"tata\tutu'", title);
|
||||
}
|
||||
|
||||
@@ -71,8 +77,7 @@ namespace Markdig.Tests
|
||||
public void TestTitleSimpleAlternate()
|
||||
{
|
||||
var text = new StringSlice(@"""tata\tutu\"""" ");
|
||||
string title;
|
||||
Assert.True(LinkHelper.TryParseTitle(ref text, out title));
|
||||
Assert.True(LinkHelper.TryParseTitle(ref text, out string title));
|
||||
Assert.AreEqual(@"tata\tutu""", title);
|
||||
Assert.AreEqual(' ', text.CurrentChar);
|
||||
}
|
||||
@@ -80,36 +85,40 @@ namespace Markdig.Tests
|
||||
[Test]
|
||||
public void TestUrlAndTitle()
|
||||
{
|
||||
// 0 1 2 3
|
||||
// 0123456789012345678901234567890123456789
|
||||
var text = new StringSlice(@"(http://google.com 'this is a title')ABC");
|
||||
string link;
|
||||
string title;
|
||||
Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title));
|
||||
Assert.True(LinkHelper.TryParseInlineLink(ref text, out string link, out string title, out SourceSpan linkSpan, out SourceSpan titleSpan));
|
||||
Assert.AreEqual("http://google.com", link);
|
||||
Assert.AreEqual("this is a title", title);
|
||||
Assert.AreEqual(new SourceSpan(1, 17), linkSpan);
|
||||
Assert.AreEqual(new SourceSpan(19, 35), titleSpan);
|
||||
Assert.AreEqual('A', text.CurrentChar);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUrlAndTitleEmpty()
|
||||
{
|
||||
// 01234
|
||||
var text = new StringSlice(@"(<>)A");
|
||||
string link;
|
||||
string title;
|
||||
Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title));
|
||||
Assert.True(LinkHelper.TryParseInlineLink(ref text, out string link, out string title, out SourceSpan linkSpan, out SourceSpan titleSpan));
|
||||
Assert.AreEqual(string.Empty, link);
|
||||
Assert.AreEqual(string.Empty, title);
|
||||
Assert.AreEqual(new SourceSpan(1, 2), linkSpan);
|
||||
Assert.AreEqual(SourceSpan.Empty, titleSpan);
|
||||
Assert.AreEqual('A', text.CurrentChar);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUrlAndTitleEmpty2()
|
||||
{
|
||||
// 012345
|
||||
var text = new StringSlice(@"( <> )A");
|
||||
string link;
|
||||
string title;
|
||||
Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title));
|
||||
Assert.True(LinkHelper.TryParseInlineLink(ref text, out string link, out string title, out SourceSpan linkSpan, out SourceSpan titleSpan));
|
||||
Assert.AreEqual(string.Empty, link);
|
||||
Assert.AreEqual(string.Empty, title);
|
||||
Assert.AreEqual(new SourceSpan(2, 3), linkSpan);
|
||||
Assert.AreEqual(SourceSpan.Empty, titleSpan);
|
||||
Assert.AreEqual('A', text.CurrentChar);
|
||||
}
|
||||
|
||||
@@ -117,12 +126,14 @@ namespace Markdig.Tests
|
||||
[Test]
|
||||
public void TestUrlEmptyWithTitleWithMultipleSpaces()
|
||||
{
|
||||
// 0 1 2
|
||||
// 0123456789012345678901234567
|
||||
var text = new StringSlice(@"( <> 'toto' )A");
|
||||
string link;
|
||||
string title;
|
||||
Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title));
|
||||
Assert.True(LinkHelper.TryParseInlineLink(ref text, out string link, out string title, out SourceSpan linkSpan, out SourceSpan titleSpan));
|
||||
Assert.AreEqual(string.Empty, link);
|
||||
Assert.AreEqual("toto", title);
|
||||
Assert.AreEqual(new SourceSpan(4, 5), linkSpan);
|
||||
Assert.AreEqual(new SourceSpan(12, 17), titleSpan);
|
||||
Assert.AreEqual('A', text.CurrentChar);
|
||||
}
|
||||
|
||||
@@ -130,60 +141,62 @@ namespace Markdig.Tests
|
||||
public void TestUrlEmpty()
|
||||
{
|
||||
var text = new StringSlice(@"()A");
|
||||
string link;
|
||||
string title;
|
||||
Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title));
|
||||
Assert.True(LinkHelper.TryParseInlineLink(ref text, out string link, out string title, out SourceSpan linkSpan, out SourceSpan titleSpan));
|
||||
Assert.AreEqual(string.Empty, link);
|
||||
Assert.AreEqual(string.Empty, title);
|
||||
Assert.AreEqual(SourceSpan.Empty, linkSpan);
|
||||
Assert.AreEqual(SourceSpan.Empty, titleSpan);
|
||||
Assert.AreEqual('A', text.CurrentChar);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMultipleLines()
|
||||
{
|
||||
var text = new StringSlice(@"(
|
||||
<http://google.com>
|
||||
'toto' )A");
|
||||
string link;
|
||||
string title;
|
||||
Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title));
|
||||
// 0 1 2 3
|
||||
// 01 2345678901234567890 1234567890123456789
|
||||
var text = new StringSlice("(\n<http://google.com>\n 'toto' )A");
|
||||
Assert.True(LinkHelper.TryParseInlineLink(ref text, out string link, out string title, out SourceSpan linkSpan, out SourceSpan titleSpan));
|
||||
Assert.AreEqual("http://google.com", link);
|
||||
Assert.AreEqual("toto", title);
|
||||
Assert.AreEqual(new SourceSpan(2, 20), linkSpan);
|
||||
Assert.AreEqual(new SourceSpan(26, 31), titleSpan);
|
||||
Assert.AreEqual('A', text.CurrentChar);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLabelSimple()
|
||||
{
|
||||
// 01234
|
||||
var text = new StringSlice("[foo]");
|
||||
string label;
|
||||
Assert.True(LinkHelper.TryParseLabel(ref text, out label));
|
||||
Assert.True(LinkHelper.TryParseLabel(ref text, out string label, out SourceSpan labelSpan));
|
||||
Assert.AreEqual(new SourceSpan(1, 3), labelSpan);
|
||||
Assert.AreEqual("foo", label);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLabelEscape()
|
||||
{
|
||||
// 012345678
|
||||
var text = new StringSlice(@"[fo\[\]o]");
|
||||
string label;
|
||||
Assert.True(LinkHelper.TryParseLabel(ref text, out label));
|
||||
Assert.True(LinkHelper.TryParseLabel(ref text, out string label, out SourceSpan labelSpan));
|
||||
Assert.AreEqual(new SourceSpan(1, 7), labelSpan);
|
||||
Assert.AreEqual(@"fo[]o", label);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLabelEscape2()
|
||||
{
|
||||
// 0123
|
||||
var text = new StringSlice(@"[\]]");
|
||||
string label;
|
||||
Assert.True(LinkHelper.TryParseLabel(ref text, out label));
|
||||
Assert.True(LinkHelper.TryParseLabel(ref text, out string label, out SourceSpan labelSpan));
|
||||
Assert.AreEqual(new SourceSpan(1, 2), labelSpan);
|
||||
Assert.AreEqual(@"]", label);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLabelInvalids()
|
||||
{
|
||||
string label;
|
||||
Assert.False(LinkHelper.TryParseLabel(new StringSlice(@"a"), out label));
|
||||
Assert.False(LinkHelper.TryParseLabel(new StringSlice(@"a"), out string label));
|
||||
Assert.False(LinkHelper.TryParseLabel(new StringSlice(@"["), out label));
|
||||
Assert.False(LinkHelper.TryParseLabel(new StringSlice(@"[\x]"), out label));
|
||||
Assert.False(LinkHelper.TryParseLabel(new StringSlice(@"[[]"), out label));
|
||||
@@ -194,32 +207,35 @@ namespace Markdig.Tests
|
||||
[Test]
|
||||
public void TestLabelWhitespaceCollapsedAndTrim()
|
||||
{
|
||||
// 0 1 2 3
|
||||
// 0123456789012345678901234567890123456789
|
||||
var text = new StringSlice(@"[ fo o z ]");
|
||||
string label;
|
||||
Assert.True(LinkHelper.TryParseLabel(ref text, out label));
|
||||
Assert.True(LinkHelper.TryParseLabel(ref text, out string label, out SourceSpan labelSpan));
|
||||
Assert.AreEqual(new SourceSpan(6, 17), labelSpan);
|
||||
Assert.AreEqual(@"fo o z", label);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestlLinkReferenceDefinitionSimple()
|
||||
{
|
||||
// 0 1 2 3
|
||||
// 0123456789012345678901234567890123456789
|
||||
var text = new StringSlice(@"[foo]: /toto 'title'");
|
||||
string label;
|
||||
string url;
|
||||
string title;
|
||||
Assert.True(LinkHelper.TryParseLinkReferenceDefinition(ref text, out label, out url, out title));
|
||||
Assert.True(LinkHelper.TryParseLinkReferenceDefinition(ref text, out string label, out string url, out string title, out SourceSpan labelSpan, out SourceSpan urlSpan, out SourceSpan titleSpan));
|
||||
Assert.AreEqual(@"foo", label);
|
||||
Assert.AreEqual(@"/toto", url);
|
||||
Assert.AreEqual(@"title", title);
|
||||
Assert.AreEqual(new SourceSpan(1, 3), labelSpan);
|
||||
Assert.AreEqual(new SourceSpan(7, 11), urlSpan);
|
||||
Assert.AreEqual(new SourceSpan(13, 19), titleSpan);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAutoLinkUrlSimple()
|
||||
{
|
||||
var text = new StringSlice(@"<http://google.com>");
|
||||
string url;
|
||||
bool isEmail;
|
||||
Assert.True(LinkHelper.TryParseAutolink(ref text, out url, out isEmail));
|
||||
Assert.True(LinkHelper.TryParseAutolink(ref text, out string url, out bool isEmail));
|
||||
Assert.False(isEmail);
|
||||
Assert.AreEqual("http://google.com", url);
|
||||
}
|
||||
@@ -228,9 +244,7 @@ namespace Markdig.Tests
|
||||
public void TestAutoLinkEmailSimple()
|
||||
{
|
||||
var text = new StringSlice(@"<user@host.com>");
|
||||
string email;
|
||||
bool isEmail;
|
||||
Assert.True(LinkHelper.TryParseAutolink(ref text, out email, out isEmail));
|
||||
Assert.True(LinkHelper.TryParseAutolink(ref text, out string email, out bool isEmail));
|
||||
Assert.True(isEmail);
|
||||
Assert.AreEqual("user@host.com", email);
|
||||
}
|
||||
@@ -238,12 +252,124 @@ namespace Markdig.Tests
|
||||
[Test]
|
||||
public void TestAutolinkInvalid()
|
||||
{
|
||||
string text;
|
||||
bool isEmail;
|
||||
Assert.False(LinkHelper.TryParseAutolink(new StringSlice(@""), out text, out isEmail));
|
||||
Assert.False(LinkHelper.TryParseAutolink(new StringSlice(@""), out string text, out bool isEmail));
|
||||
Assert.False(LinkHelper.TryParseAutolink(new StringSlice(@"<"), out text, out isEmail));
|
||||
Assert.False(LinkHelper.TryParseAutolink(new StringSlice(@"<ab"), out text, out isEmail));
|
||||
Assert.False(LinkHelper.TryParseAutolink(new StringSlice(@"<user@>"), out text, out isEmail));
|
||||
}
|
||||
|
||||
[TestCase("Header identifiers in HTML", "header-identifiers-in-html")]
|
||||
[TestCase("* Dogs*?--in *my* house?", "dogs-in-my-house")] // Not Pandoc equivalent: dogs--in...
|
||||
[TestCase("[HTML], [S5], or [RTF]?", "html-s5-or-rtf")]
|
||||
[TestCase("3. Applications", "applications")]
|
||||
[TestCase("33", "")]
|
||||
public void TestUrilizeNonAscii_Pandoc(string input, string expectedResult)
|
||||
{
|
||||
Assert.AreEqual(expectedResult, LinkHelper.Urilize(input, false));
|
||||
}
|
||||
|
||||
[TestCase("Header identifiers in HTML", "header-identifiers-in-html")]
|
||||
[TestCase("* Dogs*?--in *my* house?", "-dogs--in-my-house")]
|
||||
[TestCase("[HTML], [S5], or [RTF]?", "html-s5-or-rtf")]
|
||||
[TestCase("3. Applications", "3-applications")]
|
||||
[TestCase("33", "33")]
|
||||
public void TestUrilizeGfm(string input, string expectedResult)
|
||||
{
|
||||
Assert.AreEqual(expectedResult, LinkHelper.UrilizeAsGfm(input));
|
||||
}
|
||||
|
||||
[TestCase("abc", "abc")]
|
||||
[TestCase("a-c", "a-c")]
|
||||
[TestCase("a c", "a-c")]
|
||||
[TestCase("a_c", "a_c")]
|
||||
[TestCase("a.c", "a.c")]
|
||||
[TestCase("a,c", "ac")]
|
||||
[TestCase("a--", "a")] // Not Pandoc-equivalent: a--
|
||||
[TestCase("a__", "a")] // Not Pandoc-equivalent: a__
|
||||
[TestCase("a..", "a")] // Not Pandoc-equivalent: a..
|
||||
[TestCase("a??", "a")]
|
||||
[TestCase("a ", "a")]
|
||||
[TestCase("a--d", "a-d")]
|
||||
[TestCase("a__d", "a_d")]
|
||||
[TestCase("a??d", "ad")]
|
||||
[TestCase("a d", "a-d")]
|
||||
[TestCase("a..d", "a.d")]
|
||||
[TestCase("-bc", "bc")]
|
||||
[TestCase("_bc", "bc")]
|
||||
[TestCase(" bc", "bc")]
|
||||
[TestCase("?bc", "bc")]
|
||||
[TestCase(".bc", "bc")]
|
||||
[TestCase("a-.-", "a")] // Not Pandoc equivalent: a-.-
|
||||
public void TestUrilizeOnlyAscii_Simple(string input, string expectedResult)
|
||||
{
|
||||
Assert.AreEqual(expectedResult, LinkHelper.Urilize(input, true));
|
||||
}
|
||||
|
||||
[TestCase("bær", "br")]
|
||||
[TestCase("bør", "br")]
|
||||
[TestCase("bΘr", "br")]
|
||||
[TestCase("四五", "")]
|
||||
public void TestUrilizeOnlyAscii_NonAscii(string input, string expectedResult)
|
||||
{
|
||||
Assert.AreEqual(expectedResult, LinkHelper.Urilize(input, true));
|
||||
}
|
||||
|
||||
[TestCase("bár", "bar")]
|
||||
[TestCase("àrrivé", "arrive")]
|
||||
public void TestUrilizeOnlyAscii_Normalization(string input, string expectedResult)
|
||||
{
|
||||
Assert.AreEqual(expectedResult, LinkHelper.Urilize(input, true));
|
||||
}
|
||||
|
||||
[TestCase("123", "")]
|
||||
[TestCase("1,-b", "b")]
|
||||
[TestCase("b1,-", "b1")] // Not Pandoc equivalent: b1-
|
||||
[TestCase("ab3", "ab3")]
|
||||
[TestCase("ab3de", "ab3de")]
|
||||
public void TestUrilizeOnlyAscii_Numeric(string input, string expectedResult)
|
||||
{
|
||||
Assert.AreEqual(expectedResult, LinkHelper.Urilize(input, true));
|
||||
}
|
||||
|
||||
[TestCase("一二三四五", "一二三四五")]
|
||||
[TestCase("一,-b", "一-b")]
|
||||
public void TestUrilizeNonAscii_NonAsciiNumeric(string input, string expectedResult)
|
||||
{
|
||||
Assert.AreEqual(expectedResult, LinkHelper.Urilize(input, false));
|
||||
}
|
||||
|
||||
[TestCase("bær", "bær")]
|
||||
[TestCase("æ5el", "æ5el")]
|
||||
[TestCase("-æ5el", "æ5el")]
|
||||
[TestCase("-frø-", "frø")]
|
||||
[TestCase("-fr-ø", "fr-ø")]
|
||||
public void TestUrilizeNonAscii_Simple(string input, string expectedResult)
|
||||
{
|
||||
Assert.AreEqual(expectedResult, LinkHelper.Urilize(input, false));
|
||||
}
|
||||
|
||||
// Just to be sure, test for characters expressly forbidden in URI fragments:
|
||||
[TestCase("b#r", "br")]
|
||||
[TestCase("b%r", "br")] // Invalid except as an escape character
|
||||
[TestCase("b^r", "br")]
|
||||
[TestCase("b[r", "br")]
|
||||
[TestCase("b]r", "br")]
|
||||
[TestCase("b{r", "br")]
|
||||
[TestCase("b}r", "br")]
|
||||
[TestCase("b<r", "br")]
|
||||
[TestCase("b>r", "br")]
|
||||
[TestCase(@"b\r", "br")]
|
||||
[TestCase(@"b""r", "br")]
|
||||
[TestCase(@"Requirement 😀", "requirement")]
|
||||
public void TestUrilizeNonAscii_NonValidCharactersForFragments(string input, string expectedResult)
|
||||
{
|
||||
Assert.AreEqual(expectedResult, LinkHelper.Urilize(input, false));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnicodeInDomainNameOfLinkReferenceDefinition()
|
||||
{
|
||||
TestParser.TestSpec("[Foo]\n\n[Foo]: http://ünicode.com", "<p><a href=\"http://xn--nicode-2ya.com\">Foo</a></p>");
|
||||
}
|
||||
}
|
||||
}
|
||||
44
src/Markdig.Tests/TestLinkRewriter.cs
Normal file
44
src/Markdig.Tests/TestLinkRewriter.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Markdig.Parsers;
|
||||
using Markdig.Renderers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
public class TestLinkRewriter
|
||||
{
|
||||
[Test]
|
||||
public void ReplacesRelativeLinks()
|
||||
{
|
||||
TestSpec(s => "abc" + s, "Link: [hello](/relative.jpg)", "abc/relative.jpg");
|
||||
TestSpec(s => s + "xyz", "Link: [hello](relative.jpg)", "relative.jpgxyz");
|
||||
TestSpec(null, "Link: [hello](relative.jpg)", "relative.jpg");
|
||||
TestSpec(null, "Link: [hello](/relative.jpg)", "/relative.jpg");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReplacesRelativeImageSources()
|
||||
{
|
||||
TestSpec(s => "abc" + s, "Image: ", "abc/image.jpg");
|
||||
TestSpec(s => "abc" + s, "Image: ", "abcimage.jpg");
|
||||
TestSpec(null, "Image: ", "/image.jpg");
|
||||
}
|
||||
|
||||
public static void TestSpec(Func<string,string> linkRewriter, string markdown, string expectedLink)
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder().Build();
|
||||
|
||||
var writer = new StringWriter();
|
||||
var renderer = new HtmlRenderer(writer);
|
||||
renderer.LinkRewriter = linkRewriter;
|
||||
pipeline.Setup(renderer);
|
||||
|
||||
var document = MarkdownParser.Parse(markdown, pipeline);
|
||||
renderer.Render(document);
|
||||
writer.Flush();
|
||||
|
||||
Assert.That(writer.ToString(), Contains.Substring("=\"" + expectedLink + "\""));
|
||||
}
|
||||
}
|
||||
}
|
||||
149
src/Markdig.Tests/TestMarkdigCoreApi.cs
Normal file
149
src/Markdig.Tests/TestMarkdigCoreApi.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
using Markdig.Renderers;
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
using NUnit.Framework;
|
||||
using System.IO;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
public class TestMarkdigCoreApi
|
||||
{
|
||||
[Test]
|
||||
public void TestToHtml()
|
||||
{
|
||||
string html = Markdown.ToHtml("This is a text with some *emphasis*");
|
||||
Assert.AreEqual("<p>This is a text with some <em>emphasis</em></p>\n", html);
|
||||
|
||||
html = Markdown.ToHtml("This is a text with a https://link.tld/");
|
||||
Assert.AreNotEqual("<p>This is a text with a <a href=\"https://link.tld/\">https://link.tld/</a></p>\n", html);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestToHtmlWithPipeline()
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
.Build();
|
||||
|
||||
string html = Markdown.ToHtml("This is a text with some *emphasis*", pipeline);
|
||||
Assert.AreEqual("<p>This is a text with some <em>emphasis</em></p>\n", html);
|
||||
|
||||
html = Markdown.ToHtml("This is a text with a https://link.tld/", pipeline);
|
||||
Assert.AreNotEqual("<p>This is a text with a <a href=\"https://link.tld/\">https://link.tld/</a></p>\n", html);
|
||||
|
||||
pipeline = new MarkdownPipelineBuilder()
|
||||
.UseAdvancedExtensions()
|
||||
.Build();
|
||||
|
||||
html = Markdown.ToHtml("This is a text with a https://link.tld/", pipeline);
|
||||
Assert.AreEqual("<p>This is a text with a <a href=\"https://link.tld/\">https://link.tld/</a></p>\n", html);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestToHtmlWithWriter()
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
_ = Markdown.ToHtml("This is a text with some *emphasis*", writer);
|
||||
string html = writer.ToString();
|
||||
Assert.AreEqual("<p>This is a text with some <em>emphasis</em></p>\n", html);
|
||||
|
||||
writer = new StringWriter();
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
.UseAdvancedExtensions()
|
||||
.Build();
|
||||
|
||||
_ = Markdown.ToHtml("This is a text with a https://link.tld/", writer, pipeline);
|
||||
html = writer.ToString();
|
||||
Assert.AreEqual("<p>This is a text with a <a href=\"https://link.tld/\">https://link.tld/</a></p>\n", html);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestConvert()
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
HtmlRenderer renderer = new HtmlRenderer(writer);
|
||||
|
||||
_ = Markdown.Convert("This is a text with some *emphasis*", renderer);
|
||||
string html = writer.ToString();
|
||||
Assert.AreEqual("<p>This is a text with some <em>emphasis</em></p>\n", html);
|
||||
|
||||
writer = new StringWriter();
|
||||
renderer = new HtmlRenderer(writer);
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
.UseAdvancedExtensions()
|
||||
.Build();
|
||||
|
||||
_ = Markdown.Convert("This is a text with a https://link.tld/", renderer, pipeline);
|
||||
html = writer.ToString();
|
||||
Assert.AreEqual("<p>This is a text with a <a href=\"https://link.tld/\">https://link.tld/</a></p>\n", html);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestParse()
|
||||
{
|
||||
const string markdown = "This is a text with some *emphasis*";
|
||||
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
.UsePreciseSourceLocation()
|
||||
.Build();
|
||||
|
||||
MarkdownDocument document = Markdown.Parse(markdown, pipeline);
|
||||
|
||||
Assert.AreEqual(1, document.LineCount);
|
||||
Assert.AreEqual(markdown.Length, document.Span.Length);
|
||||
Assert.AreEqual(1, document.LineStartIndexes.Count);
|
||||
Assert.AreEqual(0, document.LineStartIndexes[0]);
|
||||
|
||||
Assert.AreEqual(1, document.Count);
|
||||
ParagraphBlock paragraph = document[0] as ParagraphBlock;
|
||||
Assert.NotNull(paragraph);
|
||||
Assert.AreEqual(markdown.Length, paragraph.Span.Length);
|
||||
LiteralInline literal = paragraph.Inline.FirstChild as LiteralInline;
|
||||
Assert.NotNull(literal);
|
||||
Assert.AreEqual("This is a text with some ", literal.ToString());
|
||||
EmphasisInline emphasis = literal.NextSibling as EmphasisInline;
|
||||
Assert.NotNull(emphasis);
|
||||
Assert.AreEqual("*emphasis*".Length, emphasis.Span.Length);
|
||||
LiteralInline emphasisLiteral = emphasis.FirstChild as LiteralInline;
|
||||
Assert.NotNull(emphasisLiteral);
|
||||
Assert.AreEqual("emphasis", emphasisLiteral.ToString());
|
||||
Assert.Null(emphasisLiteral.NextSibling);
|
||||
Assert.Null(emphasis.NextSibling);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNormalize()
|
||||
{
|
||||
string normalized = Markdown.Normalize("Heading\n=======");
|
||||
Assert.AreEqual("# Heading", normalized);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNormalizeWithWriter()
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
_ = Markdown.Normalize("Heading\n=======", writer);
|
||||
string normalized = writer.ToString();
|
||||
Assert.AreEqual("# Heading", normalized);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestToPlainText()
|
||||
{
|
||||
string plainText = Markdown.ToPlainText("*Hello*, [world](http://example.com)!");
|
||||
Assert.AreEqual("Hello, world!\n", plainText);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestToPlainTextWithWriter()
|
||||
{
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
_ = Markdown.ToPlainText("*Hello*, [world](http://example.com)!", writer);
|
||||
string plainText = writer.ToString();
|
||||
Assert.AreEqual("Hello, world!\n", plainText);
|
||||
}
|
||||
}
|
||||
}
|
||||
104
src/Markdig.Tests/TestMediaLinks.cs
Normal file
104
src/Markdig.Tests/TestMediaLinks.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using Markdig.Extensions.MediaLinks;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestMediaLinks
|
||||
{
|
||||
private MarkdownPipeline GetPipeline(MediaOptions options = null)
|
||||
{
|
||||
return new MarkdownPipelineBuilder()
|
||||
.UseMediaLinks(options)
|
||||
.Build();
|
||||
}
|
||||
|
||||
private MarkdownPipeline GetPipelineWithBootstrap(MediaOptions options = null)
|
||||
{
|
||||
return new MarkdownPipelineBuilder()
|
||||
.UseBootstrap()
|
||||
.UseMediaLinks(options)
|
||||
.Build();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("", "<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"https://sample.com/video.mp4\"></source></video></p>\n")]
|
||||
[TestCase("", "<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"//sample.com/video.mp4\"></source></video></p>\n")]
|
||||
[TestCase(@"", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
|
||||
[TestCase("", "<p><iframe src=\"https://music.yandex.ru/iframe/#track/4402274/411845/\" class=\"yandex\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n")]
|
||||
[TestCase("", "<p><iframe src=\"https://player.vimeo.com/video/8607834\" class=\"vimeo\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
|
||||
[TestCase("", "<p><iframe src=\"https://ok.ru/videoembed/26870090463\" class=\"odnoklassniki\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
|
||||
[TestCase("", "<p><iframe src=\"https://ok.ru/videoembed/26870090463\" class=\"odnoklassniki\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
|
||||
public void TestBuiltInHosts(string markdown, string expected)
|
||||
{
|
||||
string html = Markdown.ToHtml(markdown, GetPipeline());
|
||||
Assert.AreEqual(html, expected);
|
||||
}
|
||||
|
||||
private class TestHostProvider : IHostProvider
|
||||
{
|
||||
public string Class { get; } = "regex";
|
||||
public bool AllowFullScreen { get; }
|
||||
|
||||
public bool TryHandle(Uri mediaUri, bool isSchemaRelative, out string iframeUrl)
|
||||
{
|
||||
iframeUrl = null;
|
||||
var uri = isSchemaRelative ? "//" + mediaUri.GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Scheme, UriFormat.UriEscaped) : mediaUri.ToString();
|
||||
if (!matcher.IsMatch(uri))
|
||||
return false;
|
||||
iframeUrl = matcher.Replace(uri, replacement);
|
||||
return true;
|
||||
}
|
||||
|
||||
private Regex matcher;
|
||||
private string replacement;
|
||||
|
||||
public TestHostProvider(string provider, string replace)
|
||||
{
|
||||
matcher = new Regex(provider);
|
||||
replacement = replace;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("", "<p><iframe src=\"https://example.com/video.mp4\" class=\"regex\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n", @"^https?://sample.com/(.+)$", @"https://example.com/$1")]
|
||||
[TestCase("", "<p><iframe src=\"https://example.com/video.mp4\" class=\"regex\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n", @"^//sample.com/(.+)$", @"https://example.com/$1")]
|
||||
[TestCase("", "<p><iframe src=\"https://example.com/video.mp4?token=aaabbb\" class=\"regex\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n", @"^https?://sample.com/(.+)$", @"https://example.com/$1?token=aaabbb")]
|
||||
public void TestCustomHostProvider(string markdown, string expected, string provider, string replace)
|
||||
{
|
||||
string html = Markdown.ToHtml(markdown, GetPipeline(new MediaOptions
|
||||
{
|
||||
Hosts =
|
||||
{
|
||||
new TestHostProvider(provider, replace),
|
||||
}
|
||||
}));
|
||||
Assert.AreEqual(html, expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("", "<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"//sample.com/video.mp4\"></source></video></p>\n", "")]
|
||||
[TestCase(@"", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n", "")]
|
||||
[TestCase("", "<p><video class=\"k\" width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"//sample.com/video.mp4\"></source></video></p>\n", "k")]
|
||||
[TestCase(@"", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"k youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n", "k")]
|
||||
public void TestCustomClass(string markdown, string expected, string klass)
|
||||
{
|
||||
string html = Markdown.ToHtml(markdown, GetPipeline(new MediaOptions
|
||||
{
|
||||
Class = klass,
|
||||
}));
|
||||
Assert.AreEqual(html, expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("", "<p><video class=\"img-fluid\" width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"//sample.com/video.mp4\"></source></video></p>\n")]
|
||||
[TestCase(@"", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"img-fluid youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
|
||||
public void TestWithBootstrap(string markdown, string expected)
|
||||
{
|
||||
string html = Markdown.ToHtml(markdown, GetPipelineWithBootstrap());
|
||||
Assert.AreEqual(html, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user