('code', (node, context) => {
return ` `
}
+ // Raw Confluence storage-format passthrough. Emitted verbatim — no escaping, no code
+ // macro — as an escape hatch for macros with no markdown form (toc, details, status, …).
+ if (lang === 'confluence') {
+ return code
+ }
+
const params: Record = {}
if (lang) {
params.language = mapLanguage(lang)
diff --git a/test/converter.test.ts b/test/converter.test.ts
index 881df79..132dc91 100644
--- a/test/converter.test.ts
+++ b/test/converter.test.ts
@@ -74,6 +74,41 @@ describe('Code blocks', () => {
})
})
+describe('Confluence passthrough', () => {
+ it('emits a confluence fence verbatim and unescaped', () => {
+ const result = md2confluence('```confluence\n \n```')
+ expect(result).toContain(' ')
+ expect(result).not.toContain('<')
+ expect(result).not.toContain('ac:name="code"')
+ })
+
+ it('preserves special characters and nested macros byte-for-byte', () => {
+ const body =
+ 'Green public '
+ const result = md2confluence(`\`\`\`confluence\na & b "c" ${body}
\n\`\`\``)
+ expect(result).toContain(`a & b "c" ${body}
`)
+ expect(result).not.toContain('&')
+ expect(result).not.toContain('"')
+ })
+
+ it('preserves newlines in a multi-line fence body', () => {
+ const result = md2confluence('```confluence\n\n x \n
\n```')
+ expect(result).toBe('\n x \n
')
+ })
+
+ it('does not affect real language code blocks', () => {
+ const result = md2confluence('```js\nconst x = 1\n```')
+ expect(result).toContain('')
+ expect(result).toContain('javascript ')
+ })
+
+ it('matches the language exactly — uppercase falls through to a code block', () => {
+ const result = md2confluence('```Confluence\n \n```')
+ expect(result).toContain('')
+ expect(result).toContain(']]>')
+ })
+})
+
describe('Lists', () => {
it('converts unordered lists', () => {
const result = md2confluence('- Item 1\n- Item 2')