mirror of
https://github.com/xoofx/markdig.git
synced 2026-02-09 21:42:15 +00:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
751c79fce4 | ||
|
|
4dc8cc3977 | ||
|
|
a1891e2984 | ||
|
|
ff0637993c | ||
|
|
8b64ce456f | ||
|
|
a781ae1e5b | ||
|
|
2e5007241d | ||
|
|
cf6d98b7f8 | ||
|
|
ccb7e8edfa | ||
|
|
db25c1db43 | ||
|
|
5db90ede4b | ||
|
|
fef1ad3563 | ||
|
|
e9302d93bd | ||
|
|
4704c49fbf | ||
|
|
aca70e5c9a | ||
|
|
da5eff075d | ||
|
|
971207e942 | ||
|
|
fb942f9810 | ||
|
|
25a227fffd | ||
|
|
2be8cd4aa7 | ||
|
|
569b80befe | ||
|
|
0b8b14490e | ||
|
|
c59fd5c651 | ||
|
|
4893e2b177 | ||
|
|
b30b219237 | ||
|
|
d6c627aa88 | ||
|
|
a26f4298a4 | ||
|
|
d5b80f6a7b | ||
|
|
98d747c839 |
9
.github/workflows/ci.yml
vendored
9
.github/workflows/ci.yml
vendored
@@ -22,8 +22,6 @@ jobs:
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 3.0.100
|
||||
|
||||
- name: Build (Release)
|
||||
run: dotnet build src -c Release
|
||||
@@ -38,18 +36,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 netcoreapp3.1 /p:Include=\"[${{env.PROJECT_NAME}}]*\" /p:CollectCoverage=true /p:CoverletOutputFormat=lcov
|
||||
|
||||
- name: Coveralls Upload
|
||||
uses: coverallsapp/github-action@v1.0.1
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path-to-lcov: src/${{env.PROJECT_NAME}}.Tests/coverage.netcoreapp2.1.info
|
||||
path-to-lcov: src/${{env.PROJECT_NAME}}.Tests/coverage.netcoreapp3.1.info
|
||||
|
||||
- name: Pack
|
||||
run: dotnet pack src -c Release
|
||||
|
||||
- name: Pack Signed
|
||||
run: dotnet pack -c Release src/${{env.PROJECT_NAME}}.Signed/${{env.PROJECT_NAME}}.Signed.csproj
|
||||
|
||||
- name: Publish
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
|
||||
10
changelog.md
10
changelog.md
@@ -1,5 +1,15 @@
|
||||
# Changelog
|
||||
|
||||
## 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)
|
||||
|
||||
@@ -94,6 +94,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
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net452;netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFrameworks>netcoreapp3.1</TargetFrameworks>
|
||||
<OutputType>Exe</OutputType>
|
||||
<IsPackable>false</IsPackable>
|
||||
<StartupObject>Markdig.Tests.Program</StartupObject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.msbuild" Version="2.8.1">
|
||||
<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.0.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,9 +40,9 @@ Text after two newlines
|
||||
Heading
|
||||
=======
|
||||
|
||||
Text after two newlines
|
||||
Text after two newlines 1
|
||||
.
|
||||
# Heading
|
||||
|
||||
Text after two newlines
|
||||
Text after two newlines 1
|
||||
````````````````````````````````
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Sample
|
||||
|
||||
19
src/Markdig.Tests/Program.cs
Normal file
19
src/Markdig.Tests/Program.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-05-15 02:46:55
|
||||
|
||||
// --------------------------------
|
||||
// Abbreviations
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Auto Identifiers
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2020-07-21 22:02:10
|
||||
|
||||
// --------------------------------
|
||||
// Auto Links
|
||||
@@ -61,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):
|
||||
|
||||
@@ -33,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):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-15 05:23:49
|
||||
|
||||
// --------------------------------
|
||||
// Bootstrap
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Custom Containers
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-15 05:06:35
|
||||
|
||||
// --------------------------------
|
||||
// Definition Lists
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Diagrams
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2020-01-13 21:08:58
|
||||
|
||||
// --------------------------------
|
||||
// Emoji
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Emphasis Extra
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Figures, Footers and Cites
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-15 05:33:49
|
||||
|
||||
// --------------------------------
|
||||
// Footnotes
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-08-01 13:57:17
|
||||
|
||||
// --------------------------------
|
||||
// Generic Attributes
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-15 05:25:26
|
||||
|
||||
// --------------------------------
|
||||
// Globalization
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2020-04-20 07:21:20
|
||||
|
||||
// --------------------------------
|
||||
// Grid Tables
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Hardline Breaks
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-15 05:30:00
|
||||
|
||||
// --------------------------------
|
||||
// Jira Links
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// List Extras
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Math
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2020-05-12 19:59:34
|
||||
|
||||
// --------------------------------
|
||||
// Media
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// No Html
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2020-07-30 15:47:38
|
||||
|
||||
// --------------------------------
|
||||
// GFM Pipe Tables
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2020-07-30 15:32:13
|
||||
|
||||
// --------------------------------
|
||||
// Pipe Tables
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-08-01 12:33:23
|
||||
|
||||
// --------------------------------
|
||||
// Smarty Pants
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Task Lists
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Yaml
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
41
src/Markdig.Tests/TestContainerInlines.cs
Normal file
41
src/Markdig.Tests/TestContainerInlines.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,9 @@ namespace Markdig.Tests
|
||||
[TestFixture]
|
||||
public class TestDescendantsOrder
|
||||
{
|
||||
[Test]
|
||||
public void TestSchemas()
|
||||
public static void TestSchemas(MarkdownDocument[] specsSyntaxTrees)
|
||||
{
|
||||
foreach (var syntaxTree in TestParser.SpecsSyntaxTrees)
|
||||
foreach (var syntaxTree in specsSyntaxTrees)
|
||||
{
|
||||
AssertIEnumerablesAreEqual(
|
||||
Descendants_Legacy(syntaxTree),
|
||||
|
||||
@@ -124,6 +124,7 @@ namespace Markdig.Tests
|
||||
[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>&<em>foo</em>")]
|
||||
[TestCase("!1!", "!1!")]
|
||||
[TestCase("!!2!!", "<warning>2</warning>")]
|
||||
[TestCase("!!!3!!!", "<error>3</error>")]
|
||||
|
||||
@@ -22,7 +22,27 @@ namespace Markdig.Tests
|
||||
if (IsContinuousIntegration)
|
||||
return;
|
||||
|
||||
foreach (var specFilePath in SpecsFilePaths)
|
||||
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");
|
||||
|
||||
@@ -43,6 +63,8 @@ namespace Markdig.Tests
|
||||
$"{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)
|
||||
@@ -141,21 +163,7 @@ namespace Markdig.Tests
|
||||
|
||||
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;
|
||||
public static readonly string TestsDirectory = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(typeof(TestParser).Assembly.Location), "../../.."));
|
||||
|
||||
static TestParser()
|
||||
{
|
||||
@@ -165,26 +173,6 @@ namespace Markdig.Tests
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,6 +147,12 @@ namespace Markdig.Extensions.AutoLinks
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (string.Equals(link, "tel", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
int atIndex = link.IndexOf('@');
|
||||
if (atIndex == -1 ||
|
||||
|
||||
@@ -168,9 +168,7 @@ namespace Markdig.Helpers
|
||||
return IsZero(c) || IsWhitespace(c);
|
||||
}
|
||||
|
||||
// Note that we are not considering the character & as a punctuation in HTML
|
||||
// as it is used for HTML entities, print unicode, so we assume that when we have a `&`
|
||||
// it is more likely followed by a valid HTML Entity that represents a non punctuation
|
||||
// Check if a char is a space or a punctuation
|
||||
public static void CheckUnicodeCategory(this char c, out bool space, out bool punctuation)
|
||||
{
|
||||
// Credits: code from CommonMark.NET
|
||||
@@ -179,7 +177,7 @@ namespace Markdig.Helpers
|
||||
if (c <= 'ÿ')
|
||||
{
|
||||
space = c == '\0' || c == ' ' || (c >= '\t' && c <= '\r') || c == '\u00a0' || c == '\u0085';
|
||||
punctuation = c == '\0' || (c >= 33 && c <= 47 && c != 38) || (c >= 58 && c <= 64) || (c >= 91 && c <= 96) || (c >= 123 && c <= 126);
|
||||
punctuation = c == '\0' || (c >= 33 && c <= 47) || (c >= 58 && c <= 64) || (c >= 91 && c <= 96) || (c >= 123 && c <= 126);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<Description>A fast, powerful, CommonMark compliant, extensible Markdown processor for .NET with 20+ builtin extensions (pipetables, footnotes, definition lists... etc.)</Description>
|
||||
<Copyright>Alexandre Mutel</Copyright>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<VersionPrefix>0.21.0</VersionPrefix>
|
||||
<VersionPrefix>0.22.0</VersionPrefix>
|
||||
<Authors>Alexandre Mutel</Authors>
|
||||
<TargetFrameworks>net452;netstandard2.0;netstandard2.1;netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
|
||||
<PackageTags>Markdown CommonMark md html md2html</PackageTags>
|
||||
|
||||
@@ -150,6 +150,11 @@ namespace Markdig.Parsers
|
||||
/// Gets the character position before the indent occurred.
|
||||
/// </summary>
|
||||
public int StartBeforeIndent { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean indicating whether the current line being parsed is lazy continuation.
|
||||
/// </summary>
|
||||
public bool IsLazy { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current stack of <see cref="Block"/> being processed.
|
||||
@@ -577,6 +582,8 @@ namespace Markdig.Parsers
|
||||
/// </exception>
|
||||
private void TryContinueBlocks()
|
||||
{
|
||||
IsLazy = false;
|
||||
|
||||
// Set all blocks non opened.
|
||||
// They will be marked as open in the following loop
|
||||
for (int i = 1; i < OpenedBlocks.Count; i++)
|
||||
@@ -712,6 +719,7 @@ namespace Markdig.Parsers
|
||||
{
|
||||
for (int j = 0; j < parsers.Length; j++)
|
||||
{
|
||||
IsLazy = false;
|
||||
var blockParser = parsers[j];
|
||||
if (Line.IsEmpty)
|
||||
{
|
||||
@@ -731,9 +739,9 @@ namespace Markdig.Parsers
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isLazyParagraph = blockParser is ParagraphBlockParser && lastBlock is ParagraphBlock;
|
||||
IsLazy = blockParser is ParagraphBlockParser && lastBlock is ParagraphBlock;
|
||||
|
||||
var result = isLazyParagraph
|
||||
var result = IsLazy
|
||||
? blockParser.TryContinue(this, lastBlock)
|
||||
: blockParser.TryOpen(this);
|
||||
|
||||
@@ -741,7 +749,7 @@ namespace Markdig.Parsers
|
||||
{
|
||||
// If we have reached a blank line after trying to parse a paragraph
|
||||
// we can ignore it
|
||||
if (isLazyParagraph && IsBlankLine)
|
||||
if (IsLazy && IsBlankLine)
|
||||
{
|
||||
ContinueProcessingLine = false;
|
||||
break;
|
||||
@@ -752,7 +760,7 @@ namespace Markdig.Parsers
|
||||
// Special case for paragraph
|
||||
UpdateLastBlockAndContainer();
|
||||
|
||||
if (isLazyParagraph && CurrentBlock is ParagraphBlock paragraph)
|
||||
if (IsLazy && CurrentBlock is ParagraphBlock paragraph)
|
||||
{
|
||||
Debug.Assert(NewBlocks.Count == 0);
|
||||
|
||||
@@ -782,6 +790,8 @@ namespace Markdig.Parsers
|
||||
|
||||
// We have a leaf node, we can stop
|
||||
}
|
||||
|
||||
IsLazy = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Markdig.Parsers
|
||||
return BlockState.BreakDiscard;
|
||||
}
|
||||
|
||||
if (ParseSetexHeadings && !processor.IsCodeIndent && !(block.Parent is QuoteBlock))
|
||||
if (!processor.IsCodeIndent && ParseSetexHeadings)
|
||||
{
|
||||
return TryParseSetexHeading(processor, block);
|
||||
}
|
||||
@@ -86,7 +86,11 @@ namespace Markdig.Parsers
|
||||
|
||||
// If we matched a LinkReferenceDefinition before matching the heading, and the remaining
|
||||
// lines are empty, we can early exit and remove the paragraph
|
||||
if (!(TryMatchLinkReferenceDefinition(ref paragraph.Lines, state) && paragraph.Lines.Count == 0))
|
||||
var parent = block.Parent;
|
||||
|
||||
bool isSetTextHeading = !state.IsLazy || paragraph.Column == state.Column || !(parent is QuoteBlock || parent is ListItemBlock);
|
||||
|
||||
if (!(TryMatchLinkReferenceDefinition(ref paragraph.Lines, state) && paragraph.Lines.Count == 0) && isSetTextHeading)
|
||||
{
|
||||
// We discard the paragraph that will be transformed to a heading
|
||||
state.Discard(paragraph);
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace Markdig.Parsers
|
||||
if (isSetexHeading)
|
||||
{
|
||||
var parent = previousParagraph.Parent;
|
||||
if (parent is QuoteBlock || (parent is ListItemBlock && previousParagraph.Column != processor.Column))
|
||||
if (previousParagraph.Column != processor.Column && (parent is QuoteBlock || parent is ListItemBlock))
|
||||
{
|
||||
isSetexHeading = false;
|
||||
}
|
||||
|
||||
@@ -216,6 +216,18 @@ namespace Markdig.Syntax
|
||||
set
|
||||
{
|
||||
if ((uint)index >= (uint)Count) ThrowHelper.ThrowIndexOutOfRangeException();
|
||||
|
||||
if (value == null)
|
||||
ThrowHelper.ArgumentNullException_item();
|
||||
|
||||
if (value.Parent != null)
|
||||
ThrowHelper.ArgumentException("Cannot add this block as it as already attached to another container (block.Parent != null)");
|
||||
|
||||
var existingChild = children[index];
|
||||
if (existingChild != null)
|
||||
existingChild.Parent = null;
|
||||
|
||||
value.Parent = this;
|
||||
children[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@ namespace Markdig.Syntax.Inlines
|
||||
/// <seealso cref="Inline" />
|
||||
public class ContainerInline : Inline, IEnumerable<Inline>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the parent block of this inline.
|
||||
/// </summary>
|
||||
public LeafBlock ParentBlock { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first child.
|
||||
/// </summary>
|
||||
|
||||
@@ -224,7 +224,7 @@ namespace Markdig.Syntax.Inlines
|
||||
}
|
||||
}
|
||||
|
||||
internal T FirstParentOfType<T>() where T : Inline
|
||||
public T FirstParentOfType<T>() where T : Inline
|
||||
{
|
||||
var inline = this;
|
||||
while (inline != null)
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace Markdig.Syntax
|
||||
[DebuggerDisplay("{GetType().Name} Line: {Line}, {Lines}")]
|
||||
public abstract class LeafBlock : Block
|
||||
{
|
||||
private ContainerInline inline;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LeafBlock"/> class.
|
||||
/// </summary>
|
||||
@@ -33,7 +35,30 @@ namespace Markdig.Syntax
|
||||
/// <summary>
|
||||
/// Gets or sets the inline syntax tree (may be null).
|
||||
/// </summary>
|
||||
public ContainerInline Inline { get; set; }
|
||||
public ContainerInline Inline
|
||||
{
|
||||
get => inline;
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
if (value.Parent != null)
|
||||
ThrowHelper.ArgumentException("Cannot add this inline as it as already attached to another container (inline.Parent != null)");
|
||||
|
||||
if (value.ParentBlock != null)
|
||||
ThrowHelper.ArgumentException("Cannot add this inline as it as already attached to another container (inline.ParentBlock != null)");
|
||||
|
||||
value.ParentBlock = this;
|
||||
}
|
||||
|
||||
if (inline != null)
|
||||
{
|
||||
inline.ParentBlock = null;
|
||||
}
|
||||
|
||||
inline = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether <see cref="Lines"/> must be processed
|
||||
|
||||
@@ -110,20 +110,12 @@ namespace SpecFileGen
|
||||
if (File.Exists(spec.OutputPath)) // If the source hasn't changed, don't bump the generated tag
|
||||
{
|
||||
string previousSource = File.ReadAllText(spec.OutputPath).Replace("\r\n", "\n", StringComparison.Ordinal);
|
||||
int start = previousSource.IndexOf('\n', StringComparison.Ordinal) + 1;
|
||||
int previousLength = previousSource.Length - start;
|
||||
if (start != 0 && previousLength == source.Length)
|
||||
if (previousSource == source)
|
||||
{
|
||||
if (previousSource.IndexOf(source, start, previousLength, StringComparison.Ordinal) == start)
|
||||
{
|
||||
// The source did not change
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
string generated = "// Generated: " + DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") + '\n';
|
||||
File.WriteAllText(spec.OutputPath, generated + source);
|
||||
File.WriteAllText(spec.OutputPath, source);
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user