@rettangoli/fe 1.0.0-rc5 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/view/bindings.js +55 -15
package/package.json
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
const PROP_PREFIX = ":";
|
|
2
2
|
|
|
3
3
|
const UNSAFE_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
4
|
+
const ATTRIBUTE_NAME_REGEX = /^[A-Za-z_][A-Za-z0-9_.:-]*$/;
|
|
5
|
+
|
|
6
|
+
const isValidAttributeName = (value) => ATTRIBUTE_NAME_REGEX.test(value);
|
|
4
7
|
|
|
5
8
|
const lodashGet = (obj, path) => {
|
|
6
9
|
if (!path) return obj;
|
|
@@ -73,7 +76,7 @@ export const collectBindingNames = (attrsString = "") => {
|
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
const attrAssignmentRegex = /(\S+?)=(?:\"([^\"]*)\"|\'([^\']*)\'|([^\s]*))/g;
|
|
76
|
-
const booleanAttrRegex =
|
|
79
|
+
const booleanAttrRegex = /(\S+?)(?=\s|$)/g;
|
|
77
80
|
const processedAttrs = new Set();
|
|
78
81
|
const bindingNames = [];
|
|
79
82
|
let match;
|
|
@@ -97,14 +100,20 @@ export const collectBindingNames = (attrsString = "") => {
|
|
|
97
100
|
|
|
98
101
|
let boolMatch;
|
|
99
102
|
while ((boolMatch = booleanAttrRegex.exec(remainingAttrsString)) !== null) {
|
|
100
|
-
const
|
|
101
|
-
if (
|
|
103
|
+
const rawToken = boolMatch[1];
|
|
104
|
+
if (rawToken.startsWith(".")) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const attrName = rawToken.startsWith("?")
|
|
108
|
+
? rawToken.substring(1)
|
|
109
|
+
: rawToken;
|
|
110
|
+
if (!attrName || !isValidAttributeName(attrName)) {
|
|
102
111
|
continue;
|
|
103
112
|
}
|
|
104
113
|
if (
|
|
105
|
-
!processedAttrs.has(
|
|
106
|
-
&& !
|
|
107
|
-
&& !
|
|
114
|
+
!processedAttrs.has(rawToken)
|
|
115
|
+
&& !rawToken.startsWith(PROP_PREFIX)
|
|
116
|
+
&& !rawToken.includes("=")
|
|
108
117
|
) {
|
|
109
118
|
bindingNames.push(attrName);
|
|
110
119
|
}
|
|
@@ -146,6 +155,14 @@ export const parseNodeBindings = ({
|
|
|
146
155
|
props[normalizedPropName] = propValue;
|
|
147
156
|
};
|
|
148
157
|
|
|
158
|
+
const assertValidAttributeName = (attrName, sourceLabel) => {
|
|
159
|
+
if (!isValidAttributeName(attrName)) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`[Parser] Invalid ${sourceLabel} attribute name '${attrName}' on '${tagName}'.`,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
149
166
|
if (!attrsString) {
|
|
150
167
|
return { attrs, props };
|
|
151
168
|
}
|
|
@@ -180,6 +197,7 @@ export const parseNodeBindings = ({
|
|
|
180
197
|
|
|
181
198
|
if (rawBindingName.startsWith("?")) {
|
|
182
199
|
const attrName = rawBindingName.substring(1);
|
|
200
|
+
assertValidAttributeName(attrName, "boolean toggle");
|
|
183
201
|
const attrValue = rawValue;
|
|
184
202
|
assertSupportedBooleanToggleAttr(attrName);
|
|
185
203
|
|
|
@@ -203,6 +221,7 @@ export const parseNodeBindings = ({
|
|
|
203
221
|
continue;
|
|
204
222
|
}
|
|
205
223
|
|
|
224
|
+
assertValidAttributeName(rawBindingName, "binding");
|
|
206
225
|
attrs[rawBindingName] = rawValue;
|
|
207
226
|
if (isWebComponent && rawBindingName !== "id") {
|
|
208
227
|
setComponentProp(rawBindingName, rawValue, "attribute-form");
|
|
@@ -221,21 +240,42 @@ export const parseNodeBindings = ({
|
|
|
221
240
|
remainingAttrsString = remainingAttrsString.replace(processedMatch, " ");
|
|
222
241
|
});
|
|
223
242
|
|
|
224
|
-
const booleanAttrRegex =
|
|
243
|
+
const booleanAttrRegex = /(\S+?)(?=\s|$)/g;
|
|
225
244
|
let boolMatch;
|
|
226
245
|
while ((boolMatch = booleanAttrRegex.exec(remainingAttrsString)) !== null) {
|
|
227
|
-
const
|
|
228
|
-
if (
|
|
246
|
+
const rawToken = boolMatch[1];
|
|
247
|
+
if (rawToken.startsWith(".")) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (processedAttrs.has(rawToken) || rawToken.startsWith(PROP_PREFIX) || rawToken.includes("=")) {
|
|
229
251
|
continue;
|
|
230
252
|
}
|
|
253
|
+
|
|
254
|
+
if (rawToken.startsWith("?")) {
|
|
255
|
+
const toggleAttrName = rawToken.substring(1);
|
|
256
|
+
assertValidAttributeName(toggleAttrName, "boolean toggle");
|
|
257
|
+
assertSupportedBooleanToggleAttr(toggleAttrName);
|
|
258
|
+
attrs[toggleAttrName] = "";
|
|
259
|
+
if (isWebComponent && toggleAttrName !== "id") {
|
|
260
|
+
setComponentProp(toggleAttrName, true, "boolean attribute-form");
|
|
261
|
+
}
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (!isValidAttributeName(rawToken)) {
|
|
266
|
+
throw new Error(
|
|
267
|
+
`[Parser] Invalid attribute token '${rawToken}' on '${tagName}'.`,
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
231
271
|
if (
|
|
232
|
-
!processedAttrs.has(
|
|
233
|
-
&& !
|
|
234
|
-
&& !
|
|
272
|
+
!processedAttrs.has(rawToken)
|
|
273
|
+
&& !rawToken.startsWith(PROP_PREFIX)
|
|
274
|
+
&& !rawToken.includes("=")
|
|
235
275
|
) {
|
|
236
|
-
attrs[
|
|
237
|
-
if (isWebComponent &&
|
|
238
|
-
setComponentProp(
|
|
276
|
+
attrs[rawToken] = "";
|
|
277
|
+
if (isWebComponent && rawToken !== "id") {
|
|
278
|
+
setComponentProp(rawToken, true, "boolean attribute-form");
|
|
239
279
|
}
|
|
240
280
|
}
|
|
241
281
|
}
|