Skip to content

Commit 3c2dd09

Browse files
committed
feat: support Json5QuoteStrategy (#1)
1 parent e04bf8e commit 3c2dd09

File tree

4 files changed

+98
-10
lines changed

4 files changed

+98
-10
lines changed

json5/src/commonMain/kotlin/li/songe/json5/EncodeUtil.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import kotlinx.serialization.json.JsonPrimitive
77

88
internal fun stringifyKey(key: String, config: Json5EncoderConfig): String {
99
if (key.isEmpty() || !config.unquotedKey) {
10-
return stringifyString(key, config.singleQuote)
10+
return stringifyString(key, config.quoteStrategy)
1111
}
1212
if (!isIdStartChar(key[0])) {
13-
return stringifyString(key, config.singleQuote)
13+
return stringifyString(key, config.quoteStrategy)
1414
}
1515
for (c in key) {
1616
if (!isIdContinueChar(c)) {
17-
return stringifyString(key, config.singleQuote)
17+
return stringifyString(key, config.quoteStrategy)
1818
}
1919
}
2020
return key
@@ -34,8 +34,8 @@ private val escapeReplacements = hashMapOf(
3434
)
3535

3636
// https://github.com/json5/json5/blob/b935d4a280eafa8835e6182551b63809e61243b0/lib/stringify.js#L104
37-
internal fun stringifyString(value: String, singleQuote: Boolean): String {
38-
val wrapChar = if (singleQuote) '\'' else '"'
37+
internal fun stringifyString(value: String, quoteStrategy: Json5QuoteStrategy): String {
38+
val wrapChar = if (quoteStrategy.quote(value)) '\'' else '"'
3939
val sb = StringBuilder()
4040
sb.append(wrapChar)
4141
value.forEachIndexed { i, c ->
@@ -71,7 +71,7 @@ internal fun stringifyString(value: String, singleQuote: Boolean): String {
7171
}
7272

7373
internal fun stringifyPrimitive(value: JsonPrimitive, config: Json5EncoderConfig): String = when {
74-
value.isString -> stringifyString(value.content, config.singleQuote)
74+
value.isString -> stringifyString(value.content, config.quoteStrategy)
7575
else -> value.content
7676
}
7777

json5/src/commonMain/kotlin/li/songe/json5/Json5EncoderConfig.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package li.songe.json5
22

33
data class Json5EncoderConfig(
44
val indent: String = "",
5-
val singleQuote: Boolean = true,
5+
val quoteStrategy: Json5QuoteStrategy = Json5QuoteStrategy.Single,
66
val unquotedKey: Boolean = true,
77
val trailingComma: Boolean = false,
88
)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package li.songe.json5
2+
3+
4+
@Suppress("unused")
5+
sealed class Json5QuoteStrategy {
6+
/**
7+
* - true -> single quote
8+
* - false -> double quote
9+
*/
10+
internal abstract fun quote(value: String): Boolean
11+
12+
data object Single : Json5QuoteStrategy() {
13+
override fun quote(value: String) = true
14+
}
15+
16+
data object Double : Json5QuoteStrategy() {
17+
override fun quote(value: String) = false
18+
}
19+
20+
data object PreferSingle : Json5QuoteStrategy() {
21+
override fun quote(value: String): Boolean {
22+
return value.contains('"') || !value.contains('\'')
23+
}
24+
}
25+
26+
data object PreferDouble : Json5QuoteStrategy() {
27+
override fun quote(value: String): Boolean {
28+
return value.contains('"') && !value.contains('\'')
29+
}
30+
}
31+
}

json5/src/commonTest/kotlin/li/songe/json5/Json5Test.kt

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ class Json5Test {
1212

1313
private fun p(string: String) = Json.parseToJsonElement(string)
1414

15+
private fun e5(
16+
string: String,
17+
config: Json5EncoderConfig = Json5EncoderConfig(),
18+
) = Json5.encodeToString(JsonPrimitive(string), config)
19+
20+
private fun q5(
21+
string: String,
22+
strategy: Json5QuoteStrategy,
23+
) = e5(string, Json5EncoderConfig(quoteStrategy = strategy))
24+
1525
// https://github.com/json5/json5/blob/main/test/parse.js
1626
@Test
1727
fun parse() {
@@ -205,9 +215,6 @@ class Json5Test {
205215
println("element: $element")
206216
val option = Json5EncoderConfig(
207217
indent = "\u0020\u0020",
208-
singleQuote = true,
209-
unquotedKey = true,
210-
trailingComma = false,
211218
)
212219
val formatted = Json5.encodeToString(element, option)
213220
println("formatted:\n$formatted")
@@ -235,4 +242,54 @@ class Json5Test {
235242
}
236243
println(htmlText)
237244
}
245+
246+
@Test
247+
fun quote() {
248+
assertEquals(
249+
q5(
250+
""" "a' """.trim(),
251+
Json5QuoteStrategy.Single,
252+
),
253+
""" '"a\'' """.trim(),
254+
)
255+
assertEquals(
256+
q5(
257+
""" "a' """.trim(),
258+
Json5QuoteStrategy.Double,
259+
),
260+
""" "\"a'" """.trim(),
261+
)
262+
263+
assertEquals(
264+
q5(
265+
""" a" """.trim(),
266+
Json5QuoteStrategy.PreferSingle,
267+
),
268+
""" 'a"' """.trim(),
269+
)
270+
assertEquals(
271+
q5(
272+
""" a' """.trim(),
273+
Json5QuoteStrategy.PreferSingle,
274+
),
275+
""" "a'" """.trim(),
276+
)
277+
278+
assertEquals(
279+
q5(
280+
""" a' """.trim(),
281+
Json5QuoteStrategy.PreferDouble,
282+
),
283+
""" "a'" """.trim(),
284+
)
285+
286+
assertEquals(
287+
q5(
288+
""" a" """.trim(),
289+
Json5QuoteStrategy.PreferDouble,
290+
),
291+
""" 'a"' """.trim(),
292+
)
293+
294+
}
238295
}

0 commit comments

Comments
 (0)