Add encodeURI / decodeURI / encodeURIComponent / decodeURIComponent#280
Conversation
- Add `encodeURI`/`decodeURI` and `encodeURIComponent`/`decodeURIComponent` - Share URI percent-encoding logic with `import.meta.url` - Cover URI encoding behavior with built-in tests
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds ES2026 URI globals ( Changes
Sequence Diagram(s)mermaid Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tests/built-ins/encodeURI.js`:
- Around line 1-114: Add negative tests asserting that encodeURI throws a
URIError for unpaired (lone) surrogates: call encodeURI with a lone high
surrogate (e.g., "\uD800") and a lone low surrogate (e.g., "\uDC00") and assert
via expect(() => encodeURI(...)).toThrow(URIError); also include a small
positive control using a valid surrogate pair (e.g., "\uD83D\uDE00") to ensure
it does not throw. Locate tests around the existing encodeURI test suite and add
these cases referencing the encodeURI function.
In `@tests/built-ins/encodeURIComponent.js`:
- Around line 1-88: Add explicit tests that assert encodeURIComponent throws a
URIError for lone/mismatched UTF-16 surrogates: create a new test (e.g., "throws
URIError for lone surrogates") that calls encodeURIComponent with a lone high
surrogate ("\uD800"), a lone low surrogate ("\uDC00"), and a string with a
mismatched pair (e.g., "\uD800X" or "X\uDC00") and use expect(() =>
encodeURIComponent(...)).toThrow(URIError) for each case so the suite covers
this error condition alongside the existing multi-byte tests.
In `@units/Goccia.URI.pas`:
- Around line 297-308: The code incorrectly re-serializes reserved
percent-escapes using PercentEncodeByte (which uppercases hex) instead of
preserving the original three-character escape; in the Decode routine around the
DecodePercentByte call (see DecodePercentByte, PercentEncodeByte, AReservedSet
and the Buffer.Append call), capture the original percent-escape substring (the
three chars starting at current index before advancing/decoding), use
DecodePercentByte only to obtain B for character classification, but when
DecodedChar is in AReservedSet append the captured original substring verbatim
to Buffer instead of calling PercentEncodeByte, ensuring reserved escapes keep
their original hex case and form.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 281e93ea-0fa8-4bcc-8634-754d23b98f22
📒 Files selected for processing (11)
AGENTS.mddocs/built-ins.mddocs/language-restrictions.mdtests/built-ins/decodeURI.jstests/built-ins/decodeURIComponent.jstests/built-ins/encodeURI.jstests/built-ins/encodeURIComponent.jsunits/Goccia.Builtins.Globals.pasunits/Goccia.ImportMeta.pasunits/Goccia.URI.pasunits/Goccia.Values.ErrorHelper.pas
💤 Files with no reviewable changes (1)
- docs/language-restrictions.md
Suite Timing
Measured on ubuntu-latest x64. |
Benchmark Results364 benchmarks Interpreted: 🟢 99 improved · 🔴 110 regressed · 155 unchanged · avg -0.1% arraybuffer.js — Interp: 🟢 4, 🔴 2, 8 unch. · avg +0.4% · Bytecode: 🟢 14 · avg +9.6%
arrays.js — Interp: 🟢 13, 🔴 3, 3 unch. · avg +1.8% · Bytecode: 🟢 19 · avg +10.8%
async-await.js — Interp: 🟢 1, 🔴 5 · avg -1.6% · Bytecode: 🟢 6 · avg +10.1%
base64.js — Interp: 🟢 5, 🔴 3, 2 unch. · avg +1.4% · Bytecode: 🟢 10 · avg +11.9%
classes.js — Interp: 🟢 10, 🔴 5, 16 unch. · avg +0.8% · Bytecode: 🟢 24, 🔴 1, 6 unch. · avg +10.0%
closures.js — Interp: 🟢 1, 🔴 5, 5 unch. · avg -1.0% · Bytecode: 🟢 5, 🔴 1, 5 unch. · avg +3.0%
collections.js — Interp: 🟢 2, 🔴 7, 3 unch. · avg -1.1% · Bytecode: 🟢 7, 🔴 4, 1 unch. · avg +3.3%
destructuring.js — Interp: 🟢 9, 🔴 10, 3 unch. · avg +0.3% · Bytecode: 🟢 10, 🔴 6, 6 unch. · avg +1.1%
fibonacci.js — Interp: 🟢 1, 🔴 5, 2 unch. · avg -2.3% · Bytecode: 🟢 5, 🔴 1, 2 unch. · avg +9.5%
float16array.js — Interp: 🟢 7, 🔴 13, 12 unch. · avg -2.3% · Bytecode: 🟢 31, 1 unch. · avg +14.3%
for-of.js — Interp: 🟢 4, 3 unch. · avg +2.0% · Bytecode: 🟢 4, 🔴 3 · avg +3.1%
helpers/bench-module.js — Interp: 0 · Bytecode: 0
iterators.js — Interp: 🟢 5, 🔴 16, 21 unch. · avg -1.0% · Bytecode: 🟢 35, 🔴 3, 4 unch. · avg +4.8%
json.js — Interp: 🔴 11, 9 unch. · avg -1.3% · Bytecode: 🟢 19, 1 unch. · avg +5.3%
jsx.jsx — Interp: 🟢 3, 🔴 6, 12 unch. · avg -0.6% · Bytecode: 🟢 21 · avg +6.5%
modules.js — Interp: 🟢 2, 🔴 2, 5 unch. · avg +0.3% · Bytecode: 🟢 9 · avg +6.8%
numbers.js — Interp: 🟢 3, 🔴 3, 5 unch. · avg +0.6% · Bytecode: 🟢 11 · avg +12.9%
objects.js — Interp: 🟢 4, 🔴 1, 2 unch. · avg +0.7% · Bytecode: 🟢 7 · avg +6.0%
promises.js — Interp: 🟢 1, 🔴 1, 10 unch. · avg -0.1% · Bytecode: 🟢 12 · avg +5.8%
regexp.js — Interp: 🟢 1, 🔴 3, 7 unch. · avg -0.9% · Bytecode: 🟢 8, 🔴 1, 2 unch. · avg +2.8%
strings.js — Interp: 🟢 8, 🔴 1, 10 unch. · avg +2.7% · Bytecode: 🟢 12, 7 unch. · avg +4.4%
typed-arrays.js — Interp: 🟢 9, 🔴 2, 11 unch. · avg +0.9% · Bytecode: 🟢 19, 🔴 1, 2 unch. · avg +7.8%
uint8array-encoding.js — Interp: 🟢 6, 🔴 6, 6 unch. · avg -0.1% · Bytecode: 🟢 12, 🔴 3, 3 unch. · avg +4.1%
Measured on ubuntu-latest x64. Benchmark ranges compare cached main-branch min/max ops/sec with the PR run; overlapping ranges are treated as unchanged noise. Percentage deltas are secondary context. |
- Decode now captures the original %XX substring and re-emits it verbatim for reserved characters instead of normalizing hex case via PercentEncodeByte (ES2026 §19.2.6.2 step 4b.ii.1). - Add lone surrogate URIError tests to encodeURI and encodeURIComponent test suites. - Fix decodeURI test that incorrectly expected case normalization. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
encodeURI,decodeURI,encodeURIComponent, anddecodeURIComponentas global functions per ES2026 §19.2.6.Goccia.URI.pasunit with theEncode/Decodecore algorithms, UTF-8 multi-byte support, surrogate validation, and overlong-encoding rejection. Also exposesPercentEncodePathfor file-URL percent-encoding.Goccia.ImportMeta.pasnow uses the sharedPercentEncodePathfromGoccia.URIinstead of its own private copy.ThrowURIErrortoGoccia.Values.ErrorHelper.pas(theURIErrorconstructor and prototype already existed).import.metapath-separator conversion (\→/) remains unchanged and runs before the shared encoder.docs/language-restrictions.md.Testing
encodeURIComponent.js,decodeURIComponent.js,encodeURI.js,decodeURI.js), all passing in both interpreted and bytecode modesimport.metatests (22/22) continue to pass after thePercentEncodePathunificationCLAUDE.md: addedGoccia.URI.pasto architecture tabledocs/built-ins.md: documented all 4 functions with behavior detailsdocs/language-restrictions.md: removed from deferred list