-
Notifications
You must be signed in to change notification settings - Fork 0
/
create-variant-reducer.js
96 lines (91 loc) · 2.58 KB
/
create-variant-reducer.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
/* globals define */
(function (root, factory) {
'use strict'
if (typeof define === 'function' && define.amd) {
define([], factory)
} else if (typeof exports === 'object') {
module.exports = factory()
} else {
root.atom = factory()
}
}(this, function () {
'use strict'
// @TODO: move to wasmuth
function toConst (str) {
let ret = ''
let prevLowercase = false
for (const s of str) {
const isUppercase = s.toUpperCase() === s
if (isUppercase && prevLowercase) {
ret += '_'
}
ret += s
prevLowercase = !isUppercase
}
return ret.replace(/_+/g, '_').toUpperCase()
}
// @TODO: move to wasmuth
function toFnName (str) {
let ret = ''
let prevUnderscore = false
for (const s of str) {
const isUnderscore = s === '_'
if (isUnderscore) {
prevUnderscore = true
continue
}
if (!isUnderscore && prevUnderscore) {
ret += s
prevUnderscore = false
} else {
ret += s.toLowerCase()
}
}
return ret
}
function createActions (actionTypes, name, store) {
const actions = {}
actionTypes.forEach(type => {
actions[toFnName(type).replace(name, 'is')] = function () {
const args = Array.prototype.slice.call(arguments)
const action = { type, payload: { args } }
return store != null
? store.dispatch(action)
: action
}
})
return actions
}
function createReducer (actionTypes, name, Variant) {
const reduce = {}
actionTypes.forEach(type => {
reduce[type] = function (action, state) {
const { type, payload } = action
const fnName = toFnName(type).replace(name, '')
if (payload.args.length) {
state[name] = Variant[fnName].apply(Variant, payload.args)
} else {
state[name] = Variant[fnName]
}
return state
}
})
return function reducer (action, state) {
if (reduce[action.type] != null) {
return reduce[action.type](action, state)
}
return state
}
}
return function createVariantReducer (wrapper, store) {
const name = Object.keys(wrapper)[0]
const nameUpper = toConst(name)
const Variant = wrapper[name]
const proto = Object.getPrototypeOf(Variant)
const types = Object.keys(proto._types)
const actionTypes = types.map(s => nameUpper + '_' + toConst(s))
const actions = createActions(actionTypes, name.toLowerCase(), store)
const reducer = createReducer(actionTypes, name.toLowerCase(), Variant)
return { actions, reducer }
}
}))