forked from WebReflection/classtrophobic
-
Notifications
You must be signed in to change notification settings - Fork 0
/
classtrophobic.js
104 lines (104 loc) · 3.87 KB
/
classtrophobic.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
/*! (C) 2017 Andrea Giammarchi - MIT Style License */
const Class = ((Object, Reflect) => {'use strict';
const
getProp = Reflect.get,
setProp = Reflect.set,
ownProps = Reflect.ownKeys,
defProp = Reflect.defineProperty,
reConstruct = Reflect.construct,
gPO = Object.getPrototypeOf,
sPO = Object.setPrototypeOf,
defProps = Object.defineProperties,
gOPD = Object.getOwnPropertyDescriptor,
constructorHandler = {
apply: (p, self, args) => Reflect.apply(p.self, self, args),
construct: (p, args, t) => reConstruct(p.self, args, t),
defineProperty: (p, k, d) => defProp(p.self, k, d),
deleteProperty: (p, k) => Reflect.deleteProperty(p.self, k),
get: (p, k, r) => {
if (k === 'super' && !('self' in p)) {
return function () {
return (p.self = reConstruct(p.super, arguments, p.class));
};
}
const value = getProp(p.self, k);
return typeof value === 'function' ? function () {
return value.apply(this === r ? p.self : this, arguments);
} : value;
},
getOwnPropertyDescriptor: (p, k) => gOPD(p.self, k),
getPrototypeOf: (p) => gPO(p.self),
has: (p, k) => Reflect.has(p.self, k),
isExtensible: (p) => Reflect.isExtensible(p.self),
ownKeys: (p) => ownProps(p.self),
preventExtensions: (p) => Reflect.preventExtensions(p.self),
set: (p, k, v) => setProp(p.self, k, v),
setPrototypeOf: (p, v) => sPO(p.self, v)
},
superHandler = {
get: (self, prop, receiver) => function () {
const proto = gPO(self), method = proto[prop];
let result, parent = proto;
do { parent = gPO(parent); }
while ((method === parent[prop]));
try { result = parent[prop].apply(sPO(self, parent), arguments); }
finally { sPO(self, proto); }
return result;
}
},
staticHandler = {
get: (self, prop, receiver) => function () {
const proto = gPO(self), method = self[prop];
let result, parent = proto;
while ((method === parent[prop])) parent = gPO(parent);
self.method = parent[prop];
try { result = self.method.apply(sPO(self, gPO(parent)), arguments); }
finally { sPO(self, proto).method = method; }
return result;
}
},
reserved = new Set(['constructor', 'extends', 'static'])
;
return function Classtrophobic(definition) {
const
Constructor = definition.constructor,
Statics = definition.static,
Super = definition.extends,
Class = definition.hasOwnProperty('constructor') ?
(Super ?
class extends Super {
constructor() {
const target = isFunction ? function () {} : {};
target.super = Super;
target.class = Class;
return Constructor.apply(
new Proxy(target, constructorHandler),
arguments
) || target.self;
}
} :
class {
constructor() {
return Constructor.apply(this, arguments) || this;
}
}) :
(Super ? class extends Super {} : class {}),
Static = Super ? {super: {get() { return new Proxy(Class, staticHandler); }}} : {},
Prototype = Super ? {super: {get() { return new Proxy(this, superHandler); }}} : {},
isFunction = Super ? Function.prototype.isPrototypeOf(Super) : false
;
ownProps(definition)
.filter((key) => !reserved.has(key))
.forEach((key) => {
Prototype[key] = gOPD(definition, key);
Prototype[key].enumerable = false;
});
defProps(Class.prototype, Prototype);
if (Statics) ownProps(Statics).forEach((key) => {
Static[key] = gOPD(Statics, key);
Static[key].enumerable = false;
});
return defProps(Class, Static);
};
})(Object, Reflect);
try { module.exports = Class; } catch(o_O) {}