@wix/origami-lint 1.34.8 → 1.34.10
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/dist/rules/bindings.js +37 -8
- package/package.json +3 -3
package/dist/rules/bindings.js
CHANGED
|
@@ -63,7 +63,7 @@ function checkComponentBindings(at) {
|
|
|
63
63
|
if (!rulesApi.hasDataAttributes(node))
|
|
64
64
|
return;
|
|
65
65
|
boundPropOnce(at);
|
|
66
|
-
for (const [name, , value] of boundAttributes(node))
|
|
66
|
+
for (const [name, , value] of boundAttributes(node, at.input.rulesApi))
|
|
67
67
|
prop(at, name, value, true);
|
|
68
68
|
}
|
|
69
69
|
/** One elementProps entry: its `bindings`, and the keys it binds. */
|
|
@@ -80,19 +80,48 @@ function checkEntryBindings(at, entry) {
|
|
|
80
80
|
if (className)
|
|
81
81
|
classNameConditions(entryAt, className, '`className`');
|
|
82
82
|
entryPropBoundOnce(entryAt, object);
|
|
83
|
-
for (const [key, property] of boundEntryKeys(object))
|
|
83
|
+
for (const [key, property] of boundEntryKeys(object, at.input.rulesApi))
|
|
84
84
|
prop(entryAt, key, property.value, true);
|
|
85
85
|
}
|
|
86
86
|
/** A builder call in a structure attribute: it is imported, and so are the names it uses. */
|
|
87
87
|
function checkCallExpressionImports(input) {
|
|
88
88
|
if (input.node.callee.type !== 'Identifier' || !isInStructureAttribute(input.node))
|
|
89
89
|
return;
|
|
90
|
+
if (isSvgCall(input.node, input.rulesApi))
|
|
91
|
+
return checkSvgArguments(input);
|
|
90
92
|
if (!isBuilderImported(input, input.node.callee))
|
|
91
93
|
return;
|
|
92
94
|
const ctxHook = bindingNameImported(input, input.node.callee.name);
|
|
93
95
|
if (ctxHook)
|
|
94
96
|
ctxSourceHasName(input, ctxHook);
|
|
95
97
|
}
|
|
98
|
+
function isSvgCall(node, rulesApi) {
|
|
99
|
+
if (node.callee.type !== 'Identifier')
|
|
100
|
+
return false;
|
|
101
|
+
const found = rulesApi.getImport(node.callee);
|
|
102
|
+
return found?.kind === 'runtime' && found.imported === 'svg';
|
|
103
|
+
}
|
|
104
|
+
function checkSvgArguments({ node, rulesApi, report }) {
|
|
105
|
+
const [url, uri] = node.arguments;
|
|
106
|
+
if (node.arguments.length === 2 && uri.type === 'Literal' && typeof uri.value === 'string' &&
|
|
107
|
+
url.type === 'MemberExpression' && !url.computed && url.property.type === 'Identifier' && url.property.name === 'url') {
|
|
108
|
+
const call = url.object;
|
|
109
|
+
if (call.type === 'CallExpression' && call.arguments.length === 1 &&
|
|
110
|
+
call.callee.type === 'MemberExpression' && !call.callee.computed &&
|
|
111
|
+
call.callee.property.type === 'Identifier' && call.callee.property.name === 'getShapeUrl' &&
|
|
112
|
+
call.callee.object.type === 'Identifier') {
|
|
113
|
+
const media = rulesApi.getImport(call.callee.object);
|
|
114
|
+
const [identifier] = call.arguments;
|
|
115
|
+
if (media?.kind === 'sdk' && media.imported === 'media' &&
|
|
116
|
+
identifier.type === 'Literal' && identifier.value === `wix:image://v1/${uri.value}`)
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
report({
|
|
121
|
+
loc: node.loc,
|
|
122
|
+
message: tracked("An SVG media expression must be `svg(media.getShapeUrl('wix:image://v1/<uri>').url, '<uri>')`, with matching URI strings, svg imported from '@wix/origami-runtime' and media from '@wix/sdk'.", 'CONV-vectorArtExpression.ts:44'),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
96
125
|
/** Each builder's own row: the shape of its call, a key written twice in it. */
|
|
97
126
|
const ROW_OF_BUILDER = { all: 'CONV-decode.ts:196', callback: 'CONV-astValue.ts:287', ctx: 'CONV-astValue.ts:276', fn: 'CONV-astValue.ts:287', is: 'CONV-decode.ts:172', raw: 'CONV-decode.ts:28' };
|
|
98
127
|
const tracked = (message, row) => `${message.slice(0, -1)} (tracker ${row}).`;
|
|
@@ -152,7 +181,7 @@ function boundPropOnce(at) {
|
|
|
152
181
|
const props = getBindingsProps(bindings && getExpression(bindings), rulesApi);
|
|
153
182
|
if (!props)
|
|
154
183
|
return;
|
|
155
|
-
for (const [name, attribute] of boundAttributes(node)) {
|
|
184
|
+
for (const [name, attribute] of boundAttributes(node, rulesApi)) {
|
|
156
185
|
const where = props.raw ? `bindings={raw({ properties: { ${name} } })}` : `bindings={{ props: { ${name} } }}`;
|
|
157
186
|
if (props.names.has(name))
|
|
158
187
|
say(at, attribute, `${at.owner} binds \`${name}\` twice: in \`${name}={…}\` and in \`${where}\`. Keep one.`, 'CONV-parseJsx.ts:753');
|
|
@@ -162,7 +191,7 @@ function entryPropBoundOnce(at, entry) {
|
|
|
162
191
|
const props = getBindingsProps(getProperty(entry, 'bindings')?.value, at.input.rulesApi);
|
|
163
192
|
if (!props)
|
|
164
193
|
return;
|
|
165
|
-
for (const [key, property] of boundEntryKeys(entry)) {
|
|
194
|
+
for (const [key, property] of boundEntryKeys(entry, at.input.rulesApi)) {
|
|
166
195
|
const where = props.raw ? `bindings: raw({ properties: { ${key} } })` : `bindings.props.${key}`;
|
|
167
196
|
if (props.names.has(key))
|
|
168
197
|
say(at, property, `${at.owner} binds \`${key}\` twice: in \`${key}: …\` and in its \`${where}\`. Keep one.`, 'CONV-parseJsx.ts:753');
|
|
@@ -646,19 +675,19 @@ function runsAtRender(at, node) {
|
|
|
646
675
|
return isInvoke(node) || getParamReadKind(node) ? describeIn(at, node) : null;
|
|
647
676
|
}
|
|
648
677
|
/** The data attributes bound to a value the import reads as a binding; not an `on…` attribute, which it doesn't read at all (OUR-031 reports it). */
|
|
649
|
-
function boundAttributes(element) {
|
|
678
|
+
function boundAttributes(element, rulesApi) {
|
|
650
679
|
return element.openingElement.attributes.flatMap((attribute) => {
|
|
651
680
|
if (attribute.type !== 'JSXAttribute' || isReservedAttribute(getName(attribute)) || EVENT_ATTRIBUTE.test(getName(attribute)))
|
|
652
681
|
return [];
|
|
653
682
|
const value = getExpression(attribute);
|
|
654
|
-
return isBound(value) ? [[getName(attribute), attribute, value]] : [];
|
|
683
|
+
return isBound(value) && !(value.type === 'CallExpression' && isSvgCall(value, rulesApi)) ? [[getName(attribute), attribute, value]] : [];
|
|
655
684
|
});
|
|
656
685
|
}
|
|
657
|
-
function boundEntryKeys(entry) {
|
|
686
|
+
function boundEntryKeys(entry, rulesApi) {
|
|
658
687
|
return getProperties(entry).flatMap((property) => {
|
|
659
688
|
const key = getKey(property);
|
|
660
689
|
const value = bare(property.value);
|
|
661
|
-
return key !== null && !RESERVED_ENTRY_KEYS.includes(key) && isBound(value) ? [[key, property]] : [];
|
|
690
|
+
return key !== null && !RESERVED_ENTRY_KEYS.includes(key) && isBound(value) && !(value.type === 'CallExpression' && isSvgCall(value, rulesApi)) ? [[key, property]] : [];
|
|
662
691
|
});
|
|
663
692
|
}
|
|
664
693
|
function getBindingsProps(node, rulesApi) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/origami-lint",
|
|
3
|
-
"version": "1.34.
|
|
3
|
+
"version": "1.34.10",
|
|
4
4
|
"description": "Offline lint for an exported Origami site: lints the pages that changed since the last passing run",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"test": "node --test 'test/*.test.ts'"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@wix/origami-fonts": "1.0.
|
|
24
|
+
"@wix/origami-fonts": "1.0.3",
|
|
25
25
|
"oxc-parser": "^0.151.0",
|
|
26
26
|
"oxlint": "^1.39.0",
|
|
27
27
|
"postcss": "^8.5.3",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
]
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
|
-
"falconPackageHash": "
|
|
55
|
+
"falconPackageHash": "df5ca3b838244854a52ae4013469c645c6bd6d3e1651ee3702545903"
|
|
56
56
|
}
|