-
-
Notifications
You must be signed in to change notification settings - Fork 481
/
ProxyWrap.js
111 lines (89 loc) · 2.48 KB
/
ProxyWrap.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
import types from "node:util/types";
import debugUtil from "debug";
import { isPlainObject } from "@11ty/eleventy-utils";
const debug = debugUtil("Dev:Eleventy:Proxy");
function wrapObject(target, fallback) {
if (Object.isFrozen(target)) {
return target;
}
return new Proxy(target, {
getOwnPropertyDescriptor(target, prop) {
let ret;
if (Reflect.has(target, prop)) {
ret = Reflect.getOwnPropertyDescriptor(target, prop);
} else if (Reflect.has(fallback, prop)) {
ret = Reflect.getOwnPropertyDescriptor(fallback, prop);
}
return ret;
},
has(target, prop) {
if (Reflect.has(target, prop)) {
return true;
}
return Reflect.has(fallback, prop);
},
ownKeys(target) {
let s = new Set();
for (let k of Reflect.ownKeys(target)) {
s.add(k);
}
if (isPlainObject(fallback)) {
for (let k of Reflect.ownKeys(fallback)) {
s.add(k);
}
}
return Array.from(s);
},
get(target, prop) {
debug("handler:get", prop);
let value = Reflect.get(target, prop);
if (Reflect.has(target, prop)) {
// Already proxied
if (types.isProxy(value)) {
return value;
}
if (isPlainObject(value) && Reflect.has(fallback, prop)) {
if (Object.isFrozen(value)) {
return value;
}
let ret = wrapObject(value, Reflect.get(fallback, prop));
debug("handler:get (primary, object)", prop);
return ret;
}
debug("handler:get (primary)", prop);
return value;
}
// Does not exist in primary
if (Reflect.has(fallback, prop)) {
// fallback has prop
let fallbackValue = Reflect.get(fallback, prop);
if (isPlainObject(fallbackValue)) {
if (Object.isFrozen(fallbackValue)) {
return fallbackValue;
}
debug("handler:get (fallback, object)", prop);
// set empty object on primary
let emptyObject = {};
Reflect.set(target, prop, emptyObject);
return wrapObject(emptyObject, fallbackValue);
}
debug("handler:get (fallback)", prop);
return fallbackValue;
}
// primary *and* fallback do _not_ have prop
debug("handler:get (not on primary or fallback)", prop);
return value;
},
set(target, prop, value) {
debug("handler:set", prop);
return Reflect.set(target, prop, value);
},
});
}
function ProxyWrap(target, fallback) {
if (!isPlainObject(target) || !isPlainObject(fallback)) {
throw new Error("ProxyWrap expects objects for both the target and fallback");
}
return wrapObject(target, fallback);
}
export { ProxyWrap };