-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathindex.js
108 lines (90 loc) · 2.87 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
var Observ = require("observ")
var extend = require("xtend")
var blackList = {
"length": "Clashes with `Function.prototype.length`.\n",
"name": "Clashes with `Function.prototype.name`.\n",
"_diff": "_diff is reserved key of observ-struct.\n",
"_type": "_type is reserved key of observ-struct.\n",
"_version": "_version is reserved key of observ-struct.\n"
}
var NO_TRANSACTION = {}
function setNonEnumerable(object, key, value) {
Object.defineProperty(object, key, {
value: value,
writable: true,
configurable: true,
enumerable: false
})
}
/* ObservStruct := (Object<String, Observ<T>>) =>
Object<String, Observ<T>> &
Observ<Object<String, T> & {
_diff: Object<String, Any>
}>
*/
module.exports = ObservStruct
function ObservStruct(struct) {
var keys = Object.keys(struct)
var initialState = {}
var currentTransaction = NO_TRANSACTION
var nestedTransaction = NO_TRANSACTION
keys.forEach(function (key) {
if (blackList.hasOwnProperty(key)) {
throw new Error("cannot create an observ-struct " +
"with a key named '" + key + "'.\n" +
blackList[key]);
}
var observ = struct[key]
initialState[key] = typeof observ === "function" ?
observ() : observ
})
var obs = Observ(initialState)
keys.forEach(function (key) {
var observ = struct[key]
obs[key] = observ
if (typeof observ === "function") {
observ(function (value) {
if (nestedTransaction === value) {
return
}
var state = extend(obs())
state[key] = value
var diff = {}
diff[key] = value && value._diff ?
value._diff : value
setNonEnumerable(state, "_diff", diff)
currentTransaction = state
obs.set(state)
currentTransaction = NO_TRANSACTION
})
}
})
var _set = obs.set
obs.set = function trackDiff(value) {
if (currentTransaction === value) {
return _set(value)
}
var newState = extend(value)
setNonEnumerable(newState, "_diff", value)
_set(newState)
}
obs(function (newState) {
if (currentTransaction === newState) {
return
}
keys.forEach(function (key) {
var observ = struct[key]
var newObservValue = newState[key]
if (typeof observ === "function" &&
observ() !== newObservValue
) {
nestedTransaction = newObservValue
observ.set(newState[key])
nestedTransaction = NO_TRANSACTION
}
})
})
obs._type = "observ-struct"
obs._version = "5"
return obs
}