fix: lift unsafe_state_mutation constrained for SvelteDate, SvelteURL and SvelteURLSearchParams created inside the derived

pull/16221/head
Fedor Nezhivoi 3 months ago
parent 3c3255fdb9
commit a784607811

@ -2,4 +2,4 @@
'svelte': patch 'svelte': patch
--- ---
lift unsafe_state_mutation constrained for SvelteSet and SvelteMap created inside the derived lift unsafe_state_mutation constraints for SvelteSet, SvelteMap, SvelteDate, SvelteURL and SvelteURLSearchParams created inside the derived

@ -1,6 +1,6 @@
/** @import { Source } from '#client' */ /** @import { Source } from '#client' */
import { derived } from '../internal/client/index.js'; import { derived } from '../internal/client/index.js';
import { source, set } from '../internal/client/reactivity/sources.js'; import { set, state } from '../internal/client/reactivity/sources.js';
import { tag } from '../internal/client/dev/tracing.js'; import { tag } from '../internal/client/dev/tracing.js';
import { active_reaction, get, set_active_reaction } from '../internal/client/runtime.js'; import { active_reaction, get, set_active_reaction } from '../internal/client/runtime.js';
import { DEV } from 'esm-env'; import { DEV } from 'esm-env';
@ -40,7 +40,7 @@ var inited = false;
* ``` * ```
*/ */
export class SvelteDate extends Date { export class SvelteDate extends Date {
#time = source(super.getTime()); #time = state(super.getTime());
/** @type {Map<keyof Date, Source<unknown>>} */ /** @type {Map<keyof Date, Source<unknown>>} */
#deriveds = new Map(); #deriveds = new Map();

@ -1,5 +1,5 @@
import { DEV } from 'esm-env'; import { DEV } from 'esm-env';
import { source } from '../internal/client/reactivity/sources.js'; import { state } from '../internal/client/reactivity/sources.js';
import { tag } from '../internal/client/dev/tracing.js'; import { tag } from '../internal/client/dev/tracing.js';
import { get } from '../internal/client/runtime.js'; import { get } from '../internal/client/runtime.js';
import { get_current_url } from './url.js'; import { get_current_url } from './url.js';
@ -34,7 +34,7 @@ export const REPLACE = Symbol();
* ``` * ```
*/ */
export class SvelteURLSearchParams extends URLSearchParams { export class SvelteURLSearchParams extends URLSearchParams {
#version = DEV ? tag(source(0), 'SvelteURLSearchParams version') : source(0); #version = DEV ? tag(state(0), 'SvelteURLSearchParams version') : state(0);
#url = get_current_url(); #url = get_current_url();
#updating = false; #updating = false;

@ -1,5 +1,5 @@
import { DEV } from 'esm-env'; import { DEV } from 'esm-env';
import { source, set } from '../internal/client/reactivity/sources.js'; import { set, state } from '../internal/client/reactivity/sources.js';
import { tag } from '../internal/client/dev/tracing.js'; import { tag } from '../internal/client/dev/tracing.js';
import { get } from '../internal/client/runtime.js'; import { get } from '../internal/client/runtime.js';
import { REPLACE, SvelteURLSearchParams } from './url-search-params.js'; import { REPLACE, SvelteURLSearchParams } from './url-search-params.js';
@ -40,14 +40,14 @@ export function get_current_url() {
* ``` * ```
*/ */
export class SvelteURL extends URL { export class SvelteURL extends URL {
#protocol = source(super.protocol); #protocol = state(super.protocol);
#username = source(super.username); #username = state(super.username);
#password = source(super.password); #password = state(super.password);
#hostname = source(super.hostname); #hostname = state(super.hostname);
#port = source(super.port); #port = state(super.port);
#pathname = source(super.pathname); #pathname = state(super.pathname);
#hash = source(super.hash); #hash = state(super.hash);
#search = source(super.search); #search = state(super.search);
#searchParams; #searchParams;
/** /**

@ -0,0 +1,23 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
compileOptions: {
dev: true,
runes: true
},
test({ assert, target }) {
const [button1, button2] = target.querySelectorAll('button');
assert.throws(() => {
button1?.click();
flushSync();
}, /state_unsafe_mutation/);
assert.doesNotThrow(() => {
button2?.click();
flushSync();
});
}
});

@ -0,0 +1,27 @@
<script>
import { SvelteDate } from 'svelte/reactivity';
let visibleExternal = $state(false);
let external = new SvelteDate();
const throws = $derived.by(() => {
external.setTime(12345);
return external;
})
let visibleInternal = $state(false);
const works = $derived.by(() => {
let internal = new SvelteDate();
internal.setTime(12345);
return internal;
})
</script>
<button onclick={() => (visibleExternal = true)}>external</button>
{#if visibleExternal}
{throws}
{/if}
<button onclick={() => (visibleInternal = true)}>internal</button>
{#if visibleInternal}
{works}
{/if}

@ -0,0 +1,23 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
compileOptions: {
dev: true,
runes: true
},
test({ assert, target }) {
const [button1, button2] = target.querySelectorAll('button');
assert.throws(() => {
button1?.click();
flushSync();
}, /state_unsafe_mutation/);
assert.doesNotThrow(() => {
button2?.click();
flushSync();
});
}
});

@ -0,0 +1,27 @@
<script>
import { SvelteURLSearchParams } from 'svelte/reactivity';
let visibleExternal = $state(false);
let external = new SvelteURLSearchParams();
const throws = $derived.by(() => {
external.append('foo', 'bar')
return external;
})
let visibleInternal = $state(false);
const works = $derived.by(() => {
let internal = new SvelteURLSearchParams();
internal.append('foo', 'bar')
return internal;
})
</script>
<button onclick={() => (visibleExternal = true)}>external</button>
{#if visibleExternal}
{throws}
{/if}
<button onclick={() => (visibleInternal = true)}>internal</button>
{#if visibleInternal}
{works}
{/if}

@ -0,0 +1,23 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
compileOptions: {
dev: true,
runes: true
},
test({ assert, target }) {
const [button1, button2] = target.querySelectorAll('button');
assert.throws(() => {
button1?.click();
flushSync();
}, /state_unsafe_mutation/);
assert.doesNotThrow(() => {
button2?.click();
flushSync();
});
}
});

@ -0,0 +1,27 @@
<script>
import { SvelteURL } from 'svelte/reactivity';
let visibleExternal = $state(false);
let external = new SvelteURL('https://svelte.dev');
const throws = $derived.by(() => {
external.host = 'kit.svelte.dev'
return external;
})
let visibleInternal = $state(false);
const works = $derived.by(() => {
let internal = new SvelteURL('https://svelte.dev');
internal.host = 'kit.svelte.dev'
return internal;
})
</script>
<button onclick={() => (visibleExternal = true)}>external</button>
{#if visibleExternal}
{throws}
{/if}
<button onclick={() => (visibleInternal = true)}>internal</button>
{#if visibleInternal}
{works}
{/if}
Loading…
Cancel
Save