Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix failing case of nested link references by making rawBlockParser recursive #84

Merged
merged 5 commits into from Jul 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions spec-results.json
Expand Up @@ -364,6 +364,7 @@
184,
185,
186,
187,
188
],
"Links": [
Expand Down Expand Up @@ -917,6 +918,7 @@
184,
185,
186,
187,
188
],
"Links": [
Expand Down
213 changes: 143 additions & 70 deletions src/Markdown/Parser.elm
Expand Up @@ -6,13 +6,13 @@ module Markdown.Parser exposing (parse, deadEndToString)

-}

import Whitespace
import Helpers
import Dict exposing (Dict)
import Helpers
import HtmlParser exposing (Node(..))
import Markdown.Block as Block exposing (Block, Inline, ListItem, Task)
import Markdown.CodeBlock
import Markdown.Heading as Heading
import Markdown.Helpers exposing (isEven)
import Markdown.Inline as Inline
import Markdown.InlineParser
import Markdown.LinkReferenceDefinition as LinkReferenceDefinition exposing (LinkReferenceDefinition)
Expand All @@ -26,8 +26,8 @@ import Parser
import Parser.Advanced as Advanced exposing ((|.), (|=), Nestable(..), Step(..), andThen, chompIf, chompWhile, getChompedString, loop, map, oneOf, problem, succeed, symbol, token)
import Parser.Token as Token
import ThematicBreak
import Whitespace

import Markdown.Helpers exposing (isEven)

{-| Try parsing a markdown String into `Markdown.Block.Block`s.

Expand Down Expand Up @@ -188,13 +188,14 @@ mapInline inline =
Block.Strong (inlines |> List.map mapInline)

_ ->
if level |> isEven then
Block.Strong [Inline.Emphasis (level - 2) inlines |> mapInline]
if level |> isEven then
Block.Strong [ Inline.Emphasis (level - 2) inlines |> mapInline ]

else
Block.Emphasis [Inline.Emphasis (level - 1) inlines |> mapInline]
Block.Emphasis [ Inline.Emphasis (level - 1) inlines |> mapInline ]

Inline.Strikethrough inlines ->
Block.Strikethrough (inlines |> List.map mapInline)
Block.Strikethrough (inlines |> List.map mapInline)


toHeading : Int -> Result Parser.Problem Block.HeadingLevel
Expand Down Expand Up @@ -294,18 +295,16 @@ parseInlines linkReferences rawBlock =
EmptyBlock

BlockQuote rawBlocks ->
case Advanced.run rawBlockParser rawBlocks of
Ok value ->
case parseAllInlines value of
Ok parsedBlocks ->
Block.BlockQuote parsedBlocks
|> ParsedBlock
EmptyBlock

Err e ->
InlineProblem e
ParsedBlockQuote rawBlocks ->
case parseAllInlines { linkReferenceDefinitions = linkReferences, rawBlocks = rawBlocks } of
Ok parsedBlocks ->
Block.BlockQuote parsedBlocks
|> ParsedBlock

Err error ->
InlineProblem (Parser.Problem (deadEndsToString error))
Err e ->
InlineProblem e

IndentedCodeBlock codeBlockBody ->
Block.CodeBlock { body = codeBlockBody, language = Nothing }
Expand Down Expand Up @@ -616,6 +615,7 @@ rawBlockParser =
, rawBlocks = []
}
stepRawBlock
|> andThen completeBlocks


parseAllInlines : State -> Result Parser.Problem (List Block)
Expand All @@ -642,61 +642,112 @@ parseAllInlinesHelp state rawBlocks parsedBlocks =
Ok parsedBlocks


completeOrMergeBlocks : State -> RawBlock -> State
completeOrMergeBlocks : State -> RawBlock -> Parser State
completeOrMergeBlocks state newRawBlock =
{ linkReferenceDefinitions = state.linkReferenceDefinitions
, rawBlocks =
case
( newRawBlock
, state.rawBlocks
)
of
( CodeBlock block1, (CodeBlock block2) :: rest ) ->
CodeBlock
{ body = joinStringsPreserveAll block2.body block1.body
, language = Nothing
}
:: rest

( IndentedCodeBlock block1, (IndentedCodeBlock block2) :: rest ) ->
IndentedCodeBlock (joinStringsPreserveAll block2 block1)
:: rest

( OpenBlockOrParagraph (UnparsedInlines body1), (BlockQuote body2) :: rest ) ->
BlockQuote (joinRawStringsWith "\n" body2 body1)
:: rest
case
( newRawBlock
, state.rawBlocks
)
of
( CodeBlock block1, (CodeBlock block2) :: rest ) ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions
, rawBlocks =
CodeBlock
{ body = joinStringsPreserveAll block2.body block1.body
, language = Nothing
}
:: rest
}

( IndentedCodeBlock block1, (IndentedCodeBlock block2) :: rest ) ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions
, rawBlocks =
IndentedCodeBlock (joinStringsPreserveAll block2 block1)
:: rest
}

( _, (BlockQuote body2) :: rest ) ->
case newRawBlock of
BlockQuote body1 ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions
, rawBlocks =
BlockQuote (joinStringsPreserveAll body2 body1)
:: rest
}

OpenBlockOrParagraph (UnparsedInlines body1) ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions
, rawBlocks =
BlockQuote (joinRawStringsWith "\n" body2 body1)
:: rest
}

( BlockQuote body1, (BlockQuote body2) :: rest ) ->
BlockQuote (joinStringsPreserveAll body2 body1)
:: rest

( OpenBlockOrParagraph (UnparsedInlines body1), (OpenBlockOrParagraph (UnparsedInlines body2)) :: rest ) ->
OpenBlockOrParagraph (UnparsedInlines (joinRawStringsWith "\n" body2 body1))
:: rest

( SetextLine LevelOne _, (OpenBlockOrParagraph unparsedInlines) :: rest ) ->
Heading 1 unparsedInlines
:: rest

( SetextLine LevelTwo _, (OpenBlockOrParagraph unparsedInlines) :: rest ) ->
Heading 2 unparsedInlines
:: rest

( TableDelimiter (Markdown.Table.TableDelimiterRow text alignments), (OpenBlockOrParagraph (UnparsedInlines rawHeaders)) :: rest ) ->
case TableParser.parseHeader (Markdown.Table.TableDelimiterRow text alignments) rawHeaders of
Ok (Markdown.Table.TableHeader headers) ->
Table (Markdown.Table.Table headers []) :: rest

Err _ ->
OpenBlockOrParagraph (UnparsedInlines (joinRawStringsWith "\n" rawHeaders text.raw))
:: rest
_ ->
case Advanced.run rawBlockParser body2 of
Ok value ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions ++ value.linkReferenceDefinitions
, rawBlocks = newRawBlock :: (value.rawBlocks |> ParsedBlockQuote) :: rest
}

( Table updatedTable, (Table _) :: rest ) ->
Table updatedTable :: rest
Err e ->
problem (Parser.Problem (deadEndsToString e))

( OpenBlockOrParagraph (UnparsedInlines body1), (OpenBlockOrParagraph (UnparsedInlines body2)) :: rest ) ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions
, rawBlocks =
OpenBlockOrParagraph (UnparsedInlines (joinRawStringsWith "\n" body2 body1))
:: rest
}

( SetextLine LevelOne _, (OpenBlockOrParagraph unparsedInlines) :: rest ) ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions
, rawBlocks =
Heading 1 unparsedInlines
:: rest
}

( SetextLine LevelTwo _, (OpenBlockOrParagraph unparsedInlines) :: rest ) ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions
, rawBlocks =
Heading 2 unparsedInlines
:: rest
}

( TableDelimiter (Markdown.Table.TableDelimiterRow text alignments), (OpenBlockOrParagraph (UnparsedInlines rawHeaders)) :: rest ) ->
case TableParser.parseHeader (Markdown.Table.TableDelimiterRow text alignments) rawHeaders of
Ok (Markdown.Table.TableHeader headers) ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions
, rawBlocks = Table (Markdown.Table.Table headers []) :: rest
}

Err _ ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions
, rawBlocks =
OpenBlockOrParagraph (UnparsedInlines (joinRawStringsWith "\n" rawHeaders text.raw))
:: rest
}

( Table updatedTable, (Table _) :: rest ) ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions
, rawBlocks = Table updatedTable :: rest
}

_ ->
newRawBlock :: state.rawBlocks
}
_ ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions
, rawBlocks = newRawBlock :: state.rawBlocks
}



Expand Down Expand Up @@ -725,12 +776,34 @@ stepRawBlock revStmts =
_ ->
mergeableBlockNotAfterOpenBlockOrParagraphParser
)
|> map (\block -> Loop (completeOrMergeBlocks revStmts block))
|> andThen (completeOrMergeBlocks revStmts)
|> map (\block -> Loop block)
, openBlockOrParagraphParser
|> map (\block -> Loop (completeOrMergeBlocks revStmts block))
|> andThen (completeOrMergeBlocks revStmts)
|> map (\block -> Loop block)
]


completeBlocks :
State
-> Parser State --Result Parser.Problem (List Block)
completeBlocks state =
case state.rawBlocks of
(BlockQuote body2) :: rest ->
case Advanced.run rawBlockParser body2 of
Ok value ->
succeed
{ linkReferenceDefinitions = state.linkReferenceDefinitions ++ value.linkReferenceDefinitions
, rawBlocks = (value.rawBlocks |> ParsedBlockQuote) :: rest
}

Err error ->
problem (Parser.Problem (deadEndsToString error))

_ ->
succeed state



-- Note [Static Parser Structure]
--
Expand Down
1 change: 1 addition & 0 deletions src/Markdown/RawBlock.elm
Expand Up @@ -37,4 +37,5 @@ type RawBlock
| TableDelimiter Markdown.Table.TableDelimiterRow
| BlankLine
| BlockQuote String
| ParsedBlockQuote (List RawBlock)
| SetextLine SetextLevel String
2 changes: 1 addition & 1 deletion test-results/failing/CommonMark/HTML blocks.md
Expand Up @@ -498,7 +498,7 @@ Should give output:
But instead was:

````````````html
ERROR Problem at row 1 Problem at row 2 Expecting symbol
ERROR Problem at row 4 Problem at row 2 Expecting symbol
````````````
## [Example 144](https://spec.commonmark.org/0.29/#example-144)

Expand Down
22 changes: 0 additions & 22 deletions test-results/failing/CommonMark/Link reference definitions.md
Expand Up @@ -89,25 +89,3 @@ But instead was:
````````````html
<p>Foo<a href="/baz">bar</a></p>
````````````
## [Example 187](https://spec.commonmark.org/0.29/#example-187)

This markdown:

````````````markdown
[foo]

> [foo]: /url

````````````

Should give output:

````````````html
<p><a href="/url">foo</a></p><blockquote></blockquote>
````````````

But instead was:

````````````html
<p>[foo]</p><blockquote></blockquote>
````````````
2 changes: 1 addition & 1 deletion test-results/failing/GFM/HTML blocks.md
Expand Up @@ -498,7 +498,7 @@ Should give output:
But instead was:

````````````html
ERROR Problem at row 1 Problem at row 2 Expecting symbol
ERROR Problem at row 4 Problem at row 2 Expecting symbol
````````````
## [Example 144](https://spec.commonmark.org/0.29/#example-144)

Expand Down
22 changes: 0 additions & 22 deletions test-results/failing/GFM/Link reference definitions.md
Expand Up @@ -89,25 +89,3 @@ But instead was:
````````````html
<p>Foo<a href="/baz">bar</a></p>
````````````
## [Example 187](https://spec.commonmark.org/0.29/#example-187)

This markdown:

````````````markdown
[foo]

> [foo]: /url

````````````

Should give output:

````````````html
<p><a href="/url">foo</a></p><blockquote></blockquote>
````````````

But instead was:

````````````html
<p>[foo]</p><blockquote></blockquote>
````````````