Initial checklist
Affected package
mdast-util-directive 3.1.0, mdast-util-to-markdown 2.1.2, mdast-util-from-markdown 2.0.3, micromark-extension-directive 3.0.2
Steps to reproduce
import {fromMarkdown} from 'mdast-util-from-markdown'
import {toMarkdown} from 'mdast-util-to-markdown'
import {directiveFromMarkdown, directiveToMarkdown} from 'mdast-util-directive'
import {directive} from 'micromark-extension-directive'
const input = '::a}'
const tree1 = fromMarkdown(input, {extensions: [directive()], mdastExtensions: [directiveFromMarkdown()]})
// tree1: root > paragraph > text (value: '::a}') -- no directive
const text2 = toMarkdown(tree1, {extensions: [directiveToMarkdown()]})
// text2: '\\::a}\n'
const tree2 = fromMarkdown(text2, {extensions: [directive()], mdastExtensions: [directiveFromMarkdown()]})
// tree2: root > paragraph > [text, textDirective(name='a'), text]
The escape rule writes \: before a following :. After decoding the
backslash-escape, the text still contains ::a}. On re-parse, the
directive scanner sees ::a as a text directive start, so a textDirective
node appears in tree₂ that wasn't in tree₁.
Actual behavior
A textDirective node is introduced on re-parse. The escape rule escapes one
colon, but the surviving decoded text still contains ::.
Possible fixes:
- escape both colons of a leading
:: run, or
- use a numeric character reference (
:) for one of them, or
- widen the escape context to match any
:: prefix, not just : + :.
Expected behavior
Text that does not originally parse as a directive should not become one
after round-trip.
Runtime
node v24.13.1
Package manager
No response
Operating system
Ubuntu (WSL2)
Build and bundle tools
No response
Initial checklist
Affected package
mdast-util-directive 3.1.0, mdast-util-to-markdown 2.1.2, mdast-util-from-markdown 2.0.3, micromark-extension-directive 3.0.2
Steps to reproduce
The escape rule writes
\:before a following:. After decoding thebackslash-escape, the text still contains
::a}. On re-parse, thedirective scanner sees
::aas a text directive start, so atextDirectivenode appears in tree₂ that wasn't in tree₁.
Actual behavior
A
textDirectivenode is introduced on re-parse. The escape rule escapes onecolon, but the surviving decoded text still contains
::.Possible fixes:
::run, or:) for one of them, or::prefix, not just:+:.Expected behavior
Text that does not originally parse as a directive should not become one
after round-trip.
Runtime
node v24.13.1
Package manager
No response
Operating system
Ubuntu (WSL2)
Build and bundle tools
No response