-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathImmutableObject.js
More file actions
127 lines (108 loc) · 2.94 KB
/
ImmutableObject.js
File metadata and controls
127 lines (108 loc) · 2.94 KB
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
"use strict";
function ImmutableObject(props) {
if (typeof props === "undefined") {
return empty;
}
if (typeof props !== "object") {
throw new TypeError("ImmutableObject property source must be an object.");
}
if (props.__isImmutableObject__) {
return props;
}
return empty.set(props);
}
var empty = Object.freeze(Object.create(ImmutableObject.prototype));
ImmutableObject.prototype.set = function(props) {
if (!props) {
return this;
}
// allow this.set("property", value)
// call this.set({property: value})
if (typeof props === "string") {
var propsObj = {};
propsObj[props] = arguments[1];
return this.set(propsObj);
}
var keys = allKeys(props);
if (keys.length === 0) return this;
function sameKeys(x, y) {
return Object.keys(x).every(function(key) {
return y.hasOwnProperty(key);
});
}
var allSameKeys = sameKeys(this, props) && sameKeys(props, this);
if (allSameKeys) {
var p = Object.getPrototypeOf(this);
return p.set(props);
}
var propertyDefs = {};
keys.forEach(function(key) {
var value = props[key];
value = require("./factory")(value);
propertyDefs[key] = { value: value, enumerable: true };
});
var newObj = Object.create(this, propertyDefs);
Object.freeze(newObj);
return newObj;
};
ImmutableObject.prototype.unset = function(keyToExclude) {
var props = {};
var includeKey = function(key) {
props[key] = this[key];
}.bind(this);
function notExcluded(key) {
return key !== keyToExclude;
}
if (this.hasOwnProperty(keyToExclude) &&
allKeys(Object.getPrototypeOf(this)).indexOf(keyToExclude) < 0) {
Object.keys(this).filter(notExcluded).forEach(includeKey);
return Object.getPrototypeOf(this).set(props);
} else {
var keys = allKeys(this);
var filtered = keys.filter(notExcluded);
var noChange = filtered.length === keys.length;
if (noChange) {
return this;
} else {
filtered.forEach(includeKey);
return ImmutableObject(props);
}
}
};
ImmutableObject.prototype.toJSON = function() {
var json = {};
ImmutableObject.keys(this).forEach(function(key) {
var value = this[key];
json[key] = (value && typeof value.toJSON === "function")
? value.toJSON()
: value;
}, this);
return json;
};
ImmutableObject.prototype.__isImmutableObject__ = true;
Object.freeze(ImmutableObject.prototype);
function allKeys(obj) {
if (obj && obj.__isImmutableObject__) {
return ImmutableObject.keys(obj);
} else {
return Object.keys(obj);
}
}
ImmutableObject.keys = function(obj) {
var keys = [];
var seen = {};
function notSeen(key) {
if (!seen.hasOwnProperty(key)) {
seen[key] = true;
return true;
} else {
return false;
}
}
while (obj && obj !== ImmutableObject.prototype) {
keys = keys.concat( Object.keys(obj).filter(notSeen) );
obj = Object.getPrototypeOf(obj);
}
return keys;
};
module.exports = ImmutableObject;