Fix/query encode semi - #288
Open
yyz945947732 wants to merge 2 commits into
Open
yyz945947732 wants to merge 2 commits into
yyz945947732 wants to merge 2 commits into
Conversation
silverfish2525
added a commit
to silverfish2525/better-ufo
that referenced
this pull request
Jul 1, 2026
Closes upstream issues unjs#233, unjs#240, unjs#301, unjs#302, unjs#304 in a single pass, and verified against the WHATWG URL spec (\u00a75) + native URLSearchParams output. Every code point outside `[A-Za-z0-9*-._]` is now percent-encoded by `encodeQueryValue` / `encodeQueryKey`. Direct char-by-char parity check against `new URLSearchParams([['k', c]]).toString()`: 33/33 match. Concrete deltas from prior behavior: ^ -> %5E (was raw, restored from encodeURI output; issue unjs#304) ` -> %60 (was raw, restored from encodeURI output; issue unjs#302) | -> %7C (was raw, restored via encode() pipe rewrite; issue unjs#233) ; -> %3B (issue unjs#240) ? -> %3F (issue unjs#301) ! -> %21 ' -> %27 ( -> %28 ) -> %29 ~ -> %7E , -> %2C : -> %3A @ -> %40 = -> %3D (in values too, matching URLSearchParams; encodeQueryKey no longer needs a separate `=` pass, so it becomes an alias). Community consensus: 11 open upstream PRs (unjs#279, unjs#288, unjs#303, unjs#305, unjs#310, unjs#318, unjs#324, unjs#327, unjs#328, unjs#329, unjs#354) all propose subsets of this fix. This commit lands the full set at once. Path/hash encoding is UNCHANGED \u2014 the WHATWG fragment percent-encode set excludes `^{}` and `|` on purpose (fragment allows them raw), and encode() retains its pipe-restore for path/hash consumers. Tests: 991 pass + 65 xfail. Added WHATWG-URLSearchParams parity regression test that walks every contested char and asserts native-parity.
silverfish2525
added a commit
to silverfish2525/better-ufo
that referenced
this pull request
Jul 1, 2026
…paque schemes) Encoding — WHATWG application/x-www-form-urlencoded compliance - encodeQueryValue/encodeQueryKey: byte-for-byte parity with URLSearchParams.toString(); |, `, ^, @, :, ,, ;, =, ? all encoded (adopts consensus from 11 open upstream PRs: unjs#279 unjs#288 unjs#303 unjs#305 unjs#310 unjs#318 unjs#324 unjs#327 unjs#328 unjs#329 unjs#354) - Single-pass replacer; %20 → + rewrite after encodeURI, before map parseQuery — correctness + security - Single-pass charCode scanner (PR unjs#331 @saripovdenis, ~40% faster) - Empty-key preservation: =value → { "": "value" } (PR unjs#355 @spokodev; was silently losing the value with the old /([^=]+)=?(.*)/ regex) - Proto-pollution guard: __proto__ / constructor / prototype blocked (PR unjs#289 @pi0; extended to cover prototype as well) - stringifyQuery: single-pass builder (PR unjs#333 @saripovdenis) parseURL — opaque-scheme URIs (RFC 3986 §3) - mailto:, tel:, urn:, sms: — scheme NOT followed by // → opaque path surfaced in .pathname; query/fragment parsed from the opaque tail - data:, blob: round-trip correctly (tested against WPT urltestdata.json) parseAuth — RFC 3986 §3.2.1 - Split on FIRST colon only; subsequent colons belong to the password (was splitting on all colons, losing interior password chars) parseHost — IPv6 - Brackets retained on hostname to match WHATWG URL.hostname contract - Malformed unclosed bracket returns input verbatim (no silent truncation) - Non-numeric port suffix detected (was silently truncated) cleanDoubleSlashes — query/fragment protection - Double-slash collapse no longer touches query or fragment sections hasProtocol — single-char scheme rejection - Blocks Windows drive letters (C:) and bare-digit prefixes withBase / withoutBase — fragment-boundary fix - Fragment on input (#hash) no longer defeats 'base already present' check (was producing doubled base path on fragment-suffixed inputs) withFragment — empty hash strips existing fragment WPT urltestdata.json ratchet - 100-case special-scheme subset; 65 known-divergent cases run via it.fails (same count as upstream); ratchet trips if a fix lands
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I’m not sure if this is the expected behavior, but I think it's understandable that
;is not encoded in the URL path since it’s a reserved character in the URL. However, in the query, I believe it should be encoded, because some browsers might treat;as a separator instead of a normal character, which could lead to unexpected behavior.close #240