/
index.js
280 lines (245 loc) · 7.36 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
import is from 'arc-is';
import ArcArray from "arc-array";
import deepcopy from "deepcopy";
class ArcObject extends Object {
//Allow for an Object literal argument to be passed in that gets case to the ArcObject
constructor(_obj){
super();
if(is(_obj) === 'object'){
let keys,prop;
keys = Object.keys(_obj);
for(let i = 0; i < keys.length; i++){
prop = keys[i];
this[prop] = _obj[prop];
}
}
}
//Turn the object into an immutable object (deep)
deepFreeze(){
this.forEach(function(_v,_k){
const $this = this;
if(is(_v) === 'object'){
$this[_k] = ArcObject.wrap(_v);
$this[_k].deepFreeze();
}
},this);
this.freeze.call(this);
return this;
}
//Turn the object into an immutable object (shallow)
freeze() {
let obj = this;
obj = Object.freeze(obj);
return obj;
}
//Iterate over the object
forEach(_f,_thisArg){
if(is(_f) !== 'function'){
throw new TypeError('ArcObject.each first argument must be a valid function');
}
//Declare
var $this,keys,key,length;
//Our context
$this = _thisArg || this;
//Etc
keys = Object.keys(this);
length = keys.length;
//Iterate
for(let i=0;i<length;i++){
key = keys[i];
if(_f.call($this,this[key],key,this) === false){
break;
}
}
}
//An implementation closer to array.reduce
reduce(_f,_lastArg,_falseBreak){
if(is(_f) !== 'function'){
throw new TypeError('ArcObject.each first argument must be a valid function');
}
_falseBreak = (_falseBreak === false ? false : true);
//Declare
var $this,keys,key,length,cbReturn;
//Our context
$this = this;
//Etc
keys = Object.keys(this);
length = keys.length;
//Iterate
for(let i=0;i<length;i++){
key = keys[i];
cbReturn = _f.call($this,_lastArg,this[key],key);
if(cbReturn === false && _falseBreak){
break;
}
_lastArg = cbReturn || _lastArg;
}
return _lastArg;
}
//Implementation closer to array.map
map(_f, _asArray){
if(is(_f) !== 'function'){
throw new TypeError('ArcObject.map first argument must be a valid function');
}
const $this = this;
const keys = Object.keys(this);
const returnMap = (_asArray === false ? {} : []);
for(let i=0;i<keys.length;i++) {
const key = keys[i];
const cbReturn = _f.call($this,this[key],key);
if(_asArray === false) {
returnMap[key] = cbReturn;
} else {
returnMap.push(cbReturn);
}
}
return returnMap;
}
//Implementation closer array.filter
filter(_f){
if(is(_f) !== 'function'){
throw new TypeError('ArcObject.filter argument must be a valid function');
}
const $this = this;
const keys = Object.keys(this);
const returnObj = {};
for(let i=0;i<keys.length;i++) {
const key = keys[i];
if(_f.call($this,this[key],key)){
returnObj[key] = this[key];
}
}
return returnObj;
}
//Lazy
count(){
return Object.keys(this).length;
}
//Shortcut to get keys as an ArcArray
keys(){
return new ArcArray(...Object.keys(this));
}
//Obviously this is wrong, as we shouldn't trust an objects order for anything, but sometimes we do anyways. Likewise Map is really what we should be using
ksort(){
var $this = this;
var keys = $this.keys();
var copy = new ArcObject;
keys.sort();
keys.forEach(function(_key){
copy[_key] = $this[_key];
delete $this[_key];
});
copy.forEach(function(_val,_key){
$this[_key] = _val;
});
return $this;
}
//Remove the last item in the object
pop(){
let $this,lastKey,lastVal;
$this = this;
lastKey = $this.keys().pop();
if(lastKey !== undefined){
lastVal = $this[lastKey];
delete $this[lastKey];
return lastVal;
}
}
//Get the last item in the object
last(){
let lastKey = this.keys().pop();
if(lastKey !== undefined){
return this[lastKey];
}
}
//Remove the first item in the object
shift(){
let $this,firstKey,firstVal;
$this = this;
firstKey = $this.keys().shift();
if(firstKey !== undefined){
firstVal = $this[firstKey];
delete $this[firstKey];
return firstVal;
}
}
//Get the first item in the object
first(){
let firstKey = this.keys().shift();
if(firstKey !== undefined){
return this[firstKey];
}
}
constant(_key,_val,_enumerable){
ArcObject.defineConstant(this,_key,_val,_enumerable);
}
//To string: [object ArcObject]
toString(){
return '[object '+this.constructor.name+']';
}
static duckType(_primary,_duck){
if(is(_primary) !== is(_duck)){
return false;
}
let prop;
for(prop in _primary){
if(_primary.hasOwnProperty(prop) && is(_primary[prop]) === 'function'){
if(is(_duck[prop]) !== 'function'){
return false;
}
}
}
return true;
}
//Take dynamic arguments and check that they're initialized objects
deepGet(){
let lastObj = this;
for(let i=0;i<arguments.length;i++){
if(lastObj[arguments[i]] === undefined){
return undefined;
}
lastObj = lastObj[arguments[i]];
}
return lastObj;
}
//When called binds the .arc() method to the global native object type, which in turn returns an ArcObject from a native object
static bindNative(){
Object.defineProperty(Object.prototype,'arc',{
enumerable: false,
configurable: false,
writable: false,
value: function(){
let $this = this;
if(is($this,true) === 'ArcObject'){
return $this;
}
$this = new ArcObject($this);
return $this;
}
});
}
//Safely return an ArcObject or cast a native object as an ArcObject
static wrap(_obj){
if(is(_obj,true) === 'ArcObject'){
return _obj;
}
else if(is(_obj) === 'object'){
return new ArcObject(_obj);
}
else{
throw new TypeError('Cannot wrap value. Must evaluate to a native object.');
}
}
static defineConstant(_obj,_key,_val,_enumerable){
Object.defineProperty(_obj, _key, {
value: _val,
writable : false,
enumerable : (_enumerable === false ? false : true),
configurable : false
});
}
static copy(_obj){
return deepcopy(_obj);
}
}
export default ArcObject;