-
Notifications
You must be signed in to change notification settings - Fork 6
Description
Summary
When Flowmark wraps long Markdoc/Markform tags across multiple lines, it can break Markdoc's parser if the closing tag ({% /tag %}) remains on the same line as the wrapped opening tag's closing delimiter (%}).
Environment
- Flowmark version: v0.6.1.dev13+0a5781e
- Markdoc version: @markdoc/markdoc (latest)
The Problem
Flowmark correctly identifies and preserves Markdoc tag delimiters ({% ... %}), but when wrapping long tags, the closing tag placement can trigger a Markdoc parser bug that corrupts the AST structure.
Input (single line - works correctly)
{% outer %}
{% tag1 attr1=1 attr2=2 %}{% /tag1 %}
{% tag2 %}{% /tag2 %}
{% /outer %}AST result: tag1 and tag2 correctly at the same nesting level inside outer.
After Flowmark wrapping (broken)
{% outer %}
{% tag1 attr1=1
attr2=2 %}{% /tag1 %}
{% tag2 %}{% /tag2 %}
{% /outer %}AST result: tag2 incorrectly nested deep inside tag1, phantom tags appear.
Workaround that works
{% outer %}
{% tag1 attr1=1
attr2=2 %}
{% /tag1 %}
{% tag2 %}{% /tag2 %}
{% /outer %}When the closing tag is on its own line after a multi-line opening tag, parsing works correctly.
Root Cause
This is technically a Markdoc parser bug (the Markdoc spec explicitly allows multi-line tags), but it's triggered by a specific pattern that Flowmark produces.
The problematic pattern is:
{% tag attr=value
more_attrs %}{% /tag %}
Where %}{% /tag %} appears on the same line after a multi-line opening tag.
Suggested Fix
When Flowmark wraps a long Markdoc tag across multiple lines, it should place the closing tag on a new line:
Current behavior:
{% field kind="string" id="name" label="Name" required=true minLength=2
maxLength=50 placeholder="Enter your name" %}{% /field %}Suggested behavior:
{% field kind="string" id="name" label="Name" required=true minLength=2
maxLength=50 placeholder="Enter your name" %}
{% /field %}This maintains proper formatting while avoiding the Markdoc parser bug.
Reproduction
# Create test file
cat > test.md << 'TESTEOF'
{% form id="test" %}
{% group id="group1" %}
{% field kind="number" id="age" label="Age" role="user" required=true min=0 max=150 integer=true placeholder="25" %}{% /field %}
{% field kind="string" id="name" %}{% /field %}
{% /group %}
{% group id="group2" %}
{% field kind="url" id="website" %}{% /field %}
{% /group %}
{% /form %}
TESTEOF
# Format with flowmark
flowmark --auto test.md
# Parse with Markdoc and count groups (should be 2, but shows 1)
node --input-type=module -e "
import Markdoc from '@markdoc/markdoc';
import { readFileSync } from 'fs';
const ast = Markdoc.parse(readFileSync('test.md', 'utf-8'));
function countGroups(node) {
let count = 0;
if (node.type === 'tag' && node.tag === 'group') count++;
for (const child of node.children || []) count += countGroups(child);
return count;
}
console.log('Groups found:', countGroups(ast));
"Impact
This affects any project using Markdoc-style tags (Markdoc, Markform, similar template systems) where tags have many attributes that exceed the line width limit.