Fix searchParams.set duplicate updates (#18336)

## Summary
- detect `SvelteURLSearchParams#set` changes by comparing duplicate
value lists instead of joined strings
- update reactive subscribers when duplicate params collapse to a single
value with the same concatenated text
- cover both `SvelteURLSearchParams` and `SvelteURL.searchParams`
synchronization

## Tests
- pnpm exec vitest run
packages/svelte/src/reactivity/url-search-params.test.ts -t
"URLSearchParams.set updates when duplicate values collapse to the same
joined string"
- pnpm exec vitest run
packages/svelte/src/reactivity/url-search-params.test.ts
packages/svelte/src/reactivity/url.test.ts

---------

Co-authored-by: Rich Harris <hello@rich-harris.dev>
pull/18253/merge
jiyujie2006 23 hours ago committed by GitHub
parent 11985c020f
commit 2f6307af65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: update `SvelteURLSearchParams` when setting duplicate keys to the same joined value

@ -132,11 +132,12 @@ export class SvelteURLSearchParams extends URLSearchParams {
* @returns {void}
*/
set(name, value) {
var previous = super.getAll(name).join('');
var previous = super.getAll(name);
super.set(name, value);
// can't use has(name, value), because for something like https://svelte.dev?foo=1&bar=2&foo=3
// if you set `foo` to 1, then foo=3 gets deleted whilst `has("foo", "1")` returns true
if (previous !== super.getAll(name).join('')) {
var current = super.getAll(name);
if (previous.length !== current.length || previous.some((value, i) => value !== current[i])) {
this.#update_url();
increment(this.#version);
}

@ -55,6 +55,44 @@ test('URLSearchParams.set', () => {
cleanup();
});
test('URLSearchParams.set updates when duplicate values collapse to the same joined string', () => {
const params = new SvelteURLSearchParams('a=ab&a=c');
const log: any = [];
const cleanup = effect_root(() => {
render_effect(() => {
log.push(params.toString());
});
});
flushSync(() => {
params.set('a', 'abc');
});
assert.deepEqual(log, ['a=ab&a=c', 'a=abc']);
cleanup();
});
test('URLSearchParams.set updates when duplicate values collapse to the same comma-joined string', () => {
const params = new SvelteURLSearchParams('a=a&a=b');
const log: any = [];
const cleanup = effect_root(() => {
render_effect(() => {
log.push(params.toString());
});
});
flushSync(() => {
params.set('a', 'a,b');
});
assert.deepEqual(log, ['a=a&a=b', 'a=a%2Cb']);
cleanup();
});
test('URLSearchParams.append', () => {
const params = new SvelteURLSearchParams();
const log: any = [];

@ -115,6 +115,25 @@ test('url.searchParams', () => {
cleanup();
});
test('url.searchParams.set updates url when duplicate values collapse to the same joined string', () => {
const url = new SvelteURL('https://svelte.dev?a=ab&a=c');
const log: any = [];
const cleanup = effect_root(() => {
render_effect(() => {
log.push(url.href);
});
});
flushSync(() => {
url.searchParams.set('a', 'abc');
});
assert.deepEqual(log, ['https://svelte.dev/?a=ab&a=c', 'https://svelte.dev/?a=abc']);
cleanup();
});
test('url.search normalizes value', () => {
const url = new SvelteURL('https://svelte.dev');
const log: any = [];

Loading…
Cancel
Save