Skip to content

Keep callout markers on the line they were written on - #445

Merged
JakeSCahill merged 3 commits into
mainfrom
jake/preserve-callouts-in-code-blocks
Sep 23, 2026
Merged

JakeSCahill merged 3 commits into
mainfrom
jake/preserve-callouts-in-code-blocks

Conversation

@JakeSCahill

Copy link
Copy Markdown
Contributor

The Connect Helm chart quickstart rendered its Hello world callouts as "4 1 3" on one line. Three bugs stacked up:

  • 17-bloblang-yaml.js rebuilds each token from textContent and reassigns innerHTML, destroying any callout marker or editable placeholder inside it. Now guarded.
  • The conum MutationObserver in 11-editable-placeholders.js repaired those removals with appendChild, so the orphans landed at the end of the block. Now restores the original position.
  • addConumSpans matched the text inside Asciidoctor's hidden <b>(1)</b> fallback and minted a duplicate nested conum per callout. The fallback is now dropped first.

The observer fix alone is not enough: a block scalar with a blank line in it loses the position anchors, so the guard is required. It costs Bloblang colouring inside a block scalar that contains callouts, which beats markers against the wrong lines.

npm run test:callout-preservation covers this in a real browser, which is necessary because the server HTML and a cold DOM both look correct. Reverting the two source files fails it.

The page itself is fixed separately in rp-connect-docs PR 520, since this needs a release to reach the site.

@netlify

netlify Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for docs-ui ready!

Name Link
🔨 Latest commit fcf276f
🔍 Latest deploy log https://app.netlify.com/projects/docs-ui/deploys/6ab3a0542ba9590008f45115
😎 Deploy Preview https://deploy-preview-445--docs-ui.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 38 (🟢 up 2 from production)
Accessibility: 89 (no change from production)
Best Practices: 83 (no change from production)
SEO: 89 (no change from production)
PWA: -
View the detailed breakdown and full score reports
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 959c1131-6f8b-4855-82cf-c60091ac6e3a

📥 Commits

Reviewing files that changed from the base of the PR and between c0dc113 and fcf276f.

📒 Files selected for processing (6)
  • .github/workflows/test-bloblang-playground.yml
  • package.json
  • src/js/11-editable-placeholders.js
  • src/js/17-bloblang-yaml.js
  • tests/callout-preservation/fixture.html
  • tests/callout-preservation/test-runner.js
 ___________________________________________________________________________________________________________________________________________________________
< Don't be a slave to formal methods. Don't blindly adopt any technique without putting it into the context of your development practices and capabilities. >
 -----------------------------------------------------------------------------------------------------------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@kbatuigas kbatuigas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one finding, but I'll approve:

  • [P2] Preserve repeated callout numbers — [11-editable-placeholders.js](

    }
    }
    })
    // Optionally, check for added nodes to ensure conum elements were correctly reinserted
    mutation.addedNodes.forEach((addedNode) => {
    if (addedNode.nodeType === Node.ELEMENT_NODE && addedNode.classList.contains('conum')) {
    const dataValue = addedNode.getAttribute('data-value')
    const duplicates = mutation.target.querySelectorAll(`i.conum[data-value="${dataValue}"]`)
    if (duplicates.length > 1) {
    // Remove duplicates, keeping the first one
    )

    The observer treats every i.conum with the same data-value as a duplicate and removes all but the first whenever addConumSpans rewrites the block. However, explicitly repeating a callout number on multiple lines is valid AsciiDoc—for example, two <1> markers can reference the same annotation. [Asciidoctor documents this use case](https://docs.asciidoctor.org/asciidoc/latest/verbatim/callouts/#mixed-numbering). Such a block will still lose its later markers. Now that the generated <b>(N)</b> fallbacks are removed before processing, deduplication should preserve legitimate repeated markers, and the browser test should include that case.

JakeSCahill and others added 3 commits September 23, 2026 10:47
The Connect Helm chart quickstart rendered the callouts in its Hello world
example as "4 1 3" on one line. Three bugs stacked up to produce that.

17-bloblang-yaml.js: every process* function rebuilds its token from
token.textContent, which flattens child elements away, then assigns
innerHTML. Any conum or editable placeholder inside the token is
destroyed, and processMultilineMapping additionally deletes the
continuation siblings it folds in. Callouts <1> and <3> sat inside
"mapping: |" block scalars, so both were wiped. Added a hasPreservedMarkup
guard at the dispatch point and over the continuation nodes.

11-editable-placeholders.js: the conum MutationObserver repaired removals
with mutation.target.appendChild(node), which sends the marker to the end
of the block. That is what turned a silent deletion into a visible
scramble, and a callout pointing at the wrong line reads as fact. It now
restores the position from the siblings MutationRecord captured.

Same file, addConumSpans: the literal-(N) regexes matched the text inside
Asciidoctor's hidden <b>(1)</b> fallback and minted a second, nested conum
for every callout on the page. Those duplicates also defeat the observer's
own duplicate check. The fallback element is now dropped first, which
keeps "(N)" out of the copy button's output too.

The observer fix alone is not enough. When a block scalar contains a blank
line Prism splits it, the continuation nodes carrying the position anchors
are deleted, and the restore falls back to appendChild: two callouts
collapse onto one line. The guard is required. Its cost is that a block
scalar containing callouts no longer gets Bloblang colouring, which is a
better trade than markers against the wrong lines.

tests/callout-preservation runs the real scripts in a real browser, since
the server HTML and a cold DOM both look correct and the bug needs Prism,
keep-markup and the Bloblang pass to have all run over the same block.
Reverting the two source files fails it. generate:prism runs first because
prism-core.js is generated, not tracked.
The suites in validate-build.yml run with PUPPETEER_SKIP_DOWNLOAD, so a
browser test belongs in the Bloblang workflow next to the other
puppeteer ones. Its path filter already covered 17-bloblang-yaml.js but
not 11-editable-placeholders.js or the new test, so a change to either
would not have run it.
The restoration observer removed every conum past the first with a
given data-value anywhere in the code block. That was written to
guard against the <b>(N)</b> fallback minting an adjacent duplicate,
but repeating a callout number on separate lines is valid AsciiDoc
mixed numbering, and the blanket check silently deleted the second,
genuine marker.

Narrow the check to an actual adjacent sibling with the same value --
the shape the fallback bug produced -- so a second callout elsewhere
in the block survives. Added block F to the callout-preservation
fixture and its browser-test assertions; reverting the observer
change reproduces the loss (3 nodes -> 2) and confirms the new checks
catch it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@JakeSCahill
JakeSCahill force-pushed the jake/preserve-callouts-in-code-blocks branch from 3b971a3 to fcf276f Compare September 23, 2026 09:48
@JakeSCahill
JakeSCahill merged commit 009d9bd into main Sep 23, 2026
6 of 7 checks passed
@JakeSCahill
JakeSCahill deleted the jake/preserve-callouts-in-code-blocks branch September 23, 2026 09:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants