Compare commits

...

736 Commits

Author SHA1 Message Date
Alexandre Mutel
e523dfd7f4 Update the logo for the NuGet package 2020-12-02 08:04:32 +01:00
Alexandre Mutel
412500158c Merge pull request #492 from ilich/master
Added a reference to WebStoating.Markdig.Prism
2020-12-02 07:56:38 +01:00
Alexandre Mutel
fc942b4d01 Update logo 2020-12-02 07:55:18 +01:00
Ilya Verbitskiy
d1d64842ca Added a reference to WebStoating.Markdig.Prism 2020-11-10 16:40:19 +08:00
Alexandre Mutel
930eee383f Use dotnet 3.1 for SpecFileGen 2020-11-08 11:06:16 +01:00
Alexandre Mutel
87c45db46b Use latest dotnet 3.1.x SDK 2020-11-08 10:52:17 +01:00
Alexandre Mutel
751c79fce4 Bump to 0.22.0 2020-10-05 08:20:45 +02:00
Alexandre Mutel
4dc8cc3977 Bump packages in tests 2020-10-05 08:20:31 +02:00
Alexandre Mutel
a1891e2984 Fix coverlet 2020-10-05 08:10:53 +02:00
Alexandre Mutel
ff0637993c Merge branch 'pr/n471_master' 2020-10-05 07:59:19 +02:00
Alexandre Mutel
8b64ce456f Fix quoteblock with setexheading when no lazy continuations are involved 2020-10-05 07:58:48 +02:00
Alexandre Mutel
a781ae1e5b Change tests to exe 2020-10-05 07:57:16 +02:00
Alexandre Mutel
2e5007241d Delay parsing of all specs in the tests itself instead of using static to restore the debuggability of markdig 2020-10-05 07:55:24 +02:00
Alexandre Mutel
cf6d98b7f8 Update tests 2020-10-05 07:54:13 +02:00
Ham Vocke
ccb7e8edfa add failing test, partial fix for setext headings in blockquotes
attempts to fix #465
2020-10-03 07:32:03 +02:00
Alexandre Mutel
db25c1db43 Merge pull request #473 from aloisdg/patch-1
Add a link to try the example
2020-10-03 07:22:22 +02:00
Alexandre Mutel
5db90ede4b Merge pull request #470 from iskcal/iss469
Fix issue 469
2020-10-03 07:21:34 +02:00
Alexandre Mutel
fef1ad3563 Merge pull request #474 from Wurstfried/pubFirstParentOfType
Make Inline.FirstParentOfType public
2020-10-03 07:20:20 +02:00
Alexandre Mutel
e9302d93bd Merge branch 'master' into pubFirstParentOfType 2020-10-03 07:15:02 +02:00
Alexandre Mutel
4704c49fbf Merge pull request #478 from yufeih/fix-476
Fix tel: treated as autolink
2020-10-03 07:12:36 +02:00
Alexandre Mutel
aca70e5c9a Merge pull request #479 from yufeih/fix-ci
Fix NETSDK1045 CI build failure
2020-10-03 06:34:36 +02:00
Yufei Huang
da5eff075d Fix NETSDK1045 CI build failure 2020-09-30 16:32:37 +08:00
Yufei Huang
971207e942 Fix tel: treated as autolink 2020-09-30 16:23:46 +08:00
iskcal
fb942f9810 fix typo 2020-09-15 19:31:29 +08:00
Sebastian Raffel
25a227fffd CI: Use dotnet SDK 3.1.402 2020-09-13 10:19:54 +02:00
Sebastian Raffel
2be8cd4aa7 Make Inline.FirstParentOfType public 2020-09-13 08:05:34 +02:00
Alois
569b80befe Add a link to try the example 2020-09-09 18:10:36 +02:00
iskcal
0b8b14490e fix issue 469 2020-08-25 13:05:44 +08:00
Alexandre Mutel
c59fd5c651 Merge pull request #468 from yufeih/parentblock
Add ParentBlock property to ContainerInline
2020-08-18 09:59:18 +02:00
Alexandre Mutel
4893e2b177 Merge pull request #467 from yufeih/container-block-parent
Set Parent in ContainerBlock.set[index] method
2020-08-18 09:44:41 +02:00
Yufei Huang
b30b219237 Add ParentBlock property to ContainerInline 2020-08-18 15:42:29 +08:00
Yufei Huang
d6c627aa88 Address PR feedback 2020-08-18 15:40:27 +08:00
Yufei Huang
a26f4298a4 Set Parent in ContainerBlock.set[index] method 2020-08-18 14:55:15 +08:00
Alexandre Mutel
d5b80f6a7b Bump to 0.21.1 2020-08-17 12:38:37 +02:00
Alexandre Mutel
98d747c839 Fix Pack signed 2020-08-17 12:38:07 +02:00
Alexandre Mutel
7dd9321a97 Bump to 0.21.0 2020-08-17 12:13:19 +02:00
Alexandre Mutel
c22d681c20 Merge pull request #464 from 928PJY/public-property
Expose IndentCount of FencedCodeBlock
2020-08-16 15:51:26 +02:00
Alexandre Mutel
ffe7f56bc2 Merge pull request #466 from Kryptos-FR/feature/net45
Bring back net45 target
2020-08-16 15:46:14 +02:00
Nicolas Musset
16c0b6a3fa ArrayHelper is needed for the tests
Slightly different from the previous implementation in order to mimic `System.Array.Empty<T>()` closely.
2020-08-16 13:13:45 +09:00
Nicolas Musset
db867dee48 Bring back net45 target 2020-08-16 12:47:04 +09:00
JiayinPei
d35b1b82ea Expose ColumnWidth of ListBlockItem 2020-08-13 14:34:07 +08:00
JiayinPei
8b829a2dea Export IndentCount of FencedCodeBlock 2020-08-13 12:07:04 +08:00
Alexandre Mutel
4f7ef61303 Merge pull request #459 from iskcal/fix456
Write custom rel into links
2020-08-06 18:51:02 +02:00
iskcal
831a529338 fix456 2020-08-03 11:51:38 +08:00
Alexandre Mutel
4f5e9cd334 Merge pull request #455 from hamvocke/master
Pipe Tables: Normalize using header column count
2020-07-30 18:18:28 +02:00
Ham Vocke
cb0b3a6292 add 'gfm-pipetables' pipeline mode, introduce new gfm test spec 2020-07-30 17:50:53 +02:00
Ham Vocke
4390ff289e add option to PipeTableOptions, use for normalization 2020-07-30 16:16:20 +02:00
Ham Vocke
be53e778be remove extra cells, use header row to find maxColumn 2020-07-30 15:03:33 +02:00
Ham Vocke
0eab0a3107 set up example006 of pipe table spec according to new behavior 2020-07-30 15:02:15 +02:00
Ham Vocke
8fa47427ac change test for pipe table normalization 2020-07-30 14:14:52 +02:00
Alexandre Mutel
bca544575b Merge pull request #449 from MihaZupan/invalid-idn-fallback
Fallback to non-punycode encoding for invalid IDN urls
2020-07-22 22:26:10 +02:00
Alexandre Mutel
0017dbffc4 Merge pull request #444 from iskcal/master
add the missing fact attribute
2020-07-22 22:25:14 +02:00
Alexandre Mutel
569efa357a Merge pull request #453 from davidackroyd99/feature/autolink-tel-uri
Autolink tel: uri
2020-07-22 22:24:47 +02:00
Alexandre Mutel
7e9df72173 Merge pull request #452 from davidackroyd99/bug/parsing-math
Bug/parsing math
2020-07-22 22:16:54 +02:00
David Ackroyd
b2fcb1cc37 autolink tel: uri, with basic test 2020-07-21 23:10:55 +00:00
David Ackroyd
8758ba460f fix: parsing math blocks with no leading or trailing whitespace 2020-07-21 21:35:52 +00:00
David Ackroyd
477a290538 typo: fixed comment in ApiController 2020-07-21 21:17:34 +00:00
MihaZupan
0fc112a6b8 Fallback to non-punycode encoding for invalid IDN urls 2020-07-12 00:15:02 +02:00
iskcal
b7aea44502 add the missing fact attribute 2020-06-17 16:22:34 +08:00
Alexandre Mutel
0545faa9af Merge pull request #435 from RudeySH/patch-1
Fix media link classes not being added
2020-06-09 20:34:11 +02:00
Rudey
ea67a295b2 Test CSS classes using both Bootstrap and MediaLinks 2020-05-12 22:32:05 +02:00
Rudey
d53128d56d Reorder class attribute in spec tests 2020-05-12 22:02:01 +02:00
Rudey
ba192ce065 Remove redundancy, apply same fix to audio/video 2020-05-12 21:45:50 +02:00
Rudey
42462d71ac Reorder class attribute in test cases 2020-05-12 21:41:52 +02:00
Rudey
6e0363aa91 Fix media link classes not being added 2020-05-12 21:29:28 +02:00
Alexandre Mutel
e9be3725d6 Merge pull request #431 from mlaily/escape-scheme
Escape URLs scheme
2020-04-30 07:34:03 +02:00
Melvyn Laïly
38f4332de1 Escape URLs scheme (fix #365) 2020-04-27 09:35:44 +02:00
Alexandre Mutel
bcc123d240 Merge pull request #429 from KrisVandermotten/StringSliceCountAndSkipChar
Added StringSlice.CountAndSkipChar(char)
2020-04-27 09:12:15 +02:00
Alexandre Mutel
144e8ad156 Merge pull request #430 from mlaily/fix-relative-url-replacement
Fix relative uri detection to be cross-platform compatible
2020-04-26 18:26:57 +02:00
Melvyn Laïly
55a7eae4d4 Fix relative uri detection to be cross-platform compatible 2020-04-26 18:02:45 +02:00
Kris Vandermotten
d96862378d Added StringSlice.CountAndSkipChar(char) 2020-04-26 15:17:19 +02:00
Alexandre Mutel
8acf5a548e Merge pull request #427 from MihaZupan/cleanup
Cleanup
2020-04-23 07:12:28 +02:00
MihaZupan
222a99c7e4 Pattern matching, inline variable declarations 2020-04-23 01:32:22 +02:00
MihaZupan
ac4a75bdf9 Fix comment warnings 2020-04-23 00:38:16 +02:00
MihaZupan
fc2e1ab896 Cleanup license headers 2020-04-22 17:48:44 +02:00
MihaZupan
ef7f20482e Remove unused usings 2020-04-22 17:10:14 +02:00
MihaZupan
fc50e2e2e7 Simplify crefs 2020-04-22 17:08:52 +02:00
Alexandre Mutel
4d513acf6b Add rider/idea to gitignore 2020-04-22 07:03:34 +02:00
Alexandre Mutel
32b1ee7eaa Remove Scriban.Signed from solution, keep it in the CI. Remove a warning 2020-04-22 06:59:57 +02:00
Alexandre Mutel
3e2a498ae7 Merge pull request #426 from MihaZupan/renormalize
git add --renormalize .
2020-04-22 06:55:35 +02:00
Alexandre Mutel
e0ac9b7ddf Merge pull request #425 from lellid/ContainerReadonlyList
Add IReadOnlyList interface to ContainerBlock to unify and simplify e…
2020-04-22 06:54:00 +02:00
Alexandre Mutel
bbf10a7ad0 Merge pull request #420 from SebastianRaffel/patch-1
PipeTableSpecs.md: Fix duplicate Rule numbering + bold headlines
2020-04-22 06:53:41 +02:00
MihaZupan
62a0992e5e git add --renormalize . 2020-04-22 00:47:46 +02:00
MihaZupan
b2e49d174e Add .gitattributes 2020-04-22 00:46:40 +02:00
SebastianRaffel
5e218721e7 Merge branch 'master' into patch-1 2020-04-20 09:25:36 +02:00
Sebastian Raffel
c64cd53ac3 Exec SpecFileGen 2020-04-20 09:23:13 +02:00
Dirk Lellinger
920ab6cb60 Add IReadonlyList interface to ContainerBlock to unify and simplify enumeration 2020-04-19 22:43:42 +02:00
Alexandre Mutel
3ef1d735d5 Bump to 0.20.0 2020-04-18 18:31:44 +02:00
Alexandre Mutel
47c6c49f5c Merge pull request #417 from KrisVandermotten/StringBuilderCache
Cleanup StringBuilderCache
2020-04-18 18:21:39 +02:00
Kris Vandermotten
a19f78342f merged from master 2020-04-18 18:17:40 +02:00
Alexandre Mutel
edb4c6c3cb Merge pull request #422 from KrisVandermotten/ListBlockParser
Cleanup ListBlockParser
2020-04-18 17:58:49 +02:00
Alexandre Mutel
4b6d7c78f5 Merge pull request #421 from KrisVandermotten/ParagraphBlockParser
Cleanup ParagraphBlockParser
2020-04-18 17:57:51 +02:00
Alexandre Mutel
0386cfd617 Merge pull request #418 from KrisVandermotten/CodeInlineParser
Optimized away the expensive StringBuilder.Remove(0, 1) in CodeInlineParser
2020-04-18 17:55:53 +02:00
Alexandre Mutel
5c52a7249d Merge pull request #416 from MihaZupan/new
Random improvements
2020-04-18 17:54:22 +02:00
Kris Vandermotten
14fb550704 Merge branch 'master' into StringBuilderCache 2020-04-18 14:21:48 +02:00
Kris Vandermotten
741d09a4e8 Merge branch 'master' into CodeInlineParser 2020-04-18 14:21:09 +02:00
Kris Vandermotten
34d9fa2bcc Merge branch 'master' into ParagraphBlockParser 2020-04-18 14:20:24 +02:00
Kris Vandermotten
8ee50a265d Merge branch 'master' into ListBlockParser 2020-04-18 14:19:46 +02:00
MihaZupan
eb002db3c7 Cross-target netstandard2.1 2020-04-18 14:14:57 +02:00
MihaZupan
a15203a061 Don't count non-ascii chars into maxChar limit in CharacterMap 2020-04-18 14:10:01 +02:00
MihaZupan
b0a2f19ed7 Optimize CharacterMap further 2020-04-18 14:10:00 +02:00
MihaZupan
a9d78e04a1 Cross-target Core 3.1 2020-04-18 14:10:00 +02:00
MihaZupan
a8b6e2c2e4 Remove allocation in EntityHelper.DecodeEntity 2020-04-18 14:10:00 +02:00
MihaZupan
665f5f5e51 Cache string representations of numbers 0-26 2020-04-18 14:10:00 +02:00
MihaZupan
86a72c3582 Avoid delegate allocation in LinkInlineParser.MarkParentAsInactive 2020-04-18 14:10:00 +02:00
MihaZupan
784b999d6c Improve CodeGen by using ThrowHelper everywhere 2020-04-18 14:10:00 +02:00
MihaZupan
be3a893d3d Use foreach where appropriate 2020-04-18 14:10:00 +02:00
MihaZupan
2679c84788 Remove .Net Foundation license header 2020-04-18 14:10:00 +02:00
MihaZupan
3d005d6444 Avoid allocations in EntityHelper 2020-04-18 14:09:59 +02:00
MihaZupan
09593ff3da Remove unused Helper 2020-04-18 14:09:59 +02:00
MihaZupan
f0269fc61f Remove ArrayHelper 2020-04-18 14:09:59 +02:00
MihaZupan
2d97628cfd Optimize StringSlice helpers 2020-04-18 14:09:59 +02:00
MihaZupan
ee97d32ef0 Remove MethodImplOptionPortable compat helper 2020-04-18 14:09:59 +02:00
MihaZupan
9ca5cdcb31 Remove substring allocation in RomanToArabic 2020-04-18 14:09:59 +02:00
MihaZupan
5f453fbe92 Remove ExcludeFromCodeCoverage compat for net35 2020-04-18 14:09:59 +02:00
MihaZupan
8300a9cca2 Add System.Memory package for netstandard2.0 2020-04-18 14:09:59 +02:00
MihaZupan
f7d763230d Unseal MarkdownParserContext 2020-04-18 14:09:58 +02:00
MihaZupan
cce1b99edc Drop net35 and net40 targets 2020-04-18 14:07:48 +02:00
Alexandre Mutel
2dca2119fa Run coveralls.net upload only on push 2020-04-18 09:13:32 +02:00
Alexandre Mutel
faf0a20816 Fix coverlet and coverall.net upload 2020-04-18 09:02:02 +02:00
Alexandre Mutel
68196c1ce6 Fix specs 2020-04-18 08:48:49 +02:00
Kris Vandermotten
fdf125d05d Cleanup ListBlockParser 2020-04-16 20:09:00 +02:00
Kris Vandermotten
46133715ab Cleanup ParagraphBlockParser 2020-04-16 20:03:40 +02:00
SebastianRaffel
ae726b3796 Fix duplicate Rule numbering + bold headlines 2020-04-14 08:51:44 +02:00
Kris Vandermotten
4151ac2287 Optimized away the expensive StringBuilder.Remove(0, 1) in CodeInlineParser 2020-04-13 16:24:35 +02:00
Kris Vandermotten
305f722899 Cleanup StringBuilderCache 2020-04-13 16:02:04 +02:00
Alexandre Mutel
abc8aa25b7 Merge pull request #411 from WeihanLi/patch-1
make dotnet framework ReferenceAssemblies Private
2020-03-23 20:49:37 +01:00
Alexandre Mutel
e6bb83ecdf Merge pull request #410 from KrisVandermotten/RendererBase
Optimized RendererBase
2020-03-23 20:48:54 +01:00
Weihan Li
e6ea8ad274 make dotnet framework ReferenceAssemblies Private 2020-03-19 13:33:18 +08:00
Kris Vandermotten
1f3cf5962f Optimized RendererBase 2020-03-09 15:32:29 +01:00
Alexandre Mutel
83b3427805 Fix Microsoft.SourceLink.GitHub 2020-03-08 10:45:00 +01:00
Alexandre Mutel
3ff3f1ccb9 Bump to 0.18.3 2020-03-08 10:33:57 +01:00
Alexandre Mutel
5d91f0e26f Fix NuGet symbol packages 2020-03-08 10:33:13 +01:00
Alexandre Mutel
9af462e412 Bump to 0.18.2 2020-03-08 10:15:30 +01:00
Alexandre Mutel
e1ba52da20 Merge pull request #406 from FranklinWhale/patch-1
Make output of HtmlTableRenderer XML wellformed
2020-03-08 10:09:29 +01:00
Alexandre Mutel
70ee97d5c7 Merge pull request #404 from webmaster442/master
Fixes issue #303
2020-03-08 10:09:03 +01:00
Alexandre Mutel
da916a1700 Merge pull request #402 from KrisVandermotten/HeadingRendererBugFix
Fixed a bug in HeadingRenderer
2020-03-08 10:08:47 +01:00
Franklin Tse
5548246703 Update TestPlayParser.cs 2020-03-06 19:00:37 +08:00
Franklin Tse
097fc5c4e0 Update GridTableSpecs.md 2020-03-06 18:55:00 +08:00
Franklin Tse
168ad39ff6 Make output of HtmlTableRenderer XML wellformed 2020-03-06 18:49:22 +08:00
Alexandre Mutel
54e065aabe Merge pull request #405 from bbodenmiller/patch-1
Github -> GitHub
2020-03-06 08:56:56 +01:00
Ben Bodenmiller
98d58797d9 Github -> GitHub 2020-03-05 23:55:39 -08:00
Ruzsinszki Gábor
2f0dd2a6a7 Fixes issue #303 2020-03-03 11:10:17 +01:00
Kris Vandermotten
247209870e Fixed a bug in HeadingRenderer 2020-03-01 14:44:41 +01:00
Alexandre Mutel
ef5b958267 Merge pull request #399 from KrisVandermotten/StringLineGroup
Some optimizations in StringLineGroup
2020-02-18 21:01:55 +01:00
Kris Vandermotten
7d61df2c0c Some optimizations in StringLineGroup 2020-02-15 10:34:24 +01:00
Alexandre Mutel
51f9da1974 Merge pull request #396 from KrisVandermotten/CharacterMapBitVector128
Use BitVector128 in CharacterMap<T>
2020-02-06 06:56:32 +01:00
Kris Vandermotten
9321628b9c Use uint instead of ulong 2020-02-05 22:38:21 +01:00
Kris Vandermotten
525e2c7fb8 Use BitVector128 in CharacterMap<T> 2020-02-04 22:45:42 +01:00
Alexandre Mutel
1f9b70636f Merge pull request #394 from KrisVandermotten/charactermap
Use HashSet<T> instead of Dictionary<TKey, TValue> in CharacterMap<T>
2020-01-31 18:43:24 +01:00
Kris Vandermotten
d4f43f826f Use HashSet<T> instead of Dictionary<TKey, TValue> in CharacterMap<T> 2020-01-31 18:35:28 +01:00
Alexandre Mutel
62788b1101 Merge pull request #393 from MihaZupan/line-reader
Optimize LineReader.ReadLine
2020-01-31 08:01:42 +01:00
MihaZupan
c3c4d37b82 Optimize LineReader.ReadLine 2020-01-30 21:14:06 +01:00
Alexandre Mutel
333bf04274 Update ci.yml, fix publish 2020-01-29 08:14:26 +01:00
Alexandre Mutel
dab4b7176d Merge pull request #392 from RudeySH/patch-1
Add Bootstrap and YAML to exclusion list in readme
2020-01-27 19:00:14 +01:00
Rudey
25ec56e1be Change frontmatter to Front Matter 2020-01-27 18:50:25 +01:00
Rudey
3455fd12da Add Bootstrap and YAML to exclusion list in readme
Both the Bootstrap and YAML frontmatter aren't included in `UseAdvancedExtensions`, but the readme didn't specify that.
2020-01-27 18:30:53 +01:00
Alexandre Mutel
ae5d47a0ed Merge pull request #391 from MihaZupan/remove-uap-remains
Remove UAP specific code
2020-01-27 08:36:14 +01:00
MihaZupan
1ff721d512 Remove UAP specific code 2020-01-26 23:04:57 +01:00
Alexandre Mutel
2c130504e2 Merge pull request #389 from MihaZupan/code-coverage
Improve code coverage
2020-01-26 22:01:06 +01:00
Alexandre Mutel
6405b16692 Migrate to GitHub Actions 2020-01-26 19:42:23 +01:00
Alexandre Mutel
2e1912a23d Update projects to compile with dotnet build/test, remove uap10.0 2020-01-26 19:35:21 +01:00
MihaZupan
71c680388c Make ExcludeFromCodeCoverage compatibility stub internal 2020-01-22 02:27:50 +01:00
MihaZupan
3f50b3fd0b Add LinkHelper.UrilizeAsGfm tests 2020-01-22 02:18:24 +01:00
MihaZupan
99b250b4c9 Add ContainerBlock tests 2020-01-22 02:06:42 +01:00
MihaZupan
655bf13df0 Exclude CompactPrefixTree from code coverage 2020-01-22 01:43:12 +01:00
MihaZupan
d2c89a3a06 Add tests for core Markdown apis 2020-01-22 01:42:23 +01:00
MihaZupan
754d11fd44 Fix test execution inside VS Enterprise Live Unit Testing 2020-01-21 21:44:29 +01:00
MihaZupan
1252e49ba4 Add more custom emoji tests 2020-01-21 18:36:36 +01:00
MihaZupan
d18487ae53 Fix StringLineGroupIterator.PeekChar for cross-line peeks 2020-01-21 18:16:13 +01:00
MihaZupan
f401d5082e Add SmartyPants tests 2020-01-21 17:35:58 +01:00
Alexandre Mutel
dd6418d108 Bump to 0.18.1 2020-01-21 08:30:32 +01:00
Alexandre Mutel
7875e4bce9 Merge pull request #387 from MihaZupan/descendants-api
Add missing Descendants<T> api
2020-01-21 08:24:13 +01:00
Alexandre Mutel
2e1b1a1fdc Merge pull request #386 from mlaily/emoji-customization
Emojis and smileys customization
2020-01-21 08:23:48 +01:00
MihaZupan
fa2b157c1a Improve some CharHelper methods 2020-01-21 01:31:44 +01:00
MihaZupan
e4e6406546 Add missing Descendants<T> overload 2020-01-21 01:03:47 +01:00
Melvyn Laïly
1cff10270a Set the default emoji dictionaries capacity in their ctor 2020-01-16 09:12:05 +01:00
Melvyn Laïly
87023184cb Clarify emoji terminology (emoji "shortcode") 2020-01-16 09:12:04 +01:00
Melvyn Laïly
aecdf2192e Improve the emoji extension (code review remarks) 2020-01-16 09:12:04 +01:00
Melvyn Laïly
0a36382126 Update changelog 2020-01-16 09:12:04 +01:00
Melvyn Laïly
0057b368ec Add unit tests for custom emojis and smileys 2020-01-16 09:11:04 +01:00
Melvyn Laïly
3033284096 Re-allow emojis and smileys customization
(this feature was broken in #308)
2020-01-16 09:11:03 +01:00
Alexandre Mutel
9b1b791b18 Merge pull request #341 from OpportunityLiu/master
Add customizable media link; handle protocol-less media
2020-01-15 13:27:06 +01:00
Opportunity
2b7d205701 Merge branch 'master' into master 2020-01-15 19:35:17 +08:00
Opportunity
89b28659b1 Update src/Markdig/Extensions/MediaLinks/HostProviderBuilder.cs
Co-Authored-By: Alexandre Mutel <alexandre_mutel@live.com>
2020-01-15 19:32:37 +08:00
Alexandre Mutel
446b1bcc0d Bump to 0.18.0 2019-10-24 21:08:11 +02:00
Alexandre Mutel
ec7a4a6902 Create FUNDING.yml 2019-10-24 07:10:27 +02:00
Alexandre Mutel
07a77142f4 Merge pull request #377 from MihaZupan/allocation-reductions
10% time and 50% memory improvement
2019-10-15 23:06:31 +02:00
MihaZupan
3606f234b8 Update changelog 2019-10-15 15:09:34 +02:00
MihaZupan
616eed62bd Use try/finally instead of goto release in AutoLinkParser 2019-10-15 15:07:45 +02:00
MihaZupan
99f55e9ddc Resolve merge conflict 2019-10-15 14:58:03 +02:00
Alexandre Mutel
f8ab1cccc5 Merge pull request #375 from MihaZupan/balanced-link-brackets
Balanced link brackets
2019-10-15 13:46:31 +02:00
MihaZupan
f24067cd16 Update AppVeyor build image 2019-10-14 19:11:28 +02:00
MihaZupan
9af96ba2b4 Minor CharHelper optimizations 2019-10-14 19:03:15 +02:00
MihaZupan
c99f7dd96a Mark some struct methods as readonly 2019-10-14 18:39:40 +02:00
MihaZupan
bf28cbd33f Optimize ContainerBlock this[] accessor 2019-10-14 18:32:24 +02:00
MihaZupan
2040e23545 Correctly return IsEmpty for ICharIterator.TrimStart 2019-10-14 18:31:51 +02:00
MihaZupan
2761e36b6b Optimize StringSlice primitives 2019-10-14 18:28:32 +02:00
MihaZupan
891334134c Mark Readonly structs as Readonly 2019-10-14 13:38:21 +02:00
MihaZupan
0987fab6f2 Seal internal types 2019-10-14 13:33:24 +02:00
MihaZupan
ed5eea5e27 Cache List<char> in AutoLinkParser 2019-10-14 13:26:09 +02:00
MihaZupan
f73cbe4e76 Resize LineOffsets to sufficient Capacity before adding items 2019-10-14 13:11:07 +02:00
MihaZupan
aefad219cf Cache StringLine[]s in StringLineGroup with a custom ArrayPool 2019-10-14 13:04:27 +02:00
MihaZupan
76c3e88c58 Estimate LineCount from text Length to minimize List resizes 2019-10-14 12:58:03 +02:00
MihaZupan
afe4308e91 Cache HtmlRenderer on Pipeline for ToHtml(string, Pipeline) 2019-10-13 18:03:13 +02:00
MihaZupan
606556b692 Use Write(Span) on NetCore 2019-10-13 15:44:36 +02:00
MihaZupan
253be5c362 Cache HtmlRenderers in AutoIdentifier Extension 2019-10-13 15:17:33 +02:00
MihaZupan
33037d1034 Update changelog 2019-10-08 17:29:49 +02:00
MihaZupan
f16ee828db Fix link text balanced bracket matching 2019-10-08 17:27:50 +02:00
MihaZupan
a76305f39b Add tests for balanced brackets in link text
For issue #371
2019-10-08 17:26:16 +02:00
MihaZupan
f52a41e167 Cleanup LinkInline parsing code
No functional changes, readability only
Switch with a single case => if statement
Pattern matching, inline out variable declarations ...
2019-10-08 16:22:53 +02:00
Opportunity
4d172bf905 Merge branch 'master' into master 2019-10-01 21:31:02 +08:00
Opportunity
890b2cda2a Update MediaLinkExtension.cs 2019-09-30 21:09:44 +08:00
Alexandre Mutel
c818670919 Merge pull request #360 from MihaZupan/smarty-pants
Fix SmartyPants quote matching
2019-09-25 22:15:36 +02:00
Alexandre Mutel
a78a0b7016 Merge pull request #361 from MihaZupan/generic-attributes
Fix GenericAttributes matching of single-char values
2019-09-25 22:15:22 +02:00
Miha Zupan
6a0c9aeb47 Fix GenericAttributes matching of single-char values 2019-08-01 16:14:51 +02:00
Miha Zupan
b1cfcf2431 Add GenericAttributes test for #182 2019-08-01 16:13:37 +02:00
Miha Zupan
b411522a23 Increase EnsureSpecsAreUpToDate time leeway to 3min 2019-08-01 16:12:44 +02:00
Miha Zupan
1d2977d47b Fix SmartyPants quote matching 2019-08-01 15:28:20 +02:00
Miha Zupan
ee8c87c357 Add SmartyPants tests for #183 2019-08-01 15:26:04 +02:00
Alexandre Mutel
25959174d5 Merge pull request #357 from MihaZupan/master
Ignore backticks in GFM AutoLinks
2019-07-17 09:25:33 +02:00
Miha Zupan
033ddaf6a8 Ignore backticks in GFM AutoLinks 2019-07-16 10:21:52 +02:00
Alexandre Mutel
f3f7584c39 Bump to 0.17.1 2019-07-04 22:21:31 +02:00
Alexandre Mutel
d00ca4acc1 Add coverage badge to readme.readme.md 2019-07-03 09:00:45 +02:00
Alexandre Mutel
d9663ef2e6 Try to upload to coveralls.io 2019-07-03 08:39:34 +02:00
Alexandre Mutel
3106a49d02 Merge pull request #352 from MihaZupan/master
Add code coverage
2019-07-03 08:30:49 +02:00
Miha Zupan
a47a6890e7 Remove coverage report from source control 2019-07-02 15:53:32 +02:00
Miha Zupan
7d21f8b003 Add test code coverage 2019-06-29 21:04:55 +02:00
Miha Zupan
15f6205adc Ensure line ending diffs don't trigger spec regeneration 2019-06-29 19:28:45 +02:00
Miha Zupan
e6dd2cf3d4 Cleanup build configuration 2019-06-27 12:36:19 +02:00
Alexandre Mutel
ea6592b773 Merge pull request #346 from kelvindules/update-emoji-dictionary
Update Emoji Dictionary
2019-06-07 14:43:30 +02:00
Kelvin Dules
5cd20efe3e Removed duplicates 2019-06-06 20:19:41 -03:00
Kelvin Dules
31c7ba5862 Update Emoji Dictionary 2019-06-06 19:29:32 -03:00
Alexandre Mutel
0272840a62 Add Markdig.Signed project. Move Markdig.Benchmarks to new csproj 2019-05-25 22:46:27 +02:00
OpportunityLiu
8886b48634 add tests 2019-05-16 15:58:02 +08:00
OpportunityLiu
64cd8ec262 customize iframe class of each provider 2019-05-15 10:48:12 +08:00
OpportunityLiu
a1e19912a9 update changelog 2019-05-14 17:32:09 +08:00
OpportunityLiu
ca51967fb1 fix #135 2019-05-14 17:31:03 +08:00
OpportunityLiu
bb3a4f372c add change log 2019-05-14 16:07:14 +08:00
OpportunityLiu
1d6a464c5d add unit test 2019-05-14 15:59:05 +08:00
OpportunityLiu
0fe5c17a93 Add customizable media link 2019-05-14 15:30:15 +08:00
Alexandre Mutel
f879d55b4a Merge pull request #340 from MihaZupan/master
Fix regression from #315
2019-05-13 10:46:59 +02:00
Miha Zupan
6d3a3584ac Fix regression from #315 2019-05-12 11:28:04 +02:00
Alexandre Mutel
ea13b33f1a Allow to tag with version without v prefix 2019-05-11 17:22:14 +02:00
Alexandre Mutel
9b2ec2e2e5 Bump to 0.17.0 2019-05-10 18:25:10 +02:00
Alexandre Mutel
d8dffc28b4 Merge pull request #336 from FranklinWhale/youtube-enhancements
Enhancements for YouTube Links
2019-05-10 18:20:38 +02:00
Alexandre Mutel
0735042599 Merge pull request #334 from OpportunityLiu/master
fix code inline normalize
2019-05-10 18:18:03 +02:00
Franklin Tse
d1f99cdb69 Add test cases and URL escaping 2019-04-30 03:00:35 +08:00
Franklin Tse
d0a2ae2b50 Code formatting change 2019-04-30 01:46:54 +08:00
OpportunityLiu
dd4d1b349f lf as line ending 2019-04-29 16:57:33 +08:00
OpportunityLiu
e33281b8ae optimize 2019-04-29 16:39:55 +08:00
Franklin Tse
50d42560da Use null-conditional operator 2019-04-29 15:11:32 +08:00
Franklin Tse
a1e96d717b Correct lambda 2019-04-29 15:08:48 +08:00
Franklin Tse
56278657fd Fixes #335 2019-04-29 14:58:06 +08:00
OpportunityLiu
b7202084d2 fix code inline normalize 2019-04-29 10:49:37 +08:00
Alexandre Mutel
88052168d0 Merge pull request #304 from nschonni/patch-1
typo: dib -> div
2019-04-23 11:52:41 +02:00
Alexandre Mutel
27cb88773a Merge pull request #331 from nschonni/typos
typo roundup
2019-04-23 11:52:00 +02:00
Nick Schonning
fe3d5b0ccf typo: occuring -> occurring 2019-04-15 02:05:17 -04:00
Nick Schonning
86759e44e1 typo: jsut -> just 2019-04-15 02:02:30 -04:00
Nick Schonning
dd60990d3d typo: Sibliing -> Sibling 2019-04-15 02:01:46 -04:00
Nick Schonning
a3a9496c6f typo: inlnie -> inline 2019-04-15 02:01:16 -04:00
Nick Schonning
d09013ba14 typo: childrens -> children 2019-04-15 02:00:47 -04:00
Nick Schonning
9499660f83 typo: columWidth -> columnWidth 2019-04-15 02:00:25 -04:00
Nick Schonning
df24ab9846 typo: succesfull -> successful 2019-04-15 01:59:18 -04:00
Nick Schonning
40a8cd09b6 typo: proessed -> processed 2019-04-15 01:58:43 -04:00
Nick Schonning
b556f06d31 typo: balanaced -> balanced 2019-04-15 01:58:25 -04:00
Nick Schonning
54e61d3b91 typo: succsesfull -> successful 2019-04-15 01:57:18 -04:00
Nick Schonning
221afcc4d3 typo: curent -> current 2019-04-15 01:56:43 -04:00
Nick Schonning
f1fc64af42 typo: arround -> around 2019-04-15 01:55:52 -04:00
Nick Schonning
b39614f10c typo: ommitted -> omitted 2019-04-15 01:54:44 -04:00
Nick Schonning
5bda352f7a typo: backstick -> backtick 2019-04-15 01:54:08 -04:00
Nick Schonning
4f08094de0 typo: accross -> across 2019-04-15 01:51:25 -04:00
Nick Schonning
13a733a061 typo: Abreviation -> Abbreviation 2019-04-15 01:51:09 -04:00
Nick Schonning
d010a4f21e typo: occured -> occurred 2019-04-15 01:45:25 -04:00
Nick Schonning
a353c59e26 typo: Repressents -> Represents 2019-04-15 01:42:55 -04:00
Nick Schonning
01c8aedced typo: dicard -> discard 2019-04-15 01:40:58 -04:00
Nick Schonning
01d8842ac1 typo: sucessfull -> successful 2019-04-15 01:40:35 -04:00
Nick Schonning
69a2261562 typo: perfoming -> performing 2019-04-15 01:40:03 -04:00
Nick Schonning
09905db72a typo: Sligthly -> Slightly 2019-04-15 01:39:34 -04:00
Nick Schonning
754409c8fa typo: minumun -> minimum 2019-04-15 01:39:10 -04:00
Nick Schonning
cd67a3049a typo: porcess -> process 2019-04-15 01:38:35 -04:00
Nick Schonning
277aef341a typo: occurence -> occurrence 2019-04-15 01:38:03 -04:00
Nick Schonning
9a5ef61bd1 typo: implemts -> implements 2019-04-15 01:37:37 -04:00
Nick Schonning
ed6c59dd07 typo: blcok -> block 2019-04-15 01:37:08 -04:00
Nick Schonning
4deeac538a typo: openning -> opening 2019-04-15 01:36:31 -04:00
Nick Schonning
b05161d20e typo: continous -> continuous 2019-04-15 01:36:11 -04:00
Nick Schonning
d02adf1bf3 typo: elemeent -> element 2019-04-15 01:35:39 -04:00
Nick Schonning
f767b649e6 typo: mulitple -> multiple 2019-04-15 01:33:54 -04:00
Nick Schonning
bdec15d943 typo: capitalised -> capitalized
US spelling since that is normal in .Net
2019-04-15 01:30:36 -04:00
Nick Schonning
fe4ac6643a typo: preceeded -> preceded 2019-04-15 01:29:12 -04:00
Nick Schonning
eb72bc6d4f typo: onre -> one 2019-04-15 01:28:03 -04:00
Nick Schonning
f484366612 typo: hypen -> hyphen 2019-04-15 01:27:32 -04:00
Nick Schonning
bb5e45b939 typo: Nuitrion -> Nutrition 2019-04-15 01:25:52 -04:00
Nick Schonning
2b41e47170 typo: outputing -> outputting 2019-04-15 01:23:59 -04:00
Nick Schonning
3c16852219 typo: ponctuation -> punctuation 2019-04-15 01:21:33 -04:00
Nick Schonning
744417c7a2 typo: dib -> div 2019-04-15 01:07:01 -04:00
Alexandre Mutel
4039e11e08 Merge pull request #327 from MihaZupan/pr327
CommonMark 0.29, DisableHeadings extension, AutoLinkOptions
2019-04-12 17:59:01 +02:00
Miha Zupan
3c73a2d05a Apply CommonMark spec patch 2019-04-12 17:28:35 +02:00
Miha Zupan
1ef247b093 Update readme and changelog 2019-04-11 16:56:11 +02:00
Miha Zupan
d45d8873f5 [CM 0.29] Use new ListItem indendation rules 2019-04-11 16:53:18 +02:00
Miha Zupan
396a03567c Update code comments for Link- and CharHelper 2019-04-11 14:54:40 +02:00
Miha Zupan
6a98e204a5 [CM 0.29] Remove 'meta' from recognised html tags 2019-04-11 11:01:48 +02:00
Miha Zupan
210a6612c7 [CM 0.29] Apply new entity length limits 2019-04-11 11:01:37 +02:00
Miha Zupan
27c35b3b09 [CM 0.29] Correctly handle empty setex headings under a LinkReferenceDefinition 2019-04-10 23:19:40 +02:00
Miha Zupan
ac1db841d5 [CM 0.29] Permit empty urls and spaces for angle-bracket links 2019-04-10 23:18:06 +02:00
Miha Zupan
09f29615c1 [CM 0.29] Use new rule for EmphasisDelimiter matching 2019-04-10 23:07:21 +02:00
Miha Zupan
05e5a3f2bb [CM 0.29] Use new infostring rules for tilde FencedBlocks 2019-04-10 23:06:09 +02:00
Miha Zupan
6d238de69e [CM 0.29] Use new space-trimming rules for CodeInline 2019-04-10 23:02:50 +02:00
Miha Zupan
5b88dbb90a Use StringBuilderCache in JiraLink parser 2019-04-10 23:00:14 +02:00
Miha Zupan
fbd822cef7 Update CommonMark spec to 0.29 2019-04-10 22:59:23 +02:00
Miha Zupan
0e22a120f1 Use a '.generated' suffix for generated test code files 2019-04-05 18:18:26 +02:00
Alexandre Mutel
590f3d0b1b Merge pull request #326 from manuel-guilbault/master
Set ContainerBlock.Count to zero upon Clear() calls.
2019-04-05 09:01:47 -07:00
Miha Zupan
23766d84fa Rename UseHttpsForWWWLinks option 2019-04-05 16:59:51 +02:00
Miha Zupan
14e9e618a2 Update changelog 2019-04-05 16:48:11 +02:00
Miha Zupan
f523cb243b Add UseHttpsPrefixForWWWLinks option to AutoLinks 2019-04-05 16:45:09 +02:00
Miha Zupan
1064818b49 Add OpenInNewWindow option to AutoLinks 2019-04-05 16:37:15 +02:00
Miha Zupan
befd1ca846 Add 'DisableHeadings' extension 2019-04-05 16:07:15 +02:00
Miha Zupan
65c671d014 Bump target UWP version 2019-04-03 22:27:01 +02:00
Manuel Guilbault
25bc0b8bf6 Set Count to zero upon Clear() calls. 2019-04-01 15:27:17 +02:00
Miha Zupan
343a2a17e1 Add sample Normalize/PlainText spec files 2019-03-17 13:00:11 +01:00
Miha Zupan
5100ed0b68 Update changelog 2019-03-17 11:58:48 +01:00
Miha Zupan
95dd2c148c Add Spec files for Normalize and PlainText renderers 2019-03-17 11:39:47 +01:00
Alexandre Mutel
354db6b306 Merge pull request #319 from MihaZupan/allow-unicode-domain-names
Allow unicode domain names
2019-03-11 18:30:01 +01:00
Miha Zupan
50313a36dc Update changelog 2019-03-11 18:19:04 +01:00
Miha Zupan
77d5dcb6dd Drop support for netstandard1.1 and legacy PCL 2019-03-11 16:35:14 +01:00
Miha Zupan
1c88fb65c8 Use IDNA encoding for domain names containing non-ascii chars 2019-03-11 15:36:03 +01:00
Miha Zupan
db9660d090 Allow non-ascii characters in domain names 2019-03-11 15:35:55 +01:00
Miha Zupan
39ab066e2d Exclude nuget.props from source control 2019-03-11 15:35:44 +01:00
Miha Zupan
47f395dad7 Add unicode domain name test for LinkReferenceDefinitions 2019-03-09 20:16:01 +01:00
Miha Zupan
04e195cdb2 Add tests for unicode in domain names 2019-03-09 19:59:23 +01:00
Miha Zupan
3b3872ffe3 Use a universal time format for spec timestamps 2019-03-09 19:59:00 +01:00
Alexandre Mutel
c7cda0df45 Merge pull request #318 from OpportunityLiu/master
fix #242: HtmlCustomContainerRenderer does not honour EnableHtmlForBlock == false
2019-03-08 10:12:49 +01:00
OpportunityLiu
7651e75bfa fix #242 2019-03-08 16:59:47 +08:00
Alexandre Mutel
ea99cd6115 Merge pull request #315 from OpportunityLiu/patch-1
Fix ToPlainText with htmlentity
2019-03-07 10:14:40 +01:00
Opportunity
3af4f33b5d Update TestPlainText.cs 2019-03-07 16:39:03 +08:00
Opportunity
41e8d5e5fc Update LiteralInlineRenderer.cs 2019-03-07 16:37:43 +08:00
Opportunity
5a73c2bf2b Update HtmlEntityInlineRenderer.cs 2019-03-07 16:37:11 +08:00
Opportunity
f542fd0a88 Update LiteralInlineRenderer.cs 2019-03-07 16:36:29 +08:00
Opportunity
5a6300823c Update HtmlEntityInlineRenderer.cs 2019-03-07 16:33:43 +08:00
Alexandre Mutel
6dcef438c4 Bump to 0.16.0 2019-02-25 20:20:31 +01:00
Alexandre Mutel
40206c4d76 Merge pull request #311 from RickStrahl/MathExtension_Bracketing
Add Bracketing around Math Expressions for improved MathLib Rendering
2019-02-25 20:10:23 +01:00
Alexandre Mutel
24ecfc93f3 Merge pull request #310 from MihaZupan/master
Improve CompactPrefixTree's memory footprint
2019-02-25 20:08:37 +01:00
Rick Strahl
8eb52c50ec Update Math Specs and ensure tests pass. 2019-02-22 10:29:32 -10:00
Rick Strahl
9965597256 Fix tests to match bracketing. 2019-02-21 17:33:17 -10:00
Rick Strahl
987580e71e Add inline block and block display bracketing tags around rendered mathematics content so it can render 2019-02-21 17:02:39 -10:00
Miha Zupan
bba3ef04ee Improve CompactPrefixTree's memory footprint 2019-02-21 17:29:09 +01:00
Alexandre Mutel
d8a594a151 Merge pull request #309 from yishengjin1413/master
remove lazy initialize
2019-02-20 10:14:36 +01:00
Terry Jin
60c64b67c7 remove lazy initialize 2019-02-20 16:48:26 +08:00
Alexandre Mutel
7f0b39a44a Merge pull request #308 from yishengjin1413/master
fix emoji performance issue when multiple pipeline needed
2019-02-20 09:15:31 +01:00
Terry Jin
57784cedc6 fix emoji performance issue when muti pipeline needed 2019-02-20 15:24:45 +08:00
Alexandre Mutel
80b918e6f5 Merge pull request #301 from MihaZupan/improved-emphasis-parser
Improved emphasis parser
2019-02-09 14:30:02 +01:00
Miha Zupan
64883152c9 Remove HasFlag helper 2019-02-09 12:15:29 +01:00
Miha Zupan
20bd561062 Avoid a possible Null Reference Ex. 2019-02-09 00:35:19 +01:00
Miha Zupan
035ce17386 Add generic TEnum constraint to HasFlag 2019-02-08 19:50:40 +01:00
Alexandre Mutel
bc4dbd1b35 Merge pull request #300 from picrap/tr-writeattributes
HtmlTableRenderer: writing <tr> attributes
2019-02-08 17:44:50 +01:00
Alexandre Mutel
1d8266b86d Merge pull request #305 from MihaZupan/emoji-and-abbreviations-parser
Emoji and abbreviations parser
2019-02-08 17:37:59 +01:00
Miha Zupan
b5293b907f Comment-out TextMatcher test in Benchmarks 2019-02-06 17:27:00 +01:00
Miha Zupan
a11676ed7e Add test case for #296 2019-02-06 17:17:30 +01:00
Miha Zupan
18e9486c95 Remove TextMatchHelper 2019-02-06 16:32:55 +01:00
Miha Zupan
ef452c292c Fix Abbreviations parser's one-char handling 2019-02-06 16:32:37 +01:00
Miha Zupan
325495a367 Improve EmojiParser memory performance 2019-02-06 16:31:57 +01:00
Miha Zupan
d854b0b941 Port CompactPrefixTree to Markdig 2019-02-06 16:31:23 +01:00
Miha Zupan
ca38da576e Cross target NetCore 2.1 2019-02-06 15:46:12 +01:00
Miha Zupan
b15b05015e Allow single-char abbreviations 2019-02-06 15:44:12 +01:00
Miha Zupan
5266ae965b Add extended emphasis tests 2019-01-29 22:10:06 +01:00
Miha Zupan
42b201d8c2 Update internals to renewed Emphasis parser 2019-01-29 22:09:39 +01:00
Miha Zupan
d232e847dd Allow different min/max emphasis delimiter counts 2019-01-29 22:09:05 +01:00
Miha Zupan
1b5d9d46fc Emit correct warning message in tests 2019-01-29 22:07:17 +01:00
Miha Zupan
6b1b5165ca Add HasFlag enum support 2019-01-29 22:06:28 +01:00
Pascal Craponne
7719ef503f HtmlTableRenderer: writing <tr> attributes 2019-01-29 21:39:28 +01:00
Alexandre Mutel
f01b5281fd Merge pull request #295 from TravisEz13/Add_license_to_nupkg
Add the license expression to the `csproj`
2019-01-27 21:32:15 +01:00
Alexandre Mutel
3e4e6d6627 Merge pull request #294 from MihaZupan/alternative-specs-gen
Alternative specs generation
2019-01-27 21:31:11 +01:00
Miha Zupan
16ffc052a3 Update error message for modified spec files 2019-01-27 16:01:25 +01:00
neolithos
22853d9782 Add Neo.Markdig.Xaml (#298)
* Add: Neo.Markdig.Xaml to readme.md
2019-01-27 14:59:58 +01:00
Miha Zupan
8164c1fa8d Test that specs are up to date 2019-01-27 13:13:26 +01:00
Travis Plunk
8a42f74a6c removed URl to fix this error
```
  C:\Program Files\dotnet\sdk\2.2.100\Sdks\NuGet.Build.Tasks.Pack\buildCrossTargeting\NuGet.Build.Tasks.Pack.targets(202,5): error NU5035: The PackageLicenseUrl is being deprecated and cannot be used in conjunction with the PackageLicenseFile or PackageLicenseExpression. [C:\projects\markdig\src\Markdig\Markdig.csproj]
```
2019-01-22 15:26:31 -08:00
Travis Plunk
19a5a07763 Add the license expression to the csproj 2019-01-22 15:14:52 -08:00
Miha Zupan
dd68351235 Fix test path resolution 2019-01-21 16:38:58 +01:00
Miha Zupan
c346e55a46 Remove Specs.tt 2019-01-21 16:11:01 +01:00
Miha Zupan
ffdfd427ce Generate Specs 2019-01-21 16:10:34 +01:00
Miha Zupan
edbf832e0a Fail CI if specs are not synced 2019-01-21 16:00:18 +01:00
Miha Zupan
7887cf7348 Generate Specs with C# 2019-01-21 16:00:05 +01:00
Alexandre Mutel
e6432038b5 Merge pull request #288 from MihaZupan/rewrite-descendants-search
Rewrite Descendants iteratively
2019-01-19 19:27:26 +01:00
Alexandre Mutel
f8df3c80e1 Merge pull request #285 from patriksvensson/feature/GH-284
Adds markdown parser context
2019-01-19 18:04:26 +01:00
Alexandre Mutel
664c824f8b Use Dictionary and removes setter 2019-01-19 18:03:42 +01:00
Miha Zupan
95cbf0e6d2 Cache Schema markdown in Tests 2019-01-19 11:35:01 +01:00
Miha Zupan
b2a542b43e Simplify push condition 2019-01-18 20:23:17 +01:00
Miha Zupan
f1b736f918 Add Test for Descendants order 2019-01-18 19:19:42 +01:00
Miha Zupan
282da043b7 Rewrite Descendants(ContainerInline) iteratively 2019-01-18 18:52:48 +01:00
Miha Zupan
4519d3820a Rewrite Descendants(ContainerBlock) iteratively 2019-01-18 18:52:30 +01:00
Miha Zupan
37325f1bdc Use existing Descantants<T>(ContainerInline) implementation 2019-01-18 18:27:58 +01:00
Miha Zupan
1bbe20dca1 Rewrite Descendants(MarkdownObject) iteratively 2019-01-18 18:22:28 +01:00
Alexandre Mutel
b237d70298 Merge pull request #287 from MihaZupan/emphasis-patch
Emphasis patch
2019-01-15 16:31:42 +01:00
Miha Zupan
632f400a74 Add tests for EmphasisExtraOptions 2019-01-15 16:24:19 +01:00
Miha Zupan
a302db679c Respect EmphasisExtraOptions 2019-01-15 16:23:06 +01:00
Patrik Svensson
653972847c Adds markdown parser context
Closes #284
2019-01-12 22:59:41 +01:00
Alexandre Mutel
832f86cf5f Bump to 0.15.7 2019-01-11 15:52:56 +01:00
Alexandre Mutel
103434eb9b Merge pull request #283 from OsmondJiang/configurable_leading_#_count
make the max leading # count in heading block parser configurable
2019-01-07 10:50:15 +01:00
OsmondJiang
f9dd201563 move heading block extension outside 2019-01-07 17:18:52 +08:00
OsmondJiang
9b9243a61f add heading block parser to able to config max leading count of # 2019-01-07 17:03:02 +08:00
Alexandre Mutel
91dbfce18e Merge pull request #281 from FranklinWhale/bool-attr
Render XML well-formed boolean attribute
2019-01-04 13:47:45 +01:00
Franklin Tse
57692a557b controls attribute is also changed 2019-01-04 00:48:10 +08:00
Franklin Tse
02bd8149ac Use empty string instead of attribute name 2019-01-04 00:23:19 +08:00
Franklin Tse
0920001f45 Remove the unnecessary EOL at the end 2019-01-03 23:51:04 +08:00
Franklin Tse
cde939f79c Update spec and test cases 2019-01-03 23:49:38 +08:00
Franklin Tse
f932b3c87a Use attribute name as value if value is null 2019-01-03 23:43:54 +08:00
Alexandre Mutel
b2a7baa079 Bump to 0.15.6 2018-12-28 11:32:11 +01:00
Alexandre Mutel
1c37c996dc Try to fix loading files from CI 2018-12-28 11:19:37 +01:00
Alexandre Mutel
da99af68c6 Fix offset for StringLineGroup.Iterator.Remaining() 2018-12-28 10:59:34 +01:00
Alexandre Mutel
03858dc5c8 Add tests for checking that ArgumentOutOfRangeException doesn't occur on invalid input md string (#275) 2018-12-28 10:36:10 +01:00
Alexandre Mutel
ebedc6829d Fix IndexOutOfRangeException while parsing fenced code block with a single trailing space (#276) 2018-12-28 10:30:37 +01:00
Alexandre Mutel
28322c3645 Fix parsing of an invalid html entity (#277) 2018-12-28 10:23:25 +01:00
Alexandre Mutel
c3395e6779 Fix potential hang when parsing LinkReferenceDefinition (#278) 2018-12-28 10:12:17 +01:00
Alexandre Mutel
cc47d33c7d Bump version to 0.15.5 2018-12-11 13:40:22 +01:00
Alexandre Mutel
fedbe2adc5 Merge pull request #267 from redcrayonn/patch-1
AutoIdentifierOptions clarification
2018-12-11 13:34:02 +01:00
Alexandre Mutel
8efc082d1d Update typo in AutoIdentifierOptions 2018-12-04 10:02:56 +01:00
Alexandre Mutel
6c2702f9fd Merge pull request #270 from neilha/master
fixes #196 ensuring line breaks when renderer does not have html enabled
2018-11-22 15:46:33 +01:00
Neil Harrold
4824f460c0 fixes #196 ensuring line breaks when renderer does not have html enabled 2018-11-21 09:03:24 +00:00
Olaf de Mol
46fc840c35 AutoIdentifierOptions clarification
Clarified 'None' option in the options for the auto-identifiers extension.
2018-11-09 15:22:02 +01:00
Alexandre Mutel
ce3078dcf2 Merge pull request #264 from MihaZupan/autolink-prev-chars
Make AutoLink ValidPreviousCharacters configurable
2018-10-29 07:29:43 -07:00
Miha Zupan
b8255a87cf Make AutoLink ValidPreviousCharacters configurable 2018-10-29 15:10:11 +01:00
Alexandre Mutel
4f6ad47c6a Merge pull request #255 from dampee/patch-1
having three dots while it has to be three dashes
2018-10-27 07:27:49 -07:00
Alexandre Mutel
d6d6f9c5c1 Merge pull request #256 from SyntaxC4/patch-1
Fixed spelling mistake
2018-10-27 07:27:28 -07:00
Alexandre Mutel
92b06f0954 Merge pull request #260 from MihaZupan/fix-autolinks
Allow #, ? and : instead of only / as the domain separator for AutoLinks
2018-10-25 12:54:57 -07:00
Miha Zupan
ecd625d40b Test for links without a slash after the domain 2018-10-25 16:56:33 +02:00
Miha Zupan
7e81747662 AutoLink Match links without slash after domain 2018-10-25 16:54:51 +02:00
Cory Fowler
cffe5b2f4b Update FootnotesSpecs.md 2018-10-10 17:03:38 -07:00
Damiaan
c349ead32c having three dots while it has to be three dashes 2018-10-09 11:44:53 +02:00
Alexandre Mutel
07e6a13378 Merge pull request #254 from MihaZupan/issue_251
Empty image alt text for link reference definitions
2018-10-07 20:57:38 +02:00
Miha Zupan
1b54bb157c Added image alt text tests 2018-10-07 19:24:24 +02:00
Miha Zupan
e23fae26c8 Empty image alt text for link reference definitions 2018-10-07 16:27:50 +02:00
Alexandre Mutel
2501c6aaf6 Bump to 0.15.4 2018-10-07 09:23:53 +02:00
Alexandre Mutel
e390a870cc Merge branch 'pr/n253_MihaZupan' 2018-10-06 18:04:35 +02:00
Miha Zupan
e4892fc86d Update Specs.cs 2018-10-06 18:03:39 +02:00
Miha Zupan
dfc67021ee Add autolink domain validation tests 2018-10-06 17:29:14 +02:00
Miha Zupan
25db2774c3 Add autolink domain validation 2018-10-06 17:28:53 +02:00
Alexandre Mutel
22271db431 Bump to 0.15.3 2018-09-26 10:34:54 +02:00
Alexandre Mutel
446764873d Merge pull request #247 from MihaZupan/master
Expose line start indexes
2018-09-26 10:17:19 +02:00
Miha Zupan
bdb5119806 Update changelog 2018-09-25 01:03:06 +02:00
Miha Zupan
f3bb06531e Expose line start indexes 2018-09-25 00:56:36 +02:00
Alexandre Mutel
9a74f3708e Merge pull request #245 from dampee/patch-1
small typo
2018-09-18 13:58:27 +02:00
Damiaan
57033311dc small typo 2018-09-18 13:53:15 +02:00
Alexandre Mutel
bda2f8c9ad Merge pull request #244 from MihaZupan/list-item-order
Expose list item order
2018-09-17 20:13:20 +02:00
Miha Zupan
0d5d3ddb2a Expose List item order 2018-09-17 16:19:01 +02:00
Alexandre Mutel
3f8e50031b Update changelog 2018-09-15 20:58:49 +02:00
Alexandre Mutel
949d5c0c25 Merge pull request #243 from MihaZupan/all-link-definitions
Fix Link and Footnote reference definitions in syntax tree
2018-09-15 20:52:50 +02:00
Miha Zupan
31e163f9f7 Fix offset calculation 2018-09-15 15:58:35 +02:00
Miha Zupan
b1440ab788 Add a LinkReferenceDefinition source position test 2018-09-15 15:27:38 +02:00
Miha Zupan
6e55d84f01 Add a FootnoteDefinition source position test 2018-09-15 15:27:05 +02:00
Miha Zupan
595dbb9af4 Fix FootnoteLinkReferenceDefinition content and source positions 2018-09-15 15:25:33 +02:00
Miha Zupan
d1576fd2ee Fix LinkReferenceDefinition source positions 2018-09-15 15:25:16 +02:00
Alexandre Mutel
1fe05639c9 Merge pull request #241 from MihaZupan/document-lines
Expose the number of lines in a document
2018-09-04 12:01:16 +02:00
Miha Zupan
8afff09b3e Expose the number of lines in a document 2018-08-29 18:56:36 +02:00
Alexandre Mutel
694747471a Merge pull request #239 from encrypt0r/master
Globalization Extension
2018-08-28 16:06:57 +02:00
Muhammad Azeez
dfcd5cddfa Fix the specs to make sure that the requried extensions are added in the tests 2018-08-28 16:30:35 +03:00
Muhammad Azeez
a99b7f4572 update globalization specs, docs and tests 2018-08-28 16:18:25 +03:00
Muhammad Azeez
7d7598db54 fix copyright notices 2018-08-28 15:58:12 +03:00
Muhammad Azeez
8767a1d8ed take surrogate characters into account 2018-08-28 15:33:20 +03:00
Muhammad Azeez
16c0829d9e add globalization spec 2018-08-27 00:48:22 +03:00
Muhammad Azeez
fc5d832432 Add globalization case for Configure extension method 2018-08-27 00:34:50 +03:00
Muhammad Azeez
7292acc27a make sure TaskList's X doesn't affect whether a block is marked as RTL or not 2018-08-27 00:32:08 +03:00
Muhammad Azeez
d05bc1572d only take strong characters into consideration when deciding whether a block should be rtl or not 2018-08-27 00:30:47 +03:00
Muhammad Azeez
5aa138425f add globalization extension 2018-08-25 23:11:20 +03:00
Alexandre Mutel
c56041811b Bump to 0.15.2 2018-08-21 11:04:45 +02:00
Alexandre Mutel
790bff3baf Fix footnotes parsing when they are defined after a container that has been closed in the meantime (#223) 2018-08-21 11:01:07 +02:00
Alexandre Mutel
571e04fe28 Bump to 0.15.1 2018-07-10 11:02:38 +02:00
Alexandre Mutel
c847996146 Fix CRLF 2018-07-10 11:02:16 +02:00
Alexandre Mutel
2782d3b4c3 Remove usage of IDictionary 2018-07-10 10:31:34 +02:00
Alexandre Mutel
582a76f8f0 Change editorconfig to not force crlf 2018-07-10 10:31:34 +02:00
Alexandre Mutel
030d676497 Merge pull request #235 from yufeih/autolink
Make AutoIdentifierExtension thread safe
2018-07-10 10:09:17 +02:00
Yufei Huang
0794213eef Make AutoIdentifierExtension thread safe 2018-07-10 11:52:32 +08:00
Alexandre Mutel
427dc849f7 Merge pull request #234 from ForNeVeR/patch-1
Fix spelling in package description
2018-06-28 17:16:43 +02:00
Friedrich von Never
e598047964 Fix spelling in package description 2018-06-28 22:07:53 +07:00
Alexandre Mutel
15546732dd Merge pull request #228 from carbon/master
Cross target .NETSTANDARD 2.0
2018-05-22 18:40:29 +02:00
Jason Nelson
7bd238852d Fix formatting 2018-05-22 08:59:35 -07:00
Jason Nelson
0f406039a0 Enable FIXED_STRING & UNSAFE code for .NETSTANDARD 2.0 target 2018-05-22 08:55:03 -07:00
Jason Nelson
1cd9cdfca0 Cross target .NETSTANDARD 2.0 2018-05-22 08:45:46 -07:00
Alexandre Mutel
812c4fabe6 Merge pull request #222 from caioproiete/add-tests-for-ConfigureNewLine
Add tests for `ConfigureNewLineExtension`'s `ConfigureNewLine`
2018-04-13 10:27:15 +02:00
Caio Proiete
85f8f59786 Add tests for ConfigureNewLineExtension's ConfigureNewLine 2018-04-12 20:34:53 -03:00
Alexandre Mutel
b0839f114c Bump to 0.15.0 2018-04-04 11:37:41 +02:00
Alexandre Mutel
431fecb1c6 Add third party extensions (#206) 2018-04-04 11:37:24 +02:00
Alexandre Mutel
7620b2b760 Merge pull request #214 from caioproiete/add-configure-new-line-extension
Add `ConfigureNewLineExtension` markdown extension
2018-04-04 11:09:48 +02:00
Alexandre Mutel
ad18514824 Merge pull request #213 from caioproiete/add-new-use-extension-with-instance
Add alternative `Use` extension method to `MarkdownPipelineBuilder` that receives an object instance
2018-02-23 09:23:38 +01:00
Caio Proiete
c68a488717 Add ConfigureNewLine extension method to MarkdownPipelineBuilder 2018-02-20 19:53:36 -04:00
Caio Proiete
e2f0f00831 Add ConfigureNewLineExtension markdown extension 2018-02-20 19:46:14 -04:00
Caio Proiete
fea2ca5adf Add alternative Use extension method to MarkdownPipelineBuilder that receives an object instance 2018-02-20 19:32:47 -04:00
Alexandre Mutel
f77bd0b36d Merge pull request #208 from pascalberger/patch-1
Fix typo
2018-02-17 10:01:58 +01:00
Pascal Berger
20243a79a0 Fix typo 2018-02-08 22:03:06 +01:00
Alexandre Mutel
a097247272 Merge pull request #203 from matteofabbri/master
added class attribute to media link extension
2018-02-01 10:06:31 +01:00
Matteo Fabbri
f3cb0712ca added class attribute to media link extension 2018-01-31 20:23:30 +01:00
Alexandre Mutel
eedfc3cd9c Merge pull request #201 from markheath/relative-urls-2
Optional link rewriter func for HtmlRenderer
2018-01-25 07:16:10 +01:00
Mark Heath
5f4b049ce0 removing spurious nuget file 2018-01-24 14:17:01 +00:00
Mark Heath
20edf26c40 optional link rewriter func for HtmlRenderer #143 2018-01-24 14:00:28 +00:00
Alexandre Mutel
4192a00e20 Merge pull request #199 from leotsarev/fix-resharper-unit-tests
Upgrade NUnit3TestAdapter from 3.2 to 3.9
2018-01-20 17:21:59 +01:00
Leonid Tsarev
4346c52ef0 Upgrade NUnit3TestAdapter from 3.2 to 3.9 to address Resharper test runner problems 2018-01-20 18:46:34 +03:00
Alexandre Mutel
42683e043d Merge pull request #197 from markheath/relative-urls
Convert relative URLs to absolute
2018-01-17 16:23:51 +01:00
Mark Heath
96c469018e HTML renderer supports converting relative URLs on links and images to absolute #143 2018-01-17 14:59:02 +00:00
Alexandre Mutel
f64ac47841 Bump to 0.14.9 2018-01-15 10:12:42 +01:00
Alexandre Mutel
c29b7d2942 Merge pull request #195 from leotsarev/remove-mailto
AutoLinkParser should to remove mailto: in outputted text
2018-01-10 11:17:34 +01:00
Leonid Tsarev
0f7e3b8c52 AutoLinkParser should to remove mailto: in outputted text 2018-01-09 11:48:06 +03:00
Alexandre Mutel
6dff16a612 Merge pull request #191 from leotsarev/improve-test-names
Improve discoverability of test in VS test runner
2018-01-08 20:50:43 +01:00
Alexandre Mutel
8e15c8bc6a Merge pull request #193 from leotsarev/support-vk-and-yandex-music
Added yandex.music & ok.ru support to MediaLinkExtension
2018-01-08 18:06:32 +01:00
Leonid Tsarev
558db1fd70 Support odnoklassniki.ru (meaning: classmates, top 2 social network in Russia) 2018-01-08 19:30:23 +03:00
Leonid Tsarev
796b143316 Add support for yandex music 2018-01-08 19:14:01 +03:00
Leonid Tsarev
3402805ebb refactor MediaLinkExtension to make it pluggable 2018-01-08 18:48:09 +03:00
Leonid Tsarev
c3600c2ba5 Merge branch 'master' into improve-test-names 2018-01-08 18:09:54 +03:00
Leonid Tsarev
4ba98f594a Merge branch 'master' into improve-test-names 2018-01-08 18:08:47 +03:00
Leonid Tsarev
544a64e5c9 Improve discoverability of test in VS test runner 2018-01-08 18:05:19 +03:00
Alexandre Mutel
f17320702a Merge pull request #189 from markheath/patch-1
Media link extension to support MP3 by default
2018-01-03 09:08:51 +01:00
Alexandre Mutel
d883694ac4 Merge pull request #186 from tthiery/normalize-autolinks
Add Normalization Support for AutoLinks
2018-01-03 09:08:08 +01:00
Mark Heath
42fba26ea2 Media link extension to support MP3 by default
I presume MP3 wasn't intentionally left out this list?
2018-01-01 13:50:52 +00:00
T. Thiery
595dacf213 Add Normalization Support for AutoLinks (including Options) 2017-12-24 12:21:23 +01:00
T. Thiery
75adfa3fe8 Add Normalization Tests for AutoLinks 2017-12-24 12:20:26 +01:00
Alexandre Mutel
0bb8139450 Merge pull request #185 from tthiery/normalize-jiralinks
Add Normalization Support for JIRA Links
2017-12-17 20:25:59 +01:00
T. Thiery
60784901b2 Add Normalization Support for JIRA Links 2017-12-17 17:00:55 +01:00
Alexandre Mutel
5020fdd3b1 Bump to 0.14.8 2017-12-05 09:36:48 +01:00
Alexandre Mutel
bd4ea56d2a Fix potential StackOverflow exception when processing deep nested | delimiters (#179) 2017-12-05 09:34:59 +01:00
Alexandre Mutel
fbc8a4116c Bump to 0.14.7 2017-11-25 14:17:23 +01:00
Alexandre Mutel
9af318d334 Merge pull request #175 from terryjintry/fixautolink
fix autolink attribute
2017-11-24 09:29:44 +01:00
Terry Jin
88e561c3ae fix autolink attribute 2017-11-24 14:34:44 +08:00
Alexandre Mutel
1ca82eb058 Bump to 0.14.6 2017-11-21 07:36:14 +01:00
Alexandre Mutel
66007c6bbf Add TestLink example (#171) 2017-11-21 07:35:17 +01:00
Alexandre Mutel
14d4286fd7 Merge pull request #170 from yishengjin1413/master
fix yaml frontmatter issue when ending with a empty line
2017-11-20 08:26:47 +01:00
Terry Jin
58b1a48f5b fix yaml frontmatter issue when ending with a empty line 2017-11-20 15:11:16 +08:00
Alexandre Mutel
5e1eaf8590 Bump to 0.14.5 2017-11-18 17:08:21 +01:00
Alexandre Mutel
c946295d96 Fix link to changelog.md in Markdig.csproj 2017-11-18 17:08:11 +01:00
Alexandre Mutel
97cbf11f8b Bump to 0.14.4 2017-11-18 11:29:39 +01:00
Alexandre Mutel
8d4394e7c6 Fix link conflict between a link to an image definition and heading auto-identifiers (#159) 2017-11-18 11:17:06 +01:00
Alexandre Mutel
fbdb8cf063 Better handle YAML frontmatter in case the opening --- is never actually closed (#160) 2017-11-18 10:55:16 +01:00
Alexandre Mutel
964538ec79 Add support for GFM autolinks (#165, #169) 2017-11-17 21:28:27 +01:00
Alexandre Mutel
9a30883e2a Add support for compatible github auto-identifiers for headings 2017-11-10 20:42:53 +01:00
Alexandre Mutel
6408705f82 Return an empty string for / on markdig webapi 2017-11-10 10:59:27 +01:00
Alexandre Mutel
523582e588 Fix bug when a thematic break is inside a fenced code block inside a pending list (#164) 2017-11-09 09:08:51 +01:00
Alexandre Mutel
aaff022e7c Merge pull request #161 from tthiery/normalize-tasklists
Add Normalization Support for Task Lists
2017-11-04 23:09:14 +01:00
T. Thiery
37eb6aa529 Add Normalization Support for Task Lists 2017-11-04 23:01:01 +01:00
Alexandre Mutel
9b7356b05e Remove local project 2017-11-03 14:22:05 +01:00
Alexandre Mutel
33d3bc1330 Upgrade WebApp to .NET core app 2.0 and add ApplicationInsights 2017-11-03 14:19:32 +01:00
Alexandre Mutel
07a2980d5b Bump to 0.14.3 2017-11-01 07:44:41 +01:00
Alexandre Mutel
2d8872f2a1 Make EmojiExtension.EnableSmiley public 2017-11-01 07:44:30 +01:00
Alexandre Mutel
16a9bbc84e Bump to 0.14.2 2017-11-01 07:35:07 +01:00
Alexandre Mutel
0e5338a709 Add option to disable smiley parsing in EmojiAndSmiley extension 2017-11-01 07:34:57 +01:00
Alexandre Mutel
9139e0142b Fix issue with emphasis preceded/followed by an HTML entity (#157) 2017-11-01 07:26:28 +01:00
Alexandre Mutel
9a38312df0 Add support for link reference definitions for Normalize renderer (#155) 2017-10-28 09:26:14 +02:00
Alexandre Mutel
d808dcf6f8 Bump to 0.14.1 2017-10-27 22:45:53 +02:00
Alexandre Mutel
d5985fc94c Add missing HtmlBlockRenderer 2017-10-27 22:44:58 +02:00
Alexandre Mutel
994687d5ae Use original bullet character if NormalizeOptions.ListItemCharacter is not set 2017-10-27 22:44:37 +02:00
Alexandre Mutel
2f4e958ab2 Bump to 0.14.0 2017-10-27 22:13:49 +02:00
Alexandre Mutel
26beaa81da Add comments to NormalizeOptions (#155) 2017-10-27 22:08:34 +02:00
Alexandre Mutel
de5ed11963 Add support for NormalizeOptions. Add a few more tests. Better handling of loose lists. 2017-10-27 22:01:43 +02:00
Alexandre Mutel
b557d51276 Don't output a space after a blockquote 2017-10-27 18:41:09 +02:00
Alexandre Mutel
27a8345943 Use Assert.AreEqual instead of string.Compare for better error reporting 2017-10-27 18:34:38 +02:00
Alexandre Mutel
131163ff9a Add bigger sample for normalize (#155) 2017-10-27 18:34:14 +02:00
Alexandre Mutel
241f674b99 Rename test names for normalize (#155) 2017-10-27 18:33:55 +02:00
Alexandre Mutel
194edee243 Fix normalize, don't introduce non necessary new lines (#155) 2017-10-27 18:32:43 +02:00
Alexandre Mutel
0995fa0cec Add tests for backslash and hard lines 2017-10-27 18:32:01 +02:00
Alexandre Mutel
6717be5210 Add support for escape characters for normalize (#155) 2017-10-27 18:30:32 +02:00
Alexandre Mutel
e15745f346 Fix escape inline parser to use the plain string instead of only a single string char (to allow literal continuation) 2017-10-27 18:28:57 +02:00
Alexandre Mutel
a513b0c587 Merge pull request #156 from leotsarev/add-plain-text-helper
Add simple helper that enables conversion to plain text
2017-10-27 10:54:03 +02:00
Leonid Tsarev
72adb963e8 Add simple helper that enables conversion to plain text 2017-10-27 11:35:23 +03:00
Alexandre Mutel
aac7df6b87 Merge remote-tracking branch 'origin/normalize' 2017-10-25 17:11:15 +02:00
Alexandre Mutel
4cf4bfb58f Merge pull request #154 from tthiery/normalize
Add support for normalize (core CommonMark for now)
2017-10-24 17:38:42 +02:00
T. Thiery
59630aec8e Review Fix: Make IntLog10Fast method private static. 2017-10-24 17:27:42 +02:00
Alexandre Mutel
70c4f6deda Merge pull request #140 from peinearydevelopment/master
Added EnableHtmlForBlock flag on HtmlRenderer for issue #104
2017-10-24 17:02:42 +02:00
T. Thiery
e2b3f812cb Merge remote-tracking branch 'upstream/normalize' into normalize 2017-10-24 16:53:42 +02:00
Alexandre Mutel
fc8adc70e0 Merge tag 'v0.13.4' into normalize
# Conflicts:
#	src/Markdig.Tests/Markdig.Tests.csproj
2017-10-24 16:28:58 +02:00
T. Thiery
72c2c06fcb Add normalization tests for space between leaves. 2017-10-24 15:58:44 +02:00
T. Thiery
7174e32b7a Remove incomplete UnorderedList syntax test case 2017-10-24 15:51:13 +02:00
T. Thiery
600219529c Add test approach for AST based arrange. 2017-10-20 16:10:02 +02:00
Alexandre Mutel
d7fd04d14c Bump to 0.13.4 2017-10-17 23:01:26 +02:00
Alexandre Mutel
2147e434f7 Add support for single table header row without a table body rows (#141) 2017-10-17 22:58:25 +02:00
Alexandre Mutel
7bd00d115f Merge pull request #149 from maulwuff/nomnomlSupport
Nomnoml support
2017-10-17 15:44:17 +02:00
maulwuff
80ef9d2799 doc: added nomnoml specs 2017-10-17 14:54:43 +02:00
maulwuff
d6a705d76c new: support nomnoml diagrams 2017-10-17 14:54:43 +02:00
Alexandre Mutel
42472085a6 Add mdtoc simple tool to generate a markdown TOC from a local markdown file or github link to a markdown file 2017-10-15 23:31:14 +02:00
Alexandre Mutel
3897e875ee Add KeepOpeningDigits and DiscardDots options to AutoIdentifiers to match GitHub behavior 2017-10-15 23:29:02 +02:00
T. Thiery
c63392657d Add finish block method and adjusted naming in test suite. 2017-09-18 23:28:34 +02:00
T. Thiery
34579b51a1 Relabeled unit tests. 2017-09-18 23:04:08 +02:00
T. Thiery
1bb35c5fc1 Fixed issues found in straight forward normalization test cases
- Code fences with attributes
- Escaping inline code
- Escaping link titles
- Encode hard line breaks
- HTML Entity emitting
- List intend.
2017-09-18 22:16:50 +02:00
T. Thiery
0c408951b8 Add straight forward unit tests. 2017-09-18 20:42:50 +02:00
Alexandre Mutel
218a094f0d Try to workaround tight/loose lists and paragraphs (wip #17) 2017-09-17 11:08:08 +02:00
Alexandre Mutel
3cc405b05b Add normalize renderers for core CommonMark components (wip #17) 2017-09-17 11:08:08 +02:00
Alexandre Mutel
d58db530bb wip normalize (issue #17) 2017-09-17 11:07:44 +02:00
Alexandre Mutel
3628dc3b17 Merge pull request #142 from mlaily/patch-1
Fix typos in EmojiSpecs.md
2017-09-13 22:30:24 +02:00
Melvyn Laïly
89ff42805d Fix typos in EmojiSpecs.md 2017-09-13 22:26:10 +02:00
Peineary Development
48866a2609 Added EnableHtmlForBlock flag on HtmlRenderer for issue #104 2017-09-11 22:43:23 -04:00
Alexandre Mutel
9cc5856c1c Bump to 0.13.3 2017-08-30 15:47:54 +02:00
Alexandre Mutel
a4bb174a77 Add .editorconfig 2017-08-30 15:44:08 +02:00
Alexandre Mutel
82987fa879 Merge pull request #139 from kenmuse/enhance/yaml-frontmatter
Implement Pandoc compatible front matter parsing
2017-08-30 15:36:38 +02:00
Ken Muse
2df2ff17c5 Replace tabs with spaces 2017-08-30 09:29:27 -04:00
Ken Muse
4e4825cb3f Implement Pandoc compatible front matter parsing 2017-08-29 18:49:14 -04:00
Alexandre Mutel
ed2371beae Update MSBuild.Sdk.Extras to version 1.0.9 to fix compatibility with pack for uap10.0 2017-08-29 08:06:29 +02:00
Alexandre Mutel
2c2898769e Bump to 0.13.2 2017-08-29 07:48:27 +02:00
Alexandre Mutel
001a99ab77 Add support for UAP10.0 (#137) 2017-08-29 07:48:14 +02:00
Alexandre Mutel
9233ec220c Bump to 0.13.1 2017-08-21 16:23:31 +02:00
Alexandre Mutel
bb30dc21c5 Fix indenting issue after a double digit list block using a tab (#134) 2017-08-21 16:04:47 +02:00
Alexandre Mutel
c761fa2243 Bump to 0.13.0 2017-08-03 19:26:48 +02:00
Alexandre Mutel
9d172ffcc1 Update URL links to accept balanced parenthesis for CommonMark specs 0.28 2017-08-03 19:25:17 +02:00
Alexandre Mutel
1863e22328 Update to emphasis to CommonMark specs 0.28 (when *** prefer em, strong vs strong, em) 2017-08-03 19:20:58 +02:00
Alexandre Mutel
c591d1950f Update CommonMark test specs to 0.28 2017-08-03 19:20:23 +02:00
Alexandre Mutel
339fcc9152 Add signed package link to readme.md (#11) 2017-08-03 14:57:28 +02:00
Alexandre Mutel
3a54f06540 Fix appveyor.yml for multiline cmd 2017-08-03 14:47:07 +02:00
Alexandre Mutel
3f305a25a8 Add sign assembly to build 2017-08-03 14:41:52 +02:00
Alexandre Mutel
5a210223b6 Bump to 0.12.4 2017-07-31 11:17:13 +02:00
Alexandre Mutel
a7786d934d Make Profile328 (for sl50 compat) not using unsafe code to pass verifier (issue #131) 2017-07-31 11:17:01 +02:00
Alexandre Mutel
cb3c1f1505 Merge pull request #124 from joannaz/master
Fix abbreviation matching
2017-07-03 14:38:25 +02:00
Joanna Zhang
50b33b8512 Add more test cases for abbreviation 2017-07-03 13:12:23 +01:00
Joanna Zhang
80790b5038 Fix abbreviation parsing 2017-07-03 11:55:31 +01:00
Joanna Zhang
311c28ae60 Fix abbreviation matching 2017-06-29 15:00:56 +01:00
Alexandre Mutel
9906a0554f Merge pull request #123 from joannaz/master
Fix abbreviation at start of paragraphs
2017-06-28 13:59:11 +02:00
Joanna Zhang
7e92f1881d Fix Abbrevation at start 2017-06-28 12:25:14 +01:00
Alexandre Mutel
41911806a0 Bump to 0.12.3 2017-06-26 11:53:59 +02:00
Alexandre Mutel
610f1519b0 Fix issue with HTML blocks for heading h2,h3,h4,h5,h6 that were not correctly identified as HTML blocks as per CommonMark spec 2017-06-26 11:53:47 +02:00
Alexandre Mutel
29aa56b4f1 Bump to 0.12.2 2017-06-18 10:58:40 +02:00
Alexandre Mutel
5004ecedb7 Use TestParser.TestSpec instead to mitigate problem with \r 2017-06-18 10:56:44 +02:00
Alexandre Mutel
ba06a796dc Merge branch 'pr/n121_pearsonn' 2017-06-18 10:50:39 +02:00
Nick Pearson
b1d6f34976 Fix issue in GenericAttributesParser causing inline elements to be skipped 2017-06-14 15:20:16 -07:00
Alexandre Mutel
28f4236a57 Bump to 0.12.1 2017-05-29 12:26:17 +02:00
Alexandre Mutel
0739a82735 Merge pull request #119 from meziantou/master
MediaLinkExtension: Remove unexpected closing tag
2017-05-28 19:00:54 +02:00
Meziantou
3ac9f2e788 Fix issue 2017-05-28 12:18:59 +02:00
Meziantou
d9607cc687 Update tests 2017-05-28 12:18:50 +02:00
Alexandre Mutel
f0573ef9e2 Bump to 0.12.0 2017-05-28 08:24:50 +02:00
Alexandre Mutel
017a3bd7e2 Merge branch 'pr/n118_meziantou' 2017-05-28 08:17:46 +02:00
Alexandre Mutel
d6f9a1055c Remove unnecessary test in BlockProcessor (#115) 2017-05-28 08:14:58 +02:00
Alexandre Mutel
2612e9d565 Fix issue in TryParseAutolink in LinkHelper (#115) 2017-05-28 08:02:55 +02:00
Alexandre Mutel
1076d7af10 Fix issue in ScanEntity (#115) 2017-05-28 07:56:58 +02:00
Meziantou
850cecfa6c Fix issue 2017-05-27 16:16:46 +02:00
Meziantou
bfdb03bd78 Update tests 2017-05-27 16:16:33 +02:00
Alexandre Mutel
56b6e329d5 Add missing update to Tests.csproj 2017-05-18 11:31:51 +02:00
Alexandre Mutel
006e384d1a Update links 2017-05-18 11:31:24 +02:00
Alexandre Mutel
9cd9b683a5 Remove specialized renderer for JiraLinks now going through the standard LinkInline 2017-05-18 11:04:42 +02:00
Alexandre Mutel
e01e2c3d2b Add StringBuilder extensions to accept a StringSlice 2017-05-18 11:04:06 +02:00
Alexandre Mutel
97ce0da564 Update JiraLinks, allow ( and ), use StringSlice instead of strings for key/issue, add support for attributes, add tests 2017-05-18 10:33:16 +02:00
Alexandre Mutel
26c5ce59b5 Update Benchmarks to latest DotNetBenchmark. Remove nuget.targets 2017-05-18 09:33:26 +02:00
Alexandre Mutel
d2d94ecf39 Merge branch 'pr/n113_clarkd' 2017-05-18 09:18:50 +02:00
Dave Clarke
0ec82bb81d Fix comment 2017-05-17 11:55:30 +01:00
Dave Clarke
ad9e941cb0 Fix missing space before target attribute
Rename Key -> ProjectKey
2017-05-16 16:48:25 +01:00
Dave Clarke
27dab6ca6d Automatically link JIRA issue references 2017-05-16 12:02:44 +01:00
Alexandre Mutel
762196f03b Bump to 0.11.0 2017-05-08 12:05:15 +02:00
Alexandre Mutel
26a565fa45 Fix/improve parsing of math inline, improving rules for matching, disallow newline between $$/$ for inline parsing (#87) 2017-05-08 11:50:40 +02:00
Alexandre Mutel
4369db1a43 Fix issue with $$ block parsing that should be interpreted as inline parsing (#105) 2017-05-08 11:48:44 +02:00
Alexandre Mutel
d83f1f87cc Add custom arrows to emoji 2017-05-08 09:25:44 +02:00
Alexandre Mutel
14027f4be3 Migrate to VS2017 - dotnet new csproj 2017-05-06 15:41:07 +02:00
Alexandre Mutel
8bcfb53607 Merge pull request #109 from aKzenT/issue-108
Fix for issue #108
2017-04-29 11:11:05 +02:00
Thomas Krause
700bb21e03 Fix for issue #108 2017-04-28 21:47:41 +02:00
Alexandre Mutel
1bc9d9083c Merge pull request #105 from MatthewRichards/DotTerminatedUrls
Treat trailing full stop after a URL as not being part of the URL
2017-04-04 10:02:38 +02:00
Alexandre Mutel
1d7bb021a7 Bump version to 0.10.7 2017-04-01 10:20:18 +02:00
Matthew Richards
3305a74b06 Additional test case 2017-03-30 08:51:05 +01:00
Matthew Richards
6312bc0515 Treat trailing full stop after a URL as not being part of the URL 2017-03-29 16:47:41 +01:00
Alexandre Mutel
b595383281 Merge pull request #103 from Daniel15/replace
Add Replace method to replace an element in an OrderedList
2017-03-20 10:39:01 +01:00
Alexandre Mutel
bf85964543 Merge pull request #102 from Daniel15/lock-dotnet
Lock .NET Core SDK to 1.0.0-preview2
2017-03-20 10:37:16 +01:00
Daniel Lo Nigro
d5b020b784 Add Replace method to replace an element in an OrderedList 2017-03-19 14:39:24 -07:00
Daniel Lo Nigro
8ab0467e78 Lock .NET Core SDK to 1.0.0-preview2 2017-03-19 13:42:26 -07:00
Alexandre Mutel
74fe3be7c7 Bump version to 0.10.6 2017-02-24 07:52:29 +01:00
Alexandre Mutel
b47ae8d9ba Fix emphasis with HTML entities (#97) 2017-02-24 07:49:46 +01:00
Alexandre Mutel
a926e1a326 Bump version to 0.10.5 2017-02-14 17:36:54 +01:00
Alexandre Mutel
6048406f52 Merge branch 'pr/n89_johnsimons' 2017-01-31 13:01:17 +01:00
John Simons
1edf14c742 Remove requirement for space after emoji.
Fixes #88
2017-01-31 12:58:32 +01:00
Alexandre Mutel
d4bb7c0a51 Merge pull request #82 from christophano/bugfix/abbreviation_parser_fix
Fixes the IsValidAbbreviation method in AbbreviationParser
2016-12-19 14:37:32 +01:00
Chris Rodgers
ba4e463517 Adds the test I ought to have included to begin with. 2016-12-19 13:25:56 +00:00
Chris Rodgers
2d0dae4ebb Fixes the IsValidAbbreviation method in AbbreviationParser 2016-12-19 13:05:03 +00:00
Alexandre Mutel
1a9d923c44 Merge pull request #81 from volkanceylan/master
Use Char.ToUpperInvariant instead of Char.ToUpper
2016-12-18 22:20:20 +01:00
volkan.ceylan
013ec0bf80 Due to use of Char.ToUpper, ListExtraItemParser fails in cultures like Turkish where uppercase of 'i' is 'İ'. Char.ToUpperInvariant should be used instead. 2016-12-18 11:47:25 +03:00
Alexandre Mutel
f82e874cb7 Merge pull request #80 from christophano/feature/pipeline_builder_use_method
Adds fluent extension registration method to MarkdownPipelineBuilder.
2016-12-15 11:49:32 +01:00
Chris Rodgers
976fc569fa Moves new Use method to MarkdownExtensions and changes it to extension method. 2016-12-15 10:31:02 +00:00
Chris Rodgers
5aab21f0bf Adds fluent extension registration method to MarkdownPipelineBuilder. 2016-12-15 10:07:54 +00:00
Alexandre Mutel
1df8344576 Bump to 0.10.4 2016-12-12 11:03:48 +01:00
Alexandre Mutel
9eb84cf95e Normalize pipe tables so they contain the same number of columns for all rows 2016-12-11 19:01:49 +01:00
Alexandre Mutel
47d45b5577 Fix issue when parsing autolinks embraced by a pending emphasis (issue #78) 2016-12-11 18:08:51 +01:00
Alexandre Mutel
ebcc286df0 Bump version to 0.10.3 2016-11-29 18:02:39 +01:00
Alexandre Mutel
f11d8037ac Fix issue when the last character of a table is not a newline and there are spaces in-between (issue #73) 2016-11-29 17:43:28 +01:00
Alexandre Mutel
f668b3fe38 Bump version to 0.10.2 2016-11-26 11:20:49 +01:00
Alexandre Mutel
5ca4e31332 Fix exception when trying to Urilize an url with an unicode character outside the supported range by string.Normalize + NormD (issue #75) 2016-11-26 11:20:37 +01:00
Alexandre Mutel
a8fbe79e30 Bump to 0.10.1 2016-11-19 16:53:56 +01:00
Alexandre Mutel
bdb09b9820 Update to latest CommonMark specs 0.27 2016-11-19 16:53:44 +01:00
Alexandre Mutel
79348ebea8 Add span to LinkReferenceDefinition (issue #51) 2016-10-27 17:06:37 +02:00
Alexandre Mutel
b366c1a5e3 Bump to 0.10.0 2016-10-16 21:30:55 +02:00
Alexandre Mutel
a5e53b014f Add better support to discover active extensions when setup renderer (issue #66) 2016-10-16 21:30:38 +02:00
Alexandre Mutel
c2f21e21c8 Bump to 0.9.1 2016-10-11 14:45:03 +02:00
Alexandre Mutel
81b8dce7a8 Fix regression between autolink extension with html inline link a /regular or regular markdown links (issue #65) 2016-10-11 14:44:50 +02:00
Alexandre Mutel
e6223f86d8 Update readme with autolink extension 2016-10-11 13:15:10 +02:00
Alexandre Mutel
2054c16662 Bump to 0.9.0 2016-10-11 13:10:25 +02:00
Alexandre Mutel
95641e562f Add support for the autolink extension (issue #64) 2016-10-11 13:10:06 +02:00
Alexandre Mutel
e4953931c7 Update donation logo 2016-09-29 20:00:08 +02:00
Alexandre Mutel
93b5b7a091 Add donation button 2016-09-29 18:23:30 +02:00
Alexandre Mutel
4f52e893ee Disable warning for comments as it slows down build on appveyor 2016-09-23 14:01:01 +02:00
Alexandre Mutel
23ede077a1 Bump version to 0.8.5 2016-09-23 13:48:15 +02:00
Alexandre Mutel
d5e6f17683 Allow to force table alignment to left (issue #62) 2016-09-23 13:43:49 +02:00
Alexandre Mutel
4d5980a485 Bump version to 0.8.4 2016-09-22 21:48:58 +02:00
Alexandre Mutel
19dd902519 Fix issue when calculating the span of an indented code block within a list. Make sure to include first whitespace on the line 2016-09-22 21:48:15 +02:00
Alexandre Mutel
f046a46275 Bump version to 0.8.3 2016-09-22 16:26:54 +02:00
Alexandre Mutel
25e9eafa8b Allow to pass a manual pipeline to TestParser.TestSpec 2016-09-22 16:25:46 +02:00
Alexandre Mutel
f4ff981008 Fix NullReferenceException with GridTable extension when a single + is entered on a line 2016-09-22 16:25:13 +02:00
Alexandre Mutel
a1b48aff89 Bump version to 0.8.2 2016-09-22 12:44:52 +02:00
Alexandre Mutel
0aa34caa82 Merge pull request #61 from christophano/bugfix/literal-inline-parser
Fixes issue where LiteralInlineParser calls PostMatch while processor.Inline is type other than LiteralInline
2016-09-22 12:40:16 +02:00
Chris Rodgers
98ce9b1a06 Fixes issue where LiteralInlineParser calls PostMatch while processor.Inline is type other than LiteralInline 2016-09-22 09:28:52 +01:00
Alexandre Mutel
ab157b21ea Update the readme with recent extensions added 2016-09-22 09:31:43 +02:00
Alexandre Mutel
53c72d3031 Bump version to 0.8.1 2016-09-21 13:06:51 +02:00
Alexandre Mutel
165e2f97d0 Output attached html attributes for dd in definition lists (fix issue #59) 2016-09-21 13:06:37 +02:00
Alexandre Mutel
6c577059ad Add extension NonAsciiNoEscape for URI to workaround a bug/singular behavior of EDGE/IE for local file links with non US-ASCII characters 2016-09-21 12:57:16 +02:00
Alexandre Mutel
0ea4dc769b Merge pull request #60 from christophano/bugfix/abbreviation-preceded-by-punctuation
Fixes issue where punctuation forms part of word, so abbreviation is not valid
2016-09-20 16:37:21 +02:00
Chris Rodgers
a9b626e810 Fixes issue where punctuation forms part of word, so abbreviation is not valid. 2016-09-20 15:22:31 +01:00
Alexandre Mutel
b90d6f9769 Bump to 0.8.0 2016-09-19 10:36:35 +02:00
Alexandre Mutel
f0ea008c46 Add support for YAML frontmatter parsing/discard (issue #37) 2016-09-19 10:11:38 +02:00
Alexandre Mutel
c43d5ccd63 Don't create an empty LiteralInline when trimming spaces at the end of a line (issue #42) 2016-09-19 09:10:36 +02:00
Alexandre Mutel
d6d7b398e4 Update to latest CommonMark specs. Fix new corner cases when parsing inline links 2016-09-18 13:24:19 +02:00
Alexandre Mutel
e1032e5094 Bump version to 0.7.5 2016-09-18 11:21:17 +02:00
Alexandre Mutel
a32ac298c5 Merge branch 'pr/n58_christophano'
# Conflicts:
#	src/Markdig/Parsers/InlineProcessor.cs
2016-09-18 11:12:10 +02:00
Alexandre Mutel
2e6ab670cb Keep UrlSpan (and LabelSpan and TitleSpan) for a LinkReferenceDefinition (issue #51) 2016-09-18 11:07:56 +02:00
Alexandre Mutel
72b7fce48c Fix extension DisableHtml not working properly with inline HTML (issue #46) 2016-09-18 10:59:12 +02:00
Alexandre Mutel
fa281f1ca1 Fix pipetable parsing (issue #44) 2016-09-18 10:44:26 +02:00
Chris Rodgers
1b92311aeb Fixes issue when using colon (among others) on lines with abbreviations 2016-09-15 14:18:58 +01:00
Alexandre Mutel
a593212f03 Merge pull request #45 from christophano/feature/rowspan
Adds support for rowspans in grid tables
2016-09-15 09:03:44 +02:00
Alexandre Mutel
c4ec928953 Merge pull request #57 from christophano/bugfix/punctuation-exceptions
Adds exceptions to allow certain punctuation characters to behave as inline delimiters
2016-09-15 09:00:57 +02:00
Chris Rodgers
e7df7fabeb Adds exceptions to allow certain punctuation characters to behave as inline delimiters 2016-09-14 12:00:31 +01:00
Alexandre Mutel
1c187f2d81 Merge pull request #56 from christophano/bugfix/similar-abbreviations
Fixes problem with multiple, similar abbreviations not parsing correctly
2016-09-14 07:42:26 +02:00
Alexandre Mutel
da66cf90c3 Merge pull request #55 from christophano/bugfix/restart-list-after-paragraph
Checks if paragraph block is closed when deciding if continuation list is allowable with character other than '1.'
2016-09-14 07:40:33 +02:00
Alexandre Mutel
0e8bd7407f Merge pull request #49 from christophano/bugfix/nested-definition-lists
Fixes issue where multiple definition lists are created when they are nested in a list item.
2016-09-14 07:39:24 +02:00
Chris Rodgers
d70f14addb Fixes problem with multiple, similar abbreviations not parsing correctly. 2016-09-13 16:53:25 +01:00
Chris Rodgers
e7b9eea3a5 Checks if paragraph block is closed when deciding if continuation list is allowable with character other than '1.'
Fixes #54
2016-09-09 14:09:52 +01:00
Alexandre Mutel
97af9d822d Merge pull request #50 from christophano/bugfix/ordered-list-start-attribute
Changes List Extra to output valid integer for start attribute, instead of roman or latin character.
2016-08-27 09:07:46 +02:00
Alexandre Mutel
cf7a09ab76 Merge pull request #52 from christophano/bugfix/merge-auto-generated-id
fixes issue where using special attributes overwites element id, even when id is not specified
2016-08-27 09:05:22 +02:00
Chris Rodgers
e755627421 fixes issue where using special attributes overwites element id, even when id is not specified 2016-08-25 09:11:50 +01:00
Chris Rodgers
f9be64a988 Changes List Extra to output valid integer for start attribute, instead of roman or latin character. 2016-08-23 13:58:06 +01:00
Alexandre Mutel
d65431e6cc Merge pull request #47 from christophano/bugfix/inline-maths-with-trailing-text
Fixes issue where trailing text after an inline math block is both included in the math block and appended after the math block.
2016-08-23 08:19:01 +02:00
Chris Rodgers
86fb962fdb Removes BlankLineBlock if it is found after an active definition list. 2016-08-22 15:41:39 +01:00
Chris Rodgers
d003837b27 Fixes issue where multiple definition lists are created when they are nested in a list item. 2016-08-22 14:47:43 +01:00
Chris Rodgers
fd813e3c5a Fixes issue where trailing text after an inline math block is both included in the math block and appended after the math block. 2016-08-19 12:15:17 +01:00
Chris Rodgers
a3691c4423 Fixed issue when malformed tables can result in an unhandled exception being thrown. 2016-08-12 15:57:35 +01:00
Chris Rodgers
9506f22025 Adds support for rowspans in grid tables 2016-08-12 15:57:28 +01:00
Alexandre Mutel
06ae907949 Bump version to 0.7.4 2016-07-30 11:35:36 +02:00
Alexandre Mutel
555523b2af Add additional tests for emphasis (issue #43) 2016-07-30 11:33:45 +02:00
Alexandre Mutel
3b9772f772 Merge branch 'pr/n43_christophano' 2016-07-30 11:20:48 +02:00
Chris Rodgers
891c80f48c Fixes issue where sentences containing strong emphasis words did not correctly delimit the strong tag 2016-07-28 12:04:49 +01:00
Alexandre Mutel
b20b111385 Try to workaround tight/loose lists and paragraphs (wip #17) 2016-06-28 23:55:01 +09:00
Alexandre Mutel
6ac2429e2a Add normalize renderers for core CommonMark components (wip #17) 2016-06-28 23:37:52 +09:00
Alexandre Mutel
9d52732f18 wip normalize (issue #17) 2016-06-28 10:53:08 +09:00
398 changed files with 48891 additions and 24913 deletions

37
.editorconfig Normal file
View 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
View File

@@ -0,0 +1,3 @@
* text=auto
*.cs text=auto diff=csharp
*.sln text=auto eol=crlf

12
.github/FUNDING.yml vendored Normal file
View 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']

64
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,64 @@
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.1.x'
- name: Build (Release)
run: dotnet build src -c Release
- name: SpecFileGen
run: dotnet src/SpecFileGen/bin/Release/netcoreapp3.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 netcoreapp3.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.netcoreapp3.1.info
- name: Pack
run: dotnet pack src -c Release
- name: Pack Signed
run: dotnet pack -c Release src/${{env.PROJECT_NAME}}.Signed/${{env.PROJECT_NAME}}.Signed.csproj
- 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
View File

@@ -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

238
changelog.md Normal file
View File

@@ -0,0 +1,238 @@
# Changelog
## 0.22.1 (2 Dec 2020)
- Update logo for NuGet package
## 0.22.0 (05 Oct 2020)
- Fix Setext headings in block quotes.
- Fix tel: treated as autolink ([PR #478](https://github.com/lunet-io/markdig/pull/478)
- Make Inline.FirstParentOfType public ([PR #474](https://github.com/lunet-io/markdig/pull/474)
- Fix `&` to be parsed as a punctuation while it was detected as a html entity in certain cases ([PR #471](https://github.com/lunet-io/markdig/pull/471)
- Add ParentBlock property to ContainerInline ([PR #468](https://github.com/lunet-io/markdig/pull/468)
## 0.21.1 (17 Aug 2020)
- Fix Markdig.Signed on GitHub Actions
## 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 `&lt;/iframe&gt;` 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -14,11 +14,11 @@
viewBox="0 0 192 192"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="markdig.svg"
inkscape:export-filename="C:\Code\lunet-io\markdig\markdig.png"
inkscape:export-xdpi="93.400002"
inkscape:export-ydpi="93.400002">
inkscape:export-filename="C:\code\lunet\markdig\img\markdig.png"
inkscape:export-xdpi="256"
inkscape:export-ydpi="256">
<defs
id="defs4" />
<sodipodi:namedview
@@ -28,16 +28,16 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4.4374889"
inkscape:cx="174.14769"
inkscape:cy="93.189838"
inkscape:zoom="6.275557"
inkscape:cx="81.620292"
inkscape:cy="119.68434"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1377"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-width="3840"
inkscape:window-height="2066"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1"
units="px" />
<metadata
@@ -48,7 +48,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@@ -59,13 +59,8 @@
style="display:inline"
transform="translate(0,-860.36216)">
<path
style="fill:#000000"
d="M 75.009766 60.486328 L 34.648438 122.74414 C 33.793918 123.59769 37.647081 134.96384 37.052734 136.09766 L 4.0234375 177.69727 C 2.4142291 180.39677 3.2900484 182.21846 4.8730469 183.84766 C 5.9214414 184.93636 6.6591287 186.06887 8.3828125 185.67188 C 9.0750612 185.50987 10.104893 185.27338 10.875 184.76758 L 52.806641 151.81445 C 53.912466 151.23195 64.44071 154.77813 65.289062 153.92383 L 126.45312 111.46875 L 75.009766 60.486328 z M 89.632812 84.769531 L 103.77539 98.912109 L 79.027344 123.66016 L 86.238281 130.87109 L 48.621094 139.92383 L 57.435547 102.30859 L 64.884766 109.51758 L 89.632812 84.769531 z "
transform="translate(0,860.36216)"
id="path4140" />
<path
style="fill:#000000;fill-opacity:1"
d="m 111.18463,862.06984 c -1.98231,0 -3.96282,0.78454 -5.54759,2.38445 L 88.200894,881.94537 75.123368,868.82653 c -3.169466,-3.18017 -7.92567,-3.18017 -11.095213,0 -3.169466,3.18017 -3.169466,7.95108 0,11.13109 l 13.077526,13.11885 -11.095212,10.73223 82.031621,81.49227 11.09525,-11.13109 13.87084,13.51554 c 1.57915,1.59105 3.56724,2.38445 5.54759,2.38445 1.98231,0 3.96285,-0.78453 5.54762,-2.38445 3.16947,-3.18017 3.16947,-7.95111 0,-11.13109 l -13.87083,-13.11884 17.43611,-17.09442 c 1.17983,-1.59105 1.98231,-3.5788 1.98231,-5.96329 0,-1.98351 -0.79863,-3.97554 -2.37816,-5.56446 l -70.54053,-70.35856 c -1.57914,-1.59105 -3.56724,-2.38446 -5.54758,-2.38446 z m 15.86949,20.75826 9.50139,9.5291 -4.04453,23.11372 23.04691,-4.05619 9.50138,9.5291 -36.8437,36.95052 -9.50135,-9.5291 21.13082,-21.19197 -23.04672,4.05619 4.04453,-23.11396 -21.131009,21.19198 -9.501383,-9.5291 36.843662,-36.95048 z"
style="fill:#006680;fill-opacity:1;stroke-width:1.09204066"
d="m 34.5307,873.24547 c -1.506145,1.5557 -2.414834,3.72567 -2.403331,6.22497 l 0.04173,27.41047 -19.903814,-0.0324 c -4.824408,-0.009 -8.4381391,3.7242 -8.4300642,8.70738 0.00817,4.98312 3.6330369,8.72727 8.4573232,8.73554 l 19.903821,0.0324 -0.275791,17.12991 124.244306,-0.42328 -0.0273,-17.44297 20.80798,-0.27883 c 2.4087,0.009 4.52205,-0.92824 6.02671,-2.48239 1.50614,-1.55569 2.41486,-3.72569 2.40336,-6.225 -0.009,-4.98311 -3.63306,-8.7273 -8.45733,-8.73554 l -20.50656,0.59015 0.25961,-27.09914 c -0.31244,-2.17456 -1.213,-4.36429 -3.02472,-6.23561 -1.50705,-1.55665 -3.62738,-2.49321 -6.03475,-2.50058 l -107.054134,0.14282 c -2.408688,-0.009 -4.522059,0.92823 -6.026707,2.48237 z m 27.829505,3.83665 14.459233,0.0217 14.488635,21.31347 14.429017,-21.27019 14.45922,0.0217 0.0811,57.91281 -14.4592,-0.0217 -0.0464,-33.21443 -14.428869,21.27005 -14.488819,-21.31366 0.04632,33.21458 -14.459226,-0.0218 -0.08116,-57.91275 z"
id="path4142"
inkscape:connector-curvature="0" />
<rect
@@ -95,7 +90,7 @@
<flowRoot
xml:space="preserve"
id="flowRoot4797"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
transform="matrix(0.1746417,0,0,0.1459084,499.69318,366.39614)"><flowRegion
id="flowRegion4799"><rect
id="rect4801"
@@ -103,7 +98,8 @@
height="618.71844"
x="959.01355"
y="-976.15039" /></flowRegion><flowPara
id="flowPara4803" /></flowRoot> <g
id="flowPara4803"
style="font-size:40px;line-height:1.25"> </flowPara></flowRoot> <g
id="g4833"
transform="matrix(0.09510056,0,0,0.09061765,496.09965,368.83934)">
<rect
@@ -114,18 +110,20 @@
y="0"
style="fill:#ffffff" />
</g>
<path
inkscape:connector-curvature="0"
id="path4886"
d="m 111.18463,862.06984 c -1.98231,0 -3.96282,0.78454 -5.54759,2.38445 L 88.200894,881.94537 75.123368,868.82653 c -3.169466,-3.18017 -7.92567,-3.18017 -11.095213,0 -3.169466,3.18017 -3.169466,7.95108 0,11.13109 l 13.077526,13.11885 -11.095212,10.73223 82.031621,81.49227 11.09525,-11.13109 13.87084,13.51554 c 1.57915,1.59105 3.56724,2.38445 5.54759,2.38445 1.98231,0 3.96285,-0.78453 5.54762,-2.38445 3.16947,-3.18017 3.16947,-7.95111 0,-11.13109 l -13.87083,-13.11884 17.43611,-17.09442 c 1.17983,-1.59105 1.98231,-3.5788 1.98231,-5.96329 0,-1.98351 -0.79863,-3.97554 -2.37816,-5.56446 l -70.54053,-70.35856 c -1.57914,-1.59105 -3.56724,-2.38446 -5.54758,-2.38446 z m 15.86949,20.75826 9.50139,9.5291 -4.04453,23.11372 23.04691,-4.05619 9.50138,9.5291 -36.8437,36.95052 -9.50135,-9.5291 21.13082,-21.19197 -23.04672,4.05619 4.04453,-23.11396 -21.131009,21.19198 -9.501383,-9.5291 36.843662,-36.95048 z"
style="fill:#000000;fill-opacity:1" />
<g
transform="translate(234.63786,787.55486)"
id="g4170" />
<path
id="path4225"
transform="translate(0,860.36216)"
d="M 75.009766 60.486328 L 34.648438 122.74414 C 33.793918 123.59769 37.647081 134.96384 37.052734 136.09766 L 4.0234375 177.69727 C 2.4142291 180.39677 3.2900484 182.21846 4.8730469 183.84766 C 5.9214414 184.93636 6.6591287 186.06887 8.3828125 185.67188 C 9.0750612 185.50987 10.104893 185.27338 10.875 184.76758 L 52.806641 151.81445 C 53.912466 151.23195 64.44071 154.77813 65.289062 153.92383 L 126.45312 111.46875 L 75.009766 60.486328 z M 89.632812 84.769531 L 103.77539 98.912109 L 79.027344 123.66016 L 86.238281 130.87109 L 48.621094 139.92383 L 57.435547 102.30859 L 64.884766 109.51758 L 89.632812 84.769531 z "
style="fill:#000000" />
sodipodi:nodetypes="cccccccccccccc"
inkscape:connector-curvature="0"
id="path826"
d="m 45.058494,943.54749 20.013843,88.87081 c -8.87e-4,1.4793 13.909884,7.9857 28.77803,7.9868 14.868153,0 27.732473,-6.0454 27.727033,-7.5199 l 17.1004,-89.73688 z m 35.561125,8.36596 h 25.853221 l 10e-6,42.86491 h 13.18189 l -26.108514,40.41734 -26.324515,-40.20925 13.397908,-0.20809 z"
style="fill:#ff6600;stroke-width:1.2582258" />
<path
style="fill:#c83737;stroke-width:1.2582258"
d="m 45.058494,943.54749 20.013843,88.87081 c -8.87e-4,1.4793 13.909884,7.9857 28.77803,7.9868 14.868153,0 27.732473,-6.0454 27.727033,-7.5199 l 17.1004,-89.73688 z m 35.561125,8.36596 h 25.853221 l 10e-6,42.86491 h 13.18189 l -26.108514,40.41734 -26.324515,-40.20925 13.397908,-0.20809 z"
id="path828"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccc" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -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

View File

@@ -1,4 +1,4 @@
# Markdig [![Build status](https://ci.appveyor.com/api/projects/status/hk391x8jcskxt1u8?svg=true)](https://ci.appveyor.com/project/xoofx/markdig) [![NuGet](https://img.shields.io/nuget/v/Markdig.svg)](https://www.nuget.org/packages/Markdig/)
# Markdig [![Build Status](https://github.com/lunet-io/markdig/workflows/ci/badge.svg?branch=master)](https://github.com/lunet-io/markdig/actions) [![Coverage Status](https://coveralls.io/repos/github/lunet-io/markdig/badge.svg?branch=master)](https://coveralls.io/github/lunet-io/markdig?branch=master) [![NuGet](https://img.shields.io/nuget/v/Markdig.svg)](https://www.nuget.org/packages/Markdig/) [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](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">
@@ -14,51 +14,68 @@ You can **try Markdig online** and compare it to other implementations on [babel
- **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**.
- **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 **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))
- **Task Lists** inspired from [Github Task lists](https://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments).
- **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)
- [**Syntax highlighting using Prism.js**: `WebStoating.Markdig.Prism`](https://github.com/ilich/Markdig.Prism)
- [**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!
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/)
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: [![NuGet](https://img.shields.io/nuget/v/Markdig.svg)](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:
@@ -70,7 +87,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
@@ -78,6 +95,8 @@ var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
var result = Markdown.ToHtml("This is a text with some *emphasis*", pipeline);
```
[Try it online!](https://dotnetfiddle.net/GoZXyI)
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
@@ -173,6 +192,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!
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](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!
@@ -183,6 +208,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)

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;

View File

@@ -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")]

View File

@@ -1,8 +0,0 @@
{
"profiles": {
"CLASSIC": {
"executablePath": "Testamina.Markdig.Benchmarks.dll",
"workingDirectory": "..\\..\\artifacts\\bin\\Testamina.Markdig.Benchmarks\\Debug\\net45"
}
}
}

View File

@@ -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
}
}
}
*/
}

View File

@@ -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>

View File

@@ -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"
}
}

View File

@@ -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

View 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

Binary file not shown.

View File

@@ -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>

Binary file not shown.

View File

@@ -1,115 +1,24 @@
<?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>
<TargetFrameworks>netcoreapp3.1</TargetFrameworks>
<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>
<Prefer32Bit>false</Prefer32Bit>
</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 />
<IsPackable>false</IsPackable>
<StartupObject>Markdig.Tests.Program</StartupObject>
</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.9.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.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="TestHtmlAttributes.cs" />
<Compile Include="TestHtmlHelper.cs" />
<Compile Include="TestLineReader.cs" />
<Compile Include="TestLinkHelper.cs" />
<Compile Include="TestPragmaLines.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\DiagramsSpecs.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}" />
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</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>

View 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 = "![image](\"onclick=\"alert&amp;#40;'click'&amp;#41;\"://)";
string expected = "<p><img src=\"%22onclick=%22alert&amp;#40;%27click%27&amp;#41;%22://\" alt=\"image\" /></p>";
TestParser.TestSpec(input, expected);
}
[Test]
public void TestAltTextIsCorrectlyEscaped()
{
TestParser.TestSpec(
@"![This is image alt text with quotation ' and double quotation ""hello"" world](girl.png)",
@"<p><img src=""girl.png"" alt=""This is image alt text with quotation ' and double quotation &quot;hello&quot; 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&amp;ddr;&amp;*&amp;ddr;&amp;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&#174;*&#174;";
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);
}
}
}

View File

@@ -0,0 +1,92 @@
// --------------------------------
// 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 1
//
// Should be rendered as:
// # Heading
//
// Text after two newlines 1
Console.WriteLine("Example 3\nSection Headings\n");
TestNormalize.TestSpec("Heading\n=======\n\nText after two newlines 1", "# Heading\n\nText after two newlines 1", "");
}
}
}

View 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 1
.
# Heading
Text after two newlines 1
````````````````````````````````

View File

@@ -0,0 +1,34 @@
// --------------------------------
// 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", "");
}
}
}

View 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!
````````````````````````````````

View File

@@ -1,14 +1,19 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// 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;
namespace Markdig.Tests
{
public class Program
class Program
{
public static void Main()
public static void Main(string[] args)
{
new TestPlayParser().TestSimple();
Console.WriteLine("Run NUnit tests runner with this");
// Uncomment the following line to debug a specific tests more easily
//var tests = new Specs.CommonMarkV_0_29.TestLeafBlocksSetextHeadings();
//tests.LeafBlocksSetextHeadings_Example063();
}
}
}

View File

@@ -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")]

View File

@@ -0,0 +1,235 @@
// --------------------------------
// 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");
}
}
}

View File

@@ -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>
````````````````````````````````

View File

@@ -0,0 +1,223 @@
// --------------------------------
// 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 &amp;@! 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 &amp;@! 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 &amp; ^ % *</h1>
// <h1 id="section-1">1.0 &amp; ^ % *</h1>
Console.WriteLine("Example 7\nSection Extensions / Heading Auto Identifiers\n");
TestParser.TestSpec("# 1.0 & ^ % *\n# 1.0 & ^ % *", "<h1 id=\"section\">1.0 &amp; ^ % *</h1>\n<h1 id=\"section-1\">1.0 &amp; ^ % *</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");
}
}
}

View File

@@ -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>
````````````````````````````````

View File

@@ -0,0 +1,562 @@
// --------------------------------
// 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
// And not a tel:
//
// 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
// And not a tel:</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 \nAnd not a tel:", "<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\nAnd not a tel:</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&amp;hl=en">www.google.com/search?q=commonmark&amp;hl=en</a></p>
// <p><a href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&amp;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&amp;hl=en\">www.google.com/search?q=commonmark&amp;hl=en</a></p>\n<p><a href=\"http://www.google.com/search?q=commonmark\">www.google.com/search?q=commonmark</a>&amp;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>&lt;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>&lt;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");
}
}
}

View File

@@ -0,0 +1,306 @@
# 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
And not a tel:
.
<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
And not a tel:</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&amp;hl=en">www.google.com/search?q=commonmark&amp;hl=en</a></p>
<p><a href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&amp;hl;</p>
````````````````````````````````
```````````````````````````````` example
www.commonmark.org/he<lp
.
<p><a href="http://www.commonmark.org/he">www.commonmark.org/he</a>&lt;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>
````````````````````````````````

View File

@@ -0,0 +1,110 @@
// --------------------------------
// 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:
// ![Image Link](/url)
//
// 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("![Image Link](/url)", "<p><img src=\"/url\" class=\"img-fluid\" alt=\"Image Link\" /></p>", "bootstrap+pipetables+figures+attributes");
}
}
}

View File

@@ -1,6 +1,6 @@
# Extensions
Adds support for outputing bootstrap ready tags:
Adds support for outputting bootstrap ready tags:
## Bootstrap

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,210 @@
// --------------------------------
// 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");
}
}
}

View File

@@ -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>
````````````````````````````````
````````````````````````````````

View File

@@ -0,0 +1,201 @@
// --------------------------------
// 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");
}
}
}

View File

@@ -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>
````````````````````````````````

View File

@@ -0,0 +1,93 @@
// --------------------------------
// 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
}
}

View File

@@ -23,4 +23,35 @@ graph TD;
</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

View File

@@ -0,0 +1,90 @@
// --------------------------------
// 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");
}
}
}

View File

@@ -4,7 +4,7 @@ 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
@@ -12,10 +12,28 @@ 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 and followed by a space:
An emoji needs to be preceded by a space:
```````````````````````````````` example
These are not:) an :)emoji with a:) x:angry:x
These are not:) an emoji with a:) x:angry:x
.
<p>These are not:) an :)emoji with a:) x:angry:x</p>
<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>
````````````````````````````````

View File

@@ -0,0 +1,151 @@
// --------------------------------
// 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 ^&reg;^ and MyTrademark ^&trade;^
// This is text MyBrand^&reg;^ and MyTrademark^&trade;^
// This is text MyBrand~&reg;~ and MyCopyright^&copy;^
//
// 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 ^&reg;^ and MyTrademark ^&trade;^\nThis is text MyBrand^&reg;^ and MyTrademark^&trade;^\nThis is text MyBrand~&reg;~ and MyCopyright^&copy;^", "<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");
}
}
}

View File

@@ -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 ^&reg;^ and MyTrademark ^&trade;^
This is text MyBrand^&reg;^ and MyTrademark^&trade;^
This is text MyBrand~&reg;~ and MyCopyright^&copy;^
.
<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>
````````````````````````````````

View File

@@ -0,0 +1,90 @@
// --------------------------------
// 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");
}
}
}

View File

@@ -0,0 +1,192 @@
// --------------------------------
// 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">&#8617;</a><a href="#fnref:2" class="footnote-back-ref">&#8617;</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">&#8617;</a><a href="#fnref:4" class="footnote-back-ref">&#8617;</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\">&#8617;</a><a href=\"#fnref:2\" class=\"footnote-back-ref\">&#8617;</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\">&#8617;</a><a href=\"#fnref:4\" class=\"footnote-back-ref\">&#8617;</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">&#8617;</a></p></li>
// <li id="fn:2">
// <p>Footnote 2 text<a href="#fnref:2" class="footnote-back-ref">&#8617;</a></p></li>
// <li id="fn:3">
// <p>Footnote 3 text<a href="#fnref:3" class="footnote-back-ref">&#8617;</a></p></li>
// <li id="fn:4">
// <p>Footnote 4 text<a href="#fnref:4" class="footnote-back-ref">&#8617;</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\">&#8617;</a></p></li>\n<li id=\"fn:2\">\n<p>Footnote 2 text<a href=\"#fnref:2\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:3\">\n<p>Footnote 3 text<a href=\"#fnref:3\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:4\">\n<p>Footnote 4 text<a href=\"#fnref:4\" class=\"footnote-back-ref\">&#8617;</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">&#8617;</a></p></li>
// <li id="fn:2">
// <p>Footnote 2 text<a href="#fnref:2" class="footnote-back-ref">&#8617;</a></p></li>
// <li id="fn:3">
// <p>Footnote 3 text<a href="#fnref:3" class="footnote-back-ref">&#8617;</a></p></li>
// <li id="fn:4">
// <p>Footnote 4 text<a href="#fnref:4" class="footnote-back-ref">&#8617;</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\">&#8617;</a></p></li>\n<li id=\"fn:2\">\n<p>Footnote 2 text<a href=\"#fnref:2\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:3\">\n<p>Footnote 3 text<a href=\"#fnref:3\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:4\">\n<p>Footnote 4 text<a href=\"#fnref:4\" class=\"footnote-back-ref\">&#8617;</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">&#8617;</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\">&#8617;</a></p></li>\n</ol>\n</div>", "footnotes|advanced");
}
}
}

View File

@@ -2,7 +2,7 @@
This section describes the different extensions supported:
## Footontes
## Footnotes
Allows footnotes using the following syntax (taken from pandoc example):
@@ -61,7 +61,7 @@ multi-paragraph list items.<a href="#fnref:3" class="footnote-back-ref">&#8617;<
</div>
````````````````````````````````
Check with mulitple consecutive footnotes:
Check with multiple consecutive footnotes:
```````````````````````````````` example
Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4].
@@ -118,3 +118,24 @@ Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^
</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">&#8617;</a></p></li>
</ol>
</div>
````````````````````````````````

View File

@@ -0,0 +1,105 @@
// --------------------------------
// 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");
}
}
}

View File

@@ -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>
````````````````````````````````

View File

@@ -0,0 +1,233 @@
// --------------------------------
// 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");
}
}
}

View 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>
````````````````````````````````

View File

@@ -0,0 +1,398 @@
// --------------------------------
// 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");
}
}
}

View File

@@ -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>
@@ -74,9 +74,9 @@ A regular row can continue a previous regular row when column separator `|` are
| 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
@@ -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>
````````````````````````````````

View File

@@ -0,0 +1,39 @@
// --------------------------------
// 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");
}
}
}

View File

@@ -0,0 +1,179 @@
// --------------------------------
// 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");
}
}
}

View 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>
````````````````````````````````

View File

@@ -0,0 +1,216 @@
// --------------------------------
// 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");
}
}
}

View File

@@ -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>
````````````````````````````````

View File

@@ -0,0 +1,327 @@
// --------------------------------
// 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");
}
}
}

View File

@@ -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>
````````````````````````````````

View File

@@ -0,0 +1,64 @@
// --------------------------------
// 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:
// ![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)
//
// ![youtube.com with t](https://www.youtube.com/watch?v=mswPy5bt3TQ&t=100)
//
// ![youtu.be](https://youtu.be/mswPy5bt3TQ)
//
// ![youtu.be with t](https://youtu.be/mswPy5bt3TQ?t=100)
//
// ![youtube.com/embed 1](https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0)
//
// ![youtube.com/embed 2](https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6)
//
// ![vimeo](https://vimeo.com/8607834)
//
// ![static mp4](https://sample.com/video.mp4)
//
// ![yandex.ru](https://music.yandex.ru/album/411845/track/4402274)
//
// ![ok.ru](https://ok.ru/video/26870090463)
//
// 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&amp;rel=0" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://www.youtube.com/embed?listType=playlist&amp;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("![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)\n\n![youtube.com with t](https://www.youtube.com/watch?v=mswPy5bt3TQ&t=100)\n\n![youtu.be](https://youtu.be/mswPy5bt3TQ)\n\n![youtu.be with t](https://youtu.be/mswPy5bt3TQ?t=100)\n\n![youtube.com/embed 1](https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0)\n\n![youtube.com/embed 2](https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6)\n\n![vimeo](https://vimeo.com/8607834)\n\n![static mp4](https://sample.com/video.mp4)\n\n![yandex.ru](https://music.yandex.ru/album/411845/track/4402274)\n\n![ok.ru](https://ok.ru/video/26870090463)", "<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&amp;rel=0\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed?listType=playlist&amp;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");
}
}
}

View File

@@ -3,14 +3,38 @@
Adds support for media links:
## Media links
Allows to embed audio/video links to popular website:
```````````````````````````````` example
![Video1](https://www.youtube.com/watch?v=mswPy5bt3TQ)
![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)
![Video2](https://vimeo.com/8607834)
![youtube.com with t](https://www.youtube.com/watch?v=mswPy5bt3TQ&t=100)
![youtu.be](https://youtu.be/mswPy5bt3TQ)
![youtu.be with t](https://youtu.be/mswPy5bt3TQ?t=100)
![youtube.com/embed 1](https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0)
![youtube.com/embed 2](https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6)
![vimeo](https://vimeo.com/8607834)
![static mp4](https://sample.com/video.mp4)
![yandex.ru](https://music.yandex.ru/album/411845/track/4402274)
![ok.ru](https://ok.ru/video/26870090463)
.
<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&amp;rel=0" class="youtube" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://www.youtube.com/embed?listType=playlist&amp;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>
````````````````````````````````

View File

@@ -0,0 +1,58 @@
// --------------------------------
// 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&lt;/td&gt;&lt;/tr&gt;</p>
Console.WriteLine("Example 1\nSection Extensions / NoHTML\n");
TestParser.TestSpec("this is some text</td></tr>", "<p>this is some text&lt;/td&gt;&lt;/tr&gt;</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>&lt;div&gt;
// this is some text
// &lt;/div&gt;</p>
Console.WriteLine("Example 2\nSection Extensions / NoHTML\n");
TestParser.TestSpec("<div>\nthis is some text\n</div>", "<p>&lt;div&gt;\nthis is some text\n&lt;/div&gt;</p>", "nohtml");
}
}
}

View 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&lt;/td&gt;&lt;/tr&gt;</p>
````````````````````````````````
For Block HTML:
```````````````````````````````` example
<div>
this is some text
</div>
.
<p>&lt;div&gt;
this is some text
&lt;/div&gt;</p>
````````````````````````````````

View File

@@ -0,0 +1,856 @@
// --------------------------------
// 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");
}
}
}

View 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>
````````````````````````````````

View File

@@ -0,0 +1,854 @@
// --------------------------------
// 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");
}
}
}

View File

@@ -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>
@@ -238,7 +243,7 @@ A pipe may be present at both the beginning/ending of each line:
</table>
````````````````````````````````
Or may be ommitted on one side:
Or may be omitted on one side:
```````````````````````````````` example
a|b|
@@ -345,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
@@ -357,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>
@@ -448,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 `
@@ -457,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 `|`:
@@ -482,7 +488,7 @@ a <a href="" title="|"></a> | b
</table>
````````````````````````````````
**Rule #8**
**Rule #9**
Links have a higher precedence than the column delimiter character `|`:
@@ -507,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>
````````````````````````````````

View File

@@ -0,0 +1,368 @@
// --------------------------------
// 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 &ldquo;text&rdquo;</p>
Console.WriteLine("Example 1\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a \"text\"", "<p>This is a &ldquo;text&rdquo;</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 &lsquo;text&rsquo;</p>
Console.WriteLine("Example 2\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a 'text'", "<p>This is a &lsquo;text&rsquo;</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 &laquo;text&raquo;</p>
Console.WriteLine("Example 3\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a <<text>>", "<p>This is a &laquo;text&raquo;</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 &quot;text</p>
Console.WriteLine("Example 4\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a \"text", "<p>This is a &quot;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 &lt;&lt;text</p>
Console.WriteLine("Example 6\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a <<text", "<p>This is a &lt;&lt;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 &ldquo;text 'with&rdquo; 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 &ldquo;text 'with&rdquo; 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 &lsquo;a &ldquo;text 'with&rdquo; a another text&rsquo;</p>
Console.WriteLine("Example 8\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is 'a \"text 'with\" a another text'", "<p>This is &lsquo;a &ldquo;text 'with&rdquo; a another text&rsquo;</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 &lsquo;text &lt;&lt;with&rsquo; a another text&gt;&gt;</p>
Console.WriteLine("Example 9\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a 'text <<with' a another text>>", "<p>This is a &lsquo;text &lt;&lt;with&rsquo; a another text&gt;&gt;</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 &laquo;text 'with&raquo; 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 &laquo;text 'with&raquo; 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 &ldquo;a <em>text&rdquo; 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 &ldquo;a <em>text&rdquo; 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>&ldquo;aaa&rdquo; &ldquo;bbb&rdquo; &ldquo;ccc&rdquo; &ldquo;ddd&rdquo;</p>
Console.WriteLine("Example 15\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("\"aaa\" \"bbb\" \"ccc\" \"ddd\"", "<p>&ldquo;aaa&rdquo; &ldquo;bbb&rdquo; &ldquo;ccc&rdquo; &ldquo;ddd&rdquo;</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 &ndash; text</p>
Console.WriteLine("Example 16\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("This is a -- text", "<p>This is a &ndash; 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 &mdash; text</p>
Console.WriteLine("Example 17\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("This is a --- text", "<p>This is a &mdash; 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&hellip;</p>
Console.WriteLine("Example 18\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("This is a en ellipsis...", "<p>This is a en ellipsis&hellip;</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 &ldquo;quote&rdquo; with a &mdash;</p>
Console.WriteLine("Example 20\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("A \"quote\" with a ---", "<p>A &ldquo;quote&rdquo; with a &mdash;</p>", "pipetables+smartypants|advanced+smartypants");
}
}
}

View File

@@ -52,6 +52,12 @@ This is a "text 'with" a another text'
<p>This is a &ldquo;text 'with&rdquo; a another text'</p>
````````````````````````````````
```````````````````````````````` example
This is 'a "text 'with" a another text'
.
<p>This is &lsquo;a &ldquo;text 'with&rdquo; a another text&rsquo;</p>
````````````````````````````````
```````````````````````````````` example
This is a 'text <<with' a another text>>
.
@@ -91,6 +97,14 @@ This is "a *text" with an emphasis*
<p>This is &ldquo;a <em>text&rdquo; with an emphasis</em></p>
````````````````````````````````
Multiple sets of quotes can be used
```````````````````````````````` example
"aaa" "bbb" "ccc" "ddd"
.
<p>&ldquo;aaa&rdquo; &ldquo;bbb&rdquo; &ldquo;ccc&rdquo; &ldquo;ddd&rdquo;</p>
````````````````````````````````
## SmartyPants Separators
```````````````````````````````` example

File diff suppressed because it is too large Load Diff

View File

@@ -1,336 +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>("https://raw.githubusercontent.com/jgm/CommonMark/91e045ca370258903ed138450373043a496ec64b/spec.txt", string.Empty), // 0.26 specs
new KeyValuePair<string, string>(Host.ResolvePath("PipeTableSpecs.md"), "pipetables|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("FootnotesSpecs.md"), "footnotes|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("GenericAttributesSpecs.md"), "attributes|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("EmphasisExtraSpecs.md"), "emphasisextras|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("HardlineBreakSpecs.md"), "hardlinebreak|advanced+hardlinebreak"),
new KeyValuePair<string, string>(Host.ResolvePath("GridTableSpecs.md"), "gridtables|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("CustomContainerSpecs.md"), "customcontainers+attributes|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("DefinitionListSpecs.md"), "definitionlists+attributes|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("EmojiSpecs.md"), "emojis|advanced+emojis"),
new KeyValuePair<string, string>(Host.ResolvePath("AbbreviationSpecs.md"), "abbreviations|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("ListExtraSpecs.md"), "listextras|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("FigureFooterAndCiteSpecs.md"), "figures+footers+citations|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("MathSpecs.md"), "mathematics|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("BootstrapSpecs.md"), "bootstrap+pipetables+figures+attributes"),
new KeyValuePair<string, string>(Host.ResolvePath("MediaSpecs.md"), "medialinks|advanced+medialinks"),
new KeyValuePair<string, string>(Host.ResolvePath("SmartyPantsSpecs.md"), "pipetables+smartypants|advanced+smartypants"), // Check with smartypants to make sure that it doesn't break pipetables
new KeyValuePair<string, string>(Host.ResolvePath("AutoIdentifierSpecs.md"), "autoidentifiers|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("TaskListSpecs.md"), "tasklists|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("DiagramsSpecs.md"), "diagrams|advanced"),
};
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();
}
}
}
#>

View File

@@ -0,0 +1,62 @@
// --------------------------------
// 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");
}
}
}

View File

@@ -0,0 +1,213 @@
// --------------------------------
// 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");
}
}
}

View 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>
````````````````````````````````

View 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

View 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);
}
}
}

View File

@@ -0,0 +1,92 @@
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);
Assert.AreSame(container, one.Parent);
var two = new ParagraphBlock();
container.Insert(1, two);
Assert.AreEqual(2, container.Count);
Assert.AreSame(container[0], one);
Assert.AreSame(container[1], two);
Assert.AreSame(container, two.Parent);
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.AreSame(container, three.Parent);
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
}
[Test]
public void CanBeSet()
{
ContainerBlock container = new MockContainerBlock();
var one = new ParagraphBlock();
container.Insert(0, one);
Assert.AreEqual(1, container.Count);
Assert.AreSame(container[0], one);
Assert.AreSame(container, one.Parent);
var two = new ParagraphBlock();
container[0] = two;
Assert.AreSame(container, two.Parent);
Assert.Null(one.Parent);
Assert.Throws<ArgumentException>(() => container[0] = two); // two already has a parent
}
}
}

View File

@@ -0,0 +1,41 @@
using System;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
using NUnit.Framework;
namespace Markdig.Tests
{
public class TestContainerInlines
{
private class MockLeafBlock : LeafBlock
{
public MockLeafBlock()
: base(null)
{
}
}
[Test]
public void CanBeAddedToLeafBlock()
{
var leafBlock1 = new MockLeafBlock();
var one = new ContainerInline();
Assert.Null(one.ParentBlock);
leafBlock1.Inline = one;
Assert.AreSame(leafBlock1, one.ParentBlock);
var two = new ContainerInline();
Assert.Null(two.ParentBlock);
leafBlock1.Inline = two;
Assert.AreSame(leafBlock1, two.ParentBlock);
Assert.Null(one.ParentBlock);
var leafBlock2 = new MockLeafBlock();
Assert.Throws<ArgumentException>(() => leafBlock2.Inline = two);
}
}
}

View 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));
}
}
}

View File

@@ -0,0 +1,152 @@
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
{
public static void TestSchemas(MarkdownDocument[] specsSyntaxTrees)
{
foreach (var syntaxTree in 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;
}
}
}
}
}
}

View File

@@ -0,0 +1,169 @@
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>&quot;")]
[TestCase("\"\"foo\"", "&quot;<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("*foo*&_foo_", "<em>foo</em>&amp;<em>foo</em>")]
[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);
}
}
}

View 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());
}
}
}

View 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>", "");
}
}
}

View 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);
});
}
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,25 @@
using NUnit.Framework;
using System.Text.RegularExpressions;
namespace Markdig.Tests
{
[TestFixture]
public class TestImageAltText
{
[Test]
[TestCase("![](image.jpg)", "")]
[TestCase("![foo](image.jpg)", "foo")]
[TestCase("![][1]\n\n[1]: image.jpg", "")]
[TestCase("![bar][1]\n\n[1]: image.jpg", "bar")]
[TestCase("![](image.jpg 'title')", "")]
[TestCase("![foo](image.jpg 'title')", "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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
@@ -83,11 +88,7 @@ namespace Markdig.Tests
// 0 1 2 3
// 0123456789012345678901234567890123456789
var text = new StringSlice(@"(http://google.com 'this is a title')ABC");
string link;
string title;
SourceSpan linkSpan;
SourceSpan titleSpan;
Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title, out linkSpan, out titleSpan));
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);
@@ -100,11 +101,7 @@ namespace Markdig.Tests
{
// 01234
var text = new StringSlice(@"(<>)A");
string link;
string title;
SourceSpan linkSpan;
SourceSpan titleSpan;
Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title, out linkSpan, out titleSpan));
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);
@@ -117,11 +114,7 @@ namespace Markdig.Tests
{
// 012345
var text = new StringSlice(@"( <> )A");
string link;
string title;
SourceSpan linkSpan;
SourceSpan titleSpan;
Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title, out linkSpan, out titleSpan));
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);
@@ -136,11 +129,7 @@ namespace Markdig.Tests
// 0 1 2
// 0123456789012345678901234567
var text = new StringSlice(@"( <> 'toto' )A");
string link;
string title;
SourceSpan linkSpan;
SourceSpan titleSpan;
Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title, out linkSpan, out titleSpan));
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);
@@ -152,11 +141,7 @@ namespace Markdig.Tests
public void TestUrlEmpty()
{
var text = new StringSlice(@"()A");
string link;
string title;
SourceSpan linkSpan;
SourceSpan titleSpan;
Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title, out linkSpan, out titleSpan));
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);
@@ -170,11 +155,7 @@ namespace Markdig.Tests
// 0 1 2 3
// 01 2345678901234567890 1234567890123456789
var text = new StringSlice("(\n<http://google.com>\n 'toto' )A");
string link;
string title;
SourceSpan linkSpan;
SourceSpan titleSpan;
Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title, out linkSpan, out titleSpan));
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);
@@ -187,9 +168,7 @@ namespace Markdig.Tests
{
// 01234
var text = new StringSlice("[foo]");
string label;
SourceSpan labelSpan;
Assert.True(LinkHelper.TryParseLabel(ref text, out label, out labelSpan));
Assert.True(LinkHelper.TryParseLabel(ref text, out string label, out SourceSpan labelSpan));
Assert.AreEqual(new SourceSpan(1, 3), labelSpan);
Assert.AreEqual("foo", label);
}
@@ -199,9 +178,7 @@ namespace Markdig.Tests
{
// 012345678
var text = new StringSlice(@"[fo\[\]o]");
string label;
SourceSpan labelSpan;
Assert.True(LinkHelper.TryParseLabel(ref text, out label, out labelSpan));
Assert.True(LinkHelper.TryParseLabel(ref text, out string label, out SourceSpan labelSpan));
Assert.AreEqual(new SourceSpan(1, 7), labelSpan);
Assert.AreEqual(@"fo[]o", label);
}
@@ -211,9 +188,7 @@ namespace Markdig.Tests
{
// 0123
var text = new StringSlice(@"[\]]");
string label;
SourceSpan labelSpan;
Assert.True(LinkHelper.TryParseLabel(ref text, out label, out labelSpan));
Assert.True(LinkHelper.TryParseLabel(ref text, out string label, out SourceSpan labelSpan));
Assert.AreEqual(new SourceSpan(1, 2), labelSpan);
Assert.AreEqual(@"]", label);
}
@@ -221,8 +196,7 @@ namespace Markdig.Tests
[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));
@@ -236,9 +210,7 @@ namespace Markdig.Tests
// 0 1 2 3
// 0123456789012345678901234567890123456789
var text = new StringSlice(@"[ fo o z ]");
string label;
SourceSpan labelSpan;
Assert.True(LinkHelper.TryParseLabel(ref text, out label, out labelSpan));
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);
}
@@ -249,13 +221,7 @@ namespace Markdig.Tests
// 0 1 2 3
// 0123456789012345678901234567890123456789
var text = new StringSlice(@"[foo]: /toto 'title'");
string label;
string url;
string title;
SourceSpan labelSpan;
SourceSpan urlSpan;
SourceSpan titleSpan;
Assert.True(LinkHelper.TryParseLinkReferenceDefinition(ref text, out label, out url, out title, out labelSpan, out urlSpan, out titleSpan));
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);
@@ -269,9 +235,7 @@ namespace Markdig.Tests
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);
}
@@ -280,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);
}
@@ -290,9 +252,7 @@ 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));
@@ -308,6 +268,16 @@ namespace Markdig.Tests
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")]
@@ -390,9 +360,16 @@ namespace Markdig.Tests
[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>");
}
}
}

View 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: ![alt text](/image.jpg)", "abc/image.jpg");
TestSpec(s => "abc" + s, "Image: ![alt text](image.jpg \"title\")", "abcimage.jpg");
TestSpec(null, "Image: ![alt text](/image.jpg)", "/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 + "\""));
}
}
}

View 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);
}
}
}

Some files were not shown because too many files have changed in this diff Show More