Skip to content

⚡ general improvements#74

Merged
techouse merged 23 commits intomainfrom
chore/improvements
Feb 11, 2026
Merged

⚡ general improvements#74
techouse merged 23 commits intomainfrom
chore/improvements

Conversation

@techouse
Copy link
Owner

@techouse techouse commented Feb 10, 2026

This pull request introduces several important bug fixes and improvements to the query string parsing and encoding logic, focusing on correct handling of empty segments, list and parameter limits, and edge cases with byte arrays and surrogate pairs. It also expands and corrects the test suite to cover these scenarios and updates the changelog to reflect these changes.

Decoder and parameter/list limit handling:

  • Empty query segments and keys are now ignored before applying parameterLimit, ensuring delimiters do not consume the limit budget and matching the behavior of the qs library. Empty keys are also skipped during decoding. [1] [2] [3]
  • Comma list limits are now enforced correctly, with truncation or exceptions as appropriate, and duplicate key accumulation is handled according to the limit. Negative listLimit values are treated as unlimited, and overflow semantics are preserved in merges. [1] [2] [3] [4]

Encoding and decoding edge cases:

  • Corrects UTF-16 surrogate encoding, prevents segment-boundary splits in Utils.encode, and ensures proper handling of lone surrogates.
  • Byte arrays and byte buffers are now decoded and encoded via the specified charset even when encode=false, and COMMA list encoding honors this for decoding as well. [1] [2] [3]

FunctionFilter and date serialization:

  • Ensures that results from FunctionFilter still pass through date serialization and COMMA temporal normalization during encoding.

Test suite and documentation:

  • Expands tests for empty segments, comma limits, surrogates, byte buffers, filter date normalization, overflow edge cases, and corrects expected results for list merging with zero limits. [1] [2] [3] [4]
  • Updates CHANGELOG.md to document all fixes and improvements in version 1.5.0-wip.

Summary of most important changes:

Parameter and list limit enforcement:

  • Ignores empty query segments and keys before applying parameterLimit, and skips empty keys during decoding, matching qs behavior. [1] [2] [3]
  • Enforces comma list limits correctly, truncating or throwing as appropriate, and supports negative listLimit for unlimited lists. [1] [2] [3]

Encoding/decoding edge cases:

  • Corrects UTF-16 surrogate encoding, prevents segment-boundary splits, and handles lone surrogates in Utils.encode.
  • Ensures byte arrays and byte buffers are handled correctly when encode=false, including in COMMA lists. [1] [2]

FunctionFilter and date serialization:

  • Ensures FunctionFilter results pass through date serialization and COMMA temporal normalization.

Test suite improvements:

  • Expands and corrects tests for all of the above scenarios, including empty segments, list/parameter limits, surrogates, and byte buffer handling. [1] [2] [3] [4]

Documentation:

  • Updates CHANGELOG.md for version 1.5.0-wip to document these fixes and improvements.

Summary by CodeRabbit

  • Chore

    • Added 1.5.0-wip changelog entry.
  • New Features

    • Added finer-grained encoding options and exposed commaCompactNulls.
  • Bug Fixes

    • Fixed decoding/encoding edge cases: empty-segment handling, list-limit behaviors, charset/surrogate encoding, and merge semantics for complex maps/lists.
  • Improvements

    • More robust cycle detection and improved byte-array/ByteBuffer handling; internal merge/encoding reliability improved.
  • Tests

    • Expanded unit tests for decoding, encoding, merging, overflow, and cycle scenarios.

@techouse techouse self-assigned this Feb 10, 2026
@techouse techouse added the enhancement New feature or request label Feb 10, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors encoder and merge engines from recursive to stack-based state machines, adds identity-based cycle detection, refines decoder handling for list limits and empty segments, improves byte/surrogate handling in utilities, expands public EncodeOptions with commaCompactNulls, and broadens tests for encoding/decoding/merge/overflow behaviors.

Changes

Cohort / File(s) Summary
Core Encoding Engine
qs-kotlin/src/main/kotlin/io/github/techouse/qskotlin/internal/Encoder.kt
Replaced recursive encoder with stack-driven Frame/Phase (START, ITERATE, WAIT_CHILD). Added identity-based cycle detection, per-frame state, and many new encode configuration parameters (e.g., commaCompactNulls, allowEmptyLists, strictNullHandling, encoder, serializeDate, format/formatter, charset, addQueryPrefix).
Core Decoding Logic
qs-kotlin/src/main/kotlin/io/github/techouse/qskotlin/internal/Decoder.kt
Adjusted list parsing to compute remaining slots and truncate split values when listLimit is exceeded without throwing; made limit checks conditional on non-negative limits; prefilter empty segments and ignore empty keys during query parsing.
Utilities & Merging
qs-kotlin/src/main/kotlin/io/github/techouse/qskotlin/internal/Utils.kt
Introduced a non-recursive, multi-phase merge engine (MergeFrame/MergePhase) with OverflowMap support, toIndexedMap helper, overflow index management, and surrogate-aware byte/string helpers; updated combine/merge to produce/append overflow maps when limits exceeded.
Options & Models
qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/models/EncodeOptionsSpec.kt
Added commaCompactNulls flag to EncodeOptions, propagated through constructor, copy(), and builder; tests updated to expect default true via new paths.
Tests — Decoding & Parser
qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/DecodeSpec.kt, qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/QsParserSpec.kt
Added/updated tests for empty-segment/key skipping, parameter/list limit behaviors (truncation vs throwing), negative listLimit semantics, and edge cases for listLimit=0 affecting index/key outcomes.
Tests — Encoding & Utilities
qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/EncodeSpec.kt, qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/UtilsSpec.kt
Added tests for date serialization with FunctionFilter, ByteArray/ByteBuffer stringification when encode=false, lone-surrogate and surrogate-pair segmentation behavior, ByteBuffer handling, and extensive merge/overflow scenarios.
Tests — Encoder Internal
qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/internal/EncoderInternalSpec.kt
Added tests verifying empty-iterable suffix behavior with allowEmptyLists, iterable handling for commaRoundTrip, and cycle detection when a filter introduces cycles (expects "Cyclic object value" error).
Changelog
CHANGELOG.md
Added 1.5.0-wip entry listing FIX and CHORE items covering encoding/decoding/merge fixes, refactors, and expanded tests.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

test

Poem

🐰 I hop through frames and phases bright,
stack-bound paths replace recursive night.
Surrogates safe and bytes held tight,
lists and maps now take their flight,
tests cheer softly in morning light.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is vague and overly broad, using a generic term 'general improvements' that does not convey the specific nature of the substantial changes in the PR. Consider a more descriptive title that reflects the main focus, such as 'Fix query string parameter/list limit handling and surrogate encoding' or similar.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The PR description is comprehensive and covers most required sections, though the template checklist is not explicitly marked.
Docstring Coverage ✅ Passed Docstring coverage is 90.91% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/improvements

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/UtilsSpec.kt (1)

142-145: Nit: simplify the expected value literal.

"a=%26%239786%3B".removePrefix("a=") is just "%26%239786%3B". The indirection through removePrefix obscures the actual expected value and reads as though the full a=… string is significant.

Suggested simplification
-                out shouldBe "a=%26%239786%3B".removePrefix("a=") // value-only expectation
+                out shouldBe "%26%239786%3B"

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Feb 10, 2026

Codecov Report

❌ Patch coverage is 91.01307% with 55 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.71%. Comparing base (25ad888) to head (56f2d8c).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...in/io/github/techouse/qskotlin/internal/Encoder.kt 86.07% 10 Missing and 29 partials ⚠️
...tlin/io/github/techouse/qskotlin/internal/Utils.kt 95.25% 3 Missing and 12 partials ⚠️
...in/io/github/techouse/qskotlin/internal/Decoder.kt 93.75% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main      #74      +/-   ##
============================================
- Coverage     95.14%   94.71%   -0.43%     
- Complexity      452      530      +78     
============================================
  Files            15       15              
  Lines          1277     1609     +332     
  Branches        276      348      +72     
============================================
+ Hits           1215     1524     +309     
- Misses           11       16       +5     
- Partials         51       69      +18     
Flag Coverage Δ
java-17 94.71% <91.01%> (-0.43%) ⬇️
java-21 94.71% <91.01%> (-0.43%) ⬇️
java-25 94.71% <91.01%> (-0.43%) ⬇️
jvm 94.71% <91.01%> (-0.43%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@qs-kotlin/src/main/kotlin/io/github/techouse/qskotlin/internal/Encoder.kt`:
- Around line 147-167: When a FunctionFilter (frame.filter of type
FunctionFilter) is applied the code returns early and skips date normalization;
after invoking the filter via f.function(frame.prefix, obj) ensure the returned
obj still passes through the same date/temporal normalization branch (i.e. if
obj is LocalDateTime apply frame.serializeDate?.invoke(obj) ?: obj.toString(),
and if isCommaGenerator and obj is Iterable<*> map each element applying the
Instant/LocalDateTime handling). Update the block handling FunctionFilter
(and/or the subsequent else branch) so date serialization logic is executed for
the filtered result using the same checks and frame.serializeDate reference as
used for non-filtered values.
🧹 Nitpick comments (1)
qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/UtilsSpec.kt (1)

511-553: Comprehensive overflow-map merge coverage.

Four distinct scenarios are tested: scalar append, iterable append (with Undefined skipping), scalar-as-target with index shifting, and map merge preserving maxIndex. One minor note: at line 517, the @Suppress("UNCHECKED_CAST") val map = result as Map<String, Any?> cast is redundant since result is already asserted as Utils.OverflowMap (which implements Map) on line 516 — but this is a stylistic nit.

🔧 Minor: remove redundant cast
-            val result = Utils.merge(overflow, "d")
-            result.shouldBeInstanceOf<Utils.OverflowMap>()
-            `@Suppress`("UNCHECKED_CAST") val map = result as Map<String, Any?>
-            map["3"] shouldBe "d"
+            val result = Utils.merge(overflow, "d")
+            val map = result.shouldBeInstanceOf<Utils.OverflowMap>()
+            map["3"] shouldBe "d"

shouldBeInstanceOf returns the value cast to the asserted type, so the subsequent as cast is unnecessary.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7639ec04f9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@techouse techouse requested a review from Copilot February 11, 2026 20:57
@techouse
Copy link
Owner Author

@codex review

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request enhances the query string parsing and encoding library by addressing edge cases and improving reliability. The changes focus on stricter parsing semantics, improved list limit enforcement, better handling of special data types, and internal safety improvements for deeply nested structures.

Changes:

  • Skip empty query segments and empty keys during decoding to match qs library behavior
  • Enforce comma-separated list limits with proper truncation/throwing and handle negative limits
  • Correct UTF-16 surrogate encoding and prevent splitting surrogate pairs across boundaries
  • Improve byte array and buffer handling across encoding modes
  • Replace undefined holes during list merges and normalize when parseLists=false
  • Detect cycles introduced by user-defined filters during encoding
  • Refactor encode/merge internals to stack-based traversal for deep-nesting safety

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
qs-kotlin/src/main/kotlin/io/github/techouse/qskotlin/internal/Decoder.kt Skips empty segments and keys during parsing; enforces comma list limits with negative limit handling
qs-kotlin/src/main/kotlin/io/github/techouse/qskotlin/internal/Encoder.kt Replaces WeakHashMap cycle tracking with IdentityHashMap; refactors to stack-based traversal; adds ByteBuffer support
qs-kotlin/src/main/kotlin/io/github/techouse/qskotlin/internal/Utils.kt Refactors merge to stack-based approach; adds overflow map handling; corrects UTF-16 surrogate encoding; adds byte array/buffer string conversion
qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/DecodeSpec.kt Adds tests for empty segments, comma list limits, negative list limits, and parameter counting
qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/EncodeSpec.kt Adds tests for date serialization with filters, byte array/buffer encoding in various modes
qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/QsParserSpec.kt Updates expected results for list overflow behavior with listLimit=0
qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/UtilsSpec.kt Adds tests for surrogate encoding, byte buffer handling, merge with undefined holes, overflow map operations
qs-kotlin/src/test/kotlin/io/github/techouse/qskotlin/unit/internal/EncoderInternalSpec.kt Adds test for cycle detection through user-defined filters
CHANGELOG.md Documents all fixes and improvements in version 1.5.0-wip

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 40747c80f4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@techouse techouse requested a review from Copilot February 11, 2026 21:17
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

@techouse techouse merged commit 074b97a into main Feb 11, 2026
11 of 15 checks passed
@techouse techouse deleted the chore/improvements branch February 11, 2026 22:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant