Skip to content

breaking: change $state.frozen -> $state.raw #12742

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions packages/svelte/messages/client-errors/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,6 @@

> The `%rune%` rune is only available inside `.svelte` and `.svelte.js/ts` files

## state_frozen_invalid_argument

> The argument to `$state.frozen(...)` cannot be an object created with `$state(...)`. You should create a copy of it first, for example with `$state.snapshot`

## state_prototype_fixed

> Cannot set prototype of `$state` object
Expand Down
9 changes: 5 additions & 4 deletions packages/svelte/src/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,13 @@ declare namespace $state {
: never;

/**
* Declares reactive read-only state that is shallowly immutable.
* Declares state that is _not_ made deeply reactive — instead of mutating it,
* you must reassign it.
*
* Example:
* ```ts
* <script>
* let items = $state.frozen([0]);
* let items = $state.raw([0]);
*
* const addItem = () => {
* items = [...items, items.length];
Expand All @@ -123,8 +124,8 @@ declare namespace $state {
*
* @param initial The initial value
*/
export function frozen<T>(initial: T): Readonly<T>;
export function frozen<T>(): Readonly<T> | undefined;
export function raw<T>(initial: T): T;
export function raw<T>(): T | undefined;
/**
* To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`:
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function CallExpression(node, context) {
break;

case '$state':
case '$state.frozen':
case '$state.raw':
case '$derived':
case '$derived.by':
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function VariableDeclarator(node, context) {
// TODO feels like this should happen during scope creation?
if (
rune === '$state' ||
rune === '$state.frozen' ||
rune === '$state.raw' ||
rune === '$derived' ||
rune === '$derived.by' ||
rune === '$props'
Expand All @@ -32,7 +32,7 @@ export function VariableDeclarator(node, context) {
binding.kind =
rune === '$state'
? 'state'
: rune === '$state.frozen'
: rune === '$state.raw'
? 'frozen_state'
: rune === '$derived' || rune === '$derived.by'
? 'derived'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,18 +256,8 @@ export function client_component(analysis, options) {
}

if (binding?.kind === 'state' || binding?.kind === 'frozen_state') {
return [
getter,
b.set(alias ?? name, [
b.stmt(
b.call(
'$.set',
b.id(name),
b.call(binding.kind === 'state' ? '$.proxy' : '$.freeze', b.id('$$value'))
)
)
])
];
const value = binding.kind === 'state' ? b.call('$.proxy', b.id('$$value')) : b.id('$$value');
return [getter, b.set(alias ?? name, [b.stmt(b.call('$.set', b.id(name), value))])];
}

return getter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ export function build_setter(node, context, fallback, prefix, options) {
if (assignment.type === 'AssignmentExpression') {
assignment.right =
private_state.kind === 'frozen_state'
? b.call('$.freeze', value)
? value
: build_proxy_reassignment(value, private_state.id);
return assignment;
}
Expand All @@ -223,7 +223,7 @@ export function build_setter(node, context, fallback, prefix, options) {
!options?.skip_proxy_and_freeze &&
should_proxy_or_freeze(value, context.state.scope)
? private_state.kind === 'frozen_state'
? b.call('$.freeze', value)
? value
: build_proxy_reassignment(value, private_state.id)
: value
);
Expand All @@ -247,7 +247,7 @@ export function build_setter(node, context, fallback, prefix, options) {
if (assignment.type === 'AssignmentExpression') {
assignment.right =
public_state.kind === 'frozen_state'
? b.call('$.freeze', value)
? value
: build_proxy_reassignment(value, public_state.id);
return assignment;
}
Expand Down Expand Up @@ -344,7 +344,7 @@ export function build_setter(node, context, fallback, prefix, options) {
context.state.analysis.runes &&
!options?.skip_proxy_and_freeze &&
should_proxy_or_freeze(value, context.state.scope)
? b.call('$.freeze', value)
? value
: value
);
} else if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export function ClassBody(node, context) {
const rune = get_rune(definition.value, context.state.scope);
if (
rune === '$state' ||
rune === '$state.frozen' ||
rune === '$state.raw' ||
rune === '$derived' ||
rune === '$derived.by'
) {
Expand All @@ -53,7 +53,7 @@ export function ClassBody(node, context) {
kind:
rune === '$state'
? 'state'
: rune === '$state.frozen'
: rune === '$state.raw'
? 'frozen_state'
: rune === '$derived.by'
? 'derived_by'
Expand Down Expand Up @@ -117,12 +117,7 @@ export function ClassBody(node, context) {
should_proxy_or_freeze(init, context.state.scope) ? b.call('$.proxy', init) : init
)
: field.kind === 'frozen_state'
? b.call(
'$.source',
should_proxy_or_freeze(init, context.state.scope)
? b.call('$.freeze', init)
: init
)
? b.call('$.source', init)
: field.kind === 'derived_by'
? b.call('$.derived', init)
: b.call('$.derived', b.thunk(init));
Expand Down Expand Up @@ -158,12 +153,7 @@ export function ClassBody(node, context) {
// set foo(value) { this.#foo = value; }
const value = b.id('value');
body.push(
b.method(
'set',
definition.key,
[value],
[b.stmt(b.call('$.set', member, b.call('$.freeze', value)))]
)
b.method('set', definition.key, [value], [b.stmt(b.call('$.set', member, value))])
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export function VariableDeclaration(node, context) {
const value =
args.length === 0 ? b.id('undefined') : /** @type {Expression} */ (context.visit(args[0]));

if (rune === '$state' || rune === '$state.frozen') {
if (rune === '$state' || rune === '$state.raw') {
/**
* @param {Identifier} id
* @param {Expression} value
Expand All @@ -128,8 +128,8 @@ export function VariableDeclaration(node, context) {
const binding = /** @type {import('#compiler').Binding} */ (
context.state.scope.get(id.name)
);
if (should_proxy_or_freeze(value, context.state.scope)) {
value = b.call(rune === '$state' ? '$.proxy' : '$.freeze', value);
if (rune === '$state' && should_proxy_or_freeze(value, context.state.scope)) {
value = b.call('$.proxy', value);
}
if (is_state_source(binding, context.state)) {
value = b.call('$.source', value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function PropertyDefinition(node, context) {
if (context.state.analysis.runes && node.value != null && node.value.type === 'CallExpression') {
const rune = get_rune(node.value, context.state.scope);

if (rune === '$state' || rune === '$state.frozen' || rune === '$derived') {
if (rune === '$state' || rune === '$state.raw' || rune === '$derived') {
return {
...node,
value:
Expand Down
1 change: 0 additions & 1 deletion packages/svelte/src/internal/client/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,4 @@ export const INSPECT_EFFECT = 1 << 17;
export const HEAD_EFFECT = 1 << 18;

export const STATE_SYMBOL = Symbol('$state');
export const STATE_FROZEN_SYMBOL = Symbol('$state.frozen');
export const LOADING_ATTR_SYMBOL = Symbol('');
9 changes: 2 additions & 7 deletions packages/svelte/src/internal/client/dom/blocks/each.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
} from '../../reactivity/effects.js';
import { source, mutable_source, set } from '../../reactivity/sources.js';
import { is_array, is_frozen } from '../../../shared/utils.js';
import { INERT, STATE_FROZEN_SYMBOL, STATE_SYMBOL } from '../../constants.js';
import { INERT, STATE_SYMBOL } from '../../constants.js';
import { queue_micro_task } from '../task.js';
import { current_effect } from '../../runtime.js';

Expand Down Expand Up @@ -142,12 +142,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
// If we are working with an array that isn't proxied or frozen, then remove strict equality and ensure the items
// are treated as reactive, so they get wrapped in a signal.
var flags = state.flags;
if (
(flags & EACH_IS_STRICT_EQUALS) !== 0 &&
!is_frozen(array) &&
!(STATE_FROZEN_SYMBOL in array) &&
!(STATE_SYMBOL in array)
) {
if ((flags & EACH_IS_STRICT_EQUALS) !== 0 && !is_frozen(array) && !(STATE_SYMBOL in array)) {
flags ^= EACH_IS_STRICT_EQUALS;

// Additionally if we're in an keyed each block, we'll need ensure the items are all wrapped in signals.
Expand Down
40 changes: 0 additions & 40 deletions packages/svelte/src/internal/client/freeze.js

This file was deleted.

16 changes: 0 additions & 16 deletions packages/svelte/src/internal/client/freeze.test.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/svelte/src/internal/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ export {
template_with_script,
text
} from './dom/template.js';
export { freeze } from './freeze.js';
export { derived, derived_safe_equal } from './reactivity/deriveds.js';
export {
effect_tracking,
Expand Down
9 changes: 2 additions & 7 deletions packages/svelte/src/internal/client/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from '../shared/utils.js';
import { check_ownership, widen_ownership } from './dev/ownership.js';
import { source, set } from './reactivity/sources.js';
import { STATE_FROZEN_SYMBOL, STATE_SYMBOL } from './constants.js';
import { STATE_SYMBOL } from './constants.js';
import { UNINITIALIZED } from '../../constants.js';
import * as e from './errors.js';

Expand All @@ -24,12 +24,7 @@ import * as e from './errors.js';
* @returns {ProxyStateObject<T> | T}
*/
export function proxy(value, parent = null, prev) {
if (
typeof value === 'object' &&
value != null &&
!is_frozen(value) &&
!(STATE_FROZEN_SYMBOL in value)
) {
if (typeof value === 'object' && value != null && !is_frozen(value)) {
// If we have an existing proxy, return it...
if (STATE_SYMBOL in value) {
const metadata = /** @type {ProxyMetadata<T>} */ (value[STATE_SYMBOL]);
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ export function is_mathml(name) {

const RUNES = /** @type {const} */ ([
'$state',
'$state.frozen',
'$state.raw',
'$state.snapshot',
'$state.is',
'$props',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import ComponentB from './ComponentB.svelte';

let type = $state(ComponentA);
let elem = $state.frozen();
let elem = $state.raw();

$effect(() => {
console.log(elem);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ export default test({
async test({ assert, warnings }) {
assert.deepEqual(warnings, [
'`bind:value={pojo.value}` (main.svelte:50:7) is binding to a non-reactive property',
'`bind:value={frozen.value}` (main.svelte:51:7) is binding to a non-reactive property',
'`bind:value={raw.value}` (main.svelte:51:7) is binding to a non-reactive property',
'`bind:value={pojo.value}` (main.svelte:52:7) is binding to a non-reactive property',
'`bind:value={frozen.value}` (main.svelte:53:7) is binding to a non-reactive property',
'`bind:value={raw.value}` (main.svelte:53:7) is binding to a non-reactive property',
'`bind:this={pojo.value}` (main.svelte:55:6) is binding to a non-reactive property'
]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
value: 1
};

let frozen = $state.frozen({
let raw = $state.raw({
value: 2
});

Expand Down Expand Up @@ -48,9 +48,9 @@

<!-- should warn -->
<input bind:value={pojo.value} />
<input bind:value={frozen.value} />
<input bind:value={raw.value} />
<Child bind:value={pojo.value} />
<Child bind:value={frozen.value} />
<Child bind:value={raw.value} />
{#if value}
<div bind:this={pojo.value}></div>
{/if}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { test } from '../../test';
export default test({
html: `<button>0</button>`,

test({ assert, target, logs }) {
test({ assert, target }) {
const btn = target.querySelector('button');

btn?.click();
Expand All @@ -14,7 +14,5 @@ export default test({
btn?.click();
flushSync();
assert.htmlEqual(target.innerHTML, `<button>0</button>`);

assert.deepEqual(logs, ['read only', 'read only']);
}
});
Loading
Loading