• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jesperancinha / markdowner / #194

pending completion
#194

push

github-ci

web-flow
Merge pull request #149 from jesperancinha/migration-to-kotlin

Migration to kotlin

333 of 333 new or added lines in 13 files covered. (100.0%)

274 of 333 relevant lines covered (82.28%)

8.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

62.03
/markdowner-core/src/main/kotlin/org/jesperancinha/parser/markdowner/helper/Helpers.kt
1
package org.jesperancinha.parser.markdowner.helper
2

3
import org.jesperancinha.parser.markdowner.model.Paragraphs
4
import java.io.BufferedReader
5
import java.io.IOException
6
import java.io.InputStream
7
import java.io.InputStreamReader
8
import java.nio.CharBuffer
9
import java.util.*
10

11
object MergeParserHelper {
12
    /**
13
     * Receives a complete Markdown text and a [Paragraphs] instance and adds all paragraphs in the stipulated order to the end of the text
14
     *
15
     * @param readmeMd A complete String representation of a Markdown text
16
     * @param footer   A [Paragraphs] instance which will add all paragraphs to the end of the Markdown text
17
     * @return The complete String merge between a [String] text and a [Paragraphs] instances
18
     */
19
    fun mergeDocumentWithFooterTemplate(readmeMd: String, footer: Paragraphs) =
20
        readmeMd + System.lineSeparator() + System.lineSeparator() + java.lang.String.join(
24✔
21
            System.lineSeparator(),
4✔
22
            footer.tags
8✔
23
                .map { tag: String -> footer.getParagraphByTag(tag).toString() }
20✔
24
        )
2✔
25
}
26

27
object ReadmeParserHelper {
28
    /**
29
     * Reads an input marked down string and returns the exact same text without the specified cardinal tags and their content.
30
     *
31
     *
32
     * This means any content of # tags
33
     *
34
     * @param readmeInputStream An input stream of a markdown text
35
     * @param tags              All tags of the paragraphs to be removed
36
     * @return The filtered String
37
     * @throws IOException Any IO Exception thrown
38
     */
39
    @Throws(IOException::class)
40
    fun readDataSprippedOfTags(readmeInputStream: InputStream?, vararg tags: String?): String {
41
        val sb = StringBuilder()
×
42
        BufferedReader(InputStreamReader(readmeInputStream)).use { br ->
×
43
            val allTags = Arrays.asList(*tags)
×
44
            var line: String
×
45
            var currentMinHashTags = 0
×
46
            while (br.readLine().also { line = it } != null) {
×
47
                if (line.startsWith("#")) {
×
48
                    currentMinHashTags = calculateCurrentMinHashTags(line, currentMinHashTags, allTags)
×
49
                }
50
                if (currentMinHashTags == 0 && (!line.startsWith("#") || !allTags.contains(TagHelper.sanitizeTag(line)))) {
×
51
                    sb.append(line)
×
52
                    sb.append(System.lineSeparator())
×
53
                }
54
            }
55
        }
×
56
        return sb.toString().stripTrailing()
×
57
    }
58

59
    private fun calculateCurrentMinHashTags(line: String, currentMinHashTags: Int, allTags: List<String?>): Int {
60
        var newMinHashTagsCount = currentMinHashTags
×
61
        newMinHashTagsCount = if (allTags.contains(TagHelper.sanitizeTag(line))) {
×
62
            getNewMinHashTagsCountAfterMatch(line, newMinHashTagsCount)
×
63
        } else {
64
            getNewMinHashTagsCountAfterNoMatch(line, newMinHashTagsCount)
×
65
        }
66
        return newMinHashTagsCount
×
67
    }
68

69
    private fun getNewMinHashTagsCountAfterNoMatch(line: String, newMinHashTagsCount: Int): Int {
70
        var newMinHashTagsCount = newMinHashTagsCount
×
71
        val hashCount = TagHelper.counHashTags(line)
×
72
        if (hashCount <= newMinHashTagsCount) {
×
73
            newMinHashTagsCount = 0
×
74
        }
75
        return newMinHashTagsCount
×
76
    }
77

78
    private fun getNewMinHashTagsCountAfterMatch(line: String, currentHashTagsCount: Int): Int {
79
        var currentHashTagsCount = currentHashTagsCount
×
80
        val hashCount = TagHelper.counHashTags(line)
×
81
        currentHashTagsCount = if (hashCount < currentHashTagsCount) {
×
82
            0
×
83
        } else {
84
            hashCount
×
85
        }
86
        return currentHashTagsCount
×
87
    }
88
}
89

90
object TagHelper {
91
    /**
92
     * Strips the first # characters from a string and removes eventually leading spaces
93
     *
94
     * @param tag Tag [String] to be sanitized
95
     * @return The sanitized tag [String]
96
     */
97
    fun sanitizeTag(tag: String?): String {
98
        val preSanitizedTag = removeStartingHashTags(tag)
8✔
99
        var charBuff = CharBuffer.allocate(preSanitizedTag.length)
8✔
100
        var finalSize = 0
4✔
101
        for (i in 0 until preSanitizedTag.length) {
20✔
102
            val charCandidate = preSanitizedTag[i]
8✔
103
            if (charCandidate.code < 256) {
6✔
104
                charBuff = charBuff.append(charCandidate)
8✔
105
                finalSize++
2✔
106
            }
107
        }
108
        return String(Arrays.copyOfRange(charBuff.array(), 0, finalSize)).trim { it <= ' ' }
50✔
109
    }
110

111
    private fun removeStartingHashTags(tag: String?): String {
112
        var i = 0
4✔
113
        for (c in tag!!.toCharArray()) {
44✔
114
            if (c != '#') {
6✔
115
                return tag.substring(i).trim { it <= ' ' }
36✔
116
            }
117
            i++
2✔
118
        }
119
        return ""
4✔
120
    }
121

122
    /**
123
     * Counts the number of leading hash characters in a [String]
124
     *
125
     * @param tag Tag [String] to analyse
126
     * @return Number of hash (#) characters
127
     */
128
    fun counHashTags(tag: String?): Int {
129
        var count = 0
4✔
130
        for (c in tag!!.toCharArray()) {
44✔
131
            if (c == '#') {
6✔
132
                count++
4✔
133
            } else {
134
                return count
4✔
135
            }
136
        }
137
        return count
×
138
    }
139
}
140

141
object TemplateParserHelper {
142
    /**
143
     * Receives an input Markdown text stream nd parses its content to a Paragraphs object see [Paragraphs]
144
     *
145
     * @param templateInputStream An input Markdown text stream
146
     * @return A [Paragraphs] parsed object
147
     * @throws IOException Any kind of IO Exception
148
     */
149
    @Throws(IOException::class)
150
    fun findAllParagraphs(templateInputStream: InputStream): Paragraphs? {
151
        val paragraphs = Paragraphs()
16✔
152
        BufferedReader(InputStreamReader(templateInputStream)).use { br ->
44✔
153
            val sb = StringBuilder()
8✔
154
            val paragraphCounter = ParagraphCounter()
8✔
155
            while (br.readLine().also { paragraphCounter.line = it } != null) {
20✔
156
                if (reachedEndOfParagrah(paragraphCounter.line, paragraphCounter.currentHashCount)) {
14✔
157
                    createParagraphAndUpdateCounters(paragraphs, sb, paragraphCounter)
12✔
158
                } else {
159
                    sb.append(paragraphCounter.line).append(System.lineSeparator())
16✔
160
                }
161
            }
162
            createParagraphLine(paragraphs, paragraphCounter.currentTag, sb)
12✔
163
        }
4✔
164
        return paragraphs
4✔
165
    }
166

167
    private fun createParagraphAndUpdateCounters(
168
        paragraphsBuilder: Paragraphs,
169
        sb: StringBuilder,
170
        paragraphCounter: ParagraphCounter
171
    ) {
172
        createParagraphLine(paragraphsBuilder, paragraphCounter.currentTag, sb)
12✔
173
        paragraphCounter.currentTag = paragraphCounter.line
8✔
174
        paragraphCounter.currentHashCount = TagHelper.counHashTags(paragraphCounter.line)
12✔
175
    }
2✔
176

177
    private fun reachedEndOfParagrah(line: String?, currentHashCount: Int): Boolean {
178
        return line!!.startsWith("#") && (currentHashCount >= TagHelper.counHashTags(line) || currentHashCount == 0)
40✔
179
    }
180

181
    private fun createParagraphLine(paragraphsBuilder: Paragraphs, currentTag: String?, sb: StringBuilder) {
182
        if (Objects.nonNull(currentTag)) {
6✔
183
            paragraphsBuilder.withTagParagraph(currentTag, sb.toString().stripTrailing())
14✔
184
        }
185
        sb.delete(0, sb.length)
12✔
186
    }
2✔
187

188
    private class ParagraphCounter {
6✔
189
        var line: String? = null
14✔
190
        var currentTag: String? = null
14✔
191
        var currentHashCount = 0
14✔
192
    }
193
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc