From 9774c8ae1255c51a82c97fbb9afc07c8c55edaa3 Mon Sep 17 00:00:00 2001 From: redcatbaer Date: Wed, 7 Oct 2026 16:20:56 +0200 Subject: [PATCH 1/6] [574] Fix issue 574 [step 1] Preserve inline code containing Markdown markers Co-authored-by: Junie --- .../html/view/html/MarkdownSpanConverter.java | 39 +++++++++++++++++-- .../view/html/MarkdownSpanConverterTest.java | 14 +++++++ .../html/view/html/TestMarkdownConverter.java | 7 ++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java b/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java index 6836cc7ba..84a557ed5 100644 --- a/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java +++ b/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java @@ -1,6 +1,8 @@ package org.itsallcode.openfasttrace.report.html.view.html; +import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; import java.util.regex.Pattern; final class MarkdownSpanConverter @@ -14,8 +16,9 @@ final class MarkdownSpanConverter private static final RegexReplacement EMPHASIZED_TEXT = RegexReplacement.create("([_*])(\\p{L}(?:.*\\p{L}))\\1", "$2"); - private static final List ALL_MARKDOWN_REPLACEMENTS = List.of(INDENTED_CODE, BACKTICK_QUOTED_CODE, - LINK, BOLD_TEXT, EMPHASIZED_TEXT); + private static final List CODE_REPLACEMENTS = List.of(INDENTED_CODE, BACKTICK_QUOTED_CODE); + private static final List INLINE_MARKDOWN_REPLACEMENTS = List.of(LINK, BOLD_TEXT, + EMPHASIZED_TEXT); // Prevent instantiation private MarkdownSpanConverter() @@ -26,10 +29,40 @@ private MarkdownSpanConverter() static String convertLineContent(final String input) { String text = escapeHtml(input); - for (final RegexReplacement replacement : ALL_MARKDOWN_REPLACEMENTS) + final List codeSpans = new ArrayList<>(); + for (final RegexReplacement codeReplacement : CODE_REPLACEMENTS) + { + text = extractCodeSpans(codeReplacement, text, codeSpans); + } + for (final RegexReplacement replacement : INLINE_MARKDOWN_REPLACEMENTS) { text = replacement.apply(text); } + return restoreCodeSpans(text, codeSpans); + } + + private static String extractCodeSpans(final RegexReplacement codeReplacement, final String input, + final List codeSpans) + { + final Matcher matcher = codeReplacement.pattern.matcher(input); + final StringBuilder sb = new StringBuilder(); + while (matcher.find()) + { + final String placeholder = "\u0000" + codeSpans.size() + "\u0000"; + final String converted = codeReplacement.apply(matcher.group()); + codeSpans.add(converted); + matcher.appendReplacement(sb, Matcher.quoteReplacement(placeholder)); + } + matcher.appendTail(sb); + return sb.toString(); + } + + private static String restoreCodeSpans(String text, final List codeSpans) + { + for (int i = 0; i < codeSpans.size(); i++) + { + text = text.replace("\u0000" + i + "\u0000", codeSpans.get(i)); + } return text; } diff --git a/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java b/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java index 0b137b4e8..70798cb57 100644 --- a/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java +++ b/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java @@ -12,9 +12,23 @@ class MarkdownSpanConverterTest @CsvSource( { "' code\n', '
    code\n
'", + "' code_with_underscore\n', '
    code_with_underscore\n
'", "' code\n', '
     code\n
'", "' code', ' code'", "`code`, code", + "`pull_request_target`, pull_request_target", + "`GITHUB_OUTPUT`, GITHUB_OUTPUT", + "`pull_request_target` and `GITHUB_OUTPUT`, pull_request_target and GITHUB_OUTPUT", + "`_text_`, _text_", + "`__text__`, __text__", + "`*text*`, *text*", + "`**text**`, **text**", + "`$foo_bar`, $foo_bar", + "`\\d+_test`, \\d+_test", + "``, <xml_tag>", + "`[text](https://example.com)`, [text](https://example.com)", + "`pull_request_target` and _emphasis_ and **bold**, pull_request_target and emphasis and bold", + "_emphasis_ `code_with_underscore` *emphasis*, emphasis code_with_underscore emphasis", "[text](https://example.com), text", "[ text ](https://example.com), text ", "prefix [text](https://example.com) suffix, prefix text suffix", diff --git a/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/TestMarkdownConverter.java b/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/TestMarkdownConverter.java index c63392737..38f2814fb 100644 --- a/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/TestMarkdownConverter.java +++ b/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/TestMarkdownConverter.java @@ -149,6 +149,13 @@ void testConvertCode() "

This text contains code and regular text

"); } + @Test + void testConvertCodeWithUnderscores() + { + assertConverted("Workflows that run in `pull_request_target` context must not write `GITHUB_OUTPUT`.", + "

Workflows that run in pull_request_target context must not write GITHUB_OUTPUT.

"); + } + @Test void testConvertLink() { From c10c4e6583a2fa35451e1006b70eefcb72f21772 Mon Sep 17 00:00:00 2001 From: redcatbaer Date: Wed, 7 Oct 2026 16:29:51 +0200 Subject: [PATCH 2/6] [574] Fix issue 574 [step 1] Prevent code span placeholder collisions Co-authored-by: Junie --- doc/changes/changes_4.11.0.md | 4 ++++ .../html/view/html/MarkdownSpanConverter.java | 23 ++++++++++++++----- .../view/html/MarkdownSpanConverterTest.java | 11 +++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/doc/changes/changes_4.11.0.md b/doc/changes/changes_4.11.0.md index 2e3958bee..da02e2911 100644 --- a/doc/changes/changes_4.11.0.md +++ b/doc/changes/changes_4.11.0.md @@ -14,6 +14,10 @@ Fix typo and syntax in agent skills. - #612: Add support for Visual Basic in the source tag importer +## Bugfixes + +- #574: Fixed invalid HTML when inline code contains underscores + ## Documentation - #604: Fixed link to Product Lifecycle in SECURITY.md diff --git a/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java b/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java index 84a557ed5..9512a02bf 100644 --- a/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java +++ b/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java @@ -29,26 +29,37 @@ private MarkdownSpanConverter() static String convertLineContent(final String input) { String text = escapeHtml(input); + final String delimiter = createUniqueDelimiter(text); final List codeSpans = new ArrayList<>(); for (final RegexReplacement codeReplacement : CODE_REPLACEMENTS) { - text = extractCodeSpans(codeReplacement, text, codeSpans); + text = extractCodeSpans(codeReplacement, text, codeSpans, delimiter); } for (final RegexReplacement replacement : INLINE_MARKDOWN_REPLACEMENTS) { text = replacement.apply(text); } - return restoreCodeSpans(text, codeSpans); + return restoreCodeSpans(text, codeSpans, delimiter); + } + + private static String createUniqueDelimiter(final String text) + { + String delimiter = "\u0000"; + while (text.contains(delimiter)) + { + delimiter += "\u0000"; + } + return delimiter; } private static String extractCodeSpans(final RegexReplacement codeReplacement, final String input, - final List codeSpans) + final List codeSpans, final String delimiter) { final Matcher matcher = codeReplacement.pattern.matcher(input); final StringBuilder sb = new StringBuilder(); while (matcher.find()) { - final String placeholder = "\u0000" + codeSpans.size() + "\u0000"; + final String placeholder = delimiter + codeSpans.size() + delimiter; final String converted = codeReplacement.apply(matcher.group()); codeSpans.add(converted); matcher.appendReplacement(sb, Matcher.quoteReplacement(placeholder)); @@ -57,11 +68,11 @@ private static String extractCodeSpans(final RegexReplacement codeReplacement, f return sb.toString(); } - private static String restoreCodeSpans(String text, final List codeSpans) + private static String restoreCodeSpans(String text, final List codeSpans, final String delimiter) { for (int i = 0; i < codeSpans.size(); i++) { - text = text.replace("\u0000" + i + "\u0000", codeSpans.get(i)); + text = text.replace(delimiter + i + delimiter, codeSpans.get(i)); } return text; } diff --git a/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java b/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java index 70798cb57..6c1a55eae 100644 --- a/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java +++ b/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java @@ -3,6 +3,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; @@ -13,6 +14,7 @@ class MarkdownSpanConverterTest { "' code\n', '
    code\n
'", "' code_with_underscore\n', '
    code_with_underscore\n
'", + "' code with `backticks` and _underscores_\n', '
    code with `backticks` and _underscores_\n
'", "' code\n', '
     code\n
'", "' code', ' code'", "`code`, code", @@ -61,6 +63,15 @@ void assertConverted(final String inputLine, final String expected) assertThat(MarkdownSpanConverter.convertLineContent(inputLine), equalTo(expected)); } + @Test + void testPlaceholderNoCollisionWithInputControlCharacters() + { + assertThat(MarkdownSpanConverter.convertLineContent("x \u00000\u0000 `y`"), + equalTo("x \u00000\u0000 y")); + assertThat(MarkdownSpanConverter.convertLineContent("`a` \u00001\u0000 `b`"), + equalTo("a \u00001\u0000 b")); + } + // [utest->dsn~reporting.html.escape-html~1] @ParameterizedTest(name = "Line ''{0}'' escaped as HTML ''{1}''") @CsvSource( From ec393eb0fcd71558642f57d37d564650b62962ff Mon Sep 17 00:00:00 2001 From: redcatbaer Date: Wed, 7 Oct 2026 16:34:51 +0200 Subject: [PATCH 3/6] [574] Fix issue 574 [step 1] Restore HTML code spans without corrupting placeholders Co-authored-by: Junie --- .../html/view/html/MarkdownSpanConverter.java | 11 ++++++++--- .../view/html/MarkdownSpanConverterTest.java | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java b/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java index 9512a02bf..c814a3db5 100644 --- a/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java +++ b/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java @@ -70,11 +70,16 @@ private static String extractCodeSpans(final RegexReplacement codeReplacement, f private static String restoreCodeSpans(String text, final List codeSpans, final String delimiter) { - for (int i = 0; i < codeSpans.size(); i++) + final Pattern placeholderPattern = Pattern.compile(Pattern.quote(delimiter) + "(\\d+)" + Pattern.quote(delimiter)); + final Matcher matcher = placeholderPattern.matcher(text); + final StringBuilder sb = new StringBuilder(); + while (matcher.find()) { - text = text.replace(delimiter + i + delimiter, codeSpans.get(i)); + final int index = Integer.parseInt(matcher.group(1)); + matcher.appendReplacement(sb, Matcher.quoteReplacement(codeSpans.get(index))); } - return text; + matcher.appendTail(sb); + return sb.toString(); } static String escapeHtml(String text) diff --git a/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java b/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java index 6c1a55eae..5ae2408fb 100644 --- a/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java +++ b/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java @@ -5,7 +5,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; class MarkdownSpanConverterTest { @@ -73,6 +75,22 @@ void testPlaceholderNoCollisionWithInputControlCharacters() } // [utest->dsn~reporting.html.escape-html~1] + @ParameterizedTest(name = "Line ''{0}'' converted to HTML ''{1}''") + @MethodSource("provideSpecialTestCases") + void assertConvertedSpecial(final String inputLine, final String expected) + { + assertThat(MarkdownSpanConverter.convertLineContent(inputLine), equalTo(expected)); + } + + private static java.util.stream.Stream provideSpecialTestCases() + { + return java.util.stream.Stream.of( + Arguments.of("`a`, `b`0`c`", "a, b0c"), + Arguments.of("`x` `y`0`z`", "x y0z"), + Arguments.of(" indented\n0`backtick`", "
    indented\n
0backtick") + ); + } + @ParameterizedTest(name = "Line ''{0}'' escaped as HTML ''{1}''") @CsvSource( { From 9e5d115f40b40862876c0737574d72371d20c616 Mon Sep 17 00:00:00 2001 From: redcatbaer Date: Wed, 7 Oct 2026 18:51:55 +0200 Subject: [PATCH 4/6] 574: Fixed rendering of multi-line text blocks with Markdown notation support. --- .../use_cases/writing_a_specification.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/user_guide/use_cases/writing_a_specification.md b/doc/user_guide/use_cases/writing_a_specification.md index 8b95ed6d1..a3a05ba5f 100644 --- a/doc/user_guide/use_cases/writing_a_specification.md +++ b/doc/user_guide/use_cases/writing_a_specification.md @@ -177,6 +177,20 @@ is functionally equivalent to Tags are described in detail later in this document, see section [Distributing the Detailing Work](distributing_the_detailing_work.md#distributing-the-detailing-work). +#### Notation in Multiline Text Blocks + +Multiline text blocks within specification items—specifically the `Description` (or implicit description text), `Rationale`, and `Comment`—support a subset of Markdown notation. When OpenFastTrace processes and renders these blocks (such as in HTML reports), the following markup elements are supported: + +* **Paragraphs**: Blocks of text are grouped into paragraphs separated by blank lines. +* **Unordered Lists**: Lines starting with a bullet marker (`-`, `*`, or `+`) with up to three leading spaces create bulleted lists. Multi-line list items are supported by continuing text on following lines without an empty line in between. +* **Ordered Lists**: Lines starting with numbers followed by a period (e.g., `1.`, `2.`) create numbered lists. +* **Preformatted Blocks / Code**: Lines indented by at least four spaces are treated as preformatted text and rendered in `
` blocks.
+* **Inline Code**: Text enclosed in backticks (`` `code` ``) is rendered as inline monospace code (``).
+* **Hyperlinks**: Markdown links in the format `[Link Text](URL)` are rendered as clickable links.
+* **Emphasis (Italics)**: Text surrounded by single asterisks (`*text*`) or single underscores (`_text_`) is formatted with emphasis (``).
+* **Strong (Bold)**: Text surrounded by double asterisks (`**text**`) or double underscores (`__text__`) is formatted in bold (``).
+* **HTML Escaping**: Angle brackets (`<` and `>`) are automatically escaped (as `<` and `>`) so that code snippets, XML/HTML tags, or type parameters (such as ``) are safely rendered without breaking the document structure.
+
 
 ### Quality Scenarios
 

From 791a37fc0ff6f65d8173aeae7d02f2c603a80302 Mon Sep 17 00:00:00 2001
From: redcatbaer 
Date: Thu, 8 Oct 2026 07:59:13 +0200
Subject: [PATCH 5/6] 574: Simplified zero marker.

---
 .../use_cases/writing_a_specification.md      |  4 +++
 .../html/view/html/MarkdownSpanConverter.java | 28 ++++++-------------
 .../view/html/MarkdownSpanConverterTest.java  |  6 ++--
 3 files changed, 16 insertions(+), 22 deletions(-)

diff --git a/doc/user_guide/use_cases/writing_a_specification.md b/doc/user_guide/use_cases/writing_a_specification.md
index a3a05ba5f..6f0b88d15 100644
--- a/doc/user_guide/use_cases/writing_a_specification.md
+++ b/doc/user_guide/use_cases/writing_a_specification.md
@@ -191,6 +191,10 @@ Multiline text blocks within specification items—specifically the `Description
 * **Strong (Bold)**: Text surrounded by double asterisks (`**text**`) or double underscores (`__text__`) is formatted in bold (``).
 * **HTML Escaping**: Angle brackets (`<` and `>`) are automatically escaped (as `<` and `>`) so that code snippets, XML/HTML tags, or type parameters (such as ``) are safely rendered without breaking the document structure.
 
+##### Constraints on Multiline Text Blocks
+
+* **No Zero Characters**: Original multiline texts must not contain zero characters (NUL / `\0`). Any zero characters present in the text are removed before rendering.
+
 
 ### Quality Scenarios
 
diff --git a/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java b/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java
index c814a3db5..5ae775899 100644
--- a/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java
+++ b/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java
@@ -7,6 +7,8 @@
 
 final class MarkdownSpanConverter
 {
+    private static final String ZERO_SEPARATOR = "\0";
+    private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile(ZERO_SEPARATOR + "(\\d+)" + ZERO_SEPARATOR);
     private static final RegexReplacement INDENTED_CODE = RegexReplacement.create("(    .*[\n])+", "
$1
"); private static final RegexReplacement BACKTICK_QUOTED_CODE = RegexReplacement.create("`(.*?)`", "$1"); private static final RegexReplacement LINK = RegexReplacement.create("\\[([^]]*?)\\]\\(([^)].*?)\\)", @@ -28,38 +30,27 @@ private MarkdownSpanConverter() // [impl->dsn~reporting.html.escape-html~1] static String convertLineContent(final String input) { - String text = escapeHtml(input); - final String delimiter = createUniqueDelimiter(text); + String text = escapeHtml(input).replace(ZERO_SEPARATOR, ""); final List codeSpans = new ArrayList<>(); for (final RegexReplacement codeReplacement : CODE_REPLACEMENTS) { - text = extractCodeSpans(codeReplacement, text, codeSpans, delimiter); + text = extractCodeSpans(codeReplacement, text, codeSpans); } for (final RegexReplacement replacement : INLINE_MARKDOWN_REPLACEMENTS) { text = replacement.apply(text); } - return restoreCodeSpans(text, codeSpans, delimiter); - } - - private static String createUniqueDelimiter(final String text) - { - String delimiter = "\u0000"; - while (text.contains(delimiter)) - { - delimiter += "\u0000"; - } - return delimiter; + return restoreCodeSpans(text, codeSpans); } private static String extractCodeSpans(final RegexReplacement codeReplacement, final String input, - final List codeSpans, final String delimiter) + final List codeSpans) { final Matcher matcher = codeReplacement.pattern.matcher(input); final StringBuilder sb = new StringBuilder(); while (matcher.find()) { - final String placeholder = delimiter + codeSpans.size() + delimiter; + final String placeholder = ZERO_SEPARATOR + codeSpans.size() + ZERO_SEPARATOR; final String converted = codeReplacement.apply(matcher.group()); codeSpans.add(converted); matcher.appendReplacement(sb, Matcher.quoteReplacement(placeholder)); @@ -68,10 +59,9 @@ private static String extractCodeSpans(final RegexReplacement codeReplacement, f return sb.toString(); } - private static String restoreCodeSpans(String text, final List codeSpans, final String delimiter) + private static String restoreCodeSpans(final String text, final List codeSpans) { - final Pattern placeholderPattern = Pattern.compile(Pattern.quote(delimiter) + "(\\d+)" + Pattern.quote(delimiter)); - final Matcher matcher = placeholderPattern.matcher(text); + final Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); final StringBuilder sb = new StringBuilder(); while (matcher.find()) { diff --git a/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java b/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java index 5ae2408fb..890009f0b 100644 --- a/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java +++ b/reporter/html/src/test/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverterTest.java @@ -66,12 +66,12 @@ void assertConverted(final String inputLine, final String expected) } @Test - void testPlaceholderNoCollisionWithInputControlCharacters() + void testZeroCharactersStrippedBeforeRendering() { assertThat(MarkdownSpanConverter.convertLineContent("x \u00000\u0000 `y`"), - equalTo("x \u00000\u0000 y")); + equalTo("x 0 y")); assertThat(MarkdownSpanConverter.convertLineContent("`a` \u00001\u0000 `b`"), - equalTo("a \u00001\u0000 b")); + equalTo("a 1 b")); } // [utest->dsn~reporting.html.escape-html~1] From deb9041539abd3adf7cba20a4914eb43fdc411e7 Mon Sep 17 00:00:00 2001 From: redcatbaer Date: Thu, 8 Oct 2026 08:05:30 +0200 Subject: [PATCH 6/6] 574: Wrote out abbreviation for string builder. --- .../html/view/html/MarkdownSpanConverter.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java b/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java index 5ae775899..b3889cb8b 100644 --- a/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java +++ b/reporter/html/src/main/java/org/itsallcode/openfasttrace/report/html/view/html/MarkdownSpanConverter.java @@ -47,29 +47,29 @@ private static String extractCodeSpans(final RegexReplacement codeReplacement, f final List codeSpans) { final Matcher matcher = codeReplacement.pattern.matcher(input); - final StringBuilder sb = new StringBuilder(); + final StringBuilder builder = new StringBuilder(); while (matcher.find()) { final String placeholder = ZERO_SEPARATOR + codeSpans.size() + ZERO_SEPARATOR; final String converted = codeReplacement.apply(matcher.group()); codeSpans.add(converted); - matcher.appendReplacement(sb, Matcher.quoteReplacement(placeholder)); + matcher.appendReplacement(builder, Matcher.quoteReplacement(placeholder)); } - matcher.appendTail(sb); - return sb.toString(); + matcher.appendTail(builder); + return builder.toString(); } private static String restoreCodeSpans(final String text, final List codeSpans) { final Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); - final StringBuilder sb = new StringBuilder(); + final StringBuilder builder = new StringBuilder(); while (matcher.find()) { final int index = Integer.parseInt(matcher.group(1)); - matcher.appendReplacement(sb, Matcher.quoteReplacement(codeSpans.get(index))); + matcher.appendReplacement(builder, Matcher.quoteReplacement(codeSpans.get(index))); } - matcher.appendTail(sb); - return sb.toString(); + matcher.appendTail(builder); + return builder.toString(); } static String escapeHtml(String text)