Compare commits

...

319 Commits

Author SHA1 Message Date
Alexandre Mutel
c0ee97a803 Bump to 0.26.0 2021-08-27 20:34:30 +02:00
Alexandre Mutel
63ce549ea2 Merge pull request #570 from Sleepyowl/master
Fixes xoofx/markdig#567
2021-08-27 20:24:45 +02:00
Dmtry Soloviev
0faf0ef430 Make Mathematics extension respect EnableHtml* options 2021-08-24 23:03:02 +02:00
Alexandre Mutel
cdd4b40469 Merge pull request #560 from yufeih/yufeih/fix-crlf
Fix rendering diff between line endings
2021-07-06 18:36:32 +02:00
Yufei Huang
54d85ebac6 Fix rendering diff between line endings 2021-06-29 16:18:42 +08:00
Alexandre Mutel
64875c3dd9 Bump to 0.25.0 2021-06-10 09:02:03 +02:00
Alexandre Mutel
4c92fe5a3b Fix regression when parsing link reference definitions (#543) 2021-06-10 08:58:53 +02:00
Alexandre Mutel
27f625f15b Merge pull request #548 from Mysteryduck001/master
JiraLinkInlineParser.cs - Make digits in JiraKey's posible
2021-05-08 12:01:32 +02:00
Mysteryduck001
aca085703e JiraLinks.Generated.cs - add test for JiraKey's starting with a digit (not allowed) 2021-05-03 17:28:11 +02:00
Mysteryduck001
8aa0948b20 JiraLinkInlineParser.cs - prevent Jira key's to start with a digit 2021-05-03 17:22:13 +02:00
Mysteryduck001
8ce6f4d9ad JiraLinks.md - Do not allow a digit to be the first Char of the Key 2021-05-03 17:18:36 +02:00
Mysteryduck001
3a47a5115a JiraLinks.generated.cs - updated tests for JiraLink 2021-05-03 17:14:25 +02:00
Mysteryduck001
a8737e8481 JiraLinks.md - add examples with JiraKeys using Digits 2021-05-03 17:03:31 +02:00
Mysteryduck001
f56b8e6ba7 JiraLinkInlineParser.cs - Make digits in JiraKey's posible 2021-05-03 16:32:08 +02:00
Alexandre Mutel
0a0040450f Merge pull request #544 from generateui/fix_535
ignore whitespace at end of pipe table row header
2021-04-14 16:38:40 +02:00
Alexandre Mutel
fb12be5ab0 Merge pull request #540 from MihaZupan/coverage-link
Update coverage badge link
2021-04-13 07:35:27 +02:00
Ruud Poutsma
2277596e2e ignore whitespace at end of pipe table row header 2021-04-10 17:59:32 +02:00
MihaZupan
a10f6f6b8c Update coverage badge link 2021-04-07 00:18:57 +02:00
Alexandre Mutel
203cfd6508 Bump to 0.24.0 2021-03-20 08:47:20 +01:00
Alexandre Mutel
5fefcbb5b3 Merge pull request #530 from carbon/cq
Improve Code Quality
2021-03-15 20:40:54 +01:00
Alexandre Mutel
7ad7b55c48 Merge pull request #529 from MihaZupan/cache-parsers
Cache the MarkdownParser & Processors
2021-03-15 06:34:36 +01:00
Alexandre Mutel
e9ea103e32 Merge pull request #532 from MihaZupan/more-allocs
Avoid char[] & string allocations in HtmlBlockParser
2021-03-15 06:33:02 +01:00
Alexandre Mutel
c680910828 Merge pull request #531 from MihaZupan/random-perf-3
A handful of codegen improvements
2021-03-15 06:32:26 +01:00
Jason Nelson
4526d886c8 Use WriteLine char overload 2021-03-14 09:24:09 -07:00
Jason Nelson
397de86e2f Remove obvious parameter label 2021-03-14 09:15:41 -07:00
MihaZupan
f985750b82 Don't use the Roundtrip InfoParser by default 2021-03-14 11:21:34 +01:00
MihaZupan
00c175a79c Remove char[], string allocations in HtmlBlockParser 2021-03-14 11:21:14 +01:00
MihaZupan
6204095261 Remove static ctor from CharNormalizer 2021-03-14 04:13:27 +01:00
MihaZupan
63fddf4511 Add quick range check in CharNormalizer 2021-03-14 04:10:58 +01:00
MihaZupan
c964659085 Optimize Globalization StartsWithRtlCharacter check 2021-03-14 03:56:36 +01:00
MihaZupan
eabfe74e92 Avoid struct copy in Roundtrip CodeBlockRenderer 2021-03-14 03:17:59 +01:00
MihaZupan
bd1dcd952c Improve HtmlHelper 2021-03-14 03:06:47 +01:00
MihaZupan
54e2514778 Avoid struct copies in StringLineGroup 2021-03-14 02:31:08 +01:00
MihaZupan
4b7a4d21de Optimize NewLine.Length() 2021-03-14 02:07:45 +01:00
MihaZupan
6b1399ba23 Use IsEmpty instead of Length == 0 or CurrentChar == '\0' 2021-03-14 02:00:37 +01:00
MihaZupan
07467d6c30 Add ICharIterator SkipChar and PeekChar
PeekChar() already existed on StringSlice, but not on the interface, so it wasn't always getting used
2021-03-14 01:50:56 +01:00
MihaZupan
2f9588498c Add missing null check 2021-03-13 20:44:55 +01:00
MihaZupan
80ed85e2a8 Cache the MarkdownParser & Processors 2021-03-13 20:41:35 +01:00
Jason Nelson
b2306db388 Make CodeInline.Content nonnull 2021-03-12 11:31:11 -08:00
Jason Nelson
8db238797b Enable nullable on AutolinkInline 2021-03-12 11:29:53 -08:00
Jason Nelson
780e16a9c9 Simplify list initialization 2021-03-12 11:28:05 -08:00
Jason Nelson
8fdc0d59d7 Format TableState 2021-03-12 11:21:15 -08:00
Jason Nelson
f1cd0cb1b8 Enable nullable on CharacterMap 2021-03-12 11:20:57 -08:00
Jason Nelson
a724783e3f CodeBlockLines is always defined. Remove lazy initializer 2021-03-12 11:20:42 -08:00
Jason Nelson
1c862a1e07 Remove unused using statement 2021-03-12 11:10:17 -08:00
Jason Nelson
35d3160ad2 Eliminate a few allocations to hold indents 2021-03-12 11:09:53 -08:00
Jason Nelson
e0a2f9e52d Add notes on why we continue to support net452 2021-03-12 11:05:54 -08:00
Jason Nelson
c9ba236dbc Write chars, instead of strings, where possible 2021-03-12 11:01:06 -08:00
Jason Nelson
0c9b5dddc9 Use is (not) pattern to match constant strings 2021-03-12 10:50:18 -08:00
Jason Nelson
bd2bb98631 Compare strings using StringComparison.Ordinal 2021-03-12 10:49:26 -08:00
Alexandre Mutel
da0ba34165 Merge pull request #527 from MihaZupan/last-nullable
A few nullable changes
2021-03-12 06:08:54 +01:00
MihaZupan
51c5bec315 A few nullable changes 2021-03-11 20:56:55 +01:00
Alexandre Mutel
13bdab4570 Merge pull request #526 from carbon/nullability2
Complete nullable annotations
2021-03-11 20:20:50 +01:00
Jason Nelson
6b9433c7d8 Remove temporary #nullable enable directives 2021-03-11 10:41:14 -08:00
Jason Nelson
eedbb494fc Revert accidental readonly removal 2021-03-11 10:27:02 -08:00
Jason Nelson
9d36a74312 Replace == null with is null 2021-03-10 22:45:49 -08:00
Jason Nelson
4009c89321 Enable nullable at project level and add remaining nullable annotations 2021-03-10 22:44:42 -08:00
Alexandre Mutel
6b433d9352 Merge pull request #525 from carbon/nullability2
Enable nullability, round 3 of x
2021-03-11 07:05:12 +01:00
Jason Nelson
f6e6001d94 Remove unnecessary suppression 2021-03-10 18:18:41 -08:00
Jason Nelson
1474b7b29a Fix default NewLine 2021-03-10 15:28:31 -08:00
Jason Nelson
61b29b6d41 Fix incorrect logic 2021-03-10 15:20:43 -08:00
Jason Nelson
6684c8257c Enable nullable, round 3 2021-03-10 15:12:30 -08:00
Alexandre Mutel
247cd92926 Merge pull request #524 from carbon/nullability2
Enable nullable annotations, round 2 of x
2021-03-10 22:55:24 +01:00
Jason Nelson
404a94f284 Fix nullability in MarkdownParser 2021-03-10 10:01:05 -08:00
Jason Nelson
1cc8a40473 Use pattern matching to test for non-empty collections 2021-03-10 09:39:12 -08:00
Jason Nelson
dc4968d5ab Reapply nullable annotations after merge 2021-03-10 09:32:02 -08:00
Jason Nelson
b2b36038ff Merge remote-tracking branch 'upstream/master' into nullability2 2021-03-10 09:27:12 -08:00
Alexandre Mutel
4a57035aec Merge pull request #521 from MihaZupan/random-perf-2
Random perf improvements
2021-03-10 07:27:10 +01:00
Jason Nelson
1752178631 Make attachedDatas nullable 2021-03-09 17:07:02 -08:00
Jason Nelson
39c05f34d1 Enable nullable annotations, round 2 of x 2021-03-09 16:55:13 -08:00
Alexandre Mutel
640196a18f Merge pull request #520 from MihaZupan/cleanup
Some minor cleanup
2021-03-09 07:55:19 +01:00
MihaZupan
4f9119fc96 Merge master 2021-03-09 07:54:20 +01:00
MihaZupan
5eb600afc3 Expose TrackTrivia on PipelineBuilder as get-only 2021-03-09 07:35:49 +01:00
Alexandre Mutel
64ebff4012 Merge pull request #519 from grishat/document-to-html
ADD: Markdown.ToHtml from MarkdownDocument
2021-03-09 07:13:49 +01:00
Alexandre Mutel
9e5d30cd4c Merge pull request #522 from carbon/master
Enable nullability
2021-03-09 07:13:18 +01:00
Alexandre Mutel
4324caaaea Update src/Markdig/Markdown.cs 2021-03-09 07:08:15 +01:00
Jason Nelson
46c2d49243 Begin nullability enablement 2021-03-08 11:43:02 -08:00
MihaZupan
80b1cf6020 Rename NoBlockFoundBlockRenderer.cs => EmptyBlockRenderer.cs 2021-03-08 12:19:43 +01:00
MihaZupan
264f7f2132 Update Roundtrip.md 2021-03-08 12:18:12 +01:00
MihaZupan
80ec8da7d3 Add missing license headers 2021-03-08 11:54:43 +01:00
MihaZupan
1e2399669d Fix most build warnings 2021-03-08 11:37:29 +01:00
MihaZupan
ab53969f06 Revert "Fix some build warnings"
This reverts commit 325fb7158e.
2021-03-08 11:16:31 +01:00
MihaZupan
168217b4e0 Expose TrackTrivia on Pipeline as get-only 2021-03-08 11:12:55 +01:00
MihaZupan
a3ce1903c1 Cache renderers for custom writers 2021-03-07 21:28:39 +01:00
MihaZupan
db1021a979 Avoid minor allocations in ProcessInlines loop 2021-03-07 20:08:04 +01:00
MihaZupan
cbd00a45af Remove test dependency on source file's line endings
This test uses '@' strings so if source files are checked out with different line endings, it will fail
2021-03-07 19:53:57 +01:00
MihaZupan
fef4719e41 Don't change Writer's NewLine 2021-03-07 19:29:17 +01:00
MihaZupan
ae25a8f12c Reduce the size of MarkdownObject by 1 pointer size
Since this is the base type of every node on the AST, it amounts to ~3% allocated bytes reduction
2021-03-07 19:19:03 +01:00
MihaZupan
bb5403c795 Hide TrackTrivia from PipelineBuilder
EnableTrackTrivia is exposed to enable trivia
2021-03-07 19:13:34 +01:00
MihaZupan
325fb7158e Fix some build warnings 2021-03-07 18:59:23 +01:00
MihaZupan
67416e4b45 Hide TrackTrivia from Pipeline 2021-03-07 18:52:41 +01:00
Alexandre Mutel
8b48accb7e Merge pull request #481 from generateui/cst
Roundtrip implementation
2021-03-07 16:18:35 +01:00
Ruud Poutsma
bb42ee42ca code review feedback 2021-03-07 16:14:48 +01:00
Rishat Gildanov
d17660fe5d ADD: Markdown.ToHtml from MarkdownDocument (already parsed Markdown text) 2021-03-07 17:39:43 +05:00
Ruud Poutsma
19e409ceca correctly calculate newlines in StringLineGroup PeekChar 2021-03-04 23:28:37 +01:00
Ruud Poutsma
59df6d1a2e primarily define TrackTrivia on MarkdownPipeline 2021-03-04 22:57:57 +01:00
Ruud Poutsma
763ed32212 NewLine renaming remnants 2021-03-04 22:42:48 +01:00
Ruud Poutsma
8aa522c4bf Merge branch 'cst' of https://github.com/generateui/markdig into cst 2021-03-04 22:36:00 +01:00
Ruud Poutsma
9031be96f8 rename Newline to NewLine 2021-03-04 22:35:48 +01:00
Ruud Poutsma
4bc2e847d5 PR feedback 2021-03-04 22:04:26 +01:00
Alexandre Mutel
80d4e6f344 Fix StringSlice overlaps
Co-authored-by: Miha Zupan <mihazupan.zupan1@gmail.com>
2021-03-03 05:32:28 +01:00
Ruud Poutsma
b6e38a0a96 fix ContainerBlocksBlockQuotes_Example210 2021-03-01 23:26:55 +01:00
Ruud Poutsma
1d79ad8436 rerun specFileGen 2021-03-01 23:11:31 +01:00
Ruud Poutsma
383b197490 document roundtrip parsing feature 2021-03-01 23:07:40 +01:00
Ruud Poutsma
7aeee0681f rename Whitespace* member names to Trvia* member names 2021-03-01 21:12:51 +01:00
Ruud Poutsma
e017adae84 remove TODO: RTPs 2021-02-27 23:38:48 +01:00
Ruud Poutsma
7035aed74a Refactor Newline struct into enum 2021-02-27 23:32:09 +01:00
Ruud Poutsma
21b6a3869a implement NoBlocksFoundBlock, fix null character tests 2021-02-27 22:00:43 +01:00
Ruud Poutsma
aa92e59b2c merge from master 2021-02-27 21:25:44 +01:00
Alexandre Mutel
5f87e56651 Merge pull request #518 from grishat/master
FIX: Markdown.ToHtml doesnt get MarkdownParserContext parameter
2021-02-26 08:12:34 +01:00
Rishat Gildanov
9934c0033a FIX: Markdown.ToHtml doesnt get MarkdownParserContext parameter 2021-02-26 10:55:59 +05:00
Alexandre Mutel
5d1da2deac Merge pull request #511 from AndreyChechel/issue-508
Expose `TextRendererBase.Reset` method to inheritors
2021-02-17 20:57:48 +01:00
Andrey Chechel
4e424c43fb Expose TextRendererBase.Reset method to inheritors 2021-02-09 17:27:02 +03:00
Alexandre Mutel
3030b72f78 Bump to 0.23.0 2021-01-16 08:35:47 +01:00
Alexandre Mutel
d1784676b2 Rename AutolineInlineParser to AutolinkInlineParser 2021-01-16 08:34:45 +01:00
Alexandre Mutel
47e49f0a4f Add test documentation for root namespace 2021-01-16 08:28:20 +01:00
Alexandre Mutel
0bfc456509 Merge pull request #502 from yufeih/code-inline-plain-text
Fix CodeInline to plain text incorrect escape
2021-01-14 20:33:17 +01:00
Alexandre Mutel
8e14997bc1 Merge pull request #500 from MihaZupan/depth-limit
Add depth limits to avoid pathological-case parsing times/StackOverflows
2021-01-14 20:32:00 +01:00
Yufei Huang
a8ec3c1a48 Fix CodeInline to plain text incorrect escape 2021-01-12 16:11:31 +08:00
MihaZupan
f6f617a746 Add depth limits 2021-01-07 23:16:25 +01:00
Alexandre Mutel
3d65b9f6b6 Upgrade webapp settings 2020-12-22 14:36:26 +01:00
Alexandre Mutel
5f7d93be52 Use net5.0 2020-12-22 12:30:10 +01:00
Alexandre Mutel
3ec787687c Force not to use a pre-release in global.json 2020-12-22 11:16:38 +01:00
Ruud Poutsma
9fbe5eb21d merge from lunet-io/master 2020-12-12 14:26:02 +01:00
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
Ruud Poutsma
fb4abdfae3 fix broken multi-empty-line after UnorderedList and make naming of before/after consistent 2020-11-07 23:49:25 +01:00
Ruud Poutsma
7ab34d5cef fix paragraph with more then 2 newlines after 2020-11-07 18:58:37 +01:00
Ruud Poutsma
b576b08332 document MarkdownParser assigning empty lines 2020-11-07 12:46:22 +01:00
Ruud Poutsma
9c43b802bd update Roundtrip.md todo list 2020-11-07 12:38:33 +01:00
Ruud Poutsma
7dda864e4a document and cleanup 2020-11-07 12:36:07 +01:00
Ruud Poutsma
b3953dbe23 use StringSlice instead of string in InlineLink and LinkReferenceDefinition 2020-11-07 11:47:12 +01:00
Ruud Poutsma
453e8239d2 use StringSlice in IFencedBlock 2020-11-06 17:33:27 +01:00
Ruud Poutsma
8e8b95c3bb fix broken newline parsing for LineBreakInline and PipeTableParser 2020-11-06 13:27:46 +01:00
Ruud Poutsma
35b64052d6 fix whitespaces for QuoteBlock 2020-11-01 22:48:04 +01:00
Ruud Poutsma
ef495da097 fix whitespace after atx heading char 2020-11-01 20:03:13 +01:00
Ruud Poutsma
a6b9c9a41e don't trip up SpecFileGen test by placing docs in *Spec folder in .Test project 2020-11-01 17:52:26 +01:00
Ruud Poutsma
5bb2d92180 fix quoteblock > orderedlist > quoteblock rendering 2020-11-01 17:38:12 +01:00
Ruud Poutsma
929ec36c76 fix FencedCodeBlock parsing 2020-11-01 13:48:08 +01:00
Ruud Poutsma
8e17d9c94e fix newlines surrounding IndentedCodeBlock 2020-11-01 13:04:44 +01:00
Ruud Poutsma
a11cd8c28c merge from main 2020-10-31 15:48:00 +01:00
Ruud Poutsma
68d2a20d20 fix broken PeekChar() of StringLineGroup.Iterator 2020-10-31 15:38:00 +01:00
Ruud Poutsma
e3531413e1 fix broken StringSlice tests 2020-10-31 15:07:10 +01:00
Ruud Poutsma
ef534224f8 fix heading SoureceSpan bugs 2020-10-31 14:34:25 +01:00
Ruud Poutsma
2f3e1451b8 ensure to write indents when indents are added to the text renderer 2020-10-27 20:56:57 +01:00
Ruud Poutsma
a34e257d2c fix ParagraphBlockParser parsing into paragraphs instead of setext headings 2020-10-26 22:59:29 +01:00
Ruud Poutsma
9d83631cfe fix horribly broken OrderedList 2020-10-26 22:37:44 +01:00
Ruud Poutsma
61b3ffde91 better respect TrackTrivia flag 2020-10-25 21:11:37 +01:00
Ruud Poutsma
bebdf0179e respect TrackTrivia flag much more widely, restore intentionally broken behaviors 2020-10-25 20:26:56 +01:00
Ruud Poutsma
ab5e8ae9e2 apply review feedback 2020-10-25 16:12:06 +01:00
Ruud Poutsma
c8da430134 cleanup RoundtripRenderer 2020-10-25 15:48:19 +01:00
Ruud Poutsma
0e8c312fda extract RoundtripRenderer and restore NormalizeRenderer 2020-10-25 15:43:27 +01:00
Ruud Poutsma
4814e9cea5 introduce trackTrivia feature flag 2020-10-25 15:21:13 +01:00
Ruud Poutsma
068a6e7af5 check IsNewline calls 2020-10-25 14:54:52 +01:00
Ruud Poutsma
e4f2892a23 do "TODO: RTP:" todos 2020-10-25 14:52:23 +01:00
Ruud Poutsma
c2cfb05d8d fix whitespace between heading and headingchar for atx headings 2020-10-25 14:31:25 +01:00
Ruud Poutsma
813647ca10 place newline on LinkReferenceDefinition instead of leaf whitespace properties 2020-10-25 14:16:53 +01:00
Ruud Poutsma
83357dc929 fix whitespace in nested QuoteBlock 2020-10-25 13:33:06 +01:00
Ruud Poutsma
420aa79a48 fix LinkReferenceDefinition bugs 2020-10-25 13:15:46 +01:00
Ruud Poutsma
24be820827 omit LinkReferenceDefinitionGroup and insert LinkReferenceDefinitions at proper indexes of document/parent 2020-10-25 11:32:25 +01:00
Ruud Poutsma
694a764f96 fix escaped within local label of InlineLink 2020-10-24 16:18:33 +02:00
Ruud Poutsma
bb1da73da2 fix whitespace in HtmlBlock within ListItemBlock 2020-10-24 15:53:34 +02:00
Ruud Poutsma
e6b591c035 fix escapes in FencedCodeBlock info and arguments 2020-10-24 15:32:14 +02:00
Ruud Poutsma
5a19cdfebb implement ordered list item bullet rendering 2020-10-24 15:27:37 +02:00
Ruud Poutsma
34e439f494 fix whitespace rendering of FencedCodeBlock as child of ListItemBlock 2020-10-24 15:27:10 +02:00
Ruud Poutsma
b0602a7bb0 fix HtmlBlock whitespace regression 2020-10-24 14:51:09 +02:00
Ruud Poutsma
d7558f0442 fix FencedCodeBlock beforewhitespace regression 2020-10-24 14:41:35 +02:00
Ruud Poutsma
eac0ab3cca fix broken InlineLink rendering 2020-10-24 14:37:49 +02:00
Ruud Poutsma
147cd48a8d fix escapes in InlineLink regression 2020-10-24 14:29:39 +02:00
Ruud Poutsma
1b44256fc0 improve whitespace handling in FencedCodeBlock 2020-10-24 14:13:38 +02:00
Ruud Poutsma
db2856daf7 fix label rendering on LinkInline 2020-10-24 13:53:29 +02:00
Ruud Poutsma
9beb0c1613 fix whitespace on empty lines 2020-10-24 00:24:00 +02:00
Ruud Poutsma
ef343158b7 fix escapes in LinkReferenceDefinition 2020-10-24 00:11:35 +02:00
Ruud Poutsma
de5526877d fix broken AtxHeading whitespace 2020-10-23 23:31:31 +02:00
Ruud Poutsma
b00d75607b fix tabs in IndentedCodeBlock 2020-10-23 23:21:11 +02:00
Ruud Poutsma
8c37a1bef5 fix HtmlBlock whitespace before 2020-10-23 23:00:38 +02:00
Ruud Poutsma
7a9405ec9e fix ThematicBreakParser 2020-10-23 22:55:55 +02:00
Ruud Poutsma
6506e4594c fix escaped characters in LinkInline 2020-10-23 22:47:39 +02:00
Ruud Poutsma
7b20299d2b fix empty ListItem 2020-10-23 19:34:16 +02:00
Ruud Poutsma
55eaadce67 fix optional space after Atx heading leaders 2020-10-23 19:29:12 +02:00
Ruud Poutsma
87269d88b9 fix newlines after LinkReferenceDefinition 2020-10-23 18:52:48 +02:00
Ruud Poutsma
fb8162f5d7 fix whitespace surrounding closing fences of FencedCodeBlock 2020-10-23 18:28:28 +02:00
Ruud Poutsma
a04aa8a4de fix empty QuoteBlock lines 2020-10-23 17:50:07 +02:00
Ruud Poutsma
352443d9cd fix unclosed FencedCodeBlock in QuoteBlock 2020-10-23 11:32:15 +02:00
Ruud Poutsma
cd798b8d95 fix newlines after links 2020-10-18 22:40:17 +02:00
Ruud Poutsma
c5b260f708 fix rendering of empty lines with whitespace 2020-10-18 16:09:24 +02:00
Ruud Poutsma
2583463ea2 fix broken links 2020-10-18 15:05:41 +02:00
Ruud Poutsma
777ac71bd1 fix HardLineBreak, CodeInline tests 2020-10-18 14:11:47 +02:00
Ruud Poutsma
810ae49cc7 fix SetextHeading tests 2020-10-18 13:08:40 +02:00
Ruud Poutsma
225e308438 fix AtxHeading tests 2020-10-18 12:40:57 +02:00
Ruud Poutsma
05dd543d16 fix HtmlBlock tests 2020-10-18 12:17:33 +02:00
Ruud Poutsma
c711201b34 implement codegen for roundtrip parsing 2020-10-17 23:49:44 +02:00
Ruud Poutsma
47b3ac5d99 fix Autlink tests 2020-10-17 23:19:44 +02:00
Ruud Poutsma
49aa856f52 implement LinkInline 2020-10-17 23:09:53 +02:00
Ruud Poutsma
5e15575929 implement LinkReferenceDefinition 2020-10-17 15:48:36 +02:00
Ruud Poutsma
c9fc608598 update todo 2020-10-11 14:07:32 +02:00
Ruud Poutsma
6ba3c3d683 implement newline 2020-10-11 14:00:09 +02:00
Ruud Poutsma
d15edb79fa fix broken whitespace starting on newlines within a paragraph 2020-10-10 17:25:22 +02:00
Ruud Poutsma
fa3b67342d add some tests, update todolist 2020-10-10 17:10:18 +02:00
Ruud Poutsma
033f156b2b add many tests, create todolist 2020-10-10 16:37:17 +02:00
Ruud Poutsma
f3db5e882e fix FencedCodeBlock 2020-10-09 19:47:16 +02:00
Ruud Poutsma
c9365f3551 correctly render whitespace for IndentedCodeBlock 2020-10-09 18:30:03 +02:00
Ruud Poutsma
9ecb5b9950 test nested indented codeblock in quoteblock 2020-10-09 17:20:58 +02:00
Ruud Poutsma
95fb53cbc9 fix IndentedCodeBlock newlines 2020-10-09 16:44:16 +02:00
Ruud Poutsma
9d82088e03 fix quoteblock 2020-10-09 14:14:41 +02:00
Ruud Poutsma
340b75b557 add some tests, fix nested blockquote in listitem 2020-10-09 13:24:44 +02: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
Ruud Poutsma
0b79389b14 fix CodeInline parsing & rendering 2020-10-04 21:49:54 +02:00
Ruud Poutsma
111d3d3362 fix multiline quote blocks, split tests into file per node type 2020-10-04 21:20:32 +02:00
Ruud Poutsma
ac6ceb23e8 restore whitespace parsing in BlockProcessor 2020-10-03 23:13:04 +02:00
Ruud Poutsma
d31fa47cd1 add some testcases 2020-10-03 18:55:02 +02:00
Ruud Poutsma
d7f6a94f12 cleanup, add some testcases 2020-10-03 18:54:45 +02:00
Ruud Poutsma
dbdd752b73 Keep line info when parsing quoteblocks and render accordingly 2020-10-03 16:11:01 +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
Ruud Poutsma
4c2b46e0fc fix listblock-paragraph 2020-09-27 13:27:14 +02:00
Ruud Poutsma
68d12d0212 fix newlines and list blocks 2020-09-27 13:16:53 +02:00
Ruud Poutsma
fa1c117011 experiemnt with list rendering 2020-09-26 14:24:58 +02:00
Ruud Poutsma
6b1c5bc816 fix thematic break 2020-09-26 14:07:57 +02:00
Ruud Poutsma
e2cafc6b3d fix newline after listblock 2020-09-26 13:46:33 +02:00
Ruud Poutsma
aff7604b4b fix completely broken unordered list 2020-09-26 13:34:37 +02:00
Ruud Poutsma
68530aa4e0 improve linebreak handling 2020-09-26 12:59:48 +02:00
Ruud Poutsma
bfc1152b8a default newline after Html block, fix newlines before list block 2020-09-25 22:35:49 +02:00
Ruud Poutsma
37af8f8ecb implement newline with HtmlBlock 2020-09-25 22:03:34 +02:00
Ruud Poutsma
6792bffb5e better thematic break handling 2020-09-25 21:39:53 +02:00
Ruud Poutsma
976855a4c3 implement TheamticBreak renderer 2020-09-25 21:23:28 +02:00
Ruud Poutsma
acf2ba9502 allow CodeInline with multiple delimiter characters 2020-09-25 19:23:11 +02:00
Ruud Poutsma
cadbc67825 fix newline between blocks 2020-09-25 18:55:54 +02:00
Ruud Poutsma
0d86a93200 fix block nodes 2020-09-25 17:58:58 +02:00
Ruud Poutsma
f78b5c83cd handle whitespace before and after paragraphs correctly 2020-09-25 17:07:10 +02: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
Ruud Poutsma
0234d60d74 fix broken whitespace calculation 2020-08-08 18:25:08 +02:00
Ruud Poutsma
cd18087e29 implement cst for header 2020-08-08 18:18:55 +02:00
Ruud Poutsma
30f670bf5f fix NRE 2020-08-08 17:24:16 +02:00
Ruud Poutsma
c73785372b implement cst for Paragraph 2020-08-08 17:22:53 +02:00
Ruud Poutsma
147698daab revert LinkInlineRenderer 2020-08-08 14:54:57 +02:00
Ruud Poutsma
2b07e9a5b9 add naive cst implementation 2020-08-08 14:41:02 +02: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
SebastianRaffel
ae726b3796 Fix duplicate Rule numbering + bold headlines 2020-04-14 08:51:44 +02:00
398 changed files with 40766 additions and 7947 deletions

3
.gitattributes vendored Normal file
View File

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

View File

@@ -20,16 +20,16 @@ jobs:
- name: Checkout
uses: actions/checkout@v1
- name: Install .NET Core
- name: Install .NET 5.0
uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.0.100
dotnet-version: '5.0.x'
- name: Build (Release)
run: dotnet build src -c Release
- name: SpecFileGen
run: dotnet src/SpecFileGen/bin/Release/netcoreapp2.1/SpecFileGen.dll
run: dotnet src/SpecFileGen/bin/Release/net5.0/SpecFileGen.dll
- name: Test (Release)
run: dotnet test src -c Release
@@ -38,18 +38,21 @@ jobs:
run: dotnet test src -c Debug
- name: Coverlet
run: dotnet test src -c Release -f netcoreapp2.1 /p:Include=\"[${{env.PROJECT_NAME}}]*\" /p:CollectCoverage=true /p:CoverletOutputFormat=lcov
run: dotnet test src -c Release -f net5.0 /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'
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: src/${{env.PROJECT_NAME}}.Tests/coverage.netcoreapp2.1.info
path-to-lcov: src/${{env.PROJECT_NAME}}.Tests/coverage.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: |

25
.gitignore vendored
View File

@@ -138,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
@@ -216,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

View File

@@ -1,213 +1,255 @@
# Changelog
## 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
# Changelog
## 0.26.0 (27 Aug 2021)
- Fix rendering diff between line endings ([PR #560](https://github.com/lunet-io/markdig/pull/560))
- Make Mathematics extension respect EnableHtml* options ([PR #570](https://github.com/lunet-io/markdig/pull/570))
## 0.25.0 (10 June 2021)
- Fix regression when parsing link reference definitions (#543)
- Make digits in JiraKey's posible ([PR #548](https://github.com/lunet-io/markdig/pull/548))
## 0.24.0 (20 Mar 2021)
- Add support for roundtrip Markdown ([PR #481](https://github.com/lunet-io/markdig/pull/481))
- Introduction of nullability ([PR #522](https://github.com/lunet-io/markdig/pull/522) [PR #524](https://github.com/lunet-io/markdig/pull/524) [PR #525](https://github.com/lunet-io/markdig/pull/525) [PR #526](https://github.com/lunet-io/markdig/pull/526) [PR #527](https://github.com/lunet-io/markdig/pull/527))
- Various internal cleanup and small performance improvements ([PR #521](https://github.com/lunet-io/markdig/pull/521) [PR #524](https://github.com/lunet-io/markdig/pull/524) [PR #525](https://github.com/lunet-io/markdig/pull/525) [PR #529](https://github.com/lunet-io/markdig/pull/529) [PR #531](https://github.com/lunet-io/markdig/pull/531) [PR #532](https://github.com/lunet-io/markdig/pull/532))
## 0.23.0 (16 Jan 2021)
- Add depth limits to avoid pathological-case parsing times/StackOverflows (#500)
- Breaking change: rename AutolineInlineParser to AutolinkInlineParser
## 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 @@
# 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)
# 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/xoofx/markdig/badge.svg?branch=master)](https://coveralls.io/github/xoofx/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">
@@ -19,6 +19,7 @@ You can **try Markdig online** and compare it to other implementations on [babel
- 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 `@`)
- [**Roundtrip support**](./src/Markdig/Roundtrip.md): Parses trivia (whitespace, newlines and other characters) to support lossless parse ⭢ render roundtrip. This enables changing markdown documents without introducing undesired trivia changes.
- Built-in with **20+ extensions**, including:
- 2 kind of tables:
- [**Pipe tables**](src/Markdig.Tests/Specs/PipeTableSpecs.md) (inspired from GitHub tables and [PanDoc - Pipe Tables](http://pandoc.org/README.html#extension-pipe_tables))
@@ -59,6 +60,7 @@ If you are looking for support for an old .NET Framework 3.5 or 4.0, you can dow
- [**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
@@ -94,6 +96,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

View File

@@ -36,12 +36,12 @@
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.10.6" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.10.6" />
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.12.1" />
<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" />
<PackageReference Include="MarkdownSharp" Version="2.0.5" />
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.0.161401" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.62" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Markdig\Markdig.csproj" />

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

View File

@@ -2,13 +2,9 @@
// 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
{

View File

@@ -1,23 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
<OutputType>Library</OutputType>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.msbuild" Version="2.8.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Markdig\Markdig.csproj" />
</ItemGroup>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>
<StartupObject>Markdig.Tests.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<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.8.3" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Markdig\Markdig.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,241 +1,288 @@
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
{
[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 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);
}
}
}
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);
}
}
[Theory]
[TestCase('[', 9 * 1024, true, false)]
[TestCase('[', 11 * 1024, true, true)]
[TestCase('[', 100, false, false)]
[TestCase('[', 150, false, true)]
[TestCase('>', 100, true, false)]
[TestCase('>', 150, true, true)]
public void GuardsAgainstHighlyNestedNodes(char c, int count, bool parseOnly, bool shouldThrow)
{
var markdown = new string(c, count);
TestDelegate test = parseOnly ? () => Markdown.Parse(markdown) : () => Markdown.ToHtml(markdown);
if (shouldThrow)
{
Exception e = Assert.Throws<ArgumentException>(test);
Assert.True(e.Message.Contains("depth limit"));
}
else
{
test();
}
}
[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

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Headings
@@ -79,15 +78,15 @@ namespace Markdig.Tests.Specs.Normalize.Headings
// Heading
// =======
//
// Text after two newlines
// Text after two newlines 1
//
// Should be rendered as:
// # Heading
//
// Text after two newlines
// Text after two newlines 1
Console.WriteLine("Example 3\nSection Headings\n");
TestNormalize.TestSpec("Heading\n=======\n\nText after two newlines", "# Heading\n\nText after two newlines", "");
TestNormalize.TestSpec("Heading\n=======\n\nText after two newlines 1", "# Heading\n\nText after two newlines 1", "");
}
}
}

View File

@@ -1,5 +1,5 @@
# Headings
# Headings
```````````````````````````````` example
# Heading 1
@@ -24,8 +24,8 @@
##### Heading 5
###### Heading 6
````````````````````````````````
````````````````````````````````
```````````````````````````````` example
###### Heading
@@ -34,15 +34,15 @@ Text after two newlines
###### Heading
Text after two newlines
````````````````````````````````
````````````````````````````````
```````````````````````````````` example
Heading
=======
Text after two newlines
Text after two newlines 1
.
# Heading
Text after two newlines
Text after two newlines 1
````````````````````````````````

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Sample

View File

@@ -0,0 +1,19 @@
// 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
{
class Program
{
public static void Main(string[] args)
{
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();
}
}
}

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,23 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs.Inlines
{
[TestFixture]
public class TestAutoLinkInline
{
[TestCase("<http://a>")]
[TestCase(" <http://a>")]
[TestCase("<http://a> ")]
[TestCase(" <http://a> ")]
[TestCase("<example@example.com>")]
[TestCase(" <example@example.com>")]
[TestCase("<example@example.com> ")]
[TestCase(" <example@example.com> ")]
[TestCase("p http://a p")]
public void Test(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,67 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs.Inlines
{
[TestFixture]
public class TestBackslashEscapeInline
{
[TestCase(@"\!")]
[TestCase(@"\""")]
[TestCase(@"\#")]
[TestCase(@"\$")]
[TestCase(@"\&")]
[TestCase(@"\'")]
[TestCase(@"\(")]
[TestCase(@"\)")]
[TestCase(@"\*")]
[TestCase(@"\+")]
[TestCase(@"\,")]
[TestCase(@"\-")]
[TestCase(@"\.")]
[TestCase(@"\/")]
[TestCase(@"\:")]
[TestCase(@"\;")]
[TestCase(@"\<")]
[TestCase(@"\=")]
[TestCase(@"\>")]
[TestCase(@"\?")]
[TestCase(@"\@")]
[TestCase(@"\[")]
[TestCase(@"\\")]
[TestCase(@"\]")]
[TestCase(@"\^")]
[TestCase(@"\_")]
[TestCase(@"\`")]
[TestCase(@"\{")]
[TestCase(@"\|")]
[TestCase(@"\}")]
[TestCase(@"\~")]
// below test breaks visual studio
//[TestCase(@"\!\""\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~")]
public void Test(string value)
{
RoundTrip(value);
}
[TestCase(@"# \#\#h1")]
[TestCase(@"# \#\#h1\#")]
public void TestHeading(string value)
{
RoundTrip(value);
}
[TestCase(@"`\``")]
[TestCase(@"` \``")]
[TestCase(@"`\` `")]
[TestCase(@"` \` `")]
[TestCase(@" ` \` `")]
[TestCase(@"` \` ` ")]
[TestCase(@" ` \` ` ")]
public void TestCodeSpanInline(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,77 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs.Inlines
{
[TestFixture]
public class TestCodeInline
{
[TestCase("``")]
[TestCase(" ``")]
[TestCase("`` ")]
[TestCase(" `` ")]
[TestCase("`c`")]
[TestCase(" `c`")]
[TestCase("`c` ")]
[TestCase(" `c` ")]
[TestCase("` c`")]
[TestCase(" ` c`")]
[TestCase("` c` ")]
[TestCase(" ` c` ")]
[TestCase("`c `")]
[TestCase(" `c `")]
[TestCase("`c ` ")]
[TestCase(" `c ` ")]
[TestCase("`c``")] // 1, 2
[TestCase("``c`")] // 2, 1
[TestCase("``c``")] // 2, 2
[TestCase("```c``")] // 2, 3
[TestCase("``c```")] // 3, 2
[TestCase("```c```")] // 3, 3
[TestCase("```c````")] // 3, 4
[TestCase("````c```")] // 4, 3
[TestCase("````c````")] // 4, 4
[TestCase("```a``` p")]
[TestCase("```a`b`c```")]
[TestCase("```a``` p\n```a``` p")]
[TestCase("` a `")]
[TestCase(" ` a `")]
[TestCase("` a ` ")]
[TestCase(" ` a ` ")]
public void Test(string value)
{
RoundTrip(value);
}
[TestCase("p `a` p")]
[TestCase("p ``a`` p")]
[TestCase("p ```a``` p")]
[TestCase("p\n\n```a``` p")]
public void TestParagraph(string value)
{
RoundTrip(value);
}
[TestCase("`\na\n`")]
[TestCase("`\na\r`")]
[TestCase("`\na\r\n`")]
[TestCase("`\ra\r`")]
[TestCase("`\ra\n`")]
[TestCase("`\ra\r\n`")]
[TestCase("`\r\na\n`")]
[TestCase("`\r\na\r`")]
[TestCase("`\r\na\r\n`")]
public void Test_Newlines(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,132 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs.Inlines
{
[TestFixture]
public class TestEmphasisInline
{
[TestCase("_t_")]
[TestCase("_t_t")]
[TestCase("t_t_")]
[TestCase("_t t_")]
[TestCase("_t\tt_")]
[TestCase("*t*")]
[TestCase("t*t*")]
[TestCase("*t*t")]
[TestCase("*t t*")]
[TestCase("*t\tt*")]
[TestCase(" _t_")]
[TestCase(" _t_t")]
[TestCase(" t_t_")]
[TestCase(" _t t_")]
[TestCase(" _t\tt_")]
[TestCase(" *t*")]
[TestCase(" t*t*")]
[TestCase(" *t*t")]
[TestCase(" *t t*")]
[TestCase(" *t\tt*")]
[TestCase("_t_")]
[TestCase("_t_t ")]
[TestCase("t_t_ ")]
[TestCase("_t t_ ")]
[TestCase("_t\tt_ ")]
[TestCase("*t* ")]
[TestCase("t*t* ")]
[TestCase("*t*t ")]
[TestCase("*t t* ")]
[TestCase("*t\tt* ")]
[TestCase(" _t_")]
[TestCase(" _t_t ")]
[TestCase(" t_t_ ")]
[TestCase(" _t t_ ")]
[TestCase(" _t\tt_ ")]
[TestCase(" *t* ")]
[TestCase(" t*t* ")]
[TestCase(" *t*t ")]
[TestCase(" *t t* ")]
[TestCase(" *t\tt* ")]
[TestCase("_t_\t")]
[TestCase("_t_t\t")]
[TestCase("t_t_\t")]
[TestCase("_t t_\t")]
[TestCase("_t\tt_\t")]
[TestCase("*t*\t")]
[TestCase("t*t*\t")]
[TestCase("*t*t\t")]
[TestCase("*t t*\t")]
[TestCase("*t\tt*\t")]
public void Test_Emphasis(string value)
{
RoundTrip(value);
}
[TestCase("__t__")]
[TestCase("__t__t")]
[TestCase("t__t__")]
[TestCase("__t t__")]
[TestCase("__t\tt__")]
[TestCase("**t**")]
[TestCase("**t**t")]
[TestCase("t**t**")]
[TestCase("**t\tt**")]
[TestCase(" __t__")]
[TestCase(" __t__t")]
[TestCase(" t__t__")]
[TestCase(" __t t__")]
[TestCase(" __t\tt__")]
[TestCase(" **t**")]
[TestCase(" **t**t")]
[TestCase(" t**t**")]
[TestCase(" **t\tt**")]
[TestCase("__t__ ")]
[TestCase("__t__t ")]
[TestCase("t__t__ ")]
[TestCase("__t t__ ")]
[TestCase("__t\tt__ ")]
[TestCase("**t** ")]
[TestCase("**t**t ")]
[TestCase("t**t** ")]
[TestCase("**t\tt** ")]
[TestCase(" __t__ ")]
[TestCase(" __t__t ")]
[TestCase(" t__t__ ")]
[TestCase(" __t t__ ")]
[TestCase(" __t\tt__ ")]
[TestCase(" **t** ")]
[TestCase(" **t** t")]
[TestCase(" t**t** ")]
[TestCase(" **t\tt** ")]
[TestCase("__t__\t")]
[TestCase("__t__t\t")]
[TestCase("t__t__\t ")]
[TestCase("__t t__\t ")]
[TestCase("__t\tt__\t ")]
[TestCase("**t**\t ")]
[TestCase("**t**t\t ")]
[TestCase("t**t**\t ")]
[TestCase("**t\tt**\t ")]
[TestCase(" __t__\t ")]
[TestCase(" __t__t\t ")]
[TestCase(" t__t__\t ")]
[TestCase(" __t t__\t ")]
[TestCase(" __t\tt__\t ")]
[TestCase(" **t**\t ")]
[TestCase(" **t**\t t")]
[TestCase(" t**t**\t ")]
[TestCase(" **t\tt**\t ")]
public void Test_StrongEmphasis(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,53 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs.Inlines
{
/// <summary>
///
/// </summary>
/// <seealso cref="https://spec.commonmark.org/0.29/#entity-and-numeric-character-references"/>
[TestFixture]
public class TestHtmlEntityInline
{
[TestCase("&gt;")]
[TestCase("&lt;")]
[TestCase("&nbsp;")]
[TestCase("&heartsuit;")]
[TestCase("&#42;")]
[TestCase("&#0;")]
[TestCase("&#1234;")]
[TestCase("&#xcab;")]
[TestCase(" &gt;")]
[TestCase(" &lt;")]
[TestCase(" &nbsp;")]
[TestCase(" &heartsuit;")]
[TestCase(" &#42;")]
[TestCase(" &#0;")]
[TestCase(" &#1234;")]
[TestCase(" &#xcab;")]
[TestCase("&gt; ")]
[TestCase("&lt; ")]
[TestCase("&nbsp; ")]
[TestCase("&heartsuit; ")]
[TestCase("&#42; ")]
[TestCase("&#0; ")]
[TestCase("&#1234; ")]
[TestCase("&#xcab; ")]
[TestCase(" &gt; ")]
[TestCase(" &lt; ")]
[TestCase(" &nbsp; ")]
[TestCase(" &heartsuit; ")]
[TestCase(" &#42; ")]
[TestCase(" &#0; ")]
[TestCase(" &#1234; ")]
[TestCase(" &#xcab; ")]
public void Test(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,27 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs.Inlines
{
[TestFixture]
public class TestHtmlInline
{
[TestCase("<em>f</em>")]
[TestCase("<em> f</em>")]
[TestCase("<em>f </em>")]
[TestCase("<em> f </em>")]
[TestCase("<b>p</b>")]
[TestCase("<b></b>")]
[TestCase("<b> </b>")]
[TestCase("<b> </b>")]
[TestCase("<b> </b>")]
[TestCase("<b>\t</b>")]
[TestCase("<b> \t</b>")]
[TestCase("<b>\t </b>")]
[TestCase("<b> \t </b>")]
public void Test(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,25 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs.Inlines
{
[TestFixture]
public class TestImageInline
{
[TestCase("![](a)")]
[TestCase(" ![](a)")]
[TestCase("![](a) ")]
[TestCase(" ![](a) ")]
[TestCase(" ![description](http://example.com)")]
public void Test(string value)
{
RoundTrip(value);
}
[TestCase("paragraph ![description](http://example.com)")]
public void TestParagraph(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,18 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs.Inlines
{
[TestFixture]
public class TestLineBreakInline
{
[TestCase("p\n")]
[TestCase("p\r\n")]
[TestCase("p\r")]
[TestCase("[]() ![]() `` ` ` ` ` ![]() ![]()")]
public void Test(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,229 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs.Inlines
{
[TestFixture]
public class TestLinkInline
{
[TestCase("[a]")] // TODO: this is not a link but a paragraph
[TestCase("[a]()")]
[TestCase("[](b)")]
[TestCase(" [](b)")]
[TestCase("[](b) ")]
[TestCase(" [](b) ")]
[TestCase("[a](b)")]
[TestCase(" [a](b)")]
[TestCase("[a](b) ")]
[TestCase(" [a](b) ")]
[TestCase("[ a](b)")]
[TestCase(" [ a](b)")]
[TestCase("[ a](b) ")]
[TestCase(" [ a](b) ")]
[TestCase("[a ](b)")]
[TestCase(" [a ](b)")]
[TestCase("[a ](b) ")]
[TestCase(" [a ](b) ")]
[TestCase("[ a ](b)")]
[TestCase(" [ a ](b)")]
[TestCase("[ a ](b) ")]
[TestCase(" [ a ](b) ")]
// below cases are required for a full roundtrip but not have low prio for impl
[TestCase("[]( b)")]
[TestCase(" []( b)")]
[TestCase("[]( b) ")]
[TestCase(" []( b) ")]
[TestCase("[a]( b)")]
[TestCase(" [a]( b)")]
[TestCase("[a]( b) ")]
[TestCase(" [a]( b) ")]
[TestCase("[ a]( b)")]
[TestCase(" [ a]( b)")]
[TestCase("[ a]( b) ")]
[TestCase(" [ a]( b) ")]
[TestCase("[a ]( b)")]
[TestCase(" [a ]( b)")]
[TestCase("[a ]( b) ")]
[TestCase(" [a ]( b) ")]
[TestCase("[ a ]( b)")]
[TestCase(" [ a ]( b)")]
[TestCase("[ a ]( b) ")]
[TestCase(" [ a ]( b) ")]
[TestCase("[](b )")]
[TestCase(" [](b )")]
[TestCase("[](b ) ")]
[TestCase(" [](b ) ")]
[TestCase("[a](b )")]
[TestCase(" [a](b )")]
[TestCase("[a](b ) ")]
[TestCase(" [a](b ) ")]
[TestCase("[ a](b )")]
[TestCase(" [ a](b )")]
[TestCase("[ a](b ) ")]
[TestCase(" [ a](b ) ")]
[TestCase("[a ](b )")]
[TestCase(" [a ](b )")]
[TestCase("[a ](b ) ")]
[TestCase(" [a ](b ) ")]
[TestCase("[ a ](b )")]
[TestCase(" [ a ](b )")]
[TestCase("[ a ](b ) ")]
[TestCase(" [ a ](b ) ")]
[TestCase("[]( b )")]
[TestCase(" []( b )")]
[TestCase("[]( b ) ")]
[TestCase(" []( b ) ")]
[TestCase("[a]( b )")]
[TestCase(" [a]( b )")]
[TestCase("[a]( b ) ")]
[TestCase(" [a]( b ) ")]
[TestCase("[ a]( b )")]
[TestCase(" [ a]( b )")]
[TestCase("[ a]( b ) ")]
[TestCase(" [ a]( b ) ")]
[TestCase("[a ]( b )")]
[TestCase(" [a ]( b )")]
[TestCase("[a ]( b ) ")]
[TestCase(" [a ]( b ) ")]
[TestCase("[ a ]( b )")]
[TestCase(" [ a ]( b )")]
[TestCase("[ a ]( b ) ")]
[TestCase(" [ a ]( b ) ")]
public void Test(string value)
{
RoundTrip(value);
}
[TestCase("[a](b \"t\") ")]
[TestCase("[a](b \" t\") ")]
[TestCase("[a](b \"t \") ")]
[TestCase("[a](b \" t \") ")]
[TestCase("[a](b \"t\") ")]
[TestCase("[a](b \" t\") ")]
[TestCase("[a](b \"t \") ")]
[TestCase("[a](b \" t \") ")]
[TestCase("[a](b \"t\" ) ")]
[TestCase("[a](b \" t\" ) ")]
[TestCase("[a](b \"t \" ) ")]
[TestCase("[a](b \" t \" ) ")]
[TestCase("[a](b \"t\" ) ")]
[TestCase("[a](b \" t\" ) ")]
[TestCase("[a](b \"t \" ) ")]
[TestCase("[a](b \" t \" ) ")]
[TestCase("[a](b 't') ")]
[TestCase("[a](b ' t') ")]
[TestCase("[a](b 't ') ")]
[TestCase("[a](b ' t ') ")]
[TestCase("[a](b 't') ")]
[TestCase("[a](b ' t') ")]
[TestCase("[a](b 't ') ")]
[TestCase("[a](b ' t ') ")]
[TestCase("[a](b 't' ) ")]
[TestCase("[a](b ' t' ) ")]
[TestCase("[a](b 't ' ) ")]
[TestCase("[a](b ' t ' ) ")]
[TestCase("[a](b 't' ) ")]
[TestCase("[a](b ' t' ) ")]
[TestCase("[a](b 't ' ) ")]
[TestCase("[a](b ' t ' ) ")]
[TestCase("[a](b (t)) ")]
[TestCase("[a](b ( t)) ")]
[TestCase("[a](b (t )) ")]
[TestCase("[a](b ( t )) ")]
[TestCase("[a](b (t)) ")]
[TestCase("[a](b ( t)) ")]
[TestCase("[a](b (t )) ")]
[TestCase("[a](b ( t )) ")]
[TestCase("[a](b (t) ) ")]
[TestCase("[a](b ( t) ) ")]
[TestCase("[a](b (t ) ) ")]
[TestCase("[a](b ( t ) ) ")]
[TestCase("[a](b (t) ) ")]
[TestCase("[a](b ( t) ) ")]
[TestCase("[a](b (t ) ) ")]
[TestCase("[a](b ( t ) ) ")]
public void Test_Title(string value)
{
RoundTrip(value);
}
[TestCase("[a](<>)")]
[TestCase("[a]( <>)")]
[TestCase("[a](<> )")]
[TestCase("[a]( <> )")]
[TestCase("[a](< >)")]
[TestCase("[a]( < >)")]
[TestCase("[a](< > )")]
[TestCase("[a]( < > )")]
[TestCase("[a](<b>)")]
[TestCase("[a](<b >)")]
[TestCase("[a](< b>)")]
[TestCase("[a](< b >)")]
[TestCase("[a](<b b>)")]
[TestCase("[a](<b b >)")]
[TestCase("[a](< b b >)")]
public void Test_PointyBrackets(string value)
{
RoundTrip(value);
}
[TestCase("[*a*][a]")]
[TestCase("[a][b]")]
[TestCase("[a][]")]
[TestCase("[a]")]
public void Test_Inlines(string value)
{
RoundTrip(value);
}
// | [ a ]( b " t " ) |
[TestCase(" [ a ]( b \" t \" ) ")]
[TestCase("\v[\va\v](\vb\v\"\vt\v\"\v)\v")]
[TestCase("\f[\fa\f](\fb\f\"\ft\f\"\f)\f")]
[TestCase("\t[\ta\t](\tb\t\"\tt\t\"\t)\t")]
public void Test_UncommonWhitespace(string value)
{
RoundTrip(value);
}
[TestCase("[x]: https://example.com\r\n")]
public void Test_LinkReferenceDefinitionWithCarriageReturnLineFeed(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,37 @@
using Markdig.Renderers.Roundtrip;
using Markdig.Syntax;
using NUnit.Framework;
using System.IO;
namespace Markdig.Tests.RoundtripSpecs.Inlines
{
[TestFixture]
public class TestNullCharacterInline
{
[TestCase("\0", "\uFFFD")]
[TestCase("\0p", "\uFFFDp")]
[TestCase("p\0", "p\uFFFD")]
[TestCase("p\0p", "p\uFFFDp")]
[TestCase("p\0\0p", "p\uFFFD\uFFFDp")] // I promise you, this was not intentional
public void Test(string value, string expected)
{
RoundTrip(value, expected);
}
// this method is copied intentionally to ensure all other tests
// do not unintentionally use the expected parameter
private static void RoundTrip(string markdown, string expected)
{
var pipelineBuilder = new MarkdownPipelineBuilder();
pipelineBuilder.EnableTrackTrivia();
MarkdownPipeline pipeline = pipelineBuilder.Build();
MarkdownDocument markdownDocument = Markdown.Parse(markdown, pipeline);
var sw = new StringWriter();
var rr = new RoundtripRenderer(sw);
rr.Write(markdownDocument);
Assert.AreEqual(expected, sw.ToString());
}
}
}

View File

@@ -0,0 +1,55 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestAtxHeading
{
[TestCase("# h")]
[TestCase("# h ")]
[TestCase("# h\n#h")]
[TestCase("# h\n #h")]
[TestCase("# h\n # h")]
[TestCase("# h\n # h ")]
[TestCase(" # h \n # h ")]
public void Test(string value)
{
RoundTrip(value);
}
[TestCase("\n# h\n\np")]
[TestCase("\n# h\n\np\n")]
[TestCase("\n# h\n\np\n\n")]
[TestCase("\n\n# h\n\np\n\n")]
[TestCase("\n\n# h\np\n\n")]
[TestCase("\n\n# h\np\n\n")]
public void TestParagraph(string value)
{
RoundTrip(value);
}
[TestCase("\n# h")]
[TestCase("\n# h\n")]
[TestCase("\n# h\r")]
[TestCase("\n# h\r\n")]
[TestCase("\r# h")]
[TestCase("\r# h\n")]
[TestCase("\r# h\r")]
[TestCase("\r# h\r\n")]
[TestCase("\r\n# h")]
[TestCase("\r\n# h\n")]
[TestCase("\r\n# h\r")]
[TestCase("\r\n# h\r\n")]
[TestCase("# h\n\n ")]
[TestCase("# h\n\n ")]
[TestCase("# h\n\n ")]
public void TestNewline(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,58 @@
using Markdig.Helpers;
using Markdig.Renderers.Roundtrip;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
using NUnit.Framework;
using System.IO;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestExample
{
[Test]
public void Test()
{
var markdown = $@"
# Test document
This document contains an unordered list. It uses tabs to indent. This test demonstrates
a method of making the input markdown uniform without altering any other markdown in the
resulting output file.
- item1
>look, ma:
> my space is not normalized!
";
MarkdownDocument markdownDocument = Markdown.Parse(markdown, trackTrivia: true);
var listBlock = markdownDocument[2] as ListBlock;
var listItem = listBlock[0] as ListItemBlock;
var paragraph = listItem[0] as ParagraphBlock;
var containerInline = new ContainerInline();
containerInline.AppendChild(new LiteralInline(" my own text!"));
containerInline.AppendChild(new LineBreakInline { NewLine = NewLine.CarriageReturnLineFeed });
paragraph.Inline = containerInline;
var sw = new StringWriter();
var rr = new RoundtripRenderer(sw);
rr.Write(markdownDocument);
var outputMarkdown = sw.ToString();
var expected = $@"
# Test document
This document contains an unordered list. It uses tabs to indent. This test demonstrates
a method of making the input markdown uniform without altering any other markdown in the
resulting output file.
- my own text!
>look, ma:
> my space is not normalized!
";
expected = expected.Replace("\r\n", "\n").Replace("\r", "\n");
outputMarkdown = outputMarkdown.Replace("\r\n", "\n").Replace("\r", "\n");
Assert.AreEqual(expected, outputMarkdown);
}
}
}

View File

@@ -0,0 +1,107 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestFencedCodeBlock
{
[TestCase("```\nc\n```")]
[TestCase("```\nc\n```\n")]
[TestCase("\n```\nc\n```")]
[TestCase("\n\n```\nc\n```")]
[TestCase("```\nc\n```\n")]
[TestCase("```\nc\n```\n\n")]
[TestCase("\n```\nc\n```\n")]
[TestCase("\n```\nc\n```\n\n")]
[TestCase("\n\n```\nc\n```\n")]
[TestCase("\n\n```\nc\n```\n\n")]
[TestCase(" ```\nc\n````")]
[TestCase("```\nc\n````")]
[TestCase("p\n\n```\nc\n```")]
[TestCase("```\n c\n```")]
[TestCase("```\nc \n```")]
[TestCase("```\n c \n```")]
[TestCase(" ``` \n c \n ``` ")]
[TestCase("\t```\t\n\tc\t\n\t```\t")]
[TestCase("\v```\v\n\vc\v\n\v```\v")]
[TestCase("\f```\f\n\fc\f\n\f```\f")]
public void Test(string value)
{
RoundTrip(value);
}
[TestCase("~~~ aa ``` ~~~\nfoo\n~~~")]
[TestCase("~~~ aa ``` ~~~\nfoo\n~~~ ")]
public void TestTilde(string value)
{
RoundTrip(value);
}
[TestCase("```\n c \n```")]
[TestCase("```\n c \r```")]
[TestCase("```\n c \r\n```")]
[TestCase("```\r c \n```")]
[TestCase("```\r c \r```")]
[TestCase("```\r c \r\n```")]
[TestCase("```\r\n c \n```")]
[TestCase("```\r\n c \r```")]
[TestCase("```\r\n c \r\n```")]
[TestCase("```\n c \n```\n")]
[TestCase("```\n c \r```\n")]
[TestCase("```\n c \r\n```\n")]
[TestCase("```\r c \n```\n")]
[TestCase("```\r c \r```\n")]
[TestCase("```\r c \r\n```\n")]
[TestCase("```\r\n c \n```\n")]
[TestCase("```\r\n c \r```\n")]
[TestCase("```\r\n c \r\n```\n")]
[TestCase("```\n c \n```\r")]
[TestCase("```\n c \r```\r")]
[TestCase("```\n c \r\n```\r")]
[TestCase("```\r c \n```\r")]
[TestCase("```\r c \r```\r")]
[TestCase("```\r c \r\n```\r")]
[TestCase("```\r\n c \n```\r")]
[TestCase("```\r\n c \r```\r")]
[TestCase("```\r\n c \r\n```\r")]
[TestCase("```\n c \n```\r\n")]
[TestCase("```\n c \r```\r\n")]
[TestCase("```\n c \r\n```\r\n")]
[TestCase("```\r c \n```\r\n")]
[TestCase("```\r c \r```\r\n")]
[TestCase("```\r c \r\n```\r\n")]
[TestCase("```\r\n c \n```\r\n")]
[TestCase("```\r\n c \r```\r\n")]
[TestCase("```\r\n c \r\n```\r\n")]
public void TestNewline(string value)
{
RoundTrip(value);
}
[TestCase("```i a\n```")]
[TestCase("```i a a2\n```")]
[TestCase("```i a a2 a3\n```")]
[TestCase("```i a a2 a3 a4\n```")]
[TestCase("```i\ta\n```")]
[TestCase("```i\ta a2\n```")]
[TestCase("```i\ta a2 a3\n```")]
[TestCase("```i\ta a2 a3 a4\n```")]
[TestCase("```i\ta \n```")]
[TestCase("```i\ta a2 \n```")]
[TestCase("```i\ta a2 a3 \n```")]
[TestCase("```i\ta a2 a3 a4 \n```")]
public void TestInfoArguments(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,20 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestHtmlBlock
{
[TestCase("<br>")]
[TestCase("<br>\n")]
[TestCase("<br>\n\n")]
[TestCase("<div></div>\n\n# h")]
[TestCase("p\n\n<div></div>\n")]
[TestCase("<div></div>\n\n# h")]
public void Test(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,86 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestIndentedCodeBlock
{
// A codeblock is indented with 4 spaces. After the 4th space, whitespace is interpreted as content.
// l = line
[TestCase(" l")]
[TestCase(" l")]
[TestCase("\tl")]
[TestCase("\t\tl")]
[TestCase("\tl1\n l1")]
[TestCase("\n l")]
[TestCase("\n\n l")]
[TestCase("\n l\n")]
[TestCase("\n l\n\n")]
[TestCase("\n\n l\n")]
[TestCase("\n\n l\n\n")]
[TestCase(" l\n l")]
[TestCase(" l\n l\n l")]
// two newlines are needed for indented codeblock start after paragraph
[TestCase("p\n\n l")]
[TestCase("p\n\n l\n")]
[TestCase("p\n\n l\n\n")]
[TestCase("p\n\n l\n l")]
[TestCase("p\n\n l\n l")]
[TestCase(" l\n\np\n\n l")]
[TestCase(" l l\n\np\n\n l l")]
public void Test(string value)
{
RoundTrip(value);
}
[TestCase(" l\n")]
[TestCase(" l\r")]
[TestCase(" l\r\n")]
[TestCase(" l\n l")]
[TestCase(" l\n l\n")]
[TestCase(" l\n l\r")]
[TestCase(" l\n l\r\n")]
[TestCase(" l\r l")]
[TestCase(" l\r l\n")]
[TestCase(" l\r l\r")]
[TestCase(" l\r l\r\n")]
[TestCase(" l\r\n l")]
[TestCase(" l\r\n l\n")]
[TestCase(" l\r\n l\r")]
[TestCase(" l\r\n l\r\n")]
public void TestNewline(string value)
{
RoundTrip(value);
}
[TestCase(" l\n\n l\n")]
[TestCase(" l\n\n\n l\n")]
public void TestNewlinesInBetweenResultInOneCodeBlock(string value)
{
var pipelineBuilder = new MarkdownPipelineBuilder();
pipelineBuilder.EnableTrackTrivia();
MarkdownPipeline pipeline = pipelineBuilder.Build();
var markdownDocument = Markdown.Parse(value, pipeline);
Assert.AreEqual(1, markdownDocument.Count);
}
[TestCase(" l\n\np")]
[TestCase(" l\n\n\np")]
[TestCase(" l\n\n\n\np")]
public void TestParagraph(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,214 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestLinkReferenceDefinition
{
[TestCase(@"[a]: /r")]
[TestCase(@" [a]: /r")]
[TestCase(@" [a]: /r")]
[TestCase(@" [a]: /r")]
[TestCase(@"[a]: /r")]
[TestCase(@" [a]: /r")]
[TestCase(@" [a]: /r")]
[TestCase(@" [a]: /r")]
[TestCase(@"[a]: /r ")]
[TestCase(@" [a]: /r ")]
[TestCase(@" [a]: /r ")]
[TestCase(@" [a]: /r ")]
[TestCase(@"[a]: /r ""l""")]
[TestCase(@"[a]: /r ""l""")]
[TestCase(@"[a]: /r ""l""")]
[TestCase(@"[a]: /r ""l"" ")]
[TestCase(@"[a]: /r ""l""")]
[TestCase(@"[a]: /r ""l"" ")]
[TestCase(@" [a]: /r ""l""")]
[TestCase(@" [a]: /r ""l""")]
[TestCase(@" [a]: /r ""l""")]
[TestCase(@" [a]: /r ""l"" ")]
[TestCase(@" [a]: /r ""l""")]
[TestCase(@" [a]: /r ""l"" ")]
[TestCase(@" [a]: /r ""l""")]
[TestCase(@" [a]: /r ""l""")]
[TestCase(@" [a]: /r ""l""")]
[TestCase(@" [a]: /r ""l"" ")]
[TestCase(@" [a]: /r ""l""")]
[TestCase(@" [a]: /r ""l"" ")]
[TestCase(@" [a]: /r ""l""")]
[TestCase(@" [a]: /r ""l""")]
[TestCase(@" [a]: /r ""l""")]
[TestCase(@" [a]: /r ""l"" ")]
[TestCase(@" [a]: /r ""l""")]
[TestCase(@" [a]: /r ""l"" ")]
[TestCase("[a]:\t/r")]
[TestCase("[a]:\t/r\t")]
[TestCase("[a]:\t/r\t\"l\"")]
[TestCase("[a]:\t/r\t\"l\"\t")]
[TestCase("[a]: \t/r")]
[TestCase("[a]: \t/r\t")]
[TestCase("[a]: \t/r\t\"l\"")]
[TestCase("[a]: \t/r\t\"l\"\t")]
[TestCase("[a]:\t /r")]
[TestCase("[a]:\t /r\t")]
[TestCase("[a]:\t /r\t\"l\"")]
[TestCase("[a]:\t /r\t\"l\"\t")]
[TestCase("[a]: \t /r")]
[TestCase("[a]: \t /r\t")]
[TestCase("[a]: \t /r\t\"l\"")]
[TestCase("[a]: \t /r\t\"l\"\t")]
[TestCase("[a]:\t/r \t")]
[TestCase("[a]:\t/r \t\"l\"")]
[TestCase("[a]:\t/r \t\"l\"\t")]
[TestCase("[a]: \t/r")]
[TestCase("[a]: \t/r \t")]
[TestCase("[a]: \t/r \t\"l\"")]
[TestCase("[a]: \t/r \t\"l\"\t")]
[TestCase("[a]:\t /r")]
[TestCase("[a]:\t /r \t")]
[TestCase("[a]:\t /r \t\"l\"")]
[TestCase("[a]:\t /r \t\"l\"\t")]
[TestCase("[a]: \t /r")]
[TestCase("[a]: \t /r \t")]
[TestCase("[a]: \t /r \t\"l\"")]
[TestCase("[a]: \t /r \t\"l\"\t")]
[TestCase("[a]:\t/r\t ")]
[TestCase("[a]:\t/r\t \"l\"")]
[TestCase("[a]:\t/r\t \"l\"\t")]
[TestCase("[a]: \t/r")]
[TestCase("[a]: \t/r\t ")]
[TestCase("[a]: \t/r\t \"l\"")]
[TestCase("[a]: \t/r\t \"l\"\t")]
[TestCase("[a]:\t /r")]
[TestCase("[a]:\t /r\t ")]
[TestCase("[a]:\t /r\t \"l\"")]
[TestCase("[a]:\t /r\t \"l\"\t")]
[TestCase("[a]: \t /r")]
[TestCase("[a]: \t /r\t ")]
[TestCase("[a]: \t /r\t \"l\"")]
[TestCase("[a]: \t /r\t \"l\"\t")]
[TestCase("[a]:\t/r \t ")]
[TestCase("[a]:\t/r \t \"l\"")]
[TestCase("[a]:\t/r \t \"l\"\t")]
[TestCase("[a]: \t/r")]
[TestCase("[a]: \t/r \t ")]
[TestCase("[a]: \t/r \t \"l\"")]
[TestCase("[a]: \t/r \t \"l\"\t")]
[TestCase("[a]:\t /r")]
[TestCase("[a]:\t /r \t ")]
[TestCase("[a]:\t /r \t \"l\"")]
[TestCase("[a]:\t /r \t \"l\"\t")]
[TestCase("[a]: \t /r")]
[TestCase("[a]: \t /r \t ")]
[TestCase("[a]: \t /r \t \"l\"")]
[TestCase("[a]: \t /r \t \"l\"\t")]
public void Test(string value)
{
RoundTrip(value);
}
[TestCase("[a]: /r\n[b]: /r\n")]
[TestCase("[a]: /r\n[b]: /r\n[c] /r\n")]
public void TestMultiple(string value)
{
RoundTrip(value);
}
[TestCase("[a]:\f/r\f\"l\"")]
[TestCase("[a]:\v/r\v\"l\"")]
public void TestUncommonWhitespace(string value)
{
RoundTrip(value);
}
[TestCase("[a]:\n/r\n\"t\"")]
[TestCase("[a]:\n/r\r\"t\"")]
[TestCase("[a]:\n/r\r\n\"t\"")]
[TestCase("[a]:\r/r\n\"t\"")]
[TestCase("[a]:\r/r\r\"t\"")]
[TestCase("[a]:\r/r\r\n\"t\"")]
[TestCase("[a]:\r\n/r\n\"t\"")]
[TestCase("[a]:\r\n/r\r\"t\"")]
[TestCase("[a]:\r\n/r\r\n\"t\"")]
[TestCase("[a]:\n/r\n\"t\nt\"")]
[TestCase("[a]:\n/r\n\"t\rt\"")]
[TestCase("[a]:\n/r\n\"t\r\nt\"")]
[TestCase("[a]:\r\n /r\t \n \t \"t\r\nt\" ")]
[TestCase("[a]:\n/r\n\n[a],")]
[TestCase("[a]: /r\n[b]: /r\n\n[a],")]
public void TestNewlines(string value)
{
RoundTrip(value);
}
[TestCase("[ a]: /r")]
[TestCase("[a ]: /r")]
[TestCase("[ a ]: /r")]
[TestCase("[ a]: /r")]
[TestCase("[ a ]: /r")]
[TestCase("[a ]: /r")]
[TestCase("[ a ]: /r")]
[TestCase("[ a ]: /r")]
[TestCase("[a a]: /r")]
[TestCase("[a\va]: /r")]
[TestCase("[a\fa]: /r")]
[TestCase("[a\ta]: /r")]
[TestCase("[\va]: /r")]
[TestCase("[\fa]: /r")]
[TestCase("[\ta]: /r")]
[TestCase(@"[\]]: /r")]
public void TestLabel(string value)
{
RoundTrip(value);
}
[TestCase("[a]: /r ()")]
[TestCase("[a]: /r (t)")]
[TestCase("[a]: /r ( t)")]
[TestCase("[a]: /r (t )")]
[TestCase("[a]: /r ( t )")]
[TestCase("[a]: /r ''")]
[TestCase("[a]: /r 't'")]
[TestCase("[a]: /r ' t'")]
[TestCase("[a]: /r 't '")]
[TestCase("[a]: /r ' t '")]
public void Test_Title(string value)
{
RoundTrip(value);
}
[TestCase("[a]: /r\n===\n[a]")]
public void TestSetextHeader(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,23 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestNoBlocksFoundBlock
{
[TestCase("\r")]
[TestCase("\n")]
[TestCase("\r\n")]
[TestCase("\t")]
[TestCase("\v")]
[TestCase("\f")]
[TestCase(" ")]
[TestCase(" ")]
[TestCase(" ")]
public void Test(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,191 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestOrderedList
{
[TestCase("1. i")]
[TestCase("1. i")]
[TestCase("1. i ")]
[TestCase("1. i ")]
[TestCase("1. i ")]
[TestCase(" 1. i")]
[TestCase(" 1. i")]
[TestCase(" 1. i ")]
[TestCase(" 1. i ")]
[TestCase(" 1. i ")]
[TestCase(" 1. i")]
[TestCase(" 1. i")]
[TestCase(" 1. i ")]
[TestCase(" 1. i ")]
[TestCase(" 1. i ")]
[TestCase(" 1. i")]
[TestCase(" 1. i")]
[TestCase(" 1. i ")]
[TestCase(" 1. i ")]
[TestCase(" 1. i ")]
[TestCase("1. i\n")]
[TestCase("1. i\n")]
[TestCase("1. i \n")]
[TestCase("1. i \n")]
[TestCase("1. i \n")]
[TestCase(" 1. i\n")]
[TestCase(" 1. i\n")]
[TestCase(" 1. i \n")]
[TestCase(" 1. i \n")]
[TestCase(" 1. i \n")]
[TestCase(" 1. i\n")]
[TestCase(" 1. i\n")]
[TestCase(" 1. i \n")]
[TestCase(" 1. i \n")]
[TestCase(" 1. i \n")]
[TestCase(" 1. i\n")]
[TestCase(" 1. i\n")]
[TestCase(" 1. i \n")]
[TestCase(" 1. i \n")]
[TestCase(" 1. i \n")]
[TestCase("1. i\n2. j")]
[TestCase("1. i\n2. j")]
[TestCase("1. i \n2. j")]
[TestCase("1. i \n2. j")]
[TestCase("1. i \n2. j")]
[TestCase(" 1. i\n2. j")]
[TestCase(" 1. i\n2. j")]
[TestCase(" 1. i \n2. j")]
[TestCase(" 1. i \n2. j")]
[TestCase(" 1. i \n2. j")]
[TestCase(" 1. i\n2. j")]
[TestCase(" 1. i\n2. j")]
[TestCase(" 1. i \n2. j")]
[TestCase(" 1. i \n2. j")]
[TestCase(" 1. i \n2. j")]
[TestCase(" 1. i\n2. j")]
[TestCase(" 1. i\n2. j")]
[TestCase(" 1. i \n2. j")]
[TestCase(" 1. i \n2. j")]
[TestCase(" 1. i \n2. j")]
[TestCase("1. i\n2. j\n")]
[TestCase("1. i\n2. j\n")]
[TestCase("1. i \n2. j\n")]
[TestCase("1. i \n2. j\n")]
[TestCase("1. i \n2. j\n")]
[TestCase(" 1. i\n2. j\n")]
[TestCase(" 1. i\n2. j\n")]
[TestCase(" 1. i \n2. j\n")]
[TestCase(" 1. i \n2. j\n")]
[TestCase(" 1. i \n2. j\n")]
[TestCase(" 1. i\n2. j\n")]
[TestCase(" 1. i\n2. j\n")]
[TestCase(" 1. i \n2. j\n")]
[TestCase(" 1. i \n2. j\n")]
[TestCase(" 1. i \n2. j\n")]
[TestCase(" 1. i\n2. j\n")]
[TestCase(" 1. i\n2. j\n")]
[TestCase(" 1. i \n2. j\n")]
[TestCase(" 1. i \n2. j\n")]
[TestCase(" 1. i \n2. j\n")]
[TestCase("1. i\n2. j\n3. k")]
[TestCase("1. i\n2. j\n3. k\n")]
public void Test(string value)
{
RoundTrip(value);
}
[TestCase("10. i")]
[TestCase("11. i")]
[TestCase("10. i\n12. i")]
[TestCase("2. i\n3. i")]
public void Test_MoreThenOneStart(string value)
{
RoundTrip(value);
}
[TestCase("\n1. i")]
[TestCase("\r1. i")]
[TestCase("\r\n1. i")]
[TestCase("\n1. i\n")]
[TestCase("\r1. i\n")]
[TestCase("\r\n1. i\n")]
[TestCase("\n1. i\r")]
[TestCase("\r1. i\r")]
[TestCase("\r\n1. i\r")]
[TestCase("\n1. i\r\n")]
[TestCase("\r1. i\r\n")]
[TestCase("\r\n1. i\r\n")]
[TestCase("1. i\n2. i")]
[TestCase("\n1. i\n2. i")]
[TestCase("\r1. i\n2. i")]
[TestCase("\r\n1. i\n2. i")]
[TestCase("1. i\r2. i")]
[TestCase("\n1. i\r2. i")]
[TestCase("\r1. i\r2. i")]
[TestCase("\r\n1. i\r2. i")]
[TestCase("1. i\r\n2. i")]
[TestCase("\n1. i\r\n2. i")]
[TestCase("\r1. i\r\n2. i")]
[TestCase("\r\n1. i\r\n2. i")]
[TestCase("1. i\n2. i\n")]
[TestCase("\n1. i\n2. i\n")]
[TestCase("\r1. i\n2. i\n")]
[TestCase("\r\n1. i\n2. i\n")]
[TestCase("1. i\r2. i\r")]
[TestCase("\n1. i\r2. i\r")]
[TestCase("\r1. i\r2. i\r")]
[TestCase("\r\n1. i\r2. i\r")]
[TestCase("1. i\r\n2. i\r\n")]
[TestCase("\n1. i\r\n2. i\r\n")]
[TestCase("\r1. i\r\n2. i\r\n")]
[TestCase("\r\n1. i\r\n2. i\r\n")]
public void TestNewline(string value)
{
RoundTrip(value);
}
[TestCase("1. i\n 1. i")]
[TestCase("1. i\n 1. i\n")]
[TestCase("1. i\n 1. i\n 2. i")]
[TestCase("1. i\n 2. i\n 3. i")]
[TestCase("1. i\n\t1. i")]
[TestCase("1. i\n\t1. i\n2. i")]
public void TestMultipleLevels(string value)
{
RoundTrip(value);
}
[TestCase("1. c")]
[TestCase("1. c")]
public void Test_IndentedCodeBlock(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,247 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestParagraph
{
[TestCase("p")]
[TestCase(" p")]
[TestCase("p ")]
[TestCase(" p ")]
[TestCase("p\np")]
[TestCase(" p\np")]
[TestCase("p \np")]
[TestCase(" p \np")]
[TestCase("p\n p")]
[TestCase(" p\n p")]
[TestCase("p \n p")]
[TestCase(" p \n p")]
[TestCase("p\np ")]
[TestCase(" p\np ")]
[TestCase("p \np ")]
[TestCase(" p \np ")]
[TestCase("p\n\n p ")]
[TestCase(" p\n\n p ")]
[TestCase("p \n\n p ")]
[TestCase(" p \n\n p ")]
[TestCase("p\n\np")]
[TestCase(" p\n\np")]
[TestCase("p \n\np")]
[TestCase(" p \n\np")]
[TestCase("p\n\n p")]
[TestCase(" p\n\n p")]
[TestCase("p \n\n p")]
[TestCase(" p \n\n p")]
[TestCase("p\n\np ")]
[TestCase(" p\n\np ")]
[TestCase("p \n\np ")]
[TestCase(" p \n\np ")]
[TestCase("p\n\n p ")]
[TestCase(" p\n\n p ")]
[TestCase("p \n\n p ")]
[TestCase(" p \n\n p ")]
[TestCase("\np")]
[TestCase("\n p")]
[TestCase("\np ")]
[TestCase("\n p ")]
[TestCase("\np\np")]
[TestCase("\n p\np")]
[TestCase("\np \np")]
[TestCase("\n p \np")]
[TestCase("\np\n p")]
[TestCase("\n p\n p")]
[TestCase("\np \n p")]
[TestCase("\n p \n p")]
[TestCase("\np\np ")]
[TestCase("\n p\np ")]
[TestCase("\np \np ")]
[TestCase("\n p \np ")]
[TestCase("\np\n\n p ")]
[TestCase("\n p\n\n p ")]
[TestCase("\np \n\n p ")]
[TestCase("\n p \n\n p ")]
[TestCase("\np\n\np")]
[TestCase("\n p\n\np")]
[TestCase("\np \n\np")]
[TestCase("\n p \n\np")]
[TestCase("\np\n\n p")]
[TestCase("\n p\n\n p")]
[TestCase("\np \n\n p")]
[TestCase("\n p \n\n p")]
[TestCase("\np\n\np ")]
[TestCase("\n p\n\np ")]
[TestCase("\np \n\np ")]
[TestCase("\n p \n\np ")]
[TestCase("\np\n\n p ")]
[TestCase("\n p\n\n p ")]
[TestCase("\np \n\n p ")]
[TestCase("\n p \n\n p ")]
[TestCase("p p")]
[TestCase("p\tp")]
[TestCase("p \tp")]
[TestCase("p \t p")]
[TestCase("p \tp")]
// special cases
[TestCase(" p \n\n\n\n p \n\n")]
[TestCase("\n\np")]
[TestCase("p\n")]
[TestCase("p\n\n")]
[TestCase("p\np\n p")]
[TestCase("p\np\n p\n p")]
public void Test(string value)
{
RoundTrip(value);
}
[TestCase("\n")]
[TestCase("\r\n")]
[TestCase("\r")]
[TestCase("p\n")]
[TestCase("p\r")]
[TestCase("p\r\n")]
[TestCase("p\np")]
[TestCase("p\rp")]
[TestCase("p\r\np")]
[TestCase("p\np\n")]
[TestCase("p\rp\n")]
[TestCase("p\r\np\n")]
[TestCase("p\np\r")]
[TestCase("p\rp\r")]
[TestCase("p\r\np\r")]
[TestCase("p\np\r\n")]
[TestCase("p\rp\r\n")]
[TestCase("p\r\np\r\n")]
[TestCase("\np\n")]
[TestCase("\np\r")]
[TestCase("\np\r\n")]
[TestCase("\np\np")]
[TestCase("\np\rp")]
[TestCase("\np\r\np")]
[TestCase("\np\np\n")]
[TestCase("\np\rp\n")]
[TestCase("\np\r\np\n")]
[TestCase("\np\np\r")]
[TestCase("\np\rp\r")]
[TestCase("\np\r\np\r")]
[TestCase("\np\np\r\n")]
[TestCase("\np\rp\r\n")]
[TestCase("\np\r\np\r\n")]
[TestCase("\rp\n")]
[TestCase("\rp\r")]
[TestCase("\rp\r\n")]
[TestCase("\rp\np")]
[TestCase("\rp\rp")]
[TestCase("\rp\r\np")]
[TestCase("\rp\np\n")]
[TestCase("\rp\rp\n")]
[TestCase("\rp\r\np\n")]
[TestCase("\rp\np\r")]
[TestCase("\rp\rp\r")]
[TestCase("\rp\r\np\r")]
[TestCase("\rp\np\r\n")]
[TestCase("\rp\rp\r\n")]
[TestCase("\rp\r\np\r\n")]
[TestCase("\r\np\n")]
[TestCase("\r\np\r")]
[TestCase("\r\np\r\n")]
[TestCase("\r\np\np")]
[TestCase("\r\np\rp")]
[TestCase("\r\np\r\np")]
[TestCase("\r\np\np\n")]
[TestCase("\r\np\rp\n")]
[TestCase("\r\np\r\np\n")]
[TestCase("\r\np\np\r")]
[TestCase("\r\np\rp\r")]
[TestCase("\r\np\r\np\r")]
[TestCase("\r\np\np\r\n")]
[TestCase("\r\np\rp\r\n")]
[TestCase("\r\np\r\np\r\n")]
[TestCase("p\n")]
[TestCase("p\n\n")]
[TestCase("p\n\n\n")]
[TestCase("p\n\n\n\n")]
public void TestNewline(string value)
{
RoundTrip(value);
}
[TestCase(" \n")]
[TestCase(" \r")]
[TestCase(" \r\n")]
[TestCase(" \np")]
[TestCase(" \rp")]
[TestCase(" \r\np")]
[TestCase(" \np")]
[TestCase(" \rp")]
[TestCase(" \r\np")]
[TestCase(" \np")]
[TestCase(" \rp")]
[TestCase(" \r\np")]
[TestCase(" \n ")]
[TestCase(" \r ")]
[TestCase(" \r\n ")]
[TestCase(" \np ")]
[TestCase(" \rp ")]
[TestCase(" \r\np ")]
[TestCase(" \np ")]
[TestCase(" \rp ")]
[TestCase(" \r\np ")]
[TestCase(" \np ")]
[TestCase(" \rp ")]
[TestCase(" \r\np ")]
public void Test_WhitespaceWithNewline(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,286 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestQuoteBlock
{
[TestCase(">q")]
[TestCase(" >q")]
[TestCase(" >q")]
[TestCase(" >q")]
[TestCase("> q")]
[TestCase(" > q")]
[TestCase(" > q")]
[TestCase(" > q")]
[TestCase("> q")]
[TestCase(" > q")]
[TestCase(" > q")]
[TestCase(" > q")]
[TestCase(">q\n>q")]
[TestCase(">q\n >q")]
[TestCase(">q\n >q")]
[TestCase(">q\n >q")]
[TestCase(">q\n> q")]
[TestCase(">q\n > q")]
[TestCase(">q\n > q")]
[TestCase(">q\n > q")]
[TestCase(">q\n> q")]
[TestCase(">q\n > q")]
[TestCase(">q\n > q")]
[TestCase(">q\n > q")]
[TestCase(" >q\n>q")]
[TestCase(" >q\n >q")]
[TestCase(" >q\n >q")]
[TestCase(" >q\n >q")]
[TestCase(" >q\n> q")]
[TestCase(" >q\n > q")]
[TestCase(" >q\n > q")]
[TestCase(" >q\n > q")]
[TestCase(" >q\n> q")]
[TestCase(" >q\n > q")]
[TestCase(" >q\n > q")]
[TestCase(" >q\n > q")]
[TestCase(" >q\n>q")]
[TestCase(" >q\n >q")]
[TestCase(" >q\n >q")]
[TestCase(" >q\n >q")]
[TestCase(" >q\n> q")]
[TestCase(" >q\n > q")]
[TestCase(" >q\n > q")]
[TestCase(" >q\n > q")]
[TestCase(" >q\n> q")]
[TestCase(" >q\n > q")]
[TestCase(" >q\n > q")]
[TestCase(" >q\n > q")]
[TestCase("> q\n>q")]
[TestCase("> q\n >q")]
[TestCase("> q\n >q")]
[TestCase("> q\n >q")]
[TestCase("> q\n> q")]
[TestCase("> q\n > q")]
[TestCase("> q\n > q")]
[TestCase("> q\n > q")]
[TestCase("> q\n> q")]
[TestCase("> q\n > q")]
[TestCase("> q\n > q")]
[TestCase("> q\n > q")]
[TestCase(" > q\n>q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n> q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n> q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n>q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n> q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n> q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n>q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n> q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n> q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase("> q\n>q")]
[TestCase("> q\n >q")]
[TestCase("> q\n >q")]
[TestCase("> q\n >q")]
[TestCase("> q\n> q")]
[TestCase("> q\n > q")]
[TestCase("> q\n > q")]
[TestCase("> q\n > q")]
[TestCase("> q\n> q")]
[TestCase("> q\n > q")]
[TestCase("> q\n > q")]
[TestCase("> q\n > q")]
[TestCase(" > q\n>q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n> q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n> q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n>q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n> q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n> q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n>q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n >q")]
[TestCase(" > q\n> q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n> q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(" > q\n > q")]
[TestCase(">q\n>q\n>q")]
[TestCase(">q\n>\n>q")]
[TestCase(">q\np\n>q")]
[TestCase(">q\n>\n>\n>q")]
[TestCase(">q\n>\n>\n>\n>q")]
[TestCase(">q\n>\n>q\n>\n>q")]
[TestCase("p\n\n> **q**\n>p\n")]
[TestCase("> q\np\n> q")] // lazy
[TestCase("> q\n> q\np")] // lazy
[TestCase(">>q")]
[TestCase(" > > q")]
[TestCase("> **q**\n>p\n")]
[TestCase("> **q**")]
public void Test(string value)
{
RoundTrip(value);
}
[TestCase("> q")] // 5
[TestCase("> q")] // 6
[TestCase(" > q")] //5
[TestCase(" > q")] //6
[TestCase(" > \tq")]
[TestCase("> q\n> q")] // 5, 5
[TestCase("> q\n> q")] // 5, 6
[TestCase("> q\n> q")] // 6, 5
[TestCase("> q\n> q")] // 6, 6
[TestCase("> q\n\n> 5")] // 5, 5
public void TestIndentedCodeBlock(string value)
{
RoundTrip(value);
}
[TestCase("\n> q")]
[TestCase("\n> q\n")]
[TestCase("\n> q\n\n")]
[TestCase("> q\n\np")]
[TestCase("p\n\n> q\n\n# h")]
//https://github.com/lunet-io/markdig/issues/480
//[TestCase(">\np")]
//[TestCase(">**b**\n>\n>p\n>\np\n")]
public void TestParagraph(string value)
{
RoundTrip(value);
}
[TestCase("> q\n\n# h\n")]
public void TestAtxHeader(string value)
{
RoundTrip(value);
}
[TestCase(">- i")]
[TestCase("> - i")]
[TestCase(">- i\n>- i")]
[TestCase(">- >p")]
[TestCase("> - >p")]
[TestCase(">- i1\n>- i2\n")]
[TestCase("> **p** p\n>- i1\n>- i2\n")]
public void TestUnorderedList(string value)
{
RoundTrip(value);
}
[TestCase("> *q*\n>p\n")]
[TestCase("> *q*")]
public void TestEmphasis(string value)
{
RoundTrip(value);
}
[TestCase("> **q**\n>p\n")]
[TestCase("> **q**")]
public void TestStrongEmphasis(string value)
{
RoundTrip(value);
}
[TestCase(">p\n")]
[TestCase(">p\r")]
[TestCase(">p\r\n")]
[TestCase(">p\n>p")]
[TestCase(">p\r>p")]
[TestCase(">p\r\n>p")]
[TestCase(">p\n>p\n")]
[TestCase(">p\r>p\n")]
[TestCase(">p\r\n>p\n")]
[TestCase(">p\n>p\r")]
[TestCase(">p\r>p\r")]
[TestCase(">p\r\n>p\r")]
[TestCase(">p\n>p\r\n")]
[TestCase(">p\r>p\r\n")]
[TestCase(">p\r\n>p\r\n")]
public void TestNewline(string value)
{
RoundTrip(value);
}
[TestCase(">\n>q")]
[TestCase(">\n>\n>q")]
[TestCase(">q\n>\n>q")]
[TestCase(">q\n>\n>\n>q")]
[TestCase(">q\n> \n>q")]
[TestCase(">q\n> \n>q")]
[TestCase(">q\n> \n>q")]
[TestCase(">q\n>\t\n>q")]
[TestCase(">q\n>\v\n>q")]
[TestCase(">q\n>\f\n>q")]
public void TestEmptyLines(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,53 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestSetextHeading
{
[TestCase("h1\n===")] //3
[TestCase("h1\n ===")] //3
[TestCase("h1\n ===")] //3
[TestCase("h1\n ===")] //3
[TestCase("h1\n=== ")] //3
[TestCase("h1 \n===")] //3
[TestCase("h1\\\n===")] //3
[TestCase("h1\n === ")] //3
[TestCase("h1\nh1 l2\n===")] //3
[TestCase("h1\n====")] // 4
[TestCase("h1\n ====")] // 4
[TestCase("h1\n==== ")] // 4
[TestCase("h1\n ==== ")] // 4
[TestCase("h1\n===\nh1\n===")] //3
[TestCase("\\>h1\n===")] //3
public void Test(string value)
{
RoundTrip(value);
}
[TestCase("h1\r===")]
[TestCase("h1\n===")]
[TestCase("h1\r\n===")]
[TestCase("h1\r===\r")]
[TestCase("h1\n===\r")]
[TestCase("h1\r\n===\r")]
[TestCase("h1\r===\n")]
[TestCase("h1\n===\n")]
[TestCase("h1\r\n===\n")]
[TestCase("h1\r===\r\n")]
[TestCase("h1\n===\r\n")]
[TestCase("h1\r\n===\r\n")]
[TestCase("h1\n===\n\n\nh2---\n\n")]
[TestCase("h1\r===\r\r\rh2---\r\r")]
[TestCase("h1\r\n===\r\n\r\n\r\nh2---\r\n\r\n")]
public void TestNewline(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,53 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestThematicBreak
{
[TestCase("---")]
[TestCase(" ---")]
[TestCase(" ---")]
[TestCase(" ---")]
[TestCase("--- ")]
[TestCase(" --- ")]
[TestCase(" --- ")]
[TestCase(" --- ")]
[TestCase("- - -")]
[TestCase(" - - -")]
[TestCase(" - - - ")]
[TestCase("-- -")]
[TestCase("---\n")]
[TestCase("---\n\n")]
[TestCase("---\np")]
[TestCase("---\n\np")]
[TestCase("---\n# h")]
[TestCase("p\n\n---")]
// Note: "p\n---" is parsed as setext heading
public void Test(string value)
{
RoundTrip(value);
}
[TestCase("\n---")]
[TestCase("\r---")]
[TestCase("\r\n---")]
[TestCase("\n---\n")]
[TestCase("\r---\n")]
[TestCase("\r\n---\n")]
[TestCase("\n---\r")]
[TestCase("\r---\r")]
[TestCase("\r\n---\r")]
[TestCase("\n---\r\n")]
[TestCase("\r---\r\n")]
[TestCase("\r\n---\r\n")]
public void TestNewline(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -0,0 +1,183 @@
using NUnit.Framework;
using static Markdig.Tests.TestRoundtrip;
namespace Markdig.Tests.RoundtripSpecs
{
[TestFixture]
public class TestUnorderedList
{
// i = item
[TestCase("- i1")]
[TestCase("- i1 ")]
[TestCase("- i1\n")]
[TestCase("- i1\n\n")]
[TestCase("- i1\n- i2")]
[TestCase("- i1\n - i2")]
[TestCase("- i1\n - i1.1\n - i1.2")]
[TestCase("- i1 \n- i2 \n")]
[TestCase("- i1 \n- i2 \n")]
[TestCase(" - i1")]
[TestCase(" - i1")]
[TestCase(" - i1")]
[TestCase("- i1\n\n- i1")]
[TestCase("- i1\n\n\n- i1")]
[TestCase("- i1\n - i1.1\n - i1.1.1\n")]
[TestCase("-\ti1")]
[TestCase("-\ti1\n-\ti2")]
[TestCase("-\ti1\n- i2\n-\ti3")]
public void Test(string value)
{
RoundTrip(value);
}
[TestCase("- > q")]
[TestCase(" - > q")]
[TestCase(" - > q")]
[TestCase(" - > q")]
[TestCase("- > q")]
[TestCase(" - > q")]
[TestCase(" - > q")]
[TestCase(" - > q")]
[TestCase("- > q")]
[TestCase(" - > q")]
[TestCase(" - > q")]
[TestCase(" - > q")]
[TestCase("- > q")]
[TestCase(" - > q")]
[TestCase(" - > q")]
[TestCase(" - > q")]
[TestCase(" - > q1\n - > q2")]
public void TestBlockQuote(string value)
{
RoundTrip(value);
}
[TestCase("- i1\n\np\n")] // TODO: listblock should render newline, apparently last paragraph of last listitem dont have newline
[TestCase("- i1\n\n\np\n")]
[TestCase("- i1\n\np")]
[TestCase("- i1\n\np\n")]
public void TestParagraph(string value)
{
RoundTrip(value);
}
[TestCase("- i1\n\n---\n")]
[TestCase("- i1\n\n\n---\n")]
public void TestThematicBreak(string value)
{
RoundTrip(value);
}
[TestCase("- c")] // 5
[TestCase("- c\n c")] // 5, 6
[TestCase(" - c\n c")] // 5, 6
[TestCase(" - c\n c")] // 5, 7
[TestCase("- c\n c")] // 6, 6
[TestCase(" - c\n c")] // 6, 6
[TestCase(" - c\n c")] // 6, 7
public void TestIndentedCodeBlock(string value)
{
RoundTrip(value);
}
[TestCase("- ```a```")]
[TestCase("- ```\n a\n```")]
[TestCase("- i1\n - i1.1\n ```\n c\n ```")]
[TestCase("- i1\n - i1.1\n ```\nc\n```")]
[TestCase("- i1\n - i1.1\n ```\nc\n```\n")]
public void TestFencedCodeBlock(string value)
{
RoundTrip(value);
}
[TestCase("\n- i")]
[TestCase("\r- i")]
[TestCase("\r\n- i")]
[TestCase("\n- i\n")]
[TestCase("\r- i\n")]
[TestCase("\r\n- i\n")]
[TestCase("\n- i\r")]
[TestCase("\r- i\r")]
[TestCase("\r\n- i\r")]
[TestCase("\n- i\r\n")]
[TestCase("\r- i\r\n")]
[TestCase("\r\n- i\r\n")]
[TestCase("- i\n- j")]
[TestCase("- i\r- j")]
[TestCase("- i\r\n- j")]
[TestCase("\n- i\n- j")]
[TestCase("\n- i\r- j")]
[TestCase("\n- i\r\n- j")]
[TestCase("\r- i\n- j")]
[TestCase("\r- i\r- j")]
[TestCase("\r- i\r\n- j")]
[TestCase("\r\n- i\n- j")]
[TestCase("\r\n- i\r- j")]
[TestCase("\r\n- i\r\n- j")]
[TestCase("- i\n- j\n")]
[TestCase("- i\r- j\n")]
[TestCase("- i\r\n- j\n")]
[TestCase("\n- i\n- j\n")]
[TestCase("\n- i\r- j\n")]
[TestCase("\n- i\r\n- j\n")]
[TestCase("\r- i\n- j\n")]
[TestCase("\r- i\r- j\n")]
[TestCase("\r- i\r\n- j\n")]
[TestCase("\r\n- i\n- j\n")]
[TestCase("\r\n- i\r- j\n")]
[TestCase("\r\n- i\r\n- j\n")]
[TestCase("- i\n- j\r")]
[TestCase("- i\r- j\r")]
[TestCase("- i\r\n- j\r")]
[TestCase("\n- i\n- j\r")]
[TestCase("\n- i\r- j\r")]
[TestCase("\n- i\r\n- j\r")]
[TestCase("\r- i\n- j\r")]
[TestCase("\r- i\r- j\r")]
[TestCase("\r- i\r\n- j\r")]
[TestCase("\r\n- i\n- j\r")]
[TestCase("\r\n- i\r- j\r")]
[TestCase("\r\n- i\r\n- j\r")]
[TestCase("- i\n- j\r\n")]
[TestCase("- i\r- j\r\n")]
[TestCase("- i\r\n- j\r\n")]
[TestCase("\n- i\n- j\r\n")]
[TestCase("\n- i\r- j\r\n")]
[TestCase("\n- i\r\n- j\r\n")]
[TestCase("\r- i\n- j\r\n")]
[TestCase("\r- i\r- j\r\n")]
[TestCase("\r- i\r\n- j\r\n")]
[TestCase("\r\n- i\n- j\r\n")]
[TestCase("\r\n- i\r- j\r\n")]
[TestCase("\r\n- i\r\n- j\r\n")]
[TestCase("- i\n")]
[TestCase("- i\n\n")]
[TestCase("- i\n\n\n")]
[TestCase("- i\n\n\n\n")]
public void TestNewline(string value)
{
RoundTrip(value);
}
}
}

View File

@@ -1,4 +1,3 @@
// Generated: 2019-05-15 02:46:55
// --------------------------------
// Abbreviations

View File

@@ -112,9 +112,9 @@ A
The longest matching abbreviation should be used
```````````````````````````````` example
*[Foo]: foo
*[Foo Bar]: foobar
*[Foo]: foo
*[Foo Bar]: foobar
Foo B
.
<p><abbr title="foo">Foo</abbr> B</p>

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Auto Identifiers

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Auto Links
@@ -23,6 +22,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// - `http://` or `https://`
// - `ftp://`
// - `mailto:`
// - `tel:`
// - `www.`
[Test]
public void ExtensionsAutoLinks_Example001()
@@ -34,16 +34,18 @@ namespace Markdig.Tests.Specs.AutoLinks
// 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 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 plain <a href=\"http://www.google.com\">www.google.com</a></p>", "autolinks|advanced");
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:
@@ -58,15 +60,17 @@ namespace Markdig.Tests.Specs.AutoLinks
// 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</p>
// 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 ", "<p>This is not a http:/www.google.com URL and https:/www.google.com\nThis is not a ftp:/test.com\nAnd not a mailto:emailtoto.com\nAnd not a plain www. or a www.x</p>", "autolinks|advanced");
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):

View File

@@ -9,17 +9,20 @@ 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>
````````````````````````````````
@@ -30,11 +33,13 @@ 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</p>
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):
@@ -245,18 +250,18 @@ https://github.com:443
Links with unicode characters in the path / query / fragment are matched and url encoded
```````````````````````````````` example
http://abc.net/☃
http://abc.net?☃
http://abc.net#☃
```````````````````````````````` 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/%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>
````````````````````````````````
@@ -270,18 +275,18 @@ http://☃.net?☃
Same goes for regular autolinks
```````````````````````````````` example
<http://abc.net/☃>
<http://abc.net?☃>
<http://abc.net#☃>
```````````````````````````````` 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/%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>
````````````````````````````````

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-15 05:23:49
// --------------------------------
// Bootstrap

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-12 15:26:42
// --------------------------------
// CommonMark v. 0.29
@@ -14925,6 +14924,29 @@ namespace Markdig.Tests.Specs.CommonMarkV_0_29
Console.WriteLine("Example 649\nSection Inlines / Textual content\n");
TestParser.TestSpec("Multiple spaces", "<p>Multiple spaces</p>", "");
}
// Within a blockquote a setext heading takes precedence
// over a thematic break:
[Test]
public void InlinesTextualContent_Example650()
{
// Example 650
// Section: Inlines / Textual content
//
// The following Markdown:
// > Foo
// > ---
// > bar
//
// Should be rendered as:
// <blockquote>
// <h2>Foo</h2>
// <p>bar</p>
// </blockquote>
Console.WriteLine("Example 650\nSection Inlines / Textual content\n");
TestParser.TestSpec("> Foo\n> ---\n> bar", "<blockquote>\n<h2>Foo</h2>\n<p>bar</p>\n</blockquote>", "");
}
// <!-- END TESTS -->
//
// # Appendix: A parsing strategy

View File

@@ -9368,6 +9368,20 @@ Multiple spaces
<p>Multiple spaces</p>
````````````````````````````````
Within a blockquote a setext heading takes precedence
over a thematic break:
```````````````````````````````` example
> Foo
> ---
> bar
.
<blockquote>
<h2>Foo</h2>
<p>bar</p>
</blockquote>
````````````````````````````````
<!-- END TESTS -->

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Custom Containers

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-15 05:06:35
// --------------------------------
// Definition Lists

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Diagrams

View File

@@ -1,4 +1,3 @@
// Generated: 2020-01-13 21:08:58
// --------------------------------
// Emoji

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Emphasis Extra

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Figures, Footers and Cites

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-15 05:33:49
// --------------------------------
// Footnotes

View File

@@ -1,4 +1,3 @@
// Generated: 2019-08-01 13:57:17
// --------------------------------
// Generic Attributes

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-15 05:25:26
// --------------------------------
// Globalization

View File

@@ -1,4 +1,3 @@
// Generated: 2020-04-18 06:41:26
// --------------------------------
// Grid Tables

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Hardline Breaks

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-15 05:30:00
// --------------------------------
// Jira Links
@@ -24,7 +23,7 @@ namespace Markdig.Tests.Specs.JiraLinks
//
// The rules for detecting a link are:
//
// - The project key must be composed of one or more capitalized ASCII letter `[A-Z]+`
// - The project key must be composed of one or more capitalized ASCII letters or digits `[A-Z,0-9]+`
// - 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.
@@ -54,13 +53,13 @@ namespace Markdig.Tests.Specs.JiraLinks
// Section: Jira Links
//
// The following Markdown:
// This is a KIRA-1 issue
// This is a ABC4-123 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>
// <p>This is a <a href="http://your.company.abc/browse/ABC4-123" target="blank">ABC4-123</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");
TestParser.TestSpec("This is a ABC4-123 issue", "<p>This is a <a href=\"http://your.company.abc/browse/ABC4-123\" target=\"blank\">ABC4-123</a> issue</p>", "jiralinks");
}
[Test]
@@ -70,16 +69,15 @@ namespace Markdig.Tests.Specs.JiraLinks
// Section: Jira Links
//
// The following Markdown:
// This is a Z-1 issue
// This is a ABC45-123 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>
// <p>This is a <a href="http://your.company.abc/browse/ABC45-123" target="blank">ABC45-123</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");
TestParser.TestSpec("This is a ABC45-123 issue", "<p>This is a <a href=\"http://your.company.abc/browse/ABC45-123\" target=\"blank\">ABC45-123</a> issue</p>", "jiralinks");
}
// These are also valid links with `(` and `)`:
[Test]
public void JiraLinks_Example004()
{
@@ -87,13 +85,13 @@ namespace Markdig.Tests.Specs.JiraLinks
// Section: Jira Links
//
// The following Markdown:
// This is a (ABCD-123) issue
// This is a KIRA-1 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>
// <p>This is a <a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</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");
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]
@@ -103,15 +101,16 @@ namespace Markdig.Tests.Specs.JiraLinks
// Section: Jira Links
//
// The following Markdown:
// This is a (KIRA-1) issue
// This is a Z-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>
// <p>This is a <a href="http://your.company.abc/browse/Z-1" target="blank">Z-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");
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_Example006()
{
@@ -119,16 +118,15 @@ namespace Markdig.Tests.Specs.JiraLinks
// Section: Jira Links
//
// The following Markdown:
// This is a (Z-1) issue
// This is a (ABCD-123) 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>
// <p>This is a (<a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</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");
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");
}
// These are not valid links:
[Test]
public void JiraLinks_Example007()
{
@@ -136,13 +134,13 @@ namespace Markdig.Tests.Specs.JiraLinks
// Section: Jira Links
//
// The following Markdown:
// This is not aJIRA-123 issue
// This is a (ABC4-123) issue
//
// Should be rendered as:
// <p>This is not aJIRA-123 issue</p>
// <p>This is a (<a href="http://your.company.abc/browse/ABC4-123" target="blank">ABC4-123</a>) 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");
TestParser.TestSpec("This is a (ABC4-123) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/ABC4-123\" target=\"blank\">ABC4-123</a>) issue</p>", "jiralinks");
}
[Test]
@@ -152,13 +150,13 @@ namespace Markdig.Tests.Specs.JiraLinks
// Section: Jira Links
//
// The following Markdown:
// This is not JIRA-123a issue
// This is a (KIRA-1) issue
//
// Should be rendered as:
// <p>This is not JIRA-123a issue</p>
// <p>This is a (<a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a>) 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");
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]
@@ -168,13 +166,94 @@ namespace Markdig.Tests.Specs.JiraLinks
// 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 9\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_Example010()
{
// Example 10
// 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 10\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_Example011()
{
// Example 11
// Section: Jira Links
//
// The following Markdown:
// This is not 4JIRA-123 issue
//
// Should be rendered as:
// <p>This is not 4JIRA-123 issue</p>
Console.WriteLine("Example 11\nSection Jira Links\n");
TestParser.TestSpec("This is not 4JIRA-123 issue", "<p>This is not 4JIRA-123 issue</p>", "jiralinks");
}
[Test]
public void JiraLinks_Example012()
{
// Example 12
// 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 12\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_Example013()
{
// Example 13
// 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");
Console.WriteLine("Example 13\nSection Jira Links\n");
TestParser.TestSpec("This is not JIRA- issue", "<p>This is not JIRA- issue</p>", "jiralinks");
}
[Test]
public void JiraLinks_Example014()
{
// Example 14
// Section: Jira Links
//
// The following Markdown:
// This is not JIR4- issue
//
// Should be rendered as:
// <p>This is not JIR4- issue</p>
Console.WriteLine("Example 14\nSection Jira Links\n");
TestParser.TestSpec("This is not JIR4- issue", "<p>This is not JIR4- issue</p>", "jiralinks");
}
}
}

View File

@@ -10,7 +10,7 @@ var pipeline = new MarkdownPipelineBuilder()
The rules for detecting a link are:
- The project key must be composed of one or more capitalized ASCII letter `[A-Z]+`
- The project key must be composed of one or more capitalized ASCII letters or digits `[A-Z,0-9]+`
- 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.
@@ -24,6 +24,18 @@ 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 ABC4-123 issue
.
<p>This is a <a href="http://your.company.abc/browse/ABC4-123" target="blank">ABC4-123</a> issue</p>
````````````````````````````````
```````````````````````````````` example
This is a ABC45-123 issue
.
<p>This is a <a href="http://your.company.abc/browse/ABC45-123" target="blank">ABC45-123</a> issue</p>
````````````````````````````````
```````````````````````````````` example
This is a KIRA-1 issue
.
@@ -44,6 +56,12 @@ 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 (ABC4-123) issue
.
<p>This is a (<a href="http://your.company.abc/browse/ABC4-123" target="blank">ABC4-123</a>) issue</p>
````````````````````````````````
```````````````````````````````` example
This is a (KIRA-1) issue
.
@@ -64,6 +82,12 @@ This is not aJIRA-123 issue
<p>This is not aJIRA-123 issue</p>
````````````````````````````````
```````````````````````````````` example
This is not 4JIRA-123 issue
.
<p>This is not 4JIRA-123 issue</p>
````````````````````````````````
```````````````````````````````` example
This is not JIRA-123a issue
.
@@ -75,3 +99,9 @@ This is not JIRA- issue
.
<p>This is not JIRA- issue</p>
````````````````````````````````
```````````````````````````````` example
This is not JIR4- issue
.
<p>This is not JIR4- issue</p>
````````````````````````````````

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// List Extras

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Math

View File

@@ -1,4 +1,3 @@
// Generated: 2019-05-15 02:46:20
// --------------------------------
// Media
@@ -17,7 +16,7 @@ namespace Markdig.Tests.Specs.Media
// Adds support for media links:
//
// ## Media links
//
//
// Allows to embed audio/video links to popular website:
[Test]
public void ExtensionsMediaLinks_Example001()
@@ -35,7 +34,7 @@ namespace Markdig.Tests.Specs.Media
// ![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)
@@ -47,19 +46,19 @@ namespace Markdig.Tests.Specs.Media
// ![ok.ru](https://ok.ru/video/26870090463)
//
// Should be rendered as:
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100&amp;rel=0" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://www.youtube.com/embed?listType=playlist&amp;list=PLC77007E23FF423C6" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
// <p><iframe src="https://player.vimeo.com/video/8607834" width="500" height="281" class="vimeo" 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/" width="500" height="281" class="yandex" frameborder="0"></iframe></p>
// <p><iframe src="https://ok.ru/videoembed/26870090463" width="500" height="281" class="odnoklassniki" frameborder="0" allowfullscreen=""></iframe></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\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100&amp;rel=0\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed?listType=playlist&amp;list=PLC77007E23FF423C6\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://player.vimeo.com/video/8607834\" width=\"500\" height=\"281\" class=\"vimeo\" 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/\" width=\"500\" height=\"281\" class=\"yandex\" frameborder=\"0\"></iframe></p>\n<p><iframe src=\"https://ok.ru/videoembed/26870090463\" width=\"500\" height=\"281\" class=\"odnoklassniki\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>", "medialinks|advanced+medialinks");
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,7 +3,7 @@
Adds support for media links:
## Media links
Allows to embed audio/video links to popular website:
```````````````````````````````` example
@@ -16,7 +16,7 @@ Allows to embed audio/video links to popular website:
![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)
@@ -27,14 +27,14 @@ Allows to embed audio/video links to popular website:
![ok.ru](https://ok.ru/video/26870090463)
.
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100&amp;rel=0" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://www.youtube.com/embed?listType=playlist&amp;list=PLC77007E23FF423C6" width="500" height="281" class="youtube" frameborder="0" allowfullscreen=""></iframe></p>
<p><iframe src="https://player.vimeo.com/video/8607834" width="500" height="281" class="vimeo" 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/" width="500" height="281" class="yandex" frameborder="0"></iframe></p>
<p><iframe src="https://ok.ru/videoembed/26870090463" width="500" height="281" class="odnoklassniki" frameborder="0" allowfullscreen=""></iframe></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

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// No Html

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

@@ -1,4 +1,3 @@
// Generated: 2019-04-15 05:54:35
// --------------------------------
// Pipe Tables
@@ -647,7 +646,7 @@ namespace Markdig.Tests.Specs.PipeTables
TestParser.TestSpec("a | b `\n0 | ` ", "<p>a | b <code>0 |</code></p> ", "pipetables|advanced");
}
// **Rule #7**
// **Rule #8**
//
// A HTML inline has a higher precedence than a column delimiter `|`:
[Test]
@@ -681,7 +680,7 @@ namespace Markdig.Tests.Specs.PipeTables
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 #8**
// **Rule #9**
//
// Links have a higher precedence than the column delimiter character `|`:
[Test]
@@ -715,7 +714,7 @@ namespace Markdig.Tests.Specs.PipeTables
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 #9**
// **Rule #10**
//
// It is possible to have a single row header only:
[Test]
@@ -767,7 +766,7 @@ namespace Markdig.Tests.Specs.PipeTables
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**
//
// Tests trailing spaces after pipes
[Test]
@@ -816,7 +815,7 @@ namespace Markdig.Tests.Specs.PipeTables
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 **
// **Normalized columns count**
//
// The tables are normalized to the maximum number of columns found in a table
[Test]

View File

@@ -463,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 `|`:
@@ -488,7 +488,7 @@ a <a href="" title="|"></a> | b
</table>
````````````````````````````````
**Rule #8**
**Rule #9**
Links have a higher precedence than the column delimiter character `|`:
@@ -513,7 +513,7 @@ a | b
</table>
````````````````````````````````
** Rule #9**
**Rule #10**
It is possible to have a single row header only:
@@ -546,7 +546,7 @@ a | b
</table>
````````````````````````````````
** Tests **
**Tests**
Tests trailing spaces after pipes
@@ -586,7 +586,7 @@ Tests trailing spaces after pipes
</table>
````````````````````````````````
** Normalized columns count **
**Normalized columns count**
The tables are normalized to the maximum number of columns found in a table

View File

@@ -1,4 +1,3 @@
// Generated: 2019-08-01 12:33:23
// --------------------------------
// Smarty Pants

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Task Lists

View File

@@ -1,4 +1,3 @@
// Generated: 2019-04-05 16:06:14
// --------------------------------
// Yaml

View File

@@ -47,12 +47,14 @@ namespace Markdig.Tests
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);
@@ -60,11 +62,31 @@ namespace Markdig.Tests
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

@@ -1,14 +1,13 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Markdig.Extensions.Emoji;
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
@@ -28,13 +27,13 @@ namespace Markdig.Tests
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
[TestCase(":/", "<p>:/</p>\n")] // default smiley does not work
public void TestCustomSmiley(string input, string expected)
{
var emojiToUnicode = new Dictionary<string, string>();
@@ -55,8 +54,8 @@ namespace Markdig.Tests
[Test]
[TestCase(":smiley:", "<p>♥</p>\n")]
[TestCase(":)", "<p>♥</p>\n")]
[TestCase(":confused:", "<p>😕</p>\n")] // default emoji still works
[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)
{
@@ -73,8 +72,8 @@ namespace Markdig.Tests
var actual = Markdown.ToHtml(input, pipeline);
Assert.AreEqual(expected, actual);
}
}
[Test]
[TestCase(":testheart:", "<p>♥</p>\n")]
[TestCase("hello", "<p>♥</p>\n")]
@@ -99,31 +98,31 @@ namespace Markdig.Tests
}
[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));
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

@@ -1,153 +1,152 @@
using NUnit.Framework;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
using System;
using System.Linq;
using System.Collections.Generic;
namespace Markdig.Tests
{
[TestFixture]
public class TestDescendantsOrder
{
[Test]
public void TestSchemas()
{
foreach (var syntaxTree in TestParser.SpecsSyntaxTrees)
{
AssertIEnumerablesAreEqual(
Descendants_Legacy(syntaxTree),
syntaxTree.Descendants());
AssertIEnumerablesAreEqual(
syntaxTree.Descendants().OfType<ParagraphBlock>(),
syntaxTree.Descendants<ParagraphBlock>());
AssertIEnumerablesAreEqual(
syntaxTree.Descendants().OfType<ParagraphBlock>(),
(syntaxTree as ContainerBlock).Descendants<ParagraphBlock>());
AssertIEnumerablesAreEqual(
syntaxTree.Descendants().OfType<LiteralInline>(),
syntaxTree.Descendants<LiteralInline>());
foreach (LiteralInline literalInline in syntaxTree.Descendants<LiteralInline>())
{
Assert.AreSame(Array.Empty<ListBlock>(), literalInline.Descendants<ListBlock>());
Assert.AreSame(Array.Empty<ParagraphBlock>(), literalInline.Descendants<ParagraphBlock>());
Assert.AreSame(Array.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(Array.Empty<LiteralInline>(), containerInline.Descendants<LiteralInline>());
Assert.AreSame(Array.Empty<LiteralInline>(), containerInline.FindDescendants<LiteralInline>());
Assert.AreSame(Array.Empty<LiteralInline>(), (containerInline as MarkdownObject).Descendants<LiteralInline>());
}
Assert.AreSame(Array.Empty<ListBlock>(), containerInline.Descendants<ListBlock>());
Assert.AreSame(Array.Empty<ParagraphBlock>(), containerInline.Descendants<ParagraphBlock>());
}
foreach (ParagraphBlock paragraphBlock in syntaxTree.Descendants<ParagraphBlock>())
{
AssertIEnumerablesAreEqual(
(paragraphBlock as MarkdownObject).Descendants<LiteralInline>(),
paragraphBlock.Descendants<LiteralInline>());
Assert.AreSame(Array.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(Array.Empty<LiteralInline>(), containerBlock.Descendants<LiteralInline>());
Assert.AreSame(Array.Empty<LiteralInline>(), (containerBlock as Block).Descendants<LiteralInline>());
Assert.AreSame(Array.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;
}
}
}
}
}
}
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

@@ -1,168 +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("!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);
}
}
}
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

@@ -1,45 +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());
}
}
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

@@ -1,4 +1,4 @@
// 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.

View File

@@ -14,7 +14,7 @@ namespace Markdig.Tests
{
var inputTag = "<a>";
var text = new StringSlice(inputTag);
Assert.True(HtmlHelper.TryParseHtmlTag(text, out string outputTag));
Assert.True(HtmlHelper.TryParseHtmlTag(ref text, out string outputTag));
Assert.AreEqual(inputTag, outputTag);
}
@@ -23,7 +23,7 @@ namespace Markdig.Tests
{
var inputTag = "<a href='http://google.com'>";
var text = new StringSlice(inputTag);
Assert.True(HtmlHelper.TryParseHtmlTag(text, out string outputTag));
Assert.True(HtmlHelper.TryParseHtmlTag(ref text, out string outputTag));
Assert.AreEqual(inputTag, outputTag);
}
}

View File

@@ -1,25 +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);
}
}
}
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

@@ -2,7 +2,6 @@
// 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;

View File

@@ -2,7 +2,6 @@
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System.Security;
using NUnit.Framework;
using Markdig.Helpers;
using Markdig.Syntax;
@@ -16,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, out _));
Assert.AreEqual("toto", link);
Assert.AreEqual(' ', text.CurrentChar);
}
@@ -26,8 +24,7 @@ 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, out _));
Assert.AreEqual("http://google.com", link);
Assert.AreEqual(')', text.CurrentChar);
}
@@ -38,8 +35,7 @@ namespace Markdig.Tests
public void TestUrlTrailingFullStop(string uri)
{
var text = new StringSlice(uri);
string link;
Assert.True(LinkHelper.TryParseUrl(ref text, out link, true));
Assert.True(LinkHelper.TryParseUrl(ref text, out string link, out _, true));
Assert.AreEqual("http://google.com", link);
Assert.AreEqual('.', text.CurrentChar);
}
@@ -48,8 +44,7 @@ namespace Markdig.Tests
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, out _));
Assert.AreEqual("(toto)tutu(tata)", link);
Assert.AreEqual(' ', text.CurrentChar);
}
@@ -58,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, out _));
Assert.AreEqual("toto_tata_tutu", link);
Assert.AreEqual(' ', text.CurrentChar);
}
@@ -68,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, out _));
}
[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, out _));
Assert.AreEqual(@"tata\tutu'", title);
}
@@ -85,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, out _));
Assert.AreEqual(@"tata\tutu""", title);
Assert.AreEqual(' ', text.CurrentChar);
}
@@ -97,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);
@@ -114,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);
@@ -131,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);
@@ -150,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);
@@ -166,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);
@@ -184,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);
@@ -201,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);
}
@@ -213,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);
}
@@ -225,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);
}
@@ -235,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));
@@ -250,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);
}
@@ -263,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);
@@ -283,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);
}
@@ -294,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);
}
@@ -304,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));
@@ -327,9 +273,9 @@ namespace Markdig.Tests
[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));
public void TestUrilizeGfm(string input, string expectedResult)
{
Assert.AreEqual(expectedResult, LinkHelper.UrilizeAsGfm(input));
}
[TestCase("abc", "abc")]
@@ -421,9 +367,9 @@ namespace Markdig.Tests
}
[Test]
public void TestUnicodeInDomainNameOfLinkReferenceDefinition()
{
TestParser.TestSpec("[Foo]\n\n[Foo]: http://ünicode.com", "<p><a href=\"http://xn--nicode-2ya.com\">Foo</a></p>");
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

@@ -11,11 +11,14 @@ namespace Markdig.Tests
[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);
for (int i = 0; i < 5; i++)
{
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);
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]
@@ -24,49 +27,66 @@ namespace Markdig.Tests
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);
for (int i = 0; i < 5; i++)
{
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);
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);
for (int i = 0; i < 5; i++)
{
string 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();
var 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);
for (int i = 0; i < 5; i++)
{
_ = 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.GetStringBuilder().Length = 0;
}
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);
for (int i = 0; i < 5; i++)
{
_ = Markdown.ToHtml("This is a text with a https://link.tld/", writer, pipeline);
string html = writer.ToString();
Assert.AreEqual("<p>This is a text with a <a href=\"https://link.tld/\">https://link.tld/</a></p>\n", html);
writer.GetStringBuilder().Length = 0;
}
}
[Test]
public void TestConvert()
{
StringWriter writer = new StringWriter();
HtmlRenderer renderer = new HtmlRenderer(writer);
var writer = new StringWriter();
var 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);
for (int i = 0; i < 5; i++)
{
_ = 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.GetStringBuilder().Length = 0;
}
writer = new StringWriter();
renderer = new HtmlRenderer(writer);
@@ -74,9 +94,13 @@ namespace Markdig.Tests
.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);
for (int i = 0; i < 5; i++)
{
_ = Markdown.Convert("This is a text with a https://link.tld/", renderer, pipeline);
string html = writer.ToString();
Assert.AreEqual("<p>This is a text with a <a href=\"https://link.tld/\">https://link.tld/</a></p>\n", html);
writer.GetStringBuilder().Length = 0;
}
}
[Test]
@@ -88,61 +112,77 @@ namespace Markdig.Tests
.UsePreciseSourceLocation()
.Build();
MarkdownDocument document = Markdown.Parse(markdown, pipeline);
for (int i = 0; i < 5; i++)
{
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.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);
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);
for (int i = 0; i < 5; i++)
{
string normalized = Markdown.Normalize("Heading\n=======");
Assert.AreEqual("# Heading", normalized);
}
}
[Test]
public void TestNormalizeWithWriter()
{
StringWriter writer = new StringWriter();
for (int i = 0; i < 5; i++)
{
var writer = new StringWriter();
_ = Markdown.Normalize("Heading\n=======", writer);
string normalized = writer.ToString();
Assert.AreEqual("# Heading", normalized);
_ = 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);
for (int i = 0; i < 5; i++)
{
string plainText = Markdown.ToPlainText("*Hello*, [world](http://example.com)!");
Assert.AreEqual("Hello, world!\n", plainText);
}
}
[Test]
public void TestToPlainTextWithWriter()
{
StringWriter writer = new StringWriter();
for (int i = 0; i < 5; i++)
{
var writer = new StringWriter();
_ = Markdown.ToPlainText("*Hello*, [world](http://example.com)!", writer);
string plainText = writer.ToString();
Assert.AreEqual("Hello, world!\n", plainText);
_ = Markdown.ToPlainText("*Hello*, [world](http://example.com)!", writer);
string plainText = writer.ToString();
Assert.AreEqual("Hello, world!\n", plainText);
}
}
}
}

View File

@@ -15,14 +15,22 @@ namespace Markdig.Tests
.Build();
}
private MarkdownPipeline GetPipelineWithBootstrap(MediaOptions options = null)
{
return new MarkdownPipelineBuilder()
.UseBootstrap()
.UseMediaLinks(options)
.Build();
}
[Test]
[TestCase("![static mp4](https://sample.com/video.mp4)", "<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"https://sample.com/video.mp4\"></source></video></p>\n")]
[TestCase("![static mp4](//sample.com/video.mp4)", "<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"//sample.com/video.mp4\"></source></video></p>\n")]
[TestCase(@"![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
[TestCase("![yandex.ru](https://music.yandex.ru/album/411845/track/4402274)", "<p><iframe src=\"https://music.yandex.ru/iframe/#track/4402274/411845/\" width=\"500\" height=\"281\" class=\"yandex\" frameborder=\"0\"></iframe></p>\n")]
[TestCase("![vimeo](https://vimeo.com/8607834)", "<p><iframe src=\"https://player.vimeo.com/video/8607834\" width=\"500\" height=\"281\" class=\"vimeo\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
[TestCase("![ok.ru](https://ok.ru/video/26870090463)", "<p><iframe src=\"https://ok.ru/videoembed/26870090463\" width=\"500\" height=\"281\" class=\"odnoklassniki\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
[TestCase("![ok.ru](//ok.ru/video/26870090463)", "<p><iframe src=\"https://ok.ru/videoembed/26870090463\" width=\"500\" height=\"281\" class=\"odnoklassniki\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
[TestCase(@"![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
[TestCase("![yandex.ru](https://music.yandex.ru/album/411845/track/4402274)", "<p><iframe src=\"https://music.yandex.ru/iframe/#track/4402274/411845/\" class=\"yandex\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n")]
[TestCase("![vimeo](https://vimeo.com/8607834)", "<p><iframe src=\"https://player.vimeo.com/video/8607834\" class=\"vimeo\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
[TestCase("![ok.ru](https://ok.ru/video/26870090463)", "<p><iframe src=\"https://ok.ru/videoembed/26870090463\" class=\"odnoklassniki\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
[TestCase("![ok.ru](//ok.ru/video/26870090463)", "<p><iframe src=\"https://ok.ru/videoembed/26870090463\" class=\"odnoklassniki\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
public void TestBuiltInHosts(string markdown, string expected)
{
string html = Markdown.ToHtml(markdown, GetPipeline());
@@ -55,9 +63,9 @@ namespace Markdig.Tests
}
[Test]
[TestCase("![p1](https://sample.com/video.mp4)", "<p><iframe src=\"https://example.com/video.mp4\" width=\"500\" height=\"281\" class=\"regex\" frameborder=\"0\"></iframe></p>\n", @"^https?://sample.com/(.+)$", @"https://example.com/$1")]
[TestCase("![p1](//sample.com/video.mp4)", "<p><iframe src=\"https://example.com/video.mp4\" width=\"500\" height=\"281\" class=\"regex\" frameborder=\"0\"></iframe></p>\n", @"^//sample.com/(.+)$", @"https://example.com/$1")]
[TestCase("![p1](https://sample.com/video.mp4)", "<p><iframe src=\"https://example.com/video.mp4?token=aaabbb\" width=\"500\" height=\"281\" class=\"regex\" frameborder=\"0\"></iframe></p>\n", @"^https?://sample.com/(.+)$", @"https://example.com/$1?token=aaabbb")]
[TestCase("![p1](https://sample.com/video.mp4)", "<p><iframe src=\"https://example.com/video.mp4\" class=\"regex\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n", @"^https?://sample.com/(.+)$", @"https://example.com/$1")]
[TestCase("![p1](//sample.com/video.mp4)", "<p><iframe src=\"https://example.com/video.mp4\" class=\"regex\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n", @"^//sample.com/(.+)$", @"https://example.com/$1")]
[TestCase("![p1](https://sample.com/video.mp4)", "<p><iframe src=\"https://example.com/video.mp4?token=aaabbb\" class=\"regex\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n", @"^https?://sample.com/(.+)$", @"https://example.com/$1?token=aaabbb")]
public void TestCustomHostProvider(string markdown, string expected, string provider, string replace)
{
string html = Markdown.ToHtml(markdown, GetPipeline(new MediaOptions
@@ -72,9 +80,9 @@ namespace Markdig.Tests
[Test]
[TestCase("![static mp4](//sample.com/video.mp4)", "<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"//sample.com/video.mp4\"></source></video></p>\n", "")]
[TestCase(@"![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" class=\"youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n", "")]
[TestCase("![static mp4](//sample.com/video.mp4)", "<p><video width=\"500\" height=\"281\" controls=\"\" class=\"k\"><source type=\"video/mp4\" src=\"//sample.com/video.mp4\"></source></video></p>\n", "k")]
[TestCase(@"![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" class=\"k youtube\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n", "k")]
[TestCase(@"![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n", "")]
[TestCase("![static mp4](//sample.com/video.mp4)", "<p><video class=\"k\" width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"//sample.com/video.mp4\"></source></video></p>\n", "k")]
[TestCase(@"![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"k youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n", "k")]
public void TestCustomClass(string markdown, string expected, string klass)
{
string html = Markdown.ToHtml(markdown, GetPipeline(new MediaOptions
@@ -83,5 +91,14 @@ namespace Markdig.Tests
}));
Assert.AreEqual(html, expected);
}
[Test]
[TestCase("![static mp4](//sample.com/video.mp4)", "<p><video class=\"img-fluid\" width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"//sample.com/video.mp4\"></source></video></p>\n")]
[TestCase(@"![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"img-fluid youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n")]
public void TestWithBootstrap(string markdown, string expected)
{
string html = Markdown.ToHtml(markdown, GetPipelineWithBootstrap());
Assert.AreEqual(html, expected);
}
}
}

View File

@@ -0,0 +1,17 @@
using NUnit.Framework;
namespace Markdig.Tests
{
[TestFixture]
public class TestNewLine
{
[TestCase("a \nb", "<p>a<br />\nb</p>\n")]
[TestCase("a\\\nb", "<p>a<br />\nb</p>\n")]
[TestCase("a `b\nc`", "<p>a <code>b c</code></p>\n")]
public void Test(string value, string expectedHtml)
{
Assert.AreEqual(expectedHtml, Markdown.ToHtml(value));
Assert.AreEqual(expectedHtml, Markdown.ToHtml(value.Replace("\n", "\r\n")));
}
}
}

View File

@@ -21,7 +21,8 @@ namespace Markdig.Tests
AssertSyntax("````csharp\npublic void HelloWorld()\n{\n}\n````", new FencedCodeBlock(null)
{
FencedChar = '`',
FencedCharCount = 4,
OpeningFencedCharCount = 4,
ClosingFencedCharCount = 4,
Info = "csharp",
Lines = new StringLineGroup(4)
{

View File

@@ -1,190 +1,178 @@
// 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.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Markdig.Extensions.JiraLinks;
using Markdig.Syntax;
using NUnit.Framework;
namespace Markdig.Tests
{
public class TestParser
{
[Test]
public void EnsureSpecsAreUpToDate()
{
// In CI, SpecFileGen is guaranteed to run
if (IsContinuousIntegration)
return;
foreach (var specFilePath in SpecsFilePaths)
{
string testFilePath = Path.ChangeExtension(specFilePath, ".generated.cs");
Assert.True(File.Exists(testFilePath),
"A new specification file has been added. Add the spec to the list in SpecFileGen and regenerate the tests.");
DateTime specTime = File.GetLastWriteTimeUtc(specFilePath);
DateTime testTime = File.GetLastWriteTimeUtc(testFilePath);
// If file creation times aren't preserved by git, add some leeway
// If specs have come from git, assume that they were regenerated since CI would fail otherwise
testTime = testTime.AddMinutes(3);
// This might not catch a changed spec every time, but should at least sometimes. Otherwise CI will catch it
// This could also trigger, if a user has modified the spec file but reverted the change - can't think of a good workaround
Assert.Less(specTime, testTime,
$"{Path.GetFileName(specFilePath)} has been modified. Run SpecFileGen to regenerate the tests. " +
"If you have modified a specification file, but reverted all changes, ignore this error or revert the 'changed' timestamp metadata on the file.");
}
}
public static void TestSpec(string inputText, string expectedOutputText, string extensions = null, bool plainText = false)
{
foreach (var pipeline in GetPipeline(extensions))
{
Console.WriteLine($"Pipeline configured with extensions: {pipeline.Key}");
TestSpec(inputText, expectedOutputText, pipeline.Value, plainText);
}
}
public static void TestSpec(string inputText, string expectedOutputText, MarkdownPipeline pipeline, bool plainText = false)
{
// Uncomment this line to get more debug information for process inlines.
//pipeline.DebugLog = Console.Out;
var result = plainText ? Markdown.ToPlainText(inputText, pipeline) : Markdown.ToHtml(inputText, pipeline);
result = Compact(result);
expectedOutputText = Compact(expectedOutputText);
PrintAssertExpected(inputText, result, expectedOutputText);
}
public static void PrintAssertExpected(string source, string result, string expected)
{
Console.WriteLine("```````````````````Source");
Console.WriteLine(DisplaySpaceAndTabs(source));
Console.WriteLine("```````````````````Result");
Console.WriteLine(DisplaySpaceAndTabs(result));
Console.WriteLine("```````````````````Expected");
Console.WriteLine(DisplaySpaceAndTabs(expected));
Console.WriteLine("```````````````````");
Console.WriteLine();
TextAssert.AreEqual(expected, result);
}
public static IEnumerable<KeyValuePair<string, MarkdownPipeline>> GetPipeline(string extensionsGroupText)
{
// For the standard case, we make sure that both the CommmonMark core and Extra/Advanced are CommonMark compliant!
if (string.IsNullOrEmpty(extensionsGroupText))
{
yield return new KeyValuePair<string, MarkdownPipeline>("default", new MarkdownPipelineBuilder().Build());
yield return new KeyValuePair<string, MarkdownPipeline>("advanced", new MarkdownPipelineBuilder() // Use similar to advanced extension without auto-identifier
.UseAbbreviations()
//.UseAutoIdentifiers()
.UseCitations()
.UseCustomContainers()
.UseDefinitionLists()
.UseEmphasisExtras()
.UseFigures()
.UseFooters()
.UseFootnotes()
.UseGridTables()
.UseMathematics()
.UseMediaLinks()
.UsePipeTables()
.UseListExtras()
.UseGenericAttributes().Build());
yield break;
}
var extensionGroups = extensionsGroupText.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var extensionsText in extensionGroups)
{
var builder = new MarkdownPipelineBuilder();
builder.DebugLog = Console.Out;
if (extensionsText == "jiralinks")
{
builder.UseJiraLinks(new JiraLinkOptions("http://your.company.abc"));
}
else
{
builder = extensionsText == "self" ? builder.UseSelfPipeline() : builder.Configure(extensionsText);
}
yield return new KeyValuePair<string, MarkdownPipeline>(extensionsText, builder.Build());
}
}
public static string DisplaySpaceAndTabs(string text)
{
// Output special characters to check correctly the results
return text.Replace('\t', '→').Replace(' ', '·');
}
private static string Compact(string html)
{
// Normalize the output to make it compatible with CommonMark specs
html = html.Replace("\r\n", "\n").Replace(@"\r", @"\n").Trim();
html = Regex.Replace(html, @"\s+</li>", "</li>");
html = Regex.Replace(html, @"<li>\s+", "<li>");
html = html.Normalize(NormalizationForm.FormKD);
return html;
}
public static readonly bool IsContinuousIntegration = Environment.GetEnvironmentVariable("CI") != null;
public static readonly string TestsDirectory =
Path.GetFullPath(Path.Combine(Path.GetDirectoryName(typeof(TestParser).Assembly.Location), "../../.."));
/// <summary>
/// Contains absolute paths to specification markdown files (order is the same as in <see cref="SpecsMarkdown"/>)
/// </summary>
public static readonly string[] SpecsFilePaths;
/// <summary>
/// Contains the markdown source for specification files (order is the same as in <see cref="SpecsFilePaths"/>)
/// </summary>
public static readonly string[] SpecsMarkdown;
/// <summary>
/// Contains the markdown syntax tree for specification files (order is the same as in <see cref="SpecsFilePaths"/>)
/// </summary>
public static readonly MarkdownDocument[] SpecsSyntaxTrees;
static TestParser()
{
const string RunningInsideVisualStudioPath = "\\src\\.vs\\markdig\\";
int index = TestsDirectory.IndexOf(RunningInsideVisualStudioPath);
if (index != -1)
{
TestsDirectory = TestsDirectory.Substring(0, index) + "\\src\\Markdig.Tests";
}
SpecsFilePaths = Directory.GetDirectories(TestsDirectory)
.Where(dir => dir.EndsWith("Specs"))
.SelectMany(dir => Directory.GetFiles(dir)
.Where(file => file.EndsWith(".md", StringComparison.OrdinalIgnoreCase))
.Where(file => file.IndexOf("readme", StringComparison.OrdinalIgnoreCase) == -1))
.ToArray();
SpecsMarkdown = new string[SpecsFilePaths.Length];
SpecsSyntaxTrees = new MarkdownDocument[SpecsFilePaths.Length];
var pipeline = new MarkdownPipelineBuilder()
.UseAdvancedExtensions()
.Build();
for (int i = 0; i < SpecsFilePaths.Length; i++)
{
string markdown = SpecsMarkdown[i] = File.ReadAllText(SpecsFilePaths[i]);
SpecsSyntaxTrees[i] = Markdown.Parse(markdown, pipeline);
}
}
}
// 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.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Markdig.Extensions.JiraLinks;
using Markdig.Syntax;
using NUnit.Framework;
namespace Markdig.Tests
{
public class TestParser
{
[Test]
public void EnsureSpecsAreUpToDate()
{
// In CI, SpecFileGen is guaranteed to run
if (IsContinuousIntegration)
return;
var specsFilePaths = Directory.GetDirectories(TestsDirectory)
.Where(dir => dir.EndsWith("Specs"))
.SelectMany(dir => Directory.GetFiles(dir)
.Where(file => file.EndsWith(".md", StringComparison.OrdinalIgnoreCase))
.Where(file => file.IndexOf("readme", StringComparison.OrdinalIgnoreCase) == -1))
.ToArray();
var specsMarkdown = new string[specsFilePaths.Length];
var specsSyntaxTrees = new MarkdownDocument[specsFilePaths.Length];
var pipeline = new MarkdownPipelineBuilder()
.UseAdvancedExtensions()
.Build();
for (int i = 0; i < specsFilePaths.Length; i++)
{
string markdown = specsMarkdown[i] = File.ReadAllText(specsFilePaths[i]);
specsSyntaxTrees[i] = Markdown.Parse(markdown, pipeline);
}
foreach (var specFilePath in specsFilePaths)
{
string testFilePath = Path.ChangeExtension(specFilePath, ".generated.cs");
Assert.True(File.Exists(testFilePath),
"A new specification file has been added. Add the spec to the list in SpecFileGen and regenerate the tests.");
DateTime specTime = File.GetLastWriteTimeUtc(specFilePath);
DateTime testTime = File.GetLastWriteTimeUtc(testFilePath);
// If file creation times aren't preserved by git, add some leeway
// If specs have come from git, assume that they were regenerated since CI would fail otherwise
testTime = testTime.AddMinutes(3);
// This might not catch a changed spec every time, but should at least sometimes. Otherwise CI will catch it
// This could also trigger, if a user has modified the spec file but reverted the change - can't think of a good workaround
Assert.Less(specTime, testTime,
$"{Path.GetFileName(specFilePath)} has been modified. Run SpecFileGen to regenerate the tests. " +
"If you have modified a specification file, but reverted all changes, ignore this error or revert the 'changed' timestamp metadata on the file.");
}
TestDescendantsOrder.TestSchemas(specsSyntaxTrees);
}
public static void TestSpec(string inputText, string expectedOutputText, string extensions = null, bool plainText = false)
{
foreach (var pipeline in GetPipeline(extensions))
{
Console.WriteLine($"Pipeline configured with extensions: {pipeline.Key}");
TestSpec(inputText, expectedOutputText, pipeline.Value, plainText);
}
}
public static void TestSpec(string inputText, string expectedOutputText, MarkdownPipeline pipeline, bool plainText = false)
{
// Uncomment this line to get more debug information for process inlines.
//pipeline.DebugLog = Console.Out;
var result = plainText ? Markdown.ToPlainText(inputText, pipeline) : Markdown.ToHtml(inputText, pipeline);
result = Compact(result);
expectedOutputText = Compact(expectedOutputText);
PrintAssertExpected(inputText, result, expectedOutputText);
}
public static void PrintAssertExpected(string source, string result, string expected)
{
Console.WriteLine("```````````````````Source");
Console.WriteLine(DisplaySpaceAndTabs(source));
Console.WriteLine("```````````````````Result");
Console.WriteLine(DisplaySpaceAndTabs(result));
Console.WriteLine("```````````````````Expected");
Console.WriteLine(DisplaySpaceAndTabs(expected));
Console.WriteLine("```````````````````");
Console.WriteLine();
TextAssert.AreEqual(expected, result);
}
public static IEnumerable<KeyValuePair<string, MarkdownPipeline>> GetPipeline(string extensionsGroupText)
{
// For the standard case, we make sure that both the CommmonMark core and Extra/Advanced are CommonMark compliant!
if (string.IsNullOrEmpty(extensionsGroupText))
{
yield return new KeyValuePair<string, MarkdownPipeline>("default", new MarkdownPipelineBuilder().Build());
yield return new KeyValuePair<string, MarkdownPipeline>("advanced", new MarkdownPipelineBuilder() // Use similar to advanced extension without auto-identifier
.UseAbbreviations()
//.UseAutoIdentifiers()
.UseCitations()
.UseCustomContainers()
.UseDefinitionLists()
.UseEmphasisExtras()
.UseFigures()
.UseFooters()
.UseFootnotes()
.UseGridTables()
.UseMathematics()
.UseMediaLinks()
.UsePipeTables()
.UseListExtras()
.UseGenericAttributes().Build());
yield break;
}
var extensionGroups = extensionsGroupText.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var extensionsText in extensionGroups)
{
var builder = new MarkdownPipelineBuilder();
builder.DebugLog = Console.Out;
if (extensionsText == "jiralinks")
{
builder.UseJiraLinks(new JiraLinkOptions("http://your.company.abc"));
}
else
{
builder = extensionsText == "self" ? builder.UseSelfPipeline() : builder.Configure(extensionsText);
}
yield return new KeyValuePair<string, MarkdownPipeline>(extensionsText, builder.Build());
}
}
public static string DisplaySpaceAndTabs(string text)
{
// Output special characters to check correctly the results
return text.Replace('\t', '→').Replace(' ', '·');
}
private static string Compact(string html)
{
// Normalize the output to make it compatible with CommonMark specs
html = html.Replace("\r\n", "\n").Replace(@"\r", @"\n").Trim();
html = Regex.Replace(html, @"\s+</li>", "</li>");
html = Regex.Replace(html, @"<li>\s+", "<li>");
html = html.Normalize(NormalizationForm.FormKD);
return html;
}
public static readonly bool IsContinuousIntegration = Environment.GetEnvironmentVariable("CI") != null;
public static readonly string TestsDirectory = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(typeof(TestParser).Assembly.Location), "../../.."));
static TestParser()
{
const string RunningInsideVisualStudioPath = "\\src\\.vs\\markdig\\";
int index = TestsDirectory.IndexOf(RunningInsideVisualStudioPath);
if (index != -1)
{
TestsDirectory = TestsDirectory.Substring(0, index) + "\\src\\Markdig.Tests";
}
}
}
}

View File

@@ -0,0 +1,26 @@
using Markdig.Extensions.Tables;
using Markdig.Syntax;
using NUnit.Framework;
using System.Linq;
namespace Markdig.Tests
{
[TestFixture]
public sealed class TestPipeTable
{
[TestCase("| S | T |\r\n|---|---| \r\n| G | H |")]
[TestCase("| S | T |\r\n|---|---|\t\r\n| G | H |")]
[TestCase("| S | T |\r\n|---|---|\v\r\n| G | H |")]
[TestCase("| S | T |\r\n|---|---|\f\r\n| G | H |")]
[TestCase("| S | T |\r\n|---|---|\f\v\t \r\n| G | H |")]
[TestCase("| S | \r\n|---|\r\n| G |\r\n\r\n| D | D |\r\n| ---| ---| \r\n| V | V |", 2)]
public void TestTableBug(string markdown, int tableCount = 1)
{
MarkdownDocument document = Markdown.Parse(markdown, new MarkdownPipelineBuilder().UseAdvancedExtensions().Build());
Table[] tables = document.Descendants().OfType<Table>().ToArray();
Assert.AreEqual(tableCount, tables.Length);
}
}
}

View File

@@ -21,6 +21,7 @@ namespace Markdig.Tests
[TestCase(/* markdownText: */ "- foo\n- bar\n- baz", /* expected: */ "foo\nbar\nbaz\n")]
[TestCase(/* markdownText: */ "- foo<baz", /* expected: */ "foo<baz\n")]
[TestCase(/* markdownText: */ "- foo&lt;baz", /* expected: */ "foo<baz\n")]
[TestCase(/* markdownText: */ "## foo `bar::baz >`", /* expected: */ "foo bar::baz >\n")]
public void TestPlainEnsureNewLine(string markdownText, string expected)
{
var actual = Markdown.ToPlainText(markdownText);
@@ -35,9 +36,9 @@ namespace Markdig.Tests
TestParser.TestSpec(markdownText, expected, extensions, plainText: true);
}
public static void TestSpec(string markdownText, string expected, string extensions)
{
TestParser.TestSpec(markdownText, expected, extensions, plainText: true);
public static void TestSpec(string markdownText, string expected, string extensions)
{
TestParser.TestSpec(markdownText, expected, extensions, plainText: true);
}
}
}

View File

@@ -12,6 +12,16 @@ namespace Markdig.Tests
[TestFixture]
public class TestPlayParser
{
[Test]
public void TestLinksWithCarriageReturn()
{
{
var text = "[Link 1][link-1], [link 2][link-2].\r\n\r\n[link-1]: https://example.com\r\n[link-2]: https://example.com";
var result = Markdown.ToHtml(text).TrimEnd();
Assert.AreEqual("<p><a href=\"https://example.com\">Link 1</a>, <a href=\"https://example.com\">link 2</a>.</p>", result);
}
}
[Test]
public void TestLink()
{

View File

@@ -2,7 +2,6 @@
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using Markdig.Renderers;
using Markdig.Syntax;
using NUnit.Framework;

View File

@@ -0,0 +1,57 @@
using NUnit.Framework;
namespace Markdig.Tests
{
[TestFixture]
public class TestReferralLinks
{
[Test]
public void TestLinksWithNoFollowRel()
{
var markdown = "[world](http://example.com)";
var expected = "nofollow";
#pragma warning disable 0618
var pipeline = new MarkdownPipelineBuilder()
.UseNoFollowLinks()
#pragma warning restore 0618
.Build();
var html = Markdown.ToHtml(markdown, pipeline);
Assert.That(html, Contains.Substring($"rel=\"{expected}\""));
}
[Test]
[TestCase(new[] { "nofollow" }, "nofollow")]
[TestCase(new[] { "noopener" }, "noopener")]
[TestCase(new[] { "nofollow", "noopener"}, "nofollow noopener")]
public void TestLinksWithCustomRel(string[] rels, string expected)
{
var markdown = "[world](http://example.com)";
var pipeline = new MarkdownPipelineBuilder()
.UseReferralLinks(rels)
.Build();
var html = Markdown.ToHtml(markdown, pipeline);
Assert.That(html, Contains.Substring($"rel=\"{expected}\""));
}
[Test]
[TestCase(new[] { "noopener" }, "noopener")]
[TestCase(new[] { "nofollow" }, "nofollow")]
[TestCase(new[] { "nofollow", "noopener" }, "nofollow noopener")]
public void TestAutoLinksWithCustomRel(string[] rels, string expected)
{
var markdown = "http://example.com";
var pipeline = new MarkdownPipelineBuilder()
.UseAutoLinks()
.UseReferralLinks(rels)
.Build();
var html = Markdown.ToHtml(markdown, pipeline);
Assert.That(html, Contains.Substring($"rel=\"{expected}\""));
}
}
}

View File

@@ -0,0 +1,30 @@
using Markdig.Renderers.Roundtrip;
using Markdig.Syntax;
using NUnit.Framework;
using System.IO;
namespace Markdig.Tests
{
internal static class TestRoundtrip
{
internal static void TestSpec(string markdownText, string expected, string extensions)
{
RoundTrip(markdownText);
}
internal static void RoundTrip(string markdown)
{
var pipelineBuilder = new MarkdownPipelineBuilder();
pipelineBuilder.EnableTrackTrivia();
MarkdownPipeline pipeline = pipelineBuilder.Build();
MarkdownDocument markdownDocument = Markdown.Parse(markdown, pipeline);
var sw = new StringWriter();
var nr = new RoundtripRenderer(sw);
nr.Write(markdownDocument);
var result = sw.ToString();
Assert.AreEqual(markdown, result);
}
}
}

View File

@@ -140,48 +140,48 @@ literal ( 0, 2) 2-3
emphasis ( 0, 4) 4-9
literal ( 0, 6) 6-7
");
}
}
[Test]
public void TestFootnoteLinkReferenceDefinition()
public void TestFootnoteLinkReferenceDefinition()
{
// 01 2 345678
var footnote = Markdown.Parse("0\n\n [^1]:", new MarkdownPipelineBuilder().UsePreciseSourceLocation().UseFootnotes().Build()).Descendants<FootnoteLinkReferenceDefinition>().FirstOrDefault();
Assert.NotNull(footnote);
Assert.AreEqual(2, footnote.Line);
Assert.NotNull(footnote);
Assert.AreEqual(2, footnote.Line);
Assert.AreEqual(new SourceSpan(4, 7), footnote.Span);
Assert.AreEqual(new SourceSpan(5, 6), footnote.LabelSpan);
}
Assert.AreEqual(new SourceSpan(5, 6), footnote.LabelSpan);
}
[Test]
public void TestLinkReferenceDefinition1()
public void TestLinkReferenceDefinition1()
{
// 0 1
// 0123456789012345
var link = Markdown.Parse("[234]: /56 'yo' ", new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants<LinkReferenceDefinition>().FirstOrDefault();
Assert.NotNull(link);
Assert.AreEqual(0, link.Line);
Assert.NotNull(link);
Assert.AreEqual(0, link.Line);
Assert.AreEqual(new SourceSpan(0, 14), link.Span);
Assert.AreEqual(new SourceSpan(1, 3), link.LabelSpan);
Assert.AreEqual(new SourceSpan(7, 9), link.UrlSpan);
Assert.AreEqual(new SourceSpan(11, 14), link.TitleSpan);
Assert.AreEqual(new SourceSpan(11, 14), link.TitleSpan);
}
[Test]
public void TestLinkReferenceDefinition2()
public void TestLinkReferenceDefinition2()
{
// 0 1
// 01 2 34567890123456789
var link = Markdown.Parse("0\n\n [234]: /56 'yo' ", new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants<LinkReferenceDefinition>().FirstOrDefault();
Assert.NotNull(link);
Assert.AreEqual(2, link.Line);
Assert.NotNull(link);
Assert.AreEqual(2, link.Line);
Assert.AreEqual(new SourceSpan(4, 18), link.Span);
Assert.AreEqual(new SourceSpan(5, 7), link.LabelSpan);
Assert.AreEqual(new SourceSpan(11, 13), link.UrlSpan);
Assert.AreEqual(new SourceSpan(15, 18), link.TitleSpan);
Assert.AreEqual(new SourceSpan(15, 18), link.TitleSpan);
}
[Test]
@@ -395,42 +395,42 @@ listitem ( 1, 0) 4-6
paragraph ( 1, 2) 6-6
literal ( 1, 2) 6-6
");
}
}
[Test]
public void TestListBlock2()
public void TestListBlock2()
{
string test = @"
1. Foo
9. Bar
5. Foo
6. Bar
1. Foo
9. Bar
5. Foo
6. Bar
987123. FooBar";
test = test.Replace("\r\n", "\n");
var list = Markdown.Parse(test, new MarkdownPipelineBuilder().UsePreciseSourceLocation().Build()).Descendants<ListBlock>().FirstOrDefault();
Assert.NotNull(list);
Assert.AreEqual(1, list.Line);
Assert.True(list.IsOrdered);
List<ListItemBlock> items = list.Cast<ListItemBlock>().ToList();
Assert.AreEqual(5, items.Count);
// Test orders
Assert.AreEqual(1, items[0].Order);
Assert.NotNull(list);
Assert.AreEqual(1, list.Line);
Assert.True(list.IsOrdered);
List<ListItemBlock> items = list.Cast<ListItemBlock>().ToList();
Assert.AreEqual(5, items.Count);
// Test orders
Assert.AreEqual(1, items[0].Order);
Assert.AreEqual(9, items[1].Order);
Assert.AreEqual(5, items[2].Order);
Assert.AreEqual(6, items[3].Order);
Assert.AreEqual(987123, items[4].Order);
// Test positions
for (int i = 0; i < 4; i++)
{
Assert.AreEqual(i + 1, items[i].Line);
Assert.AreEqual(1 + (i * 7), items[i].Span.Start);
Assert.AreEqual(6, items[i].Span.Length);
}
Assert.AreEqual(5, items[4].Line);
Assert.AreEqual(new SourceSpan(29, 42), items[4].Span);
Assert.AreEqual(987123, items[4].Order);
// Test positions
for (int i = 0; i < 4; i++)
{
Assert.AreEqual(i + 1, items[i].Line);
Assert.AreEqual(1 + (i * 7), items[i].Span.Start);
Assert.AreEqual(6, items[i].Span.Length);
}
Assert.AreEqual(5, items[4].Line);
Assert.AreEqual(new SourceSpan(29, 42), items[4].Span);
}
[Test]

View File

@@ -1,8 +1,6 @@
using NUnit.Framework;
using System.Collections.Generic;
using System.Text;
using Markdig.Helpers;
using Markdig.Syntax;
using System;
namespace Markdig.Tests
@@ -18,8 +16,8 @@ namespace Markdig.Tests
{
var text = new StringLineGroup(4)
{
new StringSlice("ABC"),
new StringSlice("E"),
new StringSlice("ABC", NewLine.LineFeed),
new StringSlice("E", NewLine.LineFeed),
new StringSlice("F")
};
@@ -37,8 +35,8 @@ namespace Markdig.Tests
{
var text = new StringLineGroup(4)
{
new StringSlice("XABC") { Start = 1},
new StringSlice("YYE") { Start = 2},
new StringSlice("XABC", NewLine.LineFeed) { Start = 1},
new StringSlice("YYE", NewLine.LineFeed) { Start = 2},
new StringSlice("ZZZF") { Start = 3 }
};
@@ -63,7 +61,7 @@ namespace Markdig.Tests
{
var text = new StringLineGroup(4)
{
new StringSlice("ABCD"),
new StringSlice("ABCD", NewLine.LineFeed),
new StringSlice("EF"),
}.ToCharIterator();
@@ -101,7 +99,7 @@ namespace Markdig.Tests
[Test]
public void TestStringLineGroupWithModifiedStart()
{
var line1 = new StringSlice(" ABC");
var line1 = new StringSlice(" ABC", NewLine.LineFeed);
line1.NextChar();
line1.NextChar();
@@ -117,7 +115,7 @@ namespace Markdig.Tests
[Test]
public void TestStringLineGroupWithTrim()
{
var line1 = new StringSlice(" ABC ");
var line1 = new StringSlice(" ABC ", NewLine.LineFeed);
line1.NextChar();
line1.NextChar();
@@ -135,8 +133,8 @@ namespace Markdig.Tests
{
var iterator = new StringLineGroup(4)
{
new StringSlice("ABC"),
new StringSlice("E"),
new StringSlice("ABC", NewLine.LineFeed),
new StringSlice("E", NewLine.LineFeed),
new StringSlice("F")
}.ToCharIterator();
@@ -155,5 +153,33 @@ namespace Markdig.Tests
Assert.Throws<ArgumentOutOfRangeException>(() => iterator.PeekChar(-1));
}
[Test]
public void TestIteratorSkipChar()
{
var lineGroup = new StringLineGroup(4)
{
new StringSlice("ABC", NewLine.LineFeed),
new StringSlice("E", NewLine.LineFeed)
};
Test(lineGroup.ToCharIterator());
Test(new StringSlice("ABC\nE\n"));
Test(new StringSlice("Foo\nABC\nE\n", 4, 9));
static void Test<T>(T iterator) where T : ICharIterator
{
Assert.AreEqual('A', iterator.CurrentChar); iterator.SkipChar();
Assert.AreEqual('B', iterator.CurrentChar); iterator.SkipChar();
Assert.AreEqual('C', iterator.CurrentChar); iterator.SkipChar();
Assert.AreEqual('\n', iterator.CurrentChar); iterator.SkipChar();
Assert.AreEqual('E', iterator.CurrentChar); iterator.SkipChar();
Assert.AreEqual('\n', iterator.CurrentChar); iterator.SkipChar();
Assert.AreEqual('\0', iterator.CurrentChar); iterator.SkipChar();
Assert.AreEqual('\0', iterator.CurrentChar); iterator.SkipChar();
}
}
}
}

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