Parcourir la source

[CSP] Add support for nested properties to CSP build (#4238)

Simone Todaro il y a 11 mois
Parent
commit
2ddfff241f

+ 12 - 5
packages/csp/src/evaluator.js

@@ -28,11 +28,18 @@ function generateEvaluator(el, expression, dataStack) {
     return (receiver = () => {}, { scope = {}, params = [] } = {}) => {
         let completeScope = mergeProxies([scope, ...dataStack])
 
-        if (completeScope[expression] === undefined) {
-            throwExpressionError(el, expression)
-        }
-
-        runIfTypeOfFunction(receiver, completeScope[expression], completeScope, params)
+        let evaluatedExpression = expression.split('.').reduce(
+            (currentScope, currentExpression) => {
+                if (currentScope[currentExpression] === undefined) {
+                    throwExpressionError(el, expression)
+                }
+
+                return currentScope[currentExpression]
+            },
+            completeScope,
+        );
+
+        runIfTypeOfFunction(receiver, evaluatedExpression, completeScope, params)
     }
 }
 

+ 23 - 0
packages/docs/src/en/advanced/csp.md

@@ -118,3 +118,26 @@ Alpine.data('counter', () => ({
     },
 }))
 ```
+
+The CSP build supports accessing nested properties (property accessors) using the dot notation.
+
+```alpine
+<!-- This works too -->
+<div x-data="counter">
+    <button @click="foo.increment">Increment</button>
+
+    <span x-text="foo.count"></span>
+</div>
+```
+
+```js
+Alpine.data('counter', () => ({
+    foo: {
+        count: 1,
+
+        increment() {
+            this.count++
+        },
+    },
+}))
+```

+ 23 - 0
tests/cypress/integration/plugins/csp-compatibility.spec.js

@@ -20,3 +20,26 @@ test.csp('Can use components and basic expressions with CSP-compatible build',
         get('span').should(haveText('baz'))
     }
 )
+
+test.csp('Supports nested properties',
+    [html`
+        <div x-data="test">
+            <span x-text="foo.bar"></span>
+
+            <button @click="foo.change">Change Foo</button>
+        </div>
+    `,
+    `
+        Alpine.data('test', () => ({
+            foo: {
+                bar: 'baz',
+                change() { this.foo.bar = 'qux' },
+            }
+        }))
+    `],
+    ({ get }) => {
+        get('span').should(haveText('baz'))
+        get('button').click()
+        get('span').should(haveText('qux'))
+    }
+)