-
Notifications
You must be signed in to change notification settings - Fork 8
/
set-polyfill.js
167 lines (142 loc) · 3.73 KB
/
set-polyfill.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
'use strict';
var originalSet = Set;
function assert(val, msg) {
if (!val) {
throw new TypeError(msg);
}
}
function isObject(x) {
return (typeof x === 'function' || typeof x === 'object');
}
function SpeciesConstructor(O, defaultConstructor) {
assert(isObject(O), 'O is not Object');
var C = O.constructor;
if (typeof C === 'undefined') {
return defaultConstructor;
}
if (!isObject(C)) {
throw new TypeError('O.constructor is not an Object');
}
var S = C[Symbol.species];
if (S == null) {
return defaultConstructor;
}
if (typeof S === 'function' && !!S.prototype) {
return S;
}
throw new TypeError('no constructor found');
}
function isCallable(x) {
try {
Function.prototype.toString.call(x);
return true;
} catch(e) {
return false;
}
}
function isSet(obj) {
const methodNames = ['has', 'add', 'forEach', 'delete', 'keys', 'values', 'entries'];
return !!(
obj &&
methodNames.every(key=>key in obj && typeof obj[key] === 'function') &&
'size' in obj &&
typeof obj.size === 'number' &&
Number.isInteger(obj.size)
);
}
function filter(predicate, thisArg = null) {
assert(typeof predicate === 'function');
assert(isSet(this));
const ret = new (SpeciesConstructor(this));
for (const element of this) {
if (Reflect.apply(predicate, thisArg, [element, element, this])) {
ret.add(element);
}
}
return ret;
}
function map(mapFunction, thisArg = null) {
assert(typeof mapFunction === 'function');
assert(isSet(this));
const ret = new (SpeciesConstructor(this));
for (const element of this) {
ret.add(Reflect.apply(mapFunction, thisArg, [element, element, this]))
}
return ret;
}
function some(predicate, thisArg = null) {
assert(typeof predicate === 'function');
assert(isSet(this));
for (const element of this) {
if (Reflect.apply(predicate, thisArg, [element, element, this])) {
return true;
}
}
return false;
}
function find(predicate, thisArg = null) {
assert(typeof predicate === 'function');
assert(isSet(this));
for (const element of this) {
if (Reflect.apply(predicate, thisArg, [element, element, this])) {
return element;
}
}
return undefined;
}
function every(predicate, thisArg = null) {
assert(typeof predicate === 'function');
assert(isSet(this));
for (const element of this) {
if (!Reflect.apply(predicate, thisArg, [element, element, this])) {
return false;
}
}
return true;
}
function addAll(...args) {
assert(isSet(this));
for (const element of args) {
this.add(element);
}
return this;
}
function deleteAll(...items) {
const len = items.length;
const set = this;
assert(isObject(set), 'set is not an Object');
let k = 0;
const remover = set.delete;
assert(isCallable(remover), 'remover is not a function');
while (k < len) {
const value = items[k];
Reflect.apply(remover, set, [value]);
k++;
}
return this;
}
assert(typeof Set === 'function', 'Set does not exist');
const prototypeMethods = [
['map', map],
['filter', filter],
['some', some],
['every', every],
['find', find],
['addAll', addAll],
['deleteAll', deleteAll],
];
const staticMethods = [
['isSet', isSet]
];
for (const [key, value] of prototypeMethods) {
Object.defineProperty(Set.prototype, key, {
configurable: true,
value
});
}
for (const [key, value] of staticMethods) {
Object.defineProperty(Set, key, {
configurable: true,
value
});
}