AsciiDocToText.java

1
package pro.verron.officestamper.asciidoc;
2
3
import org.jspecify.annotations.NonNull;
4
5
import java.util.List;
6
import java.util.Map;
7
import java.util.function.Function;
8
import java.util.stream.Collectors;
9
10
import static pro.verron.officestamper.asciidoc.AsciiDocModel.*;
11
12
public final class AsciiDocToText
13
        implements Function<AsciiDocModel, String> {
14
15
    private static String renderInlines(List<@NonNull Inline> inlines) {
16
        var sb = new StringBuilder();
17
        for (Inline inline : inlines) {
18
            sb.append(switch (inline) {
19
                case Text(String text) -> text;
20
                case Bold(List<Inline> children) -> "*%s*".formatted(renderInlines(children));
21
                case Italic(List<Inline> children) -> "_%s_".formatted(renderInlines(children));
22
                case Sup(List<Inline> children) -> "^%s^".formatted(renderInlines(children));
23
                case Sub(List<Inline> children) -> "~%s~".formatted(renderInlines(children));
24
                case Tab _ -> sb.append("\t");
25
                case Link(String url, String text) -> "%s[%s]".formatted(url, text);
26
                case InlineImage(String path, Map<String, String> map) -> "image:%s[%s]".formatted(path,
27
                        map.entrySet()
28
                           .stream()
29 1 1. lambda$renderInlines$0 : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::lambda$renderInlines$0 → NO_COVERAGE
                           .map(e -> e.getKey() + "=" + e.getValue())
30
                           .collect(Collectors.joining(", ")));
31
                case Styled(String role, List<Inline> children) -> "[%s]#%s#".formatted(role, renderInlines(children));
32
                case InlineMacro(String name, String id, List<String> list) ->
33
                        "%s:%s[%s]".formatted(name, id, String.join(", ", list));
34
            });
35
        }
36 1 1. renderInlines : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderInlines → KILLED
        return sb.toString();
37
    }
38
39
    private static String renderCellContent(Cell cell, boolean isAsciidoc, int level) {
40
        var blockList = cell.blocks();
41 1 1. renderCellContent : negated conditional → KILLED
        if (!isAsciidoc) {
42 1 1. renderCellContent : negated conditional → KILLED
            if (blockList.isEmpty()) return "";
43
            Paragraph p = (Paragraph) blockList.getFirst();
44 1 1. renderCellContent : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderCellContent → KILLED
            return renderInlines(p.inlines());
45
        }
46
        else {
47 1 1. renderCellContent : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderCellContent → KILLED
            return blockList.stream()
48 1 1. lambda$renderCellContent$0 : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::lambda$renderCellContent$0 → KILLED
                            .map(block -> renderBlock(block, level))
49
                            .collect(Collectors.joining())
50
                            .trim();
51
        }
52
    }
53
54
    private static String renderBlock(Block block, int tableLevel) {
55 1 1. renderBlock : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderBlock → KILLED
        return switch (block) {
56 1 1. renderBlock : negated conditional → NO_COVERAGE
            case Heading(_, int level, List<Inline> inlines) -> renderHeading(level, inlines);
57
            case Paragraph(List<String> header, List<Inline> inlines) -> renderHeader(header) + renderInlines(inlines);
58
            case UnorderedList(List<ListItem> items1) -> renderList(items1, "* ");
59
            case OrderedList(List<ListItem> items) -> renderList(items, ". ");
60
            case Table(List<Row> rows) -> renderTable(rows, tableLevel);
61
            case Blockquote(List<Inline> inlines) -> renderBlockquote(inlines);
62
            case CodeBlock(String language, String content) -> renderCodeBlock(language, content);
63
            case ImageBlock(String url, String altText) -> renderImageBlock(url, altText);
64
            case OpenBlock openBlock -> render(openBlock);
65
            case MacroBlock(String name, String id, List<String> list) ->
66
                    "%s::%s[%s]".formatted(name, id, String.join(", ", list));
67
            case Break _ -> "<<<";
68
            case CommentLine(String comment) -> ("// %s").formatted(comment);
69
        } + "\n\n";
70
    }
71
72
    private static String render(OpenBlock openBlock) {
73
        var sb = new StringBuilder();
74
        sb.append("[%s]\n".formatted(String.join(", ", openBlock.header())));
75
        sb.append("--\n");
76
        openBlock.content()
77
                 .stream()
78 1 1. lambda$render$0 : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::lambda$render$0 → NO_COVERAGE
                 .map(p -> renderBlock(p, 0))
79 1 1. render : removed call to java/util/stream/Stream::forEach → NO_COVERAGE
                 .forEach(sb::append);
80
        sb.append("--\n");
81 1 1. render : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::render → NO_COVERAGE
        return sb.toString();
82
    }
83
84
    private static String renderTable(List<Row> rows, int level) {
85
        var cellDelimiter = switch (level) {
86
            case 0 -> "|";
87
            case 1 -> "!";
88
            default -> throw new IllegalArgumentException("Table nesting level must be between 0 and 1");
89
        };
90
        var tableDelimiter = cellDelimiter + "===";
91
        var sb = new StringBuilder();
92
        sb.append(tableDelimiter);
93
        sb.append("\n");
94
        for (Row row : rows) {
95
            var style = row.style();
96 1 1. renderTable : removed call to java/util/Optional::ifPresent → SURVIVED
            style.ifPresent(s -> sb.append("[%s]\n".formatted(s)));
97
            for (Cell cell : row.cells()) {
98
                var blockList = cell.blocks();
99
                var size = blockList.size();
100 4 1. renderTable : negated conditional → SURVIVED
2. renderTable : changed conditional boundary → KILLED
3. renderTable : negated conditional → KILLED
4. renderTable : negated conditional → KILLED
                boolean isAsciidoc = size > 1 || (size == 1 && !(blockList.getFirst() instanceof Paragraph));
101
                cell.style()
102 1 1. renderTable : removed call to java/util/Optional::ifPresent → SURVIVED
                    .ifPresent(s -> sb.append("[%s]\n".formatted(s)));
103 2 1. renderTable : negated conditional → KILLED
2. renderTable : Replaced integer addition with subtraction → KILLED
                sb.append(isAsciidoc ? "a" + cellDelimiter : cellDelimiter)
104
                  .append(renderCellContent(cell, isAsciidoc, level + 1))
105
                  .append("\n");
106
            }
107
        }
108
        sb.append(tableDelimiter);
109 1 1. renderTable : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderTable → KILLED
        return sb.toString();
110
    }
111
112
    private static String renderImageBlock(String url, String altText) {
113 1 1. renderImageBlock : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderImageBlock → NO_COVERAGE
        return "image::" + url + "[" + altText + "]";
114
    }
115
116
    private static String renderCodeBlock(String language, String content) {
117 2 1. renderCodeBlock : negated conditional → NO_COVERAGE
2. renderCodeBlock : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderCodeBlock → NO_COVERAGE
        return (language.isEmpty() ? "" : "[source," + language + "]\n") + "----\n" + content + "\n----";
118
    }
119
120
    private static String renderBlockquote(List<Inline> inlines) {
121 1 1. renderBlockquote : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderBlockquote → NO_COVERAGE
        return "____\n" + renderInlines(inlines) + "\n____";
122
    }
123
124
    private static String renderList(List<ListItem> items1, String x) {
125 1 1. renderList : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderList → NO_COVERAGE
        return items1.stream()
126 1 1. lambda$renderList$0 : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::lambda$renderList$0 → NO_COVERAGE
                     .map(item -> x + renderInlines(item.inlines()) + "\n")
127
                     .collect(Collectors.joining("\n"));
128
    }
129
130
    private static String renderHeading(int level, List<Inline> inlines) {
131 1 1. renderHeading : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderHeading → NO_COVERAGE
        return "=".repeat(level) + " " + renderInlines(inlines);
132
    }
133
134
    private static String renderHeader(List<String> header) {
135 1 1. renderHeader : negated conditional → KILLED
        if (header.isEmpty()) return "";
136 1 1. renderHeader : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderHeader → NO_COVERAGE
        return "[%s]\n".formatted(String.join(", ", header));
137
    }
138
139
    public String apply(AsciiDocModel model) {
140 1 1. apply : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::apply → KILLED
        return model.getBlocks()
141
                    .stream()
142 1 1. lambda$apply$0 : replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::lambda$apply$0 → KILLED
                    .map((Block block) -> renderBlock(block, 0))
143
                    .collect(Collectors.joining());
144
    }
145
}

Mutations

29

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

36

1.1
Location : renderInlines
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderInlines → KILLED

41

1.1
Location : renderCellContent
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
negated conditional → KILLED

42

1.1
Location : renderCellContent
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
negated conditional → KILLED

44

1.1
Location : renderCellContent
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderCellContent → KILLED

47

1.1
Location : renderCellContent
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderCellContent → KILLED

48

1.1
Location : lambda$renderCellContent$0
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::lambda$renderCellContent$0 → KILLED

55

1.1
Location : renderBlock
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderBlock → KILLED

56

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

78

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

79

1.1
Location : render
Killed by : none
removed call to java/util/stream/Stream::forEach → NO_COVERAGE

81

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

96

1.1
Location : renderTable
Killed by : none
removed call to java/util/Optional::ifPresent → SURVIVED
Covering tests

100

1.1
Location : renderTable
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
changed conditional boundary → KILLED

2.2
Location : renderTable
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
negated conditional → KILLED

3.3
Location : renderTable
Killed by : none
negated conditional → SURVIVED
Covering tests

4.4
Location : renderTable
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
negated conditional → KILLED

102

1.1
Location : renderTable
Killed by : none
removed call to java/util/Optional::ifPresent → SURVIVED
Covering tests

103

1.1
Location : renderTable
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
negated conditional → KILLED

2.2
Location : renderTable
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
Replaced integer addition with subtraction → KILLED

109

1.1
Location : renderTable
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderTable → KILLED

113

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

117

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

2.2
Location : renderCodeBlock
Killed by : none
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::renderCodeBlock → NO_COVERAGE

121

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

125

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

126

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

131

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

135

1.1
Location : renderHeader
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
negated conditional → KILLED

136

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

140

1.1
Location : apply
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::apply → KILLED

142

1.1
Location : lambda$apply$0
Killed by : pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest.[engine:junit-jupiter]/[class:pro.verron.officestamper.asciidoc.test.DocxToAsciiDocTest]/[method:shouldRenderNestedTable()]
replaced return value with "" for pro/verron/officestamper/asciidoc/AsciiDocToText::lambda$apply$0 → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.1