/
index.js
145 lines (123 loc) · 3.46 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import * as utils from '../utils/AltUtils'
import * as fn from '../../utils/functions'
import AltStore from './AltStore'
import StoreMixin from './StoreMixin'
function doSetState(store, storeInstance, state) {
if (!state) {
return
}
const { config } = storeInstance.StoreModel
const nextState = fn.isFunction(state)
? state(storeInstance.state)
: state
storeInstance.state = config.setState.call(
store,
storeInstance.state,
nextState
)
if (!store.alt.dispatcher.isDispatching()) {
store.emitChange()
}
}
function createPrototype(proto, alt, key, extras) {
proto.boundListeners = []
proto.lifecycleEvents = {}
proto.actionListeners = {}
proto.publicMethods = {}
proto.handlesOwnErrors = false
return fn.assign(proto, StoreMixin, {
displayName: key,
alt: alt,
dispatcher: alt.dispatcher,
preventDefault() {
this.getInstance().preventDefault = true
}
}, extras)
}
export function createStoreConfig(globalConfig, StoreModel) {
StoreModel.config = fn.assign({
getState(state) {
return fn.assign({}, state)
},
setState: fn.assign,
shouldEmitChange: true
}, globalConfig, StoreModel.config)
}
export function transformStore(transforms, StoreModel) {
return transforms.reduce((Store, transform) => transform(Store), StoreModel)
}
export function createStoreFromObject(alt, StoreModel, key) {
let storeInstance
const StoreProto = createPrototype({}, alt, key, fn.assign({
getInstance() {
return storeInstance
},
setState(nextState) {
doSetState(this, storeInstance, nextState)
}
}, StoreModel))
// bind the store listeners
/* istanbul ignore else */
if (StoreProto.bindListeners) {
StoreMixin.bindListeners.call(
StoreProto,
StoreProto.bindListeners
)
}
/* istanbul ignore else */
if (StoreProto.observe) {
StoreMixin.bindListeners.call(
StoreProto,
StoreProto.observe(alt)
)
}
// bind the lifecycle events
/* istanbul ignore else */
if (StoreProto.lifecycle) {
fn.eachObject((eventName, event) => {
StoreMixin.on.call(StoreProto, eventName, event)
}, [StoreProto.lifecycle])
}
// create the instance and fn.assign the public methods to the instance
storeInstance = fn.assign(
new AltStore(alt, StoreProto, StoreProto.state || {}, StoreModel),
StoreProto.publicMethods,
{ displayName: key }
)
return storeInstance
}
export function createStoreFromClass(alt, StoreModel, key, ...argsForClass) {
let storeInstance
const { config } = StoreModel
// Creating a class here so we don't overload the provided store's
// prototype with the mixin behaviour and I'm extending from StoreModel
// so we can inherit any extensions from the provided store.
class Store extends StoreModel {
constructor(...args) {
super(...args)
}
}
createPrototype(Store.prototype, alt, key, {
getInstance() {
return storeInstance
},
setState(nextState) {
doSetState(this, storeInstance, nextState)
}
})
const store = new Store(...argsForClass)
if (config.bindListeners) store.bindListeners(config.bindListeners)
if (config.datasource) store.registerAsync(config.datasource)
storeInstance = fn.assign(
new AltStore(
alt,
store,
typeof store.state === 'object' ? store.state : null,
StoreModel
),
utils.getInternalMethods(StoreModel),
config.publicMethods,
{ displayName: key }
)
return storeInstance
}