@@ -8,7 +8,14 @@ import {
88} from './reactive'
99import { ITERATE_KEY , MAP_KEY_ITERATE_KEY , track , trigger } from './dep'
1010import { ReactiveFlags , TrackOpTypes , TriggerOpTypes } from './constants'
11- import { capitalize , hasChanged , hasOwn , isMap , toRawType } from '@vue/shared'
11+ import {
12+ capitalize ,
13+ extend ,
14+ hasChanged ,
15+ hasOwn ,
16+ isMap ,
17+ toRawType ,
18+ } from '@vue/shared'
1219import { warn } from './warning'
1320
1421type CollectionTypes = IterableCollections | WeakCollections
@@ -23,152 +30,6 @@ const toShallow = <T extends unknown>(value: T): T => value
2330const getProto = < T extends CollectionTypes > ( v : T ) : any =>
2431 Reflect . getPrototypeOf ( v )
2532
26- function get (
27- target : MapTypes ,
28- key : unknown ,
29- isReadonly = false ,
30- isShallow = false ,
31- ) {
32- // #1772: readonly(reactive(Map)) should return readonly + reactive version
33- // of the value
34- target = target [ ReactiveFlags . RAW ]
35- const rawTarget = toRaw ( target )
36- const rawKey = toRaw ( key )
37- if ( ! isReadonly ) {
38- if ( hasChanged ( key , rawKey ) ) {
39- track ( rawTarget , TrackOpTypes . GET , key )
40- }
41- track ( rawTarget , TrackOpTypes . GET , rawKey )
42- }
43- const { has } = getProto ( rawTarget )
44- const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive
45- if ( has . call ( rawTarget , key ) ) {
46- return wrap ( target . get ( key ) )
47- } else if ( has . call ( rawTarget , rawKey ) ) {
48- return wrap ( target . get ( rawKey ) )
49- } else if ( target !== rawTarget ) {
50- // #3602 readonly(reactive(Map))
51- // ensure that the nested reactive `Map` can do tracking for itself
52- target . get ( key )
53- }
54- }
55-
56- function has ( this : CollectionTypes , key : unknown , isReadonly = false ) : boolean {
57- const target = this [ ReactiveFlags . RAW ]
58- const rawTarget = toRaw ( target )
59- const rawKey = toRaw ( key )
60- if ( ! isReadonly ) {
61- if ( hasChanged ( key , rawKey ) ) {
62- track ( rawTarget , TrackOpTypes . HAS , key )
63- }
64- track ( rawTarget , TrackOpTypes . HAS , rawKey )
65- }
66- return key === rawKey
67- ? target . has ( key )
68- : target . has ( key ) || target . has ( rawKey )
69- }
70-
71- function size ( target : IterableCollections , isReadonly = false ) {
72- target = target [ ReactiveFlags . RAW ]
73- ! isReadonly && track ( toRaw ( target ) , TrackOpTypes . ITERATE , ITERATE_KEY )
74- return Reflect . get ( target , 'size' , target )
75- }
76-
77- function add ( this : SetTypes , value : unknown , _isShallow = false ) {
78- if ( ! _isShallow && ! isShallow ( value ) && ! isReadonly ( value ) ) {
79- value = toRaw ( value )
80- }
81- const target = toRaw ( this )
82- const proto = getProto ( target )
83- const hadKey = proto . has . call ( target , value )
84- if ( ! hadKey ) {
85- target . add ( value )
86- trigger ( target , TriggerOpTypes . ADD , value , value )
87- }
88- return this
89- }
90-
91- function set ( this : MapTypes , key : unknown , value : unknown , _isShallow = false ) {
92- if ( ! _isShallow && ! isShallow ( value ) && ! isReadonly ( value ) ) {
93- value = toRaw ( value )
94- }
95- const target = toRaw ( this )
96- const { has, get } = getProto ( target )
97-
98- let hadKey = has . call ( target , key )
99- if ( ! hadKey ) {
100- key = toRaw ( key )
101- hadKey = has . call ( target , key )
102- } else if ( __DEV__ ) {
103- checkIdentityKeys ( target , has , key )
104- }
105-
106- const oldValue = get . call ( target , key )
107- target . set ( key , value )
108- if ( ! hadKey ) {
109- trigger ( target , TriggerOpTypes . ADD , key , value )
110- } else if ( hasChanged ( value , oldValue ) ) {
111- trigger ( target , TriggerOpTypes . SET , key , value , oldValue )
112- }
113- return this
114- }
115-
116- function deleteEntry ( this : CollectionTypes , key : unknown ) {
117- const target = toRaw ( this )
118- const { has, get } = getProto ( target )
119- let hadKey = has . call ( target , key )
120- if ( ! hadKey ) {
121- key = toRaw ( key )
122- hadKey = has . call ( target , key )
123- } else if ( __DEV__ ) {
124- checkIdentityKeys ( target , has , key )
125- }
126-
127- const oldValue = get ? get . call ( target , key ) : undefined
128- // forward the operation before queueing reactions
129- const result = target . delete ( key )
130- if ( hadKey ) {
131- trigger ( target , TriggerOpTypes . DELETE , key , undefined , oldValue )
132- }
133- return result
134- }
135-
136- function clear ( this : IterableCollections ) {
137- const target = toRaw ( this )
138- const hadItems = target . size !== 0
139- const oldTarget = __DEV__
140- ? isMap ( target )
141- ? new Map ( target )
142- : new Set ( target )
143- : undefined
144- // forward the operation before queueing reactions
145- const result = target . clear ( )
146- if ( hadItems ) {
147- trigger ( target , TriggerOpTypes . CLEAR , undefined , undefined , oldTarget )
148- }
149- return result
150- }
151-
152- function createForEach ( isReadonly : boolean , isShallow : boolean ) {
153- return function forEach (
154- this : IterableCollections ,
155- callback : Function ,
156- thisArg ?: unknown ,
157- ) {
158- const observed = this
159- const target = observed [ ReactiveFlags . RAW ]
160- const rawTarget = toRaw ( target )
161- const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive
162- ! isReadonly && track ( rawTarget , TrackOpTypes . ITERATE , ITERATE_KEY )
163- return target . forEach ( ( value : unknown , key : unknown ) => {
164- // important: make sure the callback is
165- // 1. invoked with the reactive map as `this` and 3rd arg
166- // 2. the value received should be a corresponding reactive/readonly.
167- return callback . call ( thisArg , wrap ( value ) , wrap ( key ) , observed )
168- } )
169- }
170- }
171-
17233function createIterableMethod (
17334 method : string | symbol ,
17435 isReadonly : boolean ,
@@ -232,74 +93,158 @@ function createReadonlyMethod(type: TriggerOpTypes): Function {
23293
23394type Instrumentations = Record < string | symbol , Function | number >
23495
235- function createInstrumentations ( ) {
236- const mutableInstrumentations : Instrumentations = {
237- get ( this : MapTypes , key : unknown ) {
238- return get ( this , key )
239- } ,
240- get size ( ) {
241- return size ( this as unknown as IterableCollections )
242- } ,
243- has,
244- add,
245- set,
246- delete : deleteEntry ,
247- clear,
248- forEach : createForEach ( false , false ) ,
249- }
250-
251- const shallowInstrumentations : Instrumentations = {
96+ function createInstrumentations (
97+ readonly : boolean ,
98+ shallow : boolean ,
99+ ) : Instrumentations {
100+ const instrumentations : Instrumentations = {
252101 get ( this : MapTypes , key : unknown ) {
253- return get ( this , key , false , true )
102+ // #1772: readonly(reactive(Map)) should return readonly + reactive version
103+ // of the value
104+ const target = this [ ReactiveFlags . RAW ]
105+ const rawTarget = toRaw ( target )
106+ const rawKey = toRaw ( key )
107+ if ( ! readonly ) {
108+ if ( hasChanged ( key , rawKey ) ) {
109+ track ( rawTarget , TrackOpTypes . GET , key )
110+ }
111+ track ( rawTarget , TrackOpTypes . GET , rawKey )
112+ }
113+ const { has } = getProto ( rawTarget )
114+ const wrap = shallow ? toShallow : readonly ? toReadonly : toReactive
115+ if ( has . call ( rawTarget , key ) ) {
116+ return wrap ( target . get ( key ) )
117+ } else if ( has . call ( rawTarget , rawKey ) ) {
118+ return wrap ( target . get ( rawKey ) )
119+ } else if ( target !== rawTarget ) {
120+ // #3602 readonly(reactive(Map))
121+ // ensure that the nested reactive `Map` can do tracking for itself
122+ target . get ( key )
123+ }
254124 } ,
255125 get size ( ) {
256- return size ( this as unknown as IterableCollections )
126+ const target = ( this as unknown as IterableCollections ) [ ReactiveFlags . RAW ]
127+ ! readonly && track ( toRaw ( target ) , TrackOpTypes . ITERATE , ITERATE_KEY )
128+ return Reflect . get ( target , 'size' , target )
257129 } ,
258- has,
259- add ( this : SetTypes , value : unknown ) {
260- return add . call ( this , value , true )
130+ has ( this : CollectionTypes , key : unknown ) : boolean {
131+ const target = this [ ReactiveFlags . RAW ]
132+ const rawTarget = toRaw ( target )
133+ const rawKey = toRaw ( key )
134+ if ( ! readonly ) {
135+ if ( hasChanged ( key , rawKey ) ) {
136+ track ( rawTarget , TrackOpTypes . HAS , key )
137+ }
138+ track ( rawTarget , TrackOpTypes . HAS , rawKey )
139+ }
140+ return key === rawKey
141+ ? target . has ( key )
142+ : target . has ( key ) || target . has ( rawKey )
261143 } ,
262- set ( this : MapTypes , key : unknown , value : unknown ) {
263- return set . call ( this , key , value , true )
144+ forEach ( this : IterableCollections , callback : Function , thisArg ?: unknown ) {
145+ const observed = this
146+ const target = observed [ ReactiveFlags . RAW ]
147+ const rawTarget = toRaw ( target )
148+ const wrap = shallow ? toShallow : readonly ? toReadonly : toReactive
149+ ! readonly && track ( rawTarget , TrackOpTypes . ITERATE , ITERATE_KEY )
150+ return target . forEach ( ( value : unknown , key : unknown ) => {
151+ // important: make sure the callback is
152+ // 1. invoked with the reactive map as `this` and 3rd arg
153+ // 2. the value received should be a corresponding reactive/readonly.
154+ return callback . call ( thisArg , wrap ( value ) , wrap ( key ) , observed )
155+ } )
264156 } ,
265- delete : deleteEntry ,
266- clear,
267- forEach : createForEach ( false , true ) ,
268157 }
269158
270- const readonlyInstrumentations : Instrumentations = {
271- get ( this : MapTypes , key : unknown ) {
272- return get ( this , key , true )
273- } ,
274- get size ( ) {
275- return size ( this as unknown as IterableCollections , true )
276- } ,
277- has ( this : MapTypes , key : unknown ) {
278- return has . call ( this , key , true )
279- } ,
280- add : createReadonlyMethod ( TriggerOpTypes . ADD ) ,
281- set : createReadonlyMethod ( TriggerOpTypes . SET ) ,
282- delete : createReadonlyMethod ( TriggerOpTypes . DELETE ) ,
283- clear : createReadonlyMethod ( TriggerOpTypes . CLEAR ) ,
284- forEach : createForEach ( true , false ) ,
285- }
159+ extend (
160+ instrumentations ,
161+ readonly
162+ ? {
163+ add : createReadonlyMethod ( TriggerOpTypes . ADD ) ,
164+ set : createReadonlyMethod ( TriggerOpTypes . SET ) ,
165+ delete : createReadonlyMethod ( TriggerOpTypes . DELETE ) ,
166+ clear : createReadonlyMethod ( TriggerOpTypes . CLEAR ) ,
167+ }
168+ : {
169+ add ( this : SetTypes , value : unknown ) {
170+ if ( ! shallow && ! isShallow ( value ) && ! isReadonly ( value ) ) {
171+ value = toRaw ( value )
172+ }
173+ const target = toRaw ( this )
174+ const proto = getProto ( target )
175+ const hadKey = proto . has . call ( target , value )
176+ if ( ! hadKey ) {
177+ target . add ( value )
178+ trigger ( target , TriggerOpTypes . ADD , value , value )
179+ }
180+ return this
181+ } ,
182+ set ( this : MapTypes , key : unknown , value : unknown ) {
183+ if ( ! shallow && ! isShallow ( value ) && ! isReadonly ( value ) ) {
184+ value = toRaw ( value )
185+ }
186+ const target = toRaw ( this )
187+ const { has, get } = getProto ( target )
188+
189+ let hadKey = has . call ( target , key )
190+ if ( ! hadKey ) {
191+ key = toRaw ( key )
192+ hadKey = has . call ( target , key )
193+ } else if ( __DEV__ ) {
194+ checkIdentityKeys ( target , has , key )
195+ }
286196
287- const shallowReadonlyInstrumentations : Instrumentations = {
288- get ( this : MapTypes , key : unknown ) {
289- return get ( this , key , true , true )
290- } ,
291- get size ( ) {
292- return size ( this as unknown as IterableCollections , true )
293- } ,
294- has ( this : MapTypes , key : unknown ) {
295- return has . call ( this , key , true )
296- } ,
297- add : createReadonlyMethod ( TriggerOpTypes . ADD ) ,
298- set : createReadonlyMethod ( TriggerOpTypes . SET ) ,
299- delete : createReadonlyMethod ( TriggerOpTypes . DELETE ) ,
300- clear : createReadonlyMethod ( TriggerOpTypes . CLEAR ) ,
301- forEach : createForEach ( true , true ) ,
302- }
197+ const oldValue = get . call ( target , key )
198+ target . set ( key , value )
199+ if ( ! hadKey ) {
200+ trigger ( target , TriggerOpTypes . ADD , key , value )
201+ } else if ( hasChanged ( value , oldValue ) ) {
202+ trigger ( target , TriggerOpTypes . SET , key , value , oldValue )
203+ }
204+ return this
205+ } ,
206+ delete ( this : CollectionTypes , key : unknown ) {
207+ const target = toRaw ( this )
208+ const { has, get } = getProto ( target )
209+ let hadKey = has . call ( target , key )
210+ if ( ! hadKey ) {
211+ key = toRaw ( key )
212+ hadKey = has . call ( target , key )
213+ } else if ( __DEV__ ) {
214+ checkIdentityKeys ( target , has , key )
215+ }
216+
217+ const oldValue = get ? get . call ( target , key ) : undefined
218+ // forward the operation before queueing reactions
219+ const result = target . delete ( key )
220+ if ( hadKey ) {
221+ trigger ( target , TriggerOpTypes . DELETE , key , undefined , oldValue )
222+ }
223+ return result
224+ } ,
225+ clear ( this : IterableCollections ) {
226+ const target = toRaw ( this )
227+ const hadItems = target . size !== 0
228+ const oldTarget = __DEV__
229+ ? isMap ( target )
230+ ? new Map ( target )
231+ : new Set ( target )
232+ : undefined
233+ // forward the operation before queueing reactions
234+ const result = target . clear ( )
235+ if ( hadItems ) {
236+ trigger (
237+ target ,
238+ TriggerOpTypes . CLEAR ,
239+ undefined ,
240+ undefined ,
241+ oldTarget ,
242+ )
243+ }
244+ return result
245+ } ,
246+ } ,
247+ )
303248
304249 const iteratorMethods = [
305250 'keys' ,
@@ -309,39 +254,14 @@ function createInstrumentations() {
309254 ] as const
310255
311256 iteratorMethods . forEach ( method => {
312- mutableInstrumentations [ method ] = createIterableMethod ( method , false , false )
313- readonlyInstrumentations [ method ] = createIterableMethod ( method , true , false )
314- shallowInstrumentations [ method ] = createIterableMethod ( method , false , true )
315- shallowReadonlyInstrumentations [ method ] = createIterableMethod (
316- method ,
317- true ,
318- true ,
319- )
257+ instrumentations [ method ] = createIterableMethod ( method , readonly , shallow )
320258 } )
321259
322- return [
323- mutableInstrumentations ,
324- readonlyInstrumentations ,
325- shallowInstrumentations ,
326- shallowReadonlyInstrumentations ,
327- ]
260+ return instrumentations
328261}
329262
330- const [
331- mutableInstrumentations ,
332- readonlyInstrumentations ,
333- shallowInstrumentations ,
334- shallowReadonlyInstrumentations ,
335- ] = /* @__PURE__ */ createInstrumentations ( )
336-
337263function createInstrumentationGetter ( isReadonly : boolean , shallow : boolean ) {
338- const instrumentations = shallow
339- ? isReadonly
340- ? shallowReadonlyInstrumentations
341- : shallowInstrumentations
342- : isReadonly
343- ? readonlyInstrumentations
344- : mutableInstrumentations
264+ const instrumentations = createInstrumentations ( isReadonly , shallow )
345265
346266 return (
347267 target : CollectionTypes ,
0 commit comments