Skip to content

Commit 7243ee5

Browse files
committed
✨ add support for sparse Lists in DecodeOptions and update compact utility method
1 parent 6a58a77 commit 7243ee5

File tree

4 files changed

+17
-11
lines changed

4 files changed

+17
-11
lines changed

qs-kotlin/src/main/kotlin/io/github/techouse/qskotlin/internal/Utils.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -476,13 +476,18 @@ internal object Utils {
476476
* intact.
477477
*
478478
* @param root The root of the Map or List structure to compact.
479+
* @param allowSparseLists If true, allows sparse Lists (i.e., Lists with Undefined values). If
480+
* false, removes all Undefined values from Lists.
479481
* @return The compacted Map or List structure.
480482
*/
481-
fun compact(root: MutableMap<String, Any?>): MutableMap<String, Any?> {
483+
fun compact(
484+
root: MutableMap<String, Any?>,
485+
allowSparseLists: Boolean = false,
486+
): MutableMap<String, Any?> {
482487
val stack = ArrayDeque<Any>()
483488
stack.add(root)
484489

485-
// Identity-based visited set: avoids infinite loops on cycles
490+
// Identity-based visited set to prevent cycles
486491
val visited: MutableSet<Any> = Collections.newSetFromMap(IdentityHashMap())
487492

488493
visited.add(root)
@@ -518,7 +523,7 @@ internal object Utils {
518523
val it = list.listIterator()
519524
while (it.hasNext()) {
520525
when (val v = it.next()) {
521-
is Undefined -> it.remove()
526+
is Undefined -> if (allowSparseLists) it.set(null) else it.remove()
522527

523528
is MutableMap<*, *> -> {
524529
if (visited.add(v)) {

qs-kotlin/src/main/kotlin/io/github/techouse/qskotlin/models/DecodeOptions.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ data class DecodeOptions(
3434
/** Set to `true` to allow empty List values inside Maps in the encoded input. */
3535
val allowEmptyLists: Boolean = false,
3636

37+
/** Set to `true` to allow sparse Lists in the encoded input. */
38+
val allowSparseLists: Boolean = false,
39+
3740
/**
3841
* QS will limit specifying indices in a List to a maximum index of `20`. Any List members with
3942
* an index of greater than `20` will instead be converted to a Map with the index as the key.

qs-kotlin/src/main/kotlin/io/github/techouse/qskotlin/qs.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ fun decode(input: Any?, options: DecodeOptions? = null): Map<String, Any?> {
6969
}
7070
}
7171

72-
return Utils.compact(obj)
72+
return Utils.compact(obj, options.allowSparseLists)
7373
}
7474

7575
/**

qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/QsParserSpec.kt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ class QsParserSpec :
366366
}
367367

368368
it("should parse sparse arrays") {
369-
val optionsAllowSparse = DecodeOptions(allowSparse = true)
369+
val optionsAllowSparse = DecodeOptions(allowSparseLists = true)
370370

371371
decode("a[4]=1&a[1]=2", optionsAllowSparse) shouldBe
372372
mapOf("a" to listOf(null, "2", null, null, "1"))
@@ -510,11 +510,11 @@ class QsParserSpec :
510510
}
511511

512512
it("should use number decoder") {
513-
val numberDecoder: io.github.techouse.qskotlin.models.Decoder = { value, _ ->
513+
val numberDecoder: Decoder = { value, _ ->
514514
try {
515515
val intValue = value?.toInt()
516516
"[$intValue]"
517-
} catch (e: NumberFormatException) {
517+
} catch (_: NumberFormatException) {
518518
value
519519
}
520520
}
@@ -665,10 +665,8 @@ class QsParserSpec :
665665
}
666666

667667
it("should allow for decoding keys and values") {
668-
val keyValueDecoder: io.github.techouse.qskotlin.models.Decoder = { content, _ ->
669-
// Note: Kotlin implementation doesn't distinguish between key and value
670-
// decoding
671-
// This is a simplified version
668+
val keyValueDecoder: Decoder = { content, _ ->
669+
// Note: Kotlin implementation doesn't distinguish between key and value decoding
672670
content?.lowercase()
673671
}
674672
val options = DecodeOptions(decoder = keyValueDecoder)

0 commit comments

Comments
 (0)