From 4c044d6365d7bdd611c3264ec76515d3a1ad8012 Mon Sep 17 00:00:00 2001 From: "heecheol.park" Date: Sun, 10 May 2026 12:54:25 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix(convert):=20route=20html=20=E2=86=92=20?= =?UTF-8?q?markdown=20through=20htmlToMarkdown?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The convert command was routing the html → markdown conversion through storageToMarkdown, which is built for Confluence storage XML (with macros and a specific schema). General HTML inputs may not match that schema and can be misinterpreted. Route this path through the dedicated htmlToMarkdown converter that already exists on the local converter surface, and add a CLI test for the path. --- bin/confluence.js | 2 +- tests/convert.test.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/confluence.js b/bin/confluence.js index 13afadd..334c94d 100755 --- a/bin/confluence.js +++ b/bin/confluence.js @@ -2200,7 +2200,7 @@ program const { convert: htmlToText } = require('html-to-text'); output = htmlToText(input, { wordwrap: 130 }); } else if (options.inputFormat === 'html' && options.outputFormat === 'markdown') { - output = converter.storageToMarkdown(input); + output = converter.htmlToMarkdown(input); } else if (options.inputFormat === 'markdown' && options.outputFormat === 'text') { const html = converter.markdown.render(input); const { convert: htmlToText } = require('html-to-text'); diff --git a/tests/convert.test.js b/tests/convert.test.js index fd96b48..c80ad71 100644 --- a/tests/convert.test.js +++ b/tests/convert.test.js @@ -95,6 +95,13 @@ describe('convert command', () => { expect(output).toContain('bold'); }); + test('html to markdown', () => { + const inputFile = writeInput('input.html', '

bold and italic

'); + const output = run(['convert', '--input-file', inputFile, '--input-format', 'html', '--output-format', 'markdown']); + expect(output).toContain('**bold**'); + expect(output).toContain('*italic*'); + }); + test('storage to text', () => { const inputFile = writeInput('input.xml', '

Title

Content

'); const output = run(['convert', '--input-file', inputFile, '--input-format', 'storage', '--output-format', 'text']); From 280800794de509bea767089cb01bd8476b6cc0b0 Mon Sep 17 00:00:00 2001 From: "heecheol.park" Date: Sun, 10 May 2026 13:05:16 +0900 Subject: [PATCH 2/2] =?UTF-8?q?test(convert):=20strengthen=20html=20?= =?UTF-8?q?=E2=86=92=20markdown=20test=20with=20discriminating=20input?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous test used /, which both htmlToMarkdown and storageToMarkdown convert identically — so it would still pass if the routing were reverted to storageToMarkdown. Replace with a multi-line
 block, which storageToMarkdown
collapses into inline `code` (losing the fence and the language tag)
while htmlToMarkdown preserves the fenced block. The test now fails
on regression and passes on the fix.
---
 tests/convert.test.js | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/tests/convert.test.js b/tests/convert.test.js
index c80ad71..c96c21c 100644
--- a/tests/convert.test.js
+++ b/tests/convert.test.js
@@ -95,11 +95,17 @@ describe('convert command', () => {
     expect(output).toContain('bold');
   });
 
-  test('html to markdown', () => {
-    const inputFile = writeInput('input.html', '

bold and italic

'); + test('html to markdown preserves fenced code blocks with language', () => { + // Multi-line
 is the discriminating case
+    // between htmlToMarkdown and storageToMarkdown: the former emits a
+    // fenced block with the language tag, the latter collapses the body
+    // into inline `code` and drops the language. This test fails if the
+    // html → markdown path is ever routed back through storageToMarkdown.
+    const html = '

bold

\n
const x = 1;\nconst y = 2;
'; + const inputFile = writeInput('input.html', html); const output = run(['convert', '--input-file', inputFile, '--input-format', 'html', '--output-format', 'markdown']); expect(output).toContain('**bold**'); - expect(output).toContain('*italic*'); + expect(output).toMatch(/```js\nconst x = 1;\nconst y = 2;\n```/); }); test('storage to text', () => {