1 | import assign from 'lodash/object/assign';
|
2 | import difference from 'lodash/array/difference';
|
3 |
|
4 | export default function createPrototypeProxy() {
|
5 | let proxy = {};
|
6 | let current = null;
|
7 | let mountedInstances = [];
|
8 |
|
9 | |
10 |
|
11 |
|
12 | function proxyToString(name) {
|
13 |
|
14 | return function toString() {
|
15 | if (typeof current[name] === 'function') {
|
16 | return current[name].toString();
|
17 | } else {
|
18 | return '<method was deleted>';
|
19 | }
|
20 | };
|
21 | }
|
22 |
|
23 | |
24 |
|
25 |
|
26 | function proxyMethod(name) {
|
27 |
|
28 | const proxiedMethod = function () {
|
29 | if (typeof current[name] === 'function') {
|
30 | return current[name].apply(this, arguments);
|
31 | }
|
32 | };
|
33 |
|
34 |
|
35 | assign(proxiedMethod, current[name]);
|
36 | proxiedMethod.toString = proxyToString(name);
|
37 |
|
38 | return proxiedMethod;
|
39 | }
|
40 |
|
41 | |
42 |
|
43 |
|
44 | function proxiedComponentDidMount() {
|
45 | mountedInstances.push(this);
|
46 | if (typeof current.componentDidMount === 'function') {
|
47 | return current.componentDidMount.apply(this, arguments);
|
48 | }
|
49 | }
|
50 | proxiedComponentDidMount.toString = proxyToString('componentDidMount');
|
51 |
|
52 | |
53 |
|
54 |
|
55 | function proxiedComponentWillUnmount() {
|
56 | const index = mountedInstances.indexOf(this);
|
57 |
|
58 | if (index !== -1) {
|
59 | mountedInstances.splice(index, 1);
|
60 | }
|
61 | if (typeof current.componentWillUnmount === 'function') {
|
62 | return current.componentWillUnmount.apply(this, arguments);
|
63 | }
|
64 | }
|
65 | proxiedComponentWillUnmount.toString = proxyToString('componentWillUnmount');
|
66 |
|
67 | |
68 |
|
69 |
|
70 | function defineProxyProperty(name, descriptor) {
|
71 | Object.defineProperty(proxy, name, descriptor);
|
72 | }
|
73 |
|
74 | |
75 |
|
76 |
|
77 | function defineProxyPropertyWithValue(name, value) {
|
78 | const {
|
79 | enumerable = false,
|
80 | writable = true
|
81 | } = Object.getOwnPropertyDescriptor(current, name) || {};
|
82 |
|
83 | defineProxyProperty(name, {
|
84 | configurable: true,
|
85 | enumerable,
|
86 | writable,
|
87 | value
|
88 | });
|
89 | }
|
90 |
|
91 | |
92 |
|
93 |
|
94 | function createAutoBindMap() {
|
95 | if (!current.__reactAutoBindMap) {
|
96 | return;
|
97 | }
|
98 |
|
99 | let __reactAutoBindMap = {};
|
100 | for (let name in current.__reactAutoBindMap) {
|
101 | if (typeof proxy[name] === 'function' && current.__reactAutoBindMap.hasOwnProperty(name)) {
|
102 | __reactAutoBindMap[name] = proxy[name];
|
103 | }
|
104 | }
|
105 |
|
106 | return __reactAutoBindMap;
|
107 | }
|
108 |
|
109 | |
110 |
|
111 |
|
112 | function update(next) {
|
113 |
|
114 | current = next;
|
115 |
|
116 |
|
117 | const currentNames = Object.getOwnPropertyNames(current);
|
118 | const previousName = Object.getOwnPropertyNames(proxy);
|
119 | const removedNames = difference(previousName, currentNames);
|
120 |
|
121 |
|
122 | removedNames.forEach(name => {
|
123 | delete proxy[name];
|
124 | });
|
125 |
|
126 |
|
127 | currentNames.forEach(name => {
|
128 | const descriptor = Object.getOwnPropertyDescriptor(current, name);
|
129 | if (typeof descriptor.value === 'function') {
|
130 |
|
131 | defineProxyPropertyWithValue(name, proxyMethod(name));
|
132 | } else {
|
133 |
|
134 | defineProxyProperty(name, descriptor);
|
135 | }
|
136 | });
|
137 |
|
138 |
|
139 | defineProxyPropertyWithValue('componentDidMount', proxiedComponentDidMount);
|
140 | defineProxyPropertyWithValue('componentWillUnmount', proxiedComponentWillUnmount);
|
141 | defineProxyPropertyWithValue('__reactAutoBindMap', createAutoBindMap());
|
142 |
|
143 |
|
144 | proxy.__proto__ = next;
|
145 |
|
146 | return mountedInstances;
|
147 | }
|
148 |
|
149 | |
150 |
|
151 |
|
152 | function get() {
|
153 | return proxy;
|
154 | }
|
155 |
|
156 | return {
|
157 | update,
|
158 | get
|
159 | };
|
160 | }; |
\ | No newline at end of file |