Skip to content

Commit 3301a33

Browse files
committed
shallow copy state when freezing
1 parent f19d138 commit 3301a33

File tree

4 files changed

+62
-44
lines changed

4 files changed

+62
-44
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { DEV } from 'esm-env';
2+
import { define_property, is_array, is_frozen, object_freeze } from '../shared/utils.js';
3+
import { STATE_FROZEN_SYMBOL, STATE_SYMBOL } from './constants.js';
4+
5+
/**
6+
* Expects a value that was wrapped with `freeze` and makes it frozen in DEV.
7+
* @template T
8+
* @param {T} value
9+
* @returns {Readonly<T>}
10+
*/
11+
export function freeze(value) {
12+
if (
13+
typeof value === 'object' &&
14+
value !== null &&
15+
!is_frozen(value) &&
16+
!(STATE_FROZEN_SYMBOL in value)
17+
) {
18+
var copy = /** @type {T} */ (value);
19+
20+
// If the object is already proxified, then clone the value
21+
if (STATE_SYMBOL in value) {
22+
copy = /** @type {T} */ (is_array(value) ? [...value] : { ...value });
23+
}
24+
25+
define_property(copy, STATE_FROZEN_SYMBOL, {
26+
value: true,
27+
writable: true,
28+
enumerable: false
29+
});
30+
31+
// Freeze the object in DEV
32+
if (DEV) {
33+
object_freeze(copy);
34+
}
35+
36+
return /** @type {Readonly<T>} */ (copy);
37+
}
38+
39+
return value;
40+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { freeze } from './freeze.js';
2+
import { assert, test } from 'vitest';
3+
import { proxy } from './proxy.js';
4+
5+
test('freezes an object', () => {
6+
const frozen = freeze({ a: 1 });
7+
8+
assert.throws(() => {
9+
// @ts-expect-error
10+
frozen.a += 1;
11+
}, /Cannot assign to read only property/);
12+
});
13+
14+
test('preserves classes', () => {
15+
class Foo {}
16+
const frozen = freeze(proxy([new Foo()]));
17+
18+
assert.ok(frozen[0] instanceof Foo);
19+
});

packages/svelte/src/internal/client/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export {
9191
template_with_script,
9292
text
9393
} from './dom/template.js';
94+
export { freeze } from './freeze.js';
9495
export { derived, derived_safe_equal } from './reactivity/deriveds.js';
9596
export {
9697
effect_tracking,
@@ -136,7 +137,6 @@ export {
136137
pop,
137138
push,
138139
unwrap,
139-
freeze,
140140
deep_read,
141141
deep_read_state,
142142
getAllContexts,

packages/svelte/src/internal/client/runtime.js

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
import { DEV } from 'esm-env';
2-
import {
3-
define_property,
4-
get_descriptors,
5-
get_prototype_of,
6-
is_frozen,
7-
object_freeze
8-
} from '../shared/utils.js';
9-
import { snapshot } from '../shared/clone.js';
2+
import { define_property, get_descriptors, get_prototype_of } from '../shared/utils.js';
103
import {
114
destroy_effect,
125
effect,
@@ -28,8 +21,7 @@ import {
2821
BLOCK_EFFECT,
2922
ROOT_EFFECT,
3023
LEGACY_DERIVED_PROP,
31-
DISCONNECTED,
32-
STATE_FROZEN_SYMBOL
24+
DISCONNECTED
3325
} from './constants.js';
3426
import { flush_tasks } from './dom/task.js';
3527
import { add_owner } from './dev/ownership.js';
@@ -1211,36 +1203,3 @@ if (DEV) {
12111203
throw_rune_error('$props');
12121204
throw_rune_error('$bindable');
12131205
}
1214-
1215-
/**
1216-
* Expects a value that was wrapped with `freeze` and makes it frozen in DEV.
1217-
* @template T
1218-
* @param {T} value
1219-
* @returns {Readonly<T>}
1220-
*/
1221-
export function freeze(value) {
1222-
if (
1223-
typeof value === 'object' &&
1224-
value != null &&
1225-
!is_frozen(value) &&
1226-
!(STATE_FROZEN_SYMBOL in value)
1227-
) {
1228-
// If the object is already proxified, then snapshot the value
1229-
var copy = STATE_SYMBOL in value ? snapshot(value) : value;
1230-
1231-
define_property(copy, STATE_FROZEN_SYMBOL, {
1232-
value: true,
1233-
writable: true,
1234-
enumerable: false
1235-
});
1236-
1237-
// Freeze the object in DEV
1238-
if (DEV) {
1239-
object_freeze(copy);
1240-
}
1241-
1242-
return /** @type {Readonly<T>} */ (copy);
1243-
}
1244-
1245-
return value;
1246-
}

0 commit comments

Comments
 (0)