-
Notifications
You must be signed in to change notification settings - Fork 3
Description
Bug Report: Code Blocks Rendering as Inline Code in Confluence
Description
When using @telefonica/markdown-confluence-sync v2.2.0, all fenced code blocks in Markdown files are rendered as inline code (with backticks) instead of proper Confluence code block macros when synced to Confluence.
Expected Behavior
Markdown code blocks should be converted to Confluence's <ac:structured-macro ac:name="code"> storage format with proper language highlighting.
Example Markdown:
```javascript
function hello() {
console.log("Hello World");
}
```Expected Confluence Output:
<ac:structured-macro ac:name="code">
<ac:parameter ac:name="language">javascript</ac:parameter>
<ac:plain-text-body><![CDATA[function hello() {
console.log("Hello World");
}]]></ac:plain-text-body>
</ac:structured-macro>Actual Behavior
Code blocks are rendered as inline code with backticks in the Confluence page body text, losing all formatting and syntax highlighting.
Root Cause
The library's markdown processing pipeline converts markdown → HTML → Confluence storage format:
remarkplugins process markdown and convert to HTMLrehypeplugins transform HTML to Confluence storage format
The Issue: The pipeline successfully converts markdown code blocks to HTML <pre><code class="language-x"> tags, but lacks a rehype plugin to convert these HTML elements to Confluence's <ac:structured-macro> format.
File: node_modules/@telefonica/markdown-confluence-sync/dist/lib/confluence/transformer/ConfluencePageTransformer.js
The processing pipeline (lines 52-78) includes plugins for other transformations but is missing a code block converter:
rehypeReplaceDetails- converts HTML details/summaryrehypeReplaceStrikethrough- converts strikethroughrehypeReplaceTaskList- converts task lists- Missing: Plugin to convert
<pre><code>to Confluence code macros
Versions Affected
@telefonica/markdown-confluence-sync: v2.2.0- Tested on: Node.js v22.18.0
- All programming languages affected (JavaScript, GraphQL, JSON, etc.)
Reproduction
- Create a markdown file with a fenced code block:
# Test File
```javascript
console.log("test");
```- Sync to Confluence using the library
- Observe that code appears as inline code with backticks instead of a proper code block
Workaround/Fix
We've created a patch that adds the missing rehype plugin:
New file: rehype-confluence-code-blocks.js
// SPDX-FileCopyrightText: 2025 Acoustic, L.P.
// SPDX-License-Identifier: Apache-2.0
import { visit } from 'unist-util-visit';
/**
* Rehype plugin to convert HTML code blocks to Confluence storage format.
*
* Converts:
* <pre><code class="language-javascript">code</code></pre>
*
* To Confluence storage format:
* <ac:structured-macro ac:name="code">
* <ac:parameter ac:name="language">javascript</ac:parameter>
* <ac:plain-text-body><![CDATA[code]]></ac:plain-text-body>
* </ac:structured-macro>
*/
export default function rehypeConfluenceCodeBlocks() {
return (tree) => {
visit(tree, 'element', (node, index, parent) => {
// Look for <pre> elements containing <code>
if (node.tagName === 'pre' && node.children && node.children.length > 0) {
const codeNode = node.children[0];
if (codeNode.type === 'element' && codeNode.tagName === 'code') {
// Extract language from class (e.g., "language-javascript" -> "javascript")
let language = '';
if (codeNode.properties && codeNode.properties.className) {
const classes = codeNode.properties.className;
const langClass = classes.find(c => c.startsWith('language-'));
if (langClass) {
language = langClass.replace('language-', '');
}
}
// Extract code content
let code = '';
const extractText = (node) => {
if (node.type === 'text') {
return node.value;
}
if (node.children) {
return node.children.map(extractText).join('');
}
return '';
};
code = extractText(codeNode);
// Create Confluence code macro structure
const confluenceCodeMacro = {
type: 'element',
tagName: 'ac:structured-macro',
properties: {
'ac:name': 'code',
},
children: [],
};
// Add language parameter if specified
if (language) {
confluenceCodeMacro.children.push({
type: 'element',
tagName: 'ac:parameter',
properties: {
'ac:name': 'language',
},
children: [
{
type: 'text',
value: language,
},
],
});
}
// Add code content wrapped in CDATA
confluenceCodeMacro.children.push({
type: 'element',
tagName: 'ac:plain-text-body',
properties: {},
children: [
{
type: 'raw',
value: `<![CDATA[${code}]]>`,
},
],
});
// Replace the <pre> node with the Confluence macro
if (parent && typeof index === 'number') {
parent.children[index] = confluenceCodeMacro;
}
}
}
});
};
}Modification to: ConfluencePageTransformer.js
// Add import at top with other rehype plugins (after line 18)
import rehypeConfluenceCodeBlocks from "./support/rehype/rehype-confluence-code-blocks.js";
// Add to processing pipeline (after line 65, after rehypeReplaceTaskList)
.use(rehypeConfluenceCodeBlocks)This fix has been tested and confirmed to work correctly, converting all code blocks to proper Confluence code macros with syntax highlighting.
Impact
This bug affects all users trying to sync markdown documentation with code examples to Confluence. Technical documentation, API references, and any content with code snippets will display incorrectly.
Suggested Solution
Add the rehype-confluence-code-blocks plugin (or similar functionality) to the library's default rehype processing pipeline in ConfluencePageTransformer.js.
Environment
- OS: macOS (Darwin 25.0.0)
- Node.js: v22.18.0
- Package version: @telefonica/[email protected]
- npm: Latest