fix: lift unsafe_state_mutation constrained for SvelteSet and SvelteMap created inside the derived

pull/16221/head
Fedor Nezhivoi 3 months ago
parent 669a2233ee
commit 26180d5f07

@ -1,6 +1,6 @@
/** @import { Source } from '#client' */
import { DEV } from 'esm-env';
import { set, source } from '../internal/client/reactivity/sources.js';
import { set, source, state } from '../internal/client/reactivity/sources.js';
import { label, tag } from '../internal/client/dev/tracing.js';
import { get } from '../internal/client/runtime.js';
import { increment } from './utils.js';
@ -54,8 +54,8 @@ import { increment } from './utils.js';
export class SvelteMap extends Map {
/** @type {Map<K, Source<number>>} */
#sources = new Map();
#version = source(0);
#size = source(0);
#version = state(0);
#size = state(0);
/**
* @param {Iterable<readonly [K, V]> | null | undefined} [value]

@ -1,6 +1,6 @@
/** @import { Source } from '#client' */
import { DEV } from 'esm-env';
import { source, set } from '../internal/client/reactivity/sources.js';
import { source, set, state } from '../internal/client/reactivity/sources.js';
import { label, tag } from '../internal/client/dev/tracing.js';
import { get } from '../internal/client/runtime.js';
import { increment } from './utils.js';
@ -48,8 +48,8 @@ var inited = false;
export class SvelteSet extends Set {
/** @type {Map<T, Source<boolean>>} */
#sources = new Map();
#version = source(0);
#size = source(0);
#version = state(0);
#size = state(0);
/**
* @param {Iterable<T> | null | undefined} [value]

@ -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,25 @@
<script>
let visibleExternal = $state(false);
let external = $state([]);
const throws = $derived.by(() => {
external.push(1);
return external;
});
let visibleInternal = $state(false)
const works = $derived.by(() => {
let internal = $state([]);
internal.push(1);
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 { SvelteMap } from 'svelte/reactivity';
let visibleExternal = $state(false);
let external = new SvelteMap();
const throws = $derived.by(() => {
external.set(1, 1);
return external;
});
let visibleInternal = $state(false);
const works = $derived.by(() => {
let internal = new SvelteMap();
internal.set(1, 1);
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,25 @@
<script>
let visibleExternal = $state(false);
let external = $state({ v: 1 });
const throws = $derived.by(() => {
external.v = 2;
return external;
});
let visibleInternal = $state(false)
const works = $derived.by(() => {
let internal = $state({ v: 1 });
internal.v = 2;
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,25 @@
<script>
let visibleExternal = $state(false);
let external = $state(1);
const throws = $derived.by(() => {
external = 2;
return external;
});
let visibleInternal = $state(false);
const works = $derived.by(() => {
let internal = $state(1);
internal = 2;
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 { SvelteSet } from 'svelte/reactivity';
let visibleExternal = $state(false);
let external = new SvelteSet();
const throws = $derived.by(() => {
external.add(1);
return external;
})
let visibleInternal = $state(false);
const works = $derived.by(() => {
let internal = new SvelteSet();
internal.add(1);
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