Skip to content

Commit 76bcae0

Browse files
authored
Several cosmetic fixes for multiline strings (#217)
### What's done: - On multiline strings we forgot to update isMultiline flag while decoding and parsing - Adding extra info to prettyPrint - Adding a test for validation of line numbers - Removing deprecated 'content' from the TomlNode - Added newline alignment for multiline strings (newlines after/before quotes-separators)
1 parent 15683ed commit 76bcae0

File tree

7 files changed

+151
-51
lines changed

7 files changed

+151
-51
lines changed

ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/decoders/TomlMainDecoder.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ public class TomlMainDecoder(
101101
is TomlKeyValuePrimitive -> node
102102
is TomlKeyValueArray -> node
103103
// empty nodes will be filtered by iterateUntilWillFindAnyKnownName() method, but in case we came into this
104-
// branch, we should throw an exception as it is not expected at all and we should catch this in tests
104+
// branch, we should throw an exception as it is not expected at all, and we should catch this in tests
105105
else ->
106106
throw InternalDecodingException(
107-
"Node of type [${node::class}] should not be processed in TomlDecoder.decodeValue(): <${node.content}>."
107+
"Node of type [${node::class}] should not be processed in TomlDecoder.decodeValue(): <$node>."
108108
)
109109
}
110110
}

ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/nodes/TomlNode.kt

Lines changed: 20 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,6 @@ public sealed class TomlNode(
2929
comments: List<String>,
3030
public val inlineComment: String
3131
) {
32-
@Deprecated(
33-
message = "content was replaced with toString; will be removed in future releases.",
34-
replaceWith = ReplaceWith("toString()")
35-
)
36-
@Suppress("CUSTOM_GETTERS_SETTERS")
37-
public val content: String get() = toString()
38-
3932
/**
4033
* A list of comments prepended to the node.
4134
*/
@@ -187,20 +180,25 @@ public sealed class TomlNode(
187180

188181
/**
189182
* print the structure of parsed AST tree
183+
* Important: as prettyPrint calls toString() of the node, and not just prints the value, but emits and reconstruct a source string,
184+
* so in some cases (for example in case of multiline strings) it can work incorrectly.
185+
*
186+
* @param emitLine - if true - will print line number in this debug print
190187
*/
191188
@Suppress("DEBUG_PRINT")
192-
public fun prettyPrint() {
189+
public fun prettyPrint(emitLine: Boolean = false) {
193190
val sb = StringBuilder()
194-
prettyPrint(this, sb)
191+
prettyPrint(this, sb, emitLine)
195192
println(sb.toString())
196193
}
197194

198195
/**
196+
* @param emitLine - if true - will print line number in this debug print
199197
* @return the string with AST tree visual representation
200198
*/
201-
public fun prettyStr(): String {
199+
public fun prettyStr(emitLine: Boolean = false): String {
202200
val sb = StringBuilder()
203-
prettyPrint(this, sb)
201+
prettyPrint(this, sb, emitLine)
204202
return sb.toString()
205203
}
206204

@@ -233,37 +231,6 @@ public sealed class TomlNode(
233231
}
234232
}
235233

236-
@Deprecated(
237-
message = "TomlConfig is deprecated; use TomlOutputConfig instead. Will be removed in next releases.",
238-
replaceWith = ReplaceWith(
239-
"write(emitter, config, multiline)",
240-
"com.akuleshov7.ktoml.TomlOutputConfig"
241-
)
242-
)
243-
public fun write(
244-
emitter: TomlEmitter,
245-
config: TomlConfig,
246-
multiline: Boolean = false
247-
): Unit = write(emitter, config.output, multiline)
248-
249-
/**
250-
* Writes this node as text to [emitter].
251-
*
252-
* @param emitter The [TomlEmitter] instance to write to.
253-
* @param config The [TomlConfig] instance. Defaults to the node's config.
254-
* @param multiline Whether to write the node over multiple lines, if possible.
255-
*/
256-
@Deprecated(
257-
message = "The multiline parameter overload is deprecated, use the multiline" +
258-
" property on supported TomlValue types instead. Will be removed in next releases.",
259-
replaceWith = ReplaceWith("write(emitter, config)")
260-
)
261-
public fun write(
262-
emitter: TomlEmitter,
263-
config: TomlOutputConfig = TomlOutputConfig(),
264-
multiline: Boolean = false
265-
): Unit = write(emitter, config)
266-
267234
/**
268235
* Writes this node as text to [emitter].
269236
*
@@ -328,26 +295,32 @@ public sealed class TomlNode(
328295
.writeNode(this)
329296
.replace(" = ", "=")
330297

298+
internal fun print(emitLine: Boolean = false): String =
299+
"${this::class.simpleName} ($this)${if (emitLine) "[line:${this.lineNo}]" else ""}\n"
300+
331301
public companion object {
332302
// number of spaces that is used to indent levels
333303
internal const val INDENTING_LEVEL = 4
334304

335305
/**
336306
* recursive print the tree using the current node
337307
*
338-
* @param node
339-
* @param level
340-
* @param result
308+
* @param node that will be printed
309+
* @param level depth of hierarchy for print
310+
* @param result string builder where the result is stored
311+
* @param emitLine if true - will print line number in this debug print
341312
*/
342313
public fun prettyPrint(
343314
node: TomlNode,
344315
result: StringBuilder,
316+
emitLine: Boolean = false,
345317
level: Int = 0
346318
) {
347319
val spaces = " ".repeat(INDENTING_LEVEL * level)
348-
result.append("$spaces - ${node::class.simpleName} ($node)\n")
320+
// we are using print() method here instead of toString()
321+
result.append("$spaces - ${node.print(emitLine)}")
349322
node.children.forEach { child ->
350-
prettyPrint(child, result, level + 1)
323+
prettyPrint(child, result, emitLine, level + 1)
351324
}
352325
}
353326
}

ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/tree/nodes/pairs/values/TomlLiteralString.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class TomlLiteralString internal constructor(
2828
content: String,
2929
lineNo: Int,
3030
config: TomlInputConfig = TomlInputConfig()
31-
) : this(content.verifyAndTrimQuotes(lineNo, config))
31+
) : this(content.verifyAndTrimQuotes(lineNo, config), content.contains("\n"))
3232

3333
@Deprecated(
3434
message = "TomlConfig is deprecated; use TomlInputConfig instead. Will be removed in next releases."
@@ -45,7 +45,7 @@ public class TomlLiteralString internal constructor(
4545

4646
override fun write(
4747
emitter: TomlEmitter,
48-
config: TomlOutputConfig
48+
config: TomlOutputConfig,
4949
) {
5050
val content = content as String
5151

ktoml-core/src/commonMain/kotlin/com/akuleshov7/ktoml/writers/TomlEmitter.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,9 @@ public abstract class TomlEmitter(config: TomlOutputConfig) {
180180
val quotes = if (isLiteral) "'''" else "\"\"\""
181181

182182
emit(quotes)
183+
.emitNewLine()
183184
.emit(string)
185+
.emitNewLine()
184186
.emit(quotes)
185187
} else {
186188
val quote = if (isLiteral) '\'' else '"'

ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/encoders/EncodingAnnotationTest.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,16 +269,22 @@ class EncodingAnnotationTest {
269269
value = File(),
270270
expectedToml = """
271271
mlTextA = $tripleQuotes
272+
272273
\tMultiline
273274
text!
275+
274276
$tripleQuotes
275277
mlTextB = $tripleQuotes
278+
276279
Text with escaped quotes ""\"\
277280
and line break
281+
278282
$tripleQuotes
279283
mlTextC = '''
284+
280285
"Multiline
281286
text!"
287+
282288
'''
283289
""".trimIndent()
284290
)

ktoml-core/src/commonTest/kotlin/com/akuleshov7/ktoml/encoders/PrimitiveEncoderTest.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.akuleshov7.ktoml.encoders
22

33
import com.akuleshov7.ktoml.annotations.TomlLiteral
4+
import com.akuleshov7.ktoml.annotations.TomlMultiline
45
import kotlinx.serialization.SerialName
56
import kotlinx.serialization.Serializable
67
import kotlin.test.Test
@@ -81,6 +82,38 @@ class PrimitiveEncoderTest {
8182
)
8283
}
8384

85+
@Test
86+
fun multilineStringsSpecifications() {
87+
@Serializable
88+
data class MultilineLiteralStr(
89+
@TomlMultiline
90+
@TomlLiteral
91+
val a: String
92+
)
93+
94+
@Serializable
95+
data class MultilineBasicStr(
96+
@TomlMultiline
97+
val a: String
98+
)
99+
100+
assertEncodedEquals(
101+
value = MultilineLiteralStr("test \n test \n test \'\'\'"),
102+
expectedToml = """
103+
|a = '''
104+
|test
105+
| test
106+
| test ''\'
107+
|'''
108+
""".trimMargin()
109+
)
110+
111+
assertEncodedEquals(
112+
value = MultilineBasicStr("test \n test \n test \'\'\'"),
113+
expectedToml = "a = \"\"\"\ntest \n test \n test \'\'\'\n\"\"\""
114+
)
115+
}
116+
84117
@Test
85118
fun jsWholeDoubleRegression() {
86119
@Serializable
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.akuleshov7.ktoml.parsers
2+
3+
import com.akuleshov7.ktoml.Toml
4+
import kotlin.test.Test
5+
import kotlin.test.assertEquals
6+
7+
class SetLineNoTest {
8+
@Test
9+
fun checkingLineNumbersGeneral() {
10+
val string =
11+
"""
12+
13+
# comment 1
14+
15+
[a] # comment 2
16+
# comment 3
17+
test = 1 # comment 4
18+
19+
# ====
20+
21+
[[a.b]] # comment 5
22+
test = 1
23+
24+
mlls = '''
25+
1
26+
2
27+
3
28+
'''
29+
30+
mla = [
31+
"a",
32+
"b",
33+
"c"
34+
]
35+
""".trimIndent()
36+
val parsedToml = Toml.tomlParser.parseString(string)
37+
38+
parsedToml.prettyPrint(true)
39+
assertEquals(
40+
"""
41+
| - TomlFile (rootNode)[line:0]
42+
| - TomlTablePrimitive ([a])[line:4]
43+
| - TomlKeyValuePrimitive (test=1)[line:6]
44+
| - TomlArrayOfTables ([[a.b]])[line:10]
45+
| - TomlArrayOfTablesElement (technical_node)[line:10]
46+
| - TomlKeyValuePrimitive (test=1)[line:11]
47+
| - TomlKeyValuePrimitive (mlls='''
48+
| 1
49+
| 2
50+
| 3
51+
|
52+
|''')[line:13]
53+
| - TomlKeyValueArray (mla=[ "a", "b", "c" ])[line:18]
54+
|
55+
""".trimMargin(),
56+
parsedToml.prettyStr(true)
57+
)
58+
}
59+
60+
@Test
61+
fun checkingLineNumbers() {
62+
val string = "\n\n" +
63+
"mlls = '''\n" +
64+
"1\n" +
65+
"\n" +
66+
"2\n" +
67+
"3" +
68+
"'''"
69+
val parsedToml = Toml.tomlParser.parseString(string)
70+
parsedToml.prettyPrint(true)
71+
72+
assertEquals(
73+
"""
74+
| - TomlFile (rootNode)[line:0]
75+
| - TomlKeyValuePrimitive (mlls='''
76+
|1
77+
|
78+
|2
79+
|3
80+
|''')[line:3]
81+
|
82+
""".trimMargin(),
83+
parsedToml.prettyStr(true)
84+
)
85+
}
86+
}

0 commit comments

Comments
 (0)