fix: ensure unstate() only deeply applies to plain objects and arrays (#10191)

* fix: ensure unstate() only deeply applies to plain objects and arrays

* tweak
pull/10197/head
Dominic Gannaway 2 years ago committed by GitHub
parent 5dce70e6cf
commit 86bbc83544
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: ensure unstate() only deeply applies to plain objects and arrays

@ -11,11 +11,15 @@ import {
batch_inspect
} from '../runtime.js';
import {
array_prototype,
define_property,
get_descriptor,
get_descriptors,
get_prototype_of,
is_array,
object_keys
is_frozen,
object_keys,
object_prototype
} from '../utils.js';
/** @typedef {{ s: Map<string | symbol, import('../types.js').SourceSignal<any>>; v: import('../types.js').SourceSignal<number>; a: boolean, i: boolean, p: StateObject }} Metadata */
@ -23,12 +27,6 @@ import {
export const STATE_SYMBOL = Symbol('$state');
export const READONLY_SYMBOL = Symbol('readonly');
const object_prototype = Object.prototype;
const array_prototype = Array.prototype;
const get_prototype_of = Object.getPrototypeOf;
const is_frozen = Object.isFrozen;
/**
* @template {StateObject} T
* @param {T} value

@ -1,7 +1,16 @@
import { DEV } from 'esm-env';
import { subscribe_to_store } from '../../store/utils.js';
import { EMPTY_FUNC, run_all } from '../common.js';
import { get_descriptor, get_descriptors, is_array, is_frozen, object_freeze } from './utils.js';
import {
array_prototype,
get_descriptor,
get_descriptors,
get_prototype_of,
is_array,
is_frozen,
object_freeze,
object_prototype
} from './utils.js';
import {
PROPS_IS_LAZY_INITIAL,
PROPS_IS_IMMUTABLE,
@ -1975,19 +1984,23 @@ function deep_unstate(value, visited = new Map()) {
visited.set(value, unstated);
return unstated;
}
let contains_unstated = false;
/** @type {any} */
const nested_unstated = Array.isArray(value) ? [] : {};
for (let key in value) {
const result = deep_unstate(value[key], visited);
nested_unstated[key] = result;
if (result !== value[key]) {
contains_unstated = true;
const prototype = get_prototype_of(value);
// Only deeply unstate plain objects and arrays
if (prototype === object_prototype || prototype === array_prototype) {
let contains_unstated = false;
/** @type {any} */
const nested_unstated = Array.isArray(value) ? [] : {};
for (let key in value) {
const result = deep_unstate(value[key], visited);
nested_unstated[key] = result;
if (result !== value[key]) {
contains_unstated = true;
}
}
visited.set(value, contains_unstated ? nested_unstated : value);
} else {
visited.set(value, value);
}
visited.set(value, contains_unstated ? nested_unstated : value);
}
return visited.get(value) ?? value;

@ -10,6 +10,9 @@ export var object_freeze = Object.freeze;
export var define_property = Object.defineProperty;
export var get_descriptor = Object.getOwnPropertyDescriptor;
export var get_descriptors = Object.getOwnPropertyDescriptors;
export var object_prototype = Object.prototype;
export var array_prototype = Array.prototype;
export var get_prototype_of = Object.getPrototypeOf;
/**
* @param {any} thing

Loading…
Cancel
Save