@@ -18,7 +18,6 @@ import {
18
18
get_prototype_of ,
19
19
is_array ,
20
20
is_frozen ,
21
- object_keys ,
22
21
object_prototype
23
22
} from './utils.js' ;
24
23
@@ -33,28 +32,29 @@ export const READONLY_SYMBOL = Symbol('readonly');
33
32
*/
34
33
export function proxy ( value , immutable = true ) {
35
34
if ( typeof value === 'object' && value != null && ! is_frozen ( value ) ) {
35
+ // If we have an existing proxy, return it...
36
36
if ( STATE_SYMBOL in value ) {
37
37
const metadata = /** @type {import('./types.js').ProxyMetadata<T> } */ ( value [ STATE_SYMBOL ] ) ;
38
- // Check that the incoming value is the same proxy that this state symbol was created for:
39
- // If someone copies over the state symbol to a new object (using Reflect.ownKeys) the referenced
40
- // proxy could be stale and we should not return it.
38
+ // ...unless the proxy belonged to a different object, because
39
+ // someone copied the state symbol using `Reflect.ownKeys(...)`
41
40
if ( metadata . t === value || metadata . p === value ) return metadata . p ;
42
41
}
43
42
44
43
const prototype = get_prototype_of ( value ) ;
45
44
46
45
// TODO handle Map and Set as well
47
46
if ( prototype === object_prototype || prototype === array_prototype ) {
48
- const proxy = new Proxy (
49
- value ,
50
- /** @type {ProxyHandler<import('./types.js').ProxyStateObject<T>> } */ ( state_proxy_handler )
51
- ) ;
47
+ const proxy = new Proxy ( value , state_proxy_handler ) ;
48
+
52
49
define_property ( value , STATE_SYMBOL , {
53
- value : init (
54
- /** @type {import('./types.js').ProxyStateObject<T> } */ ( value ) ,
55
- /** @type {import('./types.js').ProxyStateObject<T> } */ ( proxy ) ,
56
- immutable
57
- ) ,
50
+ value : /** @type {import('./types.js').ProxyMetadata } */ ( {
51
+ s : new Map ( ) ,
52
+ v : source ( 0 ) ,
53
+ a : is_array ( value ) ,
54
+ i : immutable ,
55
+ p : proxy ,
56
+ t : value
57
+ } ) ,
58
58
writable : true ,
59
59
enumerable : false
60
60
} ) ;
@@ -72,12 +72,13 @@ export function proxy(value, immutable = true) {
72
72
* @param {Map<T, Record<string | symbol, any>> } already_unwrapped
73
73
* @returns {Record<string | symbol, any> }
74
74
*/
75
- function unwrap ( value , already_unwrapped = new Map ( ) ) {
75
+ function unwrap ( value , already_unwrapped ) {
76
76
if ( typeof value === 'object' && value != null && STATE_SYMBOL in value ) {
77
77
const unwrapped = already_unwrapped . get ( value ) ;
78
78
if ( unwrapped !== undefined ) {
79
79
return unwrapped ;
80
80
}
81
+
81
82
if ( is_array ( value ) ) {
82
83
/** @type {Record<string | symbol, any> } */
83
84
const array = [ ] ;
@@ -92,6 +93,7 @@ function unwrap(value, already_unwrapped = new Map()) {
92
93
const keys = Reflect . ownKeys ( value ) ;
93
94
const descriptors = get_descriptors ( value ) ;
94
95
already_unwrapped . set ( value , obj ) ;
96
+
95
97
for ( const key of keys ) {
96
98
if ( key === STATE_SYMBOL || ( DEV && key === READONLY_SYMBOL ) ) continue ;
97
99
if ( descriptors [ key ] . get ) {
@@ -102,6 +104,7 @@ function unwrap(value, already_unwrapped = new Map()) {
102
104
obj [ key ] = unwrap ( property , already_unwrapped ) ;
103
105
}
104
106
}
107
+
105
108
return obj ;
106
109
}
107
110
}
@@ -115,27 +118,12 @@ function unwrap(value, already_unwrapped = new Map()) {
115
118
* @returns {T }
116
119
*/
117
120
export function unstate ( value ) {
118
- return /** @type {T } */ ( unwrap ( /** @type {import('./types.js').ProxyStateObject } */ ( value ) ) ) ;
119
- }
120
-
121
- /**
122
- * @param {import('./types.js').ProxyStateObject } value
123
- * @param {import('./types.js').ProxyStateObject } proxy
124
- * @param {boolean } immutable
125
- * @returns {import('./types.js').ProxyMetadata }
126
- */
127
- function init ( value , proxy , immutable ) {
128
- return {
129
- s : new Map ( ) ,
130
- v : source ( 0 ) ,
131
- a : is_array ( value ) ,
132
- i : immutable ,
133
- p : proxy ,
134
- t : value
135
- } ;
121
+ return /** @type {T } */ (
122
+ unwrap ( /** @type {import('./types.js').ProxyStateObject } */ ( value ) , new Map ( ) )
123
+ ) ;
136
124
}
137
125
138
- /** @type {ProxyHandler<import('./types.js').ProxyStateObject> } */
126
+ /** @type {ProxyHandler<import('./types.js').ProxyStateObject<any> > } */
139
127
const state_proxy_handler = {
140
128
defineProperty ( target , prop , descriptor ) {
141
129
if ( descriptor . value ) {
0 commit comments