Summary
The INFO / WARNING / NOTE callout markers in MacroConverter produce two related issues that diverge from the documented behavior:
- The marker text (
**INFO** / **WARNING** / **NOTE**) leaks into the rendered macro body for the README-documented > **INFO**\n> body form.
- Detection wraps any blockquote that merely mentions the marker keyword in prose (e.g.
> Use **INFO** at the start.) in a callout macro.
Reproduction
1. Marker text leak
const MacroConverter = require('confluence-cli/lib/macro-converter');
const c = new MacroConverter({ isCloud: true });
console.log(c.markdownToStorage('> **INFO**\n> Heads up.'));
Actual output:
<ac:structured-macro ac:name="info">
<ac:rich-text-body>
<p><strong>INFO</strong>
Heads up.</p>
</ac:rich-text-body>
</ac:structured-macro>
Expected (per README and #5):
<ac:structured-macro ac:name="info">
<ac:rich-text-body>
<p>Heads up.</p>
</ac:rich-text-body>
</ac:structured-macro>
The same single-paragraph shape is what the [!info] preprocessor emits, so [!info]\nbody round-trip is also affected.
The cleanup regex on line 89 currently matches only the separated-paragraph form <p><strong>INFO</strong></p>, but markdown-it parses > **INFO**\n> body as a single paragraph <p><strong>INFO</strong>\nbody</p>, which never matches.
2. False-positive macro wrapping
console.log(c.markdownToStorage('> Use **INFO** at the start of a callout.'));
Actual output:
<ac:structured-macro ac:name="info">
<ac:rich-text-body>
<p>Use <strong>INFO</strong> at the start of a callout.</p>
</ac:rich-text-body>
</ac:structured-macro>
Expected: a plain <blockquote> (the marker keyword is just being mentioned, not used as a callout signal).
The detection step uses content.includes('<strong>INFO</strong>'), which matches any occurrence of the keyword anywhere in the blockquote.
Impact
- All documented input paths produce visibly leaked marker text:
- Authors quoting the marker keyword in prose get an unintended callout box
Root cause
Both stem from the marker handling having different anchor semantics in detection vs. stripping:
- Detection:
content.includes('<strong>MARKER</strong>') — too broad
- Stripping:
<p><strong>MARKER</strong></p> — too narrow (only the separated-paragraph shape)
A single anchor — "the marker is the first thing inside the first paragraph, immediately followed by </p> or \n" — covers both correctly.
Happy to send a fix.
Summary
The
INFO/WARNING/NOTEcallout markers inMacroConverterproduce two related issues that diverge from the documented behavior:**INFO**/**WARNING**/**NOTE**) leaks into the rendered macro body for the README-documented> **INFO**\n> bodyform.> Use **INFO** at the start.) in a callout macro.Reproduction
1. Marker text leak
Actual output:
Expected (per README and #5):
The same single-paragraph shape is what the
[!info]preprocessor emits, so[!info]\nbodyround-trip is also affected.The cleanup regex on line 89 currently matches only the separated-paragraph form
<p><strong>INFO</strong></p>, but markdown-it parses> **INFO**\n> bodyas a single paragraph<p><strong>INFO</strong>\nbody</p>, which never matches.2. False-positive macro wrapping
Actual output:
Expected: a plain
<blockquote>(the marker keyword is just being mentioned, not used as a callout signal).The detection step uses
content.includes('<strong>INFO</strong>'), which matches any occurrence of the keyword anywhere in the blockquote.Impact
> **INFO**\n> body(feat!: change blockquote default from info macro to plain <blockquote> #127 README form)> **INFO**\n>\n> bodyworks correctly only because the empty>line splits the paragraph[!info]\nbody(feat: Enhanced Markdown Support with Bidirectional Conversion #5 admonition form, via preprocessor expansion)> **WARNING**\n> body,> **NOTE**\n> body, and the[!warning]/[!note]round-trip variantsRoot cause
Both stem from the marker handling having different anchor semantics in detection vs. stripping:
content.includes('<strong>MARKER</strong>')— too broad<p><strong>MARKER</strong></p>— too narrow (only the separated-paragraph shape)A single anchor — "the marker is the first thing inside the first paragraph, immediately followed by
</p>or\n" — covers both correctly.Happy to send a fix.