diff --git a/src/commonMain/kotlin/ch/derlin/bitdowntoc/BitGenerator.kt b/src/commonMain/kotlin/ch/derlin/bitdowntoc/BitGenerator.kt index 71aada6..e6436cb 100644 --- a/src/commonMain/kotlin/ch/derlin/bitdowntoc/BitGenerator.kt +++ b/src/commonMain/kotlin/ch/derlin/bitdowntoc/BitGenerator.kt @@ -76,6 +76,10 @@ object BitGenerator { val codeMarker = listOf('`', '~').firstNotNullOfOrNull { line.getCodeStart(it) } if (!codeMarker.isNullOrBlank()) iter.consumeCode(codeMarker) + else if (line.isCompleteHtmlComment()) { + // Single-line HTML comment, keep in output but don't process for TOC + } + else if (line.isHtmlCommentStart()) iter.consumeHtmlComment() else if (commenter.isAnchor(line)) iter.remove() else { line.parseHeader(toc)?.let { @@ -122,10 +126,25 @@ object BitGenerator { .takeIf { it.startsWith("$char".repeat(3)) } ?.let { trimmedLine -> trimmedLine.takeWhile { it == char } } + private fun String.isHtmlCommentStart(): Boolean { + val trimmed = this.trim() + return trimmed.startsWith("") && !trimmed.contains("TOC") + } private fun Iterator.consumeCode(codeMarker: String) { while (this.hasNext() && !this.next().trim().startsWith(codeMarker)); } + private fun Iterator.consumeHtmlComment() { + while (this.hasNext()) { + if (this.next().trim().endsWith("-->")) break + } + } + private fun Iterable.asText() = this.joinToString(NL) } diff --git a/src/commonTest/kotlin/ch.derlin.bitdowntoc/HtmlCommentsTest.kt b/src/commonTest/kotlin/ch.derlin.bitdowntoc/HtmlCommentsTest.kt new file mode 100644 index 0000000..b417beb --- /dev/null +++ b/src/commonTest/kotlin/ch.derlin.bitdowntoc/HtmlCommentsTest.kt @@ -0,0 +1,174 @@ +package ch.derlin.bitdowntoc + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import kotlin.test.assertFalse + +class HtmlCommentsTest { + + @Test + fun testHtmlCommentsAreIgnored() { + val input = """ + # Example + + [TOC] + + ## Section A + + TODO + + + + ## Section B + + TODO + """.trimIndent() + + val expected = """ + # Example + + + + - [Section A](#section-a) + - [Section B](#section-b) + + + + ## Section A + + TODO + + + + ## Section B + + TODO + """.trimIndent() + + assertEquals( + expected, + BitGenerator.generate(input, BitGenerator.Params(generateAnchors = false)) + ) + } + + @Test + fun testSingleLineHtmlCommentsAreIgnored() { + val input = """ + # Example + + [TOC] + + ## Section A + + + + ## Section B + """.trimIndent() + + val expected = """ + # Example + + + + - [Section A](#section-a) + - [Section B](#section-b) + + + + ## Section A + + + + ## Section B + """.trimIndent() + + assertEquals( + expected, + BitGenerator.generate(input, BitGenerator.Params(generateAnchors = false)) + ) + } + + @Test + fun testMultipleHeadingsInHtmlCommentsAreIgnored() { + val input = """ + # Example + + [TOC] + + ## Section A + + + + ## Section B + """.trimIndent() + + val expected = """ + # Example + + + + - [Section A](#section-a) + - [Section B](#section-b) + + + + ## Section A + + + + ## Section B + """.trimIndent() + + assertEquals( + expected, + BitGenerator.generate(input, BitGenerator.Params(generateAnchors = false)) + ) + } + + @Test + fun testBitDownTocCommentsAreNotIgnored() { + val input = """ + # Example + + [TOC] + + ## Section A + + + + ## Section B + """.trimIndent() + + val result = BitGenerator.generate(input, BitGenerator.Params(generateAnchors = true)) + + // Check that HTML comments are preserved in output + assertTrue(result.contains(""), "HTML comments should be preserved in output") + + // Check that TOC only contains Section A and Section B, not Placeholder SubSection + val tocLines = result.lines().dropWhile { !it.contains("TOC start") }.takeWhile { !it.contains("TOC end") } + val tocContent = tocLines.joinToString("\n") + assertTrue(tocContent.contains("Section A"), "TOC should contain Section A") + assertTrue(tocContent.contains("Section B"), "TOC should contain Section B") + assertFalse(tocContent.contains("Placeholder SubSection"), "TOC should NOT contain Placeholder SubSection") + + // Check that BitDownToc comments are preserved + assertTrue(result.contains(""), "BitDownToc comments should be preserved") + } +} \ No newline at end of file