From 019b4693747d385c32d7ee79a1897ad3af155127 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 16 Feb 2026 09:18:52 +0100 Subject: [PATCH] Add Markdown.HTMLBlock stdlib interop To cope with changes in Julia 1.14, see and Co-authored-by: Codex --- CHANGELOG.md | 4 ++++ docs/src/stdlib.md | 2 ++ src/stdlib/fromstdlib.jl | 3 +++ src/stdlib/tostdlib.jl | 6 +++++- test/fromstdlib.jl | 10 +++++++++- test/tostdlib.jl | 18 +++++++++++++----- 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 018af2b..bac8c1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # MarkdownAST.jl changelog +## Version `Unreleased` + +* ![Feature][badge-feature] Added support for converting `HTMLBlock` nodes to and from `Markdown.HTMLBlock` when using Julia 1.14+, where the corresponding stdlib type is available. + ## Version `v0.1.2` * ![Feature][badge-feature] Implemented `replace` and `replace!` to safely mutate trees in arbitrary ways, and `empty!(node.children)` to remove all the children of a node. ([#22][github-22]) diff --git a/docs/src/stdlib.md b/docs/src/stdlib.md index 680fc55..991f57d 100644 --- a/docs/src/stdlib.md +++ b/docs/src/stdlib.md @@ -28,6 +28,7 @@ Due to the differences between the Markdown representations, the following thing - In case the standard library AST contains any inline nodes in block context (e.g. as children for `Markdown.MD`), the get wrapped in a [`Paragraph`](@ref) element too. - When converting a `Markdown.Table`, the resulting table will be normalized, such as adding empty cells to rows, to make sure that all rows have the same number of cells. - For links and images, the `.title` attribute is set to an empty string, since the standard library AST does not support parsing titles. +- On Julia 1.14 and newer, `Markdown.HTMLBlock` values are converted to [`HTMLBlock`](@ref) elements. On older Julia versions, such nodes do not exist in the standard library AST. ## Conversion to standard library representation @@ -45,6 +46,7 @@ Due to the differences between the Markdown representations, the following thing - The `.title` attribute of [`Link`](@ref) and [`Image`](@ref) elements gets discarded. - The standard library does not support storing the child nodes of [`Image`](@ref) elements (i.e. "alt text", `![alt text]()`) as AST, and it is instead reduced to a string with the help of the `Markdown.plain` function. - The standard library AST does not have dedicated elements for [`SoftBreak`](@ref) and [`Backslash`](@ref), and these get converted into strings (i.e. text elements) instead. +- On Julia 1.14 and newer, [`HTMLBlock`](@ref) elements are converted into `Markdown.HTMLBlock`. On older Julia versions they are converted into `Markdown.Code("html", ...)`. ## Index diff --git a/src/stdlib/fromstdlib.jl b/src/stdlib/fromstdlib.jl index 969815e..62809bc 100644 --- a/src/stdlib/fromstdlib.jl +++ b/src/stdlib/fromstdlib.jl @@ -53,6 +53,9 @@ end _convert_block(nodefn::NodeFn, b::Markdown.BlockQuote) = _convert(nodefn, BlockQuote(), _convert_block, b.content) _convert_block(nodefn::NodeFn, ::Markdown.HorizontalRule) = nodefn(ThematicBreak()) _convert_block(nodefn::NodeFn, b::Markdown.Code) = nodefn(CodeBlock(b.language, b.code)) +@static if isdefined(Markdown, :HTMLBlock) + _convert_block(nodefn::NodeFn, b::Markdown.HTMLBlock) = nodefn(HTMLBlock(join(b.content, '\n'))) +end # Non-Commonmark extensions _convert_block(nodefn::NodeFn, b::Markdown.Admonition) = _convert(nodefn, Admonition(b.category, b.title), _convert_block, b.content) _convert_block(nodefn::NodeFn, b::Markdown.LaTeX) = nodefn(DisplayMath(b.formula)) diff --git a/src/stdlib/tostdlib.jl b/src/stdlib/tostdlib.jl index 7cb776c..7e25345 100644 --- a/src/stdlib/tostdlib.jl +++ b/src/stdlib/tostdlib.jl @@ -66,5 +66,9 @@ _convert_element(n::Node, ::LineBreak) = Markdown.LineBreak() _convert_element(n::Node, ::SoftBreak) = " " _convert_element(n::Node, ::Backslash) = "\\" # Raw HTML -_convert_element(::Node, e::HTMLBlock) = Markdown.Code("html", e.html) +@static if isdefined(Markdown, :HTMLBlock) + _convert_element(::Node, e::HTMLBlock) = Markdown.HTMLBlock(split(e.html, '\n'; keepempty = true)) +else + _convert_element(::Node, e::HTMLBlock) = Markdown.Code("html", e.html) +end _convert_element(::Node, e::HTMLInline) = Markdown.Code("", e.html) diff --git a/test/fromstdlib.jl b/test/fromstdlib.jl index 82be570..794ef60 100644 --- a/test/fromstdlib.jl +++ b/test/fromstdlib.jl @@ -3,7 +3,7 @@ using MarkdownAST: MarkdownAST, Node, @ast, Document, Paragraph, Heading, CodeBlock, BlockQuote, DisplayMath, ThematicBreak, List, Item, FootnoteLink, FootnoteDefinition, Admonition, Table, TableHeader, TableBody, TableRow, TableCell, - JuliaValue, LineBreak + JuliaValue, LineBreak, HTMLBlock using Markdown: Markdown using Test @@ -351,6 +351,14 @@ using Test end end end + @static if isdefined(Markdown, :HTMLBlock) + let m = Markdown.MD() + push!(m.content, Markdown.HTMLBlock(["
", "x", "
"])) + @test convert(Node, m) == @ast Document() do + HTMLBlock("
\nx\n
") + end + end + end # Tests from the Documenter Markdown2 module let ast = convert(Node, Markdown.parse(raw""" diff --git a/test/tostdlib.jl b/test/tostdlib.jl index 0465d73..fca3753 100644 --- a/test/tostdlib.jl +++ b/test/tostdlib.jl @@ -264,11 +264,19 @@ struct UnknownBlock <: MarkdownAST.AbstractBlock end Paragraph() do; HTMLInline(""); end end md = convert(Markdown.MD, ast) - # Markdown can't represent raw HTML, so it gets converted into Code - # nodes instead - @test convert(Node, md) == @ast MarkdownAST.Document() do - CodeBlock("html", "") - Paragraph() do; Code(""); end + if isdefined(Markdown, :HTMLBlock) + @test md.content[1] isa Markdown.HTMLBlock + @test convert(Node, md) == @ast MarkdownAST.Document() do + HTMLBlock("") + Paragraph() do; Code(""); end + end + else + # Markdown can't represent raw HTML, so it gets converted into Code + # nodes instead + @test convert(Node, md) == @ast MarkdownAST.Document() do + CodeBlock("html", "") + Paragraph() do; Code(""); end + end end end end