Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
667e52d
:zap: enhance list parsing logic to handle empty segments and improve…
techouse Feb 10, 2026
3e99122
:zap: enhance Encoder to support cycle detection and improve handling…
techouse Feb 10, 2026
dc35199
:zap: enhance merge functionality to handle undefined values and impr…
techouse Feb 10, 2026
cc6b1b0
:zap: enhance list decoding logic to correctly map array indices in q…
techouse Feb 10, 2026
7639ec0
:memo: enhance decoding and merging logic to handle empty segments, e…
techouse Feb 10, 2026
715006a
:zap: enhance Encoder to apply date serialization for FunctionFilter …
techouse Feb 11, 2026
40747c8
:zap: enhance Decoder to ignore empty segments when applying paramete…
techouse Feb 11, 2026
2c56f15
refactor: change Frame data class to a regular class for better flexi…
techouse Feb 11, 2026
6306372
:bulb: introduce traversal phases and encapsulate Frame class for int…
techouse Feb 11, 2026
28ecd92
:zap: optimize handling of empty parts in Decoder by using sequence f…
techouse Feb 11, 2026
bbd990e
:zap: add toIndexedMap function for stable index-value mapping in mer…
techouse Feb 11, 2026
f5b9e9a
:zap: update merge function to preserve indices when merging with null
techouse Feb 11, 2026
bc13139
:zap: skip Undefined values when combining iterables in Utils.combine
techouse Feb 11, 2026
d10e833
:fix: update CHANGELOG with detailed descriptions for empty query seg…
techouse Feb 11, 2026
8638fb4
:white_check_mark: add test to filter empty segments with unlimited p…
techouse Feb 11, 2026
cbd2af2
:white_check_mark: add tests for merging null and scalar with mixed-k…
techouse Feb 11, 2026
77ed791
:white_check_mark: add tests for parameter limit handling in DecodeSpec
techouse Feb 11, 2026
dd3333b
:white_check_mark: add test for merging overflow map updates in Utils…
techouse Feb 11, 2026
095d4b2
:white_check_mark: add support for commaCompactNulls in EncodeOptions…
techouse Feb 11, 2026
b5ad567
:white_check_mark: add tests for encoding latin1 bytes and merging un…
techouse Feb 11, 2026
ada277c
:white_check_mark: add tests for handling empty non-collection iterab…
techouse Feb 11, 2026
b43f8e9
:white_check_mark: add test for handling list limit with duplicates i…
techouse Feb 11, 2026
56f2d8c
:white_check_mark: add tests for merging Undefined iterables and hand…
techouse Feb 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
## 1.5.0-wip

* [FIX] ignore empty query segments before applying `parameterLimit` so delimiters do not consume the limit budget
* [FIX] skip empty keys during decode to match `qs`
* [FIX] enforce comma list limits with truncation or throwing, including duplicate key accumulation
* [FIX] correct UTF-16 surrogate encoding and prevent segment-boundary splits in `Utils.encode`
* [FIX] decode `ByteArray`/`ByteBuffer` values via charset even when `encode=false`
* [FIX] ensure `FunctionFilter` results still pass through date serialization and COMMA temporal normalization
* [FIX] replace undefined holes during list merges and normalize when `parseLists=false`
* [FIX] detect cycles introduced by filters during encoding
* [FIX] append scalars to overflow maps during merge to preserve list-limit semantics
* [FIX] preserve overflow indices/maxIndex when merging `OverflowMap` into `null` targets
* [FIX] skip `Undefined` values when appending iterables into `OverflowMap` via `combine`
* [FIX] preserve overflow semantics in merge/combine (overflow sources, negative `listLimit`)
* [FIX] COMMA list encoding honors ByteArray/ByteBuffer decoding when `encode=false`
* [CHORE] refactor encode/merge internals to stack-based traversal for deep-nesting safety
* [CHORE] expand tests for empty segments, comma limits, surrogates, byte buffers, filter date normalization, and overflow edge cases

## 1.4.4

* [CHORE] update Kotlin to 2.3.10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,28 @@ internal object Decoder {
private fun parseListValue(value: Any?, options: DecodeOptions, currentListLength: Int): Any? {
if (value is String && value.isNotEmpty() && options.comma && value.contains(',')) {
val splitVal = value.split(',')
if (options.throwOnLimitExceeded && splitVal.size > options.listLimit) {
throw IndexOutOfBoundsException(
"List limit exceeded. " +
"Only ${options.listLimit} element${if (options.listLimit == 1) "" else "s"} allowed in a list."
)
if (options.listLimit >= 0) {
val remaining = options.listLimit - currentListLength
if (
options.throwOnLimitExceeded &&
(currentListLength + splitVal.size) > options.listLimit
) {
throw IndexOutOfBoundsException(
"List limit exceeded. " +
"Only ${options.listLimit} element${if (options.listLimit == 1) "" else "s"} allowed in a list."
)
}
if (remaining <= 0) return emptyList<String>()
return if (splitVal.size <= remaining) splitVal else splitVal.subList(0, remaining)
}
return splitVal
}

if (options.throwOnLimitExceeded && currentListLength >= options.listLimit) {
if (
options.listLimit >= 0 &&
options.throwOnLimitExceeded &&
currentListLength >= options.listLimit
) {
throw IndexOutOfBoundsException(
"List limit exceeded. " +
"Only ${options.listLimit} element${if (options.listLimit == 1) "" else "s"} allowed in a list."
Expand Down Expand Up @@ -68,13 +80,13 @@ internal object Decoder {
throw IllegalArgumentException("Parameter limit must be a positive integer.")
}

val allParts: List<String> = options.delimiter.split(cleanStr)
val parts =
if (limit != null) {
val allParts: List<String> = options.delimiter.split(cleanStr)
val takeCount: Int = if (options.throwOnLimitExceeded) limit + 1 else limit
allParts.take(takeCount)
allParts.asSequence().filter { it.isNotEmpty() }.take(takeCount).toList()
} else {
options.delimiter.split(cleanStr)
allParts.asSequence().filter { it.isNotEmpty() }.toList()
}

if (options.throwOnLimitExceeded && limit != null && parts.size > limit) {
Expand Down Expand Up @@ -105,6 +117,7 @@ internal object Decoder {
if (i == skipIndex) continue

val part = parts[i]
if (part.isEmpty()) continue
val bracketEqualsPos = part.indexOf("]=")
val pos = if (bracketEqualsPos == -1) part.indexOf('=') else bracketEqualsPos + 1

Expand All @@ -131,6 +144,7 @@ internal object Decoder {
options.decodeValue(v as String?, charset)
}
}
if (key.isEmpty()) continue

if (
value != null &&
Expand Down
Loading
Loading