From 81e016c209705cc463945d949b3c270391c1d649 Mon Sep 17 00:00:00 2001 From: Dmitry Pavlov Date: Mon, 24 Jun 2024 10:35:37 +0300 Subject: [PATCH] Fixes for asciidoc: - Escaping & symbol in ri:url attribute. Fixes #183 - Support for attributes in curly braces. Fixes #176 Extra: updated dependencies --- CHANGELOG.md | 6 +++++- convert/pom.xml | 2 +- .../zeldigas/text2confl/convert/Converter.kt | 16 ++++++++++++---- .../text2confl/convert/PageAttributes.kt | 18 +++++++++++++----- .../convert/asciidoc/AsciidocParser.kt | 5 +++++ .../text2confl/asciidoc/block_image.html.slim | 7 ++++--- .../zeldigas/text2confl/asciidoc/helpers.rb | 5 +++++ .../convert/UniversalConverterTest.kt | 1 + .../convert/asciidoc/RenderingOfImagesTest.kt | 8 ++++---- .../convert/asciidoc/RenderingOfLinksTest.kt | 2 +- pom.xml | 8 ++++---- 11 files changed, 55 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab793bf2..14619ece 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +## 0.17.0 - 2024-06-24 + ### Added - Check for conflict of published page with pages parent (#142) @@ -15,12 +17,14 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Changed - dependency updates: - - plantuml to 1.2024.3 + - plantuml to 1.2024.5 - other deps (kotlin, ktor, logback, asciidoctor) ### Fixed - Handling of quotes in image titles and alt text (#166) +- Escaping url for block images (#183) +- Using attributes enclosed in quotes, but not jsons (#176) ## 0.16.0 - 2024-01-07 diff --git a/convert/pom.xml b/convert/pom.xml index 79a2f932..4c69febc 100644 --- a/convert/pom.xml +++ b/convert/pom.xml @@ -13,7 +13,7 @@ 0.64.4 - 2.5.12 + 2.5.13 2.3.0 diff --git a/convert/src/main/kotlin/com/github/zeldigas/text2confl/convert/Converter.kt b/convert/src/main/kotlin/com/github/zeldigas/text2confl/convert/Converter.kt index 89e7757b..51069722 100644 --- a/convert/src/main/kotlin/com/github/zeldigas/text2confl/convert/Converter.kt +++ b/convert/src/main/kotlin/com/github/zeldigas/text2confl/convert/Converter.kt @@ -20,7 +20,7 @@ interface Converter { } -open class ConversionException(message: String) : RuntimeException(message) +open class ConversionException(message: String, e: Throwable? = null) : RuntimeException(message, e) class FileDoesNotExistException(val file: Path) : ConversionException("File does not exist: $file") class DuplicateTitlesException(val duplicates: List, message: String) : ConversionException(message) @@ -64,13 +64,12 @@ internal class UniversalConverter( ) : Converter { override fun convertFile(file: Path): Page { - val converter = converterFor(file) if (!file.exists()) { throw FileDoesNotExistException(file) } return Page( - converter.convert(file, ConvertingContext(ReferenceProvider.singleFile(), conversionParameters, space)), + performConversion(file, ConvertingContext(ReferenceProvider.singleFile(), conversionParameters, space)), file, emptyList() ) @@ -121,7 +120,7 @@ internal class UniversalConverter( private fun convertFilesInDirectory(dir: Path, context: ConvertingContext): List = pagesDetector.scanDirectoryRecursively(dir, filter = { it.supported() }, - converter = { file -> converterFor(file).convert(file, context) }, + converter = { file -> performConversion(file, context) }, assembler = { file, content, children -> Page(content, file, children) } ) @@ -129,6 +128,15 @@ internal class UniversalConverter( converters[file.extension.lowercase()] ?: throw IllegalArgumentException("Unsupported extension: ${file.extension}") + private fun performConversion(file: Path, context: ConvertingContext): PageContent { + val convert = converterFor(file) + return try { + convert.convert(file, context) + } catch(e: Exception) { + throw ConversionException("Failed to convert $file: ${e.message}", e) + } + } + private fun File.supported() = isFile && !name.startsWith("_") && extension.lowercase() in converters private fun Path.supported() = toFile().supported() } \ No newline at end of file diff --git a/convert/src/main/kotlin/com/github/zeldigas/text2confl/convert/PageAttributes.kt b/convert/src/main/kotlin/com/github/zeldigas/text2confl/convert/PageAttributes.kt index 20b04838..ca2ba876 100644 --- a/convert/src/main/kotlin/com/github/zeldigas/text2confl/convert/PageAttributes.kt +++ b/convert/src/main/kotlin/com/github/zeldigas/text2confl/convert/PageAttributes.kt @@ -1,17 +1,25 @@ package com.github.zeldigas.text2confl.convert +import com.fasterxml.jackson.core.JsonParseException import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.readValue +import io.github.oshai.kotlinlogging.KotlinLogging +private val logger = KotlinLogging.logger {} private val JSON_PARSER = ObjectMapper() fun parseAttribute(value: Any): Any { return if (value is String) { - if (value.enclosedIn('{', '}')) { - JSON_PARSER.readValue>(value) - } else if (value.enclosedIn('[', ']')) { - JSON_PARSER.readValue>(value) - } else { + try { + if (value.enclosedIn('{', '}')) { + JSON_PARSER.readValue>(value) + } else if (value.enclosedIn('[', ']')) { + JSON_PARSER.readValue>(value) + } else { + value + } + } catch (e: JsonParseException) { + logger.debug(e) { "Failed to parse value $value, looks like not a valid json" } value } } else { diff --git a/convert/src/main/kotlin/com/github/zeldigas/text2confl/convert/asciidoc/AsciidocParser.kt b/convert/src/main/kotlin/com/github/zeldigas/text2confl/convert/asciidoc/AsciidocParser.kt index 03e02b76..8a640f00 100644 --- a/convert/src/main/kotlin/com/github/zeldigas/text2confl/convert/asciidoc/AsciidocParser.kt +++ b/convert/src/main/kotlin/com/github/zeldigas/text2confl/convert/asciidoc/AsciidocParser.kt @@ -92,4 +92,9 @@ data class AsciidocRenderingParameters( object Converter { fun convert(string: String): String = unescapeHtml(string) + + fun escapeXml(string: String) = string.replace("&", "&") + .replace("<", "<") + .replace(">", ">") + .replace("\"", """) } \ No newline at end of file diff --git a/convert/src/main/resources/com/github/zeldigas/text2confl/asciidoc/block_image.html.slim b/convert/src/main/resources/com/github/zeldigas/text2confl/asciidoc/block_image.html.slim index ebee3fa2..f118d9ea 100644 --- a/convert/src/main/resources/com/github/zeldigas/text2confl/asciidoc/block_image.html.slim +++ b/convert/src/main/resources/com/github/zeldigas/text2confl/asciidoc/block_image.html.slim @@ -1,12 +1,13 @@ p = html_a_tag_if (attr? :link) ac:image ac:height=(attr :height) ac:width=(attr :width) ac:title=(escape_quotes(title) if title?) ac:alt=(escape_quotes(attr :alt) if attr :alt) ac:thumbnail=(attr :thumbnail) ac:align=(attr :align) ac:border=(attr :border) ac:class=(attr :class) ac:style=(attr :imgstyle) ac:vspace=(attr :vspace) ac:hspace=(attr :hspace) ac:queryparams=(escape_quotes(attr :queryparams) if attr :queryparams) + - target = attr :target - if uriish? attr :target - ri:url ri:value=(attr :target) / + ri:url ri:value=(escape_xml_attr target) / - else - - attachment = page_attachment(attr :target) + - attachment = page_attachment(target) - if attachment.nil? - ri:url ri:value=(attr :target) / + ri:url ri:value=(escape_xml_attr target) / - else ri:attachment ri:filename=(attachment) / - if title? diff --git a/convert/src/main/resources/com/github/zeldigas/text2confl/asciidoc/helpers.rb b/convert/src/main/resources/com/github/zeldigas/text2confl/asciidoc/helpers.rb index 83d6836e..6dc29509 100644 --- a/convert/src/main/resources/com/github/zeldigas/text2confl/asciidoc/helpers.rb +++ b/convert/src/main/resources/com/github/zeldigas/text2confl/asciidoc/helpers.rb @@ -291,5 +291,10 @@ def escape_quotes val val.gsub(/"/, '"'.freeze) end + def escape_xml_attr val + decoder = document.attr 't2c-decoder' + decoder.escapeXml(val) + end + end diff --git a/convert/src/test/kotlin/com/github/zeldigas/text2confl/convert/UniversalConverterTest.kt b/convert/src/test/kotlin/com/github/zeldigas/text2confl/convert/UniversalConverterTest.kt index d2e8cb0c..4dcc6194 100644 --- a/convert/src/test/kotlin/com/github/zeldigas/text2confl/convert/UniversalConverterTest.kt +++ b/convert/src/test/kotlin/com/github/zeldigas/text2confl/convert/UniversalConverterTest.kt @@ -71,6 +71,7 @@ internal class UniversalConverterTest( @Test internal fun `No file conversion for unsupported format`(@TempDir dir: Path) { val src = dir.resolve("test.unsupported") + Files.createFile(src) assertFailure { converter.convertFile(src) } .isInstanceOf(IllegalArgumentException::class).hasMessage("Unsupported extension: unsupported") diff --git a/convert/src/test/kotlin/com/github/zeldigas/text2confl/convert/asciidoc/RenderingOfImagesTest.kt b/convert/src/test/kotlin/com/github/zeldigas/text2confl/convert/asciidoc/RenderingOfImagesTest.kt index 66ce723e..747091bf 100644 --- a/convert/src/test/kotlin/com/github/zeldigas/text2confl/convert/asciidoc/RenderingOfImagesTest.kt +++ b/convert/src/test/kotlin/com/github/zeldigas/text2confl/convert/asciidoc/RenderingOfImagesTest.kt @@ -14,7 +14,7 @@ internal class RenderingOfImagesTest : RenderingTestBase() { .A Title image::https://example.org/test.jpg[Alt text] - image::https://example.org/test.jpg[] + image::https://example.org/test.jpg?id=12¶m=b[] image::assets/image.jpg[] @@ -34,7 +34,7 @@ internal class RenderingOfImagesTest : RenderingTestBase() { assertThat(result).isEqualToConfluenceFormat( """

Figure 1. A Title

-

+

Figure 2. "Quoted text" regular text <special text>

""".trimIndent(), @@ -45,7 +45,7 @@ internal class RenderingOfImagesTest : RenderingTestBase() { internal fun `Existing images inline rendering`() { val result = toHtml( """ - External image inside paragraph - image:https://example.org/test.jpg[Alt text,title="A Title"] + External image inside paragraph - image:https://example.org/test.jpg?id=12¶m=b[Alt text,title="A Title"] Attachment image inside paragraph - image:assets/image.jpg[Alt,title="Asset"] """.trimIndent(), @@ -60,7 +60,7 @@ internal class RenderingOfImagesTest : RenderingTestBase() { assertThat(result).isEqualToConfluenceFormat( """ -

External image inside paragraph -

+

External image inside paragraph -

Attachment image inside paragraph -

""".trimIndent(), ) diff --git a/convert/src/test/kotlin/com/github/zeldigas/text2confl/convert/asciidoc/RenderingOfLinksTest.kt b/convert/src/test/kotlin/com/github/zeldigas/text2confl/convert/asciidoc/RenderingOfLinksTest.kt index 5cfbb0e7..57151875 100644 --- a/convert/src/test/kotlin/com/github/zeldigas/text2confl/convert/asciidoc/RenderingOfLinksTest.kt +++ b/convert/src/test/kotlin/com/github/zeldigas/text2confl/convert/asciidoc/RenderingOfLinksTest.kt @@ -165,7 +165,7 @@ internal class RenderingOfLinksTest : RenderingTestBase() { assertThat(result).isEqualToConfluenceFormat( """ -

Subscribe

+

Subscribe

Send email to example@example.org

Send email

""".trimIndent(), diff --git a/pom.xml b/pom.xml index 47efe5fb..6da0ada5 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ 11 11 - 1.9.24 + 2.0.0 UTF-8 UTF-8 @@ -72,7 +72,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.5 + 3.3.0 @@ -89,7 +89,7 @@ org.jetbrains.kotlinx kotlinx-coroutines-bom - 1.8.0 + 1.8.1 pom import @@ -120,7 +120,7 @@ io.github.oshai kotlin-logging-jvm - 6.0.9 + 7.0.0 io.mockk