AsciiDocToHtml.java

1
package pro.verron.officestamper.asciidoc;
2
3
import java.util.List;
4
import java.util.Map;
5
import java.util.function.Function;
6
import java.util.stream.Collectors;
7
8
import static pro.verron.officestamper.asciidoc.AsciiDocModel.*;
9
10
/// The AsciiDocToHtml class is responsible for rendering an AsciiDoc representation
11
/// into its corresponding HTML output. It implements the [Function] interface,
12
/// converting an [AsciiDocModel] to a String containing the HTML representation.
13
///
14
/// This class provides static utility methods for rendering various AsciiDoc block
15
/// types and inline elements into their HTML counterparts. The following block types
16
/// are supported for conversion:
17
///
18
/// - Headings
19
/// - Paragraphs
20
/// - Unordered and Ordered Lists
21
/// - Tables
22
/// - Blockquotes
23
/// - Code Blocks
24
/// - Image Blocks
25
///
26
/// Additionally, inline elements such as bold, italic, links, images, and text are
27
/// rendered with appropriate HTML tags.
28
///
29
/// The class adheres to the functional programming paradigm by implementing the
30
/// [#apply(AsciiDocModel)] method to facilitate the mapping of AsciiDoc models to HTML.
31
///
32
/// This class is immutable and cannot be instantiated.
33
public final class AsciiDocToHtml
34
        implements Function<AsciiDocModel, String> {
35
36
    private static String renderBlock(Block block) {
37
        switch (block) {
38 1 1. renderBlock : negated conditional → NO_COVERAGE
            case Heading(_, int level, List<Inline> inlines) -> {
39 1 1. renderBlock : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE
                return String.format("<h%d>%s</h%d>\n", level, renderInlines(inlines), level);
40
            }
41
            case Paragraph(List<String> header, List<Inline> inlines) -> {
42 2 1. renderBlock : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE
2. renderBlock : negated conditional → NO_COVERAGE
                if (header.isEmpty()) return String.format("<p>%s</p>\n", renderInlines(inlines));
43 1 1. renderBlock : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE
                else return String.format("<p class=\"%s\">%s</p>\n", header.getFirst(), renderInlines(inlines));
44
            }
45
            case UnorderedList(List<ListItem> items) -> {
46 1 1. renderBlock : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE
                return "<ul>\n" + items.stream()
47 1 1. lambda$renderBlock$0 : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::lambda$renderBlock$0 → NO_COVERAGE
                                       .map(item -> "  <li>" + renderInlines(item.inlines()) + "</li>\n")
48
                                       .collect(Collectors.joining()) + "</ul>\n";
49
            }
50
            case OrderedList(List<ListItem> items) -> {
51 1 1. renderBlock : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE
                return "<ol>\n" + items.stream()
52 1 1. lambda$renderBlock$1 : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::lambda$renderBlock$1 → NO_COVERAGE
                                       .map(item -> "  <li>" + renderInlines(item.inlines()) + "</li>\n")
53
                                       .collect(Collectors.joining()) + "</ol>\n";
54
            }
55
            case Table(List<Row> rows) -> {
56
                StringBuilder sb = new StringBuilder("<table>\n");
57
                for (Row row : rows) {
58
                    sb.append("  <tr>\n");
59
                    for (Cell cell : row.cells()) {
60
                        sb.append("    <td>")
61
                          .append(cell.blocks()
62
                                      .stream()
63
                                      .map(AsciiDocToHtml::renderBlock)
64
                                      .collect(Collectors.joining()))
65
                          .append("</td>\n");
66
                    }
67
                    sb.append("  </tr>\n");
68
                }
69
                sb.append("</table>\n");
70 1 1. renderBlock : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE
                return sb.toString();
71
            }
72
            case Blockquote(List<Inline> inlines) -> {
73 1 1. renderBlock : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE
                return "<blockquote>" + renderInlines(inlines) + "</blockquote>\n";
74
            }
75
            case CodeBlock(String language, String content) -> {
76 1 1. renderBlock : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE
                return String.format("<pre><code class=\"language-%s\">%s</code></pre>\n", language, content);
77
            }
78
            case ImageBlock(String url, String altText) -> {
79 1 1. renderBlock : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE
                return String.format("<img src=\"%s\" alt=\"%s\">\n", url, altText);
80
            }
81
            default -> { /* DO NOTHING */ }
82
        }
83
        return "";
84
    }
85
86
    private static String renderInlines(List<Inline> inlines) {
87
        StringBuilder sb = new StringBuilder();
88
        for (Inline inline : inlines) {
89
            switch (inline) {
90
                case Text(String text1) -> sb.append(text1);
91
                case Bold(List<Inline> children1) -> sb.append("<b>")
92
                                                       .append(renderInlines(children1))
93
                                                       .append("</b>");
94
                case Italic(List<Inline> children) -> sb.append("<i>")
95
                                                        .append(renderInlines(children))
96
                                                        .append("</i>");
97
                case Tab _ -> sb.append("&nbsp;&nbsp;&nbsp;&nbsp;");
98
                case Link(String url1, String text) -> sb.append(String.format("<a href=\"%s\">%s</a>", url1, text));
99
                case InlineImage(String url, Map<String, String> map) ->
100
                        sb.append(String.format("<img src=\"%s\" alt=\"%s\">", url, map.get("title")));
101
                default -> { /* DO NOTHING */ }
102
            }
103
        }
104 1 1. renderInlines : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderInlines → NO_COVERAGE
        return sb.toString();
105
    }
106
107
    /// Converts the given AsciiDoc model into an HTML document string.
108
    ///
109
    /// @param model the AsciiDocModel containing the blocks to be processed.
110
    /// @return the resulting HTML document as a string.
111
    public String apply(AsciiDocModel model) {
112
        StringBuilder html = new StringBuilder();
113
        html.append("<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n</head>\n<body>\n");
114
        for (Block block : model.getBlocks()) {
115
            html.append(renderBlock(block));
116
        }
117
        html.append("</body>\n</html>");
118 1 1. apply : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::apply → NO_COVERAGE
        return html.toString();
119
    }
120
}

Mutations

38

1.1
Location : renderBlock
Killed by : none
negated conditional → NO_COVERAGE

39

1.1
Location : renderBlock
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE

42

1.1
Location : renderBlock
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE

2.2
Location : renderBlock
Killed by : none
negated conditional → NO_COVERAGE

43

1.1
Location : renderBlock
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE

46

1.1
Location : renderBlock
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE

47

1.1
Location : lambda$renderBlock$0
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::lambda$renderBlock$0 → NO_COVERAGE

51

1.1
Location : renderBlock
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE

52

1.1
Location : lambda$renderBlock$1
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::lambda$renderBlock$1 → NO_COVERAGE

70

1.1
Location : renderBlock
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE

73

1.1
Location : renderBlock
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE

76

1.1
Location : renderBlock
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE

79

1.1
Location : renderBlock
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderBlock → NO_COVERAGE

104

1.1
Location : renderInlines
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::renderInlines → NO_COVERAGE

118

1.1
Location : apply
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToHtml::apply → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.23.1 support