summaryrefslogtreecommitdiff
path: root/node_modules/@11ty/eleventy/src/Util/Objects/ProxyWrap.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/@11ty/eleventy/src/Util/Objects/ProxyWrap.js')
-rw-r--r--node_modules/@11ty/eleventy/src/Util/Objects/ProxyWrap.js118
1 files changed, 118 insertions, 0 deletions
diff --git a/node_modules/@11ty/eleventy/src/Util/Objects/ProxyWrap.js b/node_modules/@11ty/eleventy/src/Util/Objects/ProxyWrap.js
new file mode 100644
index 0000000..38730fd
--- /dev/null
+++ b/node_modules/@11ty/eleventy/src/Util/Objects/ProxyWrap.js
@@ -0,0 +1,118 @@
+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();
+ // The fallback keys need to come first to preserve proper key order
+ // https://github.com/11ty/eleventy/issues/3849
+ if (isPlainObject(fallback)) {
+ for (let k of Reflect.ownKeys(fallback)) {
+ s.add(k);
+ }
+ }
+ for (let k of Reflect.ownKeys(target)) {
+ if (!s.has(k)) {
+ 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 (
+ (typeof fallback === "object" || typeof fallback === "function") &&
+ 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 };