1
1
import { EffectScope } from '@vue/reactivity'
2
- import { EMPTY_OBJ , isFunction } from '@vue/shared'
2
+ import { EMPTY_OBJ , NOOP , isFunction } from '@vue/shared'
3
3
import type { Block } from './apiRender'
4
4
import type { DirectiveBinding } from './directives'
5
5
import {
@@ -20,12 +20,48 @@ import {
20
20
import { VaporLifecycleHooks } from './apiLifecycle'
21
21
22
22
import type { Data } from '@vue/shared'
23
+ import { warn } from './warning'
23
24
24
25
export type Component = FunctionalComponent | ObjectComponent
25
26
26
- export type SetupFn = ( props : any , ctx : any ) => Block | Data | void
27
+ export type SetupFn = ( props : any , ctx : SetupContext ) => Block | Data | void
27
28
export type FunctionalComponent = SetupFn & Omit < ObjectComponent , 'setup' >
28
29
30
+ export type SetupContext < E = EmitsOptions > = E extends any
31
+ ? {
32
+ attrs : Data
33
+ emit : EmitFn < E >
34
+ expose : ( exposed ?: Record < string , any > ) => void
35
+ // TODO slots
36
+ }
37
+ : never
38
+
39
+ export function createSetupContext (
40
+ instance : ComponentInternalInstance ,
41
+ ) : SetupContext {
42
+ if ( __DEV__ ) {
43
+ // We use getters in dev in case libs like test-utils overwrite instance
44
+ // properties (overwrites should not be done in prod)
45
+ return Object . freeze ( {
46
+ get attrs ( ) {
47
+ return getAttrsProxy ( instance )
48
+ } ,
49
+ get emit ( ) {
50
+ return ( event : string , ...args : any [ ] ) => instance . emit ( event , ...args )
51
+ } ,
52
+ expose : NOOP ,
53
+ } )
54
+ } else {
55
+ return {
56
+ get attrs ( ) {
57
+ return getAttrsProxy ( instance )
58
+ } ,
59
+ emit : instance . emit ,
60
+ expose : NOOP ,
61
+ }
62
+ }
63
+ }
64
+
29
65
export interface ObjectComponent {
30
66
props ?: ComponentPropsOptions
31
67
inheritAttrs ?: boolean
@@ -59,12 +95,15 @@ export interface ComponentInternalInstance {
59
95
60
96
// state
61
97
setupState : Data
98
+ setupContext : SetupContext | null
62
99
props : Data
63
100
emit : EmitFn
64
101
emitted : Record < string , boolean > | null
65
102
attrs : Data
66
103
refs : Data
67
104
105
+ attrsProxy : Data | null
106
+
68
107
// lifecycle
69
108
isMounted : boolean
70
109
isUnmounted : boolean
@@ -169,12 +208,15 @@ export function createComponentInstance(
169
208
170
209
// state
171
210
setupState : EMPTY_OBJ ,
211
+ setupContext : null ,
172
212
props : EMPTY_OBJ ,
173
213
emit : null ! ,
174
214
emitted : null ,
175
215
attrs : EMPTY_OBJ ,
176
216
refs : EMPTY_OBJ ,
177
217
218
+ attrsProxy : null ,
219
+
178
220
// lifecycle
179
221
isMounted : false ,
180
222
isUnmounted : false ,
@@ -234,3 +276,31 @@ export function createComponentInstance(
234
276
235
277
return instance
236
278
}
279
+
280
+ function getAttrsProxy ( instance : ComponentInternalInstance ) : Data {
281
+ return (
282
+ instance . attrsProxy ||
283
+ ( instance . attrsProxy = new Proxy (
284
+ instance . attrs ,
285
+ __DEV__
286
+ ? {
287
+ get ( target , key : string ) {
288
+ return target [ key ]
289
+ } ,
290
+ set ( ) {
291
+ warn ( `setupContext.attrs is readonly.` )
292
+ return false
293
+ } ,
294
+ deleteProperty ( ) {
295
+ warn ( `setupContext.attrs is readonly.` )
296
+ return false
297
+ } ,
298
+ }
299
+ : {
300
+ get ( target , key : string ) {
301
+ return target [ key ]
302
+ } ,
303
+ } ,
304
+ ) )
305
+ )
306
+ }
0 commit comments