1
- import Vue , { ComponentOptions , VueConstructor } from 'vue'
1
+ import { computed , reactive , watch } from 'vue'
2
2
3
3
type C = { new ( ...args : any [ ] ) : { } }
4
4
@@ -14,69 +14,84 @@ function getDescriptors (model: R) {
14
14
return { ...prototypeDescriptors , ...descriptors }
15
15
}
16
16
17
- export function makeOptions ( model : R ) : ComponentOptions < any > {
18
- // prototype
19
- const prototype = Object . getPrototypeOf ( model )
20
- const descriptors = getDescriptors ( prototype )
17
+ function getValue ( value : Record < any , any > , path : string | string [ ] ) {
18
+ const segments = typeof path === 'string'
19
+ ? path . split ( '.' )
20
+ : path
21
+ const segment : string | undefined = segments . shift ( )
22
+ return segment
23
+ ? getValue ( value [ segment ] , segments )
24
+ : value
25
+ }
26
+
27
+ export function makeReactive ( model ) {
28
+ // properties
29
+ const descriptors = getDescriptors ( model )
21
30
22
31
// options
23
- const name = prototype . constructor . name
24
- const data : R = { }
25
- const computed : R = { }
26
- const methods : R = { }
27
- const watch : R = { }
32
+ const data = { }
33
+ const watched = { }
28
34
29
35
// data, string watches
30
- Object . keys ( model ) . forEach ( key => {
36
+ Object . keys ( model ) . forEach ( ( key : string ) => {
31
37
const value = model [ key ]
32
38
if ( key . startsWith ( 'on:' ) ) {
33
- watch [ key . substring ( 3 ) ] = value
39
+ watched [ key . substring ( 3 ) ] = value
34
40
}
35
41
else {
36
42
data [ key ] = value
37
43
}
38
44
} )
39
45
40
46
// function watches, methods, computed
41
- Object . keys ( descriptors ) . forEach ( key => {
42
- if ( key !== 'constructor' && ! key . startsWith ( '__' ) ) {
43
- const { value, get, set } = descriptors [ key ]
44
- if ( key . startsWith ( 'on:' ) ) {
45
- watch [ key . substring ( 3 ) ] = value
46
- }
47
- else if ( value ) {
48
- methods [ key ] = value
49
- }
50
- else if ( get && set ) {
51
- computed [ key ] = { get, set }
52
- }
53
- else if ( get ) {
54
- computed [ key ] = get
47
+ const state = reactive ( {
48
+ ...data ,
49
+ ...Object . keys ( descriptors ) . reduce ( ( output , key ) => {
50
+ if ( key !== 'constructor' && ! key . startsWith ( '__' ) ) {
51
+ const { value, get, set } = descriptors [ key ]
52
+ // watch
53
+ if ( key . startsWith ( 'on:' ) ) {
54
+ watched [ key . substring ( 3 ) ] = value
55
+ }
56
+ // method
57
+ else if ( value ) {
58
+ output [ key ] = ( ...args ) => value . call ( state , ...args )
59
+ }
60
+ // computed
61
+ else if ( get && set ) {
62
+ output [ key ] = computed ( {
63
+ set : ( value ) => set . call ( state , value ) ,
64
+ get : ( ) => get . call ( state ) ,
65
+ } )
66
+ }
67
+ else if ( get ) {
68
+ output [ key ] = computed ( ( ) => get . call ( state ) )
69
+ }
55
70
}
71
+ return output
72
+ } , { } ) ,
73
+ } )
74
+
75
+ // set up watches
76
+ Object . keys ( watched ) . forEach ( key => {
77
+ const callback : Function = typeof watched [ key ] === 'string'
78
+ ? model [ getValue ( model , 'on:' + key ) ]
79
+ : watched [ key ]
80
+ if ( typeof callback === 'function' ) {
81
+ watch ( ( ) => getValue ( state , key ) , callback . bind ( state ) )
56
82
}
57
83
} )
58
84
59
85
// return
60
- return {
61
- name,
62
- computed,
63
- methods,
64
- watch,
65
- data,
66
- }
67
- }
68
-
69
- export function makeVue < T extends R > ( model : T ) : T {
70
- const options = makeOptions ( model )
71
- return ( new Vue ( options ) as unknown ) as T
86
+ return state
72
87
}
73
88
74
89
export default function VueStore < T extends C > ( constructor : T ) : T {
75
90
function construct ( ...args : any [ ] ) {
76
91
const instance = new ( constructor as C ) ( ...args )
77
- return makeVue ( instance )
92
+ return makeReactive ( instance )
78
93
}
79
94
return ( construct as unknown ) as T
80
95
}
81
96
82
- VueStore . create = makeVue
97
+ VueStore . create = makeReactive
0 commit comments