1
0
Эх сурвалжийг харах

:recycle: improves merge proxies (#3722)

* :bug: Allows JSON stringifying $data

* :recycle: Uses Reflect

* :zap: Shortcircuits on unscopables

* :recycle: Extract proxyTraps

* :white_check_mark: Uses legacy syntax

* :mute: removes log

Co-authored-by: Christian Taylor <christianbtaylor@gmail.com>

* Tweak styling

---------

Co-authored-by: Christian Taylor <christianbtaylor@gmail.com>
Co-authored-by: Caleb Porzio <calebporzio@gmail.com>
Eric Kwoka 1 жил өмнө
parent
commit
e1a6bf040e

+ 50 - 61
packages/alpinejs/src/scope.js

@@ -33,65 +33,54 @@ export function closestDataProxy(el) {
     return mergeProxies(closestDataStack(el))
 }
 
-export function mergeProxies(objects) {
-    let thisProxy = new Proxy({}, {
-        ownKeys: () => {
-            return Array.from(new Set(objects.flatMap(i => Object.keys(i))))
-        },
-
-        has: (target, name) => {
-            return objects.some(obj => obj.hasOwnProperty(name))
-        },
-
-        get: (target, name) => {
-            return (objects.find(obj => {
-                if (obj.hasOwnProperty(name)) {
-                    let descriptor = Object.getOwnPropertyDescriptor(obj, name)
-
-                    // If we already bound this getter, don't rebind.
-                    if ((descriptor.get && descriptor.get._x_alreadyBound) || (descriptor.set && descriptor.set._x_alreadyBound)) {
-                        return true
-                    }
-
-                    // Properly bind getters and setters to this wrapper Proxy.
-                    if ((descriptor.get || descriptor.set) && descriptor.enumerable) {
-                        // Only bind user-defined getters, not our magic properties.
-                        let getter = descriptor.get
-                        let setter = descriptor.set
-                        let property = descriptor
-
-                        getter = getter && getter.bind(thisProxy)
-                        setter = setter && setter.bind(thisProxy)
-
-                        if (getter) getter._x_alreadyBound = true
-                        if (setter) setter._x_alreadyBound = true
-
-                        Object.defineProperty(obj, name, {
-                            ...property,
-                            get: getter,
-                            set: setter,
-                        })
-                    }
-
-                    return true
-                }
-
-                return false
-            }) || {})[name]
-        },
-
-        set: (target, name, value) => {
-            let closestObjectWithKey = objects.find(obj => obj.hasOwnProperty(name))
-
-            if (closestObjectWithKey) {
-                closestObjectWithKey[name] = value
-            } else {
-                objects[objects.length - 1][name] = value
-            }
-
-            return true
-        },
-    })
-
-    return thisProxy
+export function mergeProxies (objects) {
+    return new Proxy({ objects }, mergeProxyTrap);
+}
+
+let mergeProxyTrap = {
+    ownKeys({ objects }) {
+        return Array.from(
+            new Set(objects.flatMap((i) => Object.keys(i)))
+        )
+    },
+
+    has({ objects }, name) {
+        if (name == Symbol.unscopables) return false;
+
+        return objects.some((obj) =>
+            Object.prototype.hasOwnProperty.call(obj, name)
+        );
+    },
+
+    get({ objects }, name, thisProxy) {
+        if (name == "toJSON") return collapseProxies
+
+        return Reflect.get(
+            objects.find((obj) =>
+                Object.prototype.hasOwnProperty.call(obj, name)
+            ) || {},
+            name,
+            thisProxy
+        )
+    },
+
+    set({ objects }, name, value) {
+        return Reflect.set(
+            objects.find((obj) =>
+                Object.prototype.hasOwnProperty.call(obj, name)
+            ) || objects[objects.length-1],
+            name,
+            value
+        )
+    },
+}
+
+function collapseProxies() {
+    let keys = Reflect.ownKeys(this)
+
+    return keys.reduce((acc, key) => {
+        acc[key] = Reflect.get(this, key)
+
+        return acc;
+    }, {})
 }