Skip to content

feat: Add strict parsing mode as the default - #4

Merged
razor-x merged 2 commits into
mainfrom
claude/url-param-parser-migration-i9foa1
Aug 5, 2026
Merged

feat: Add strict parsing mode as the default#4
razor-x merged 2 commits into
mainfrom
claude/url-param-parser-migration-i9foa1

Conversation

@razor-x

@razor-x razor-x commented Aug 5, 2026

Copy link
Copy Markdown
Member

Summary

Follow-up to #3 (Zod v3/v4 support, released as 0.2.0). Adds a strict option to parseUrlSearchParams, defaulting to true. Strict mode parses only the expected output of @seamapi/url-search-params-serializer, making the parser a perfect inverse of the serializer. Generous parsing (the previous behavior) moves behind strict: false, isolating its extra input formats and their limitations.

Needed by seamapi/nextlove#182, which uses strict: false to keep accepting all array formats.

Strict mode (strict: true, the default)

Perfectly aligned with the serializer — only its output format is parsed:

  • Arrays use only the repeated format foo=a&foo=b (plus foo= for the empty array).
  • Array values may contain commas and are never splitfoo=a,b&foo=c parses as ['a,b', 'c']. The serializer can emit such values, so strict mode round-trips them; the "no commas in array values" limitation now only applies to generous mode.
  • There is no bracket array format. Since the serializer never outputs foo[]=a for an array named foo, a param named foo[] is unrelated to foo: it parses as a param literally named foo[] (which the serializer produces for a key of that name, so it round-trips). The same applies to record keys ending in [] — literal keys in strict mode.
  • Booleans parse only from the exact strings true / false.
  • Whitespace is never trimmed and never treated as empty; only a truly empty value is null / the empty array.

New bijection tests cover the previously non-invertible cases: array values containing commas, and params literally named with a bracket suffix.

Generous mode (strict: false)

Preserves the previous behavior: comma (foo=a,b) and bracket (foo[]=a) array formats, generous booleans (yes, 1, NO, …), and whitespace trimming/null handling — at the cost of array values not containing commas.

Unchanged in both modes: unparseable values pass through as strings for the schema to reject, empty z.string() is null, unknown params are ignored, and the ambiguity errors for repeated non-array params, mixed empty array values, and conflicting nested params.

Usage

parseUrlSearchParams('foo=a,b&foo=c', schema) // strict: { foo: ['a,b', 'c'] }
parseUrlSearchParams('foo=a,b', schema, { strict: false }) // generous: { foo: ['a', 'b'] }

Testing

166 tests pass: the existing suite (updated to pass strict: false where it exercises generous parsing), a new test/strict-parsing.test.ts (including literal foo[] params), and the Zod v4 suite updated for both modes. The README now documents Strict Parsing, Generous Parsing, and the rules shared by both.

Breaking change

Generous parsing is no longer the default: pass strict: false to keep the previous behavior.

Semantic-release: publishes as 0.3.0 (0.x minor bump for the breaking feat!).


Generated by Claude Code

claude added 2 commits August 5, 2026 22:02
Add a strict option to parseUrlSearchParams, defaulting to true.
In strict mode, only the expected output of
@seamapi/url-search-params-serializer is parsed, making the parser a
true inverse of the serializer: arrays use only the repeated format,
array values may contain commas and are never split, the bracket format
throws UnparseableSearchParamError, only the strings true and false
parse as booleans, and whitespace is never trimmed or treated as empty.

Pass strict: false for generous parsing, which preserves the previous
behavior: comma and bracket array formats, generous boolean values, and
whitespace trimming, at the cost of array values not containing commas.

BREAKING CHANGE: Generous parsing is no longer the default; pass
strict: false to parseUrlSearchParams to keep the previous behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015jWzL9LC7Q6bTGaXDoKq4z
In strict mode there is no bracket array format: since the serializer
never outputs foo[]= for an array named foo, a param named foo[] is
unrelated to foo and is parsed as a param literally named "foo[]".
The same applies to record keys ending in [], which are literal keys
in strict mode. Previously strict mode threw
UnparseableSearchParamError for the bracket format.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015jWzL9LC7Q6bTGaXDoKq4z
@razor-x razor-x changed the title feat!: Add strict parsing mode as the default feat: Add strict parsing mode as the default Aug 5, 2026
@razor-x
razor-x marked this pull request as ready for review August 5, 2026 22:08
@razor-x
razor-x merged commit 6363a34 into main Aug 5, 2026
13 checks passed
@razor-x
razor-x deleted the claude/url-param-parser-migration-i9foa1 branch August 5, 2026 22:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants