@nordcraft/search 1.0.59 → 1.0.61
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/issues/dom/createRequiredElementAttributeRule.js +25 -12
- package/dist/rules/issues/dom/createRequiredElementAttributeRule.js.map +1 -1
- package/dist/rules/issues/dom/createRequiredElementAttributeRule.test.js +93 -0
- package/dist/rules/issues/dom/createRequiredElementAttributeRule.test.js.map +1 -1
- package/dist/rules/issues/dom/domRules.index.js +1 -1
- package/dist/rules/issues/dom/domRules.index.js.map +1 -1
- package/dist/rules/issues/dom/imageWithoutDimensionRule.js +34 -16
- package/dist/rules/issues/dom/imageWithoutDimensionRule.js.map +1 -1
- package/dist/rules/issues/dom/imageWithoutDimensionRule.test.js +199 -0
- package/dist/rules/issues/dom/imageWithoutDimensionRule.test.js.map +1 -1
- package/package.json +3 -3
- package/src/rules/issues/dom/createRequiredElementAttributeRule.test.ts +101 -0
- package/src/rules/issues/dom/createRequiredElementAttributeRule.ts +33 -14
- package/src/rules/issues/dom/domRules.index.ts +1 -1
- package/src/rules/issues/dom/imageWithoutDimensionRule.test.ts +219 -0
- package/src/rules/issues/dom/imageWithoutDimensionRule.ts +41 -20
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import { isDefined } from '@nordcraft/core/dist/utils/util';
|
|
1
|
+
import { isDefined, toBoolean } from '@nordcraft/core/dist/utils/util';
|
|
2
|
+
import { contextlessEvaluateFormula } from '../../../util/contextlessEvaluateFormula';
|
|
3
|
+
/**
|
|
4
|
+
* @param tag - The HTML tag of the element to check (e.g., 'img', 'a').
|
|
5
|
+
* @param attribute - The required attribute that must be present on the element (e.g., 'alt', 'href'). Can also be an array of attributes to check where any one being present is sufficient. Only the first attribute will be reported in the issue details.
|
|
6
|
+
* @param level - The severity level of the issue ('warning' by default).
|
|
7
|
+
* @param allowEmptyString - Whether to allow the attribute to be an empty string (false by default).
|
|
8
|
+
* @returns An issue rule that reports when an element of the specified tag is missing the specified attribute.
|
|
9
|
+
*/
|
|
2
10
|
export function createRequiredElementAttributeRule({ tag, attribute, level = 'warning', allowEmptyString = false, }) {
|
|
11
|
+
const mainAttribute = Array.isArray(attribute) ? attribute[0] : attribute;
|
|
3
12
|
return {
|
|
4
13
|
code: 'required element attribute',
|
|
5
14
|
level: level,
|
|
@@ -8,19 +17,23 @@ export function createRequiredElementAttributeRule({ tag, attribute, level = 'wa
|
|
|
8
17
|
if (nodeType === 'component-node' &&
|
|
9
18
|
value.type === 'element' &&
|
|
10
19
|
value.tag === tag) {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
if (attributeValue.type === 'value') {
|
|
17
|
-
if (!isDefined(attributeValue.value)) {
|
|
18
|
-
return report(path, { tag, attribute });
|
|
19
|
-
}
|
|
20
|
-
if (!allowEmptyString && attributeValue.value === '') {
|
|
21
|
-
return report(path, { tag, attribute });
|
|
20
|
+
const attributes = Array.isArray(attribute) ? attribute : [attribute];
|
|
21
|
+
if (attributes.some((attr) => {
|
|
22
|
+
if (!isDefined(value.attrs[attr])) {
|
|
23
|
+
return false;
|
|
22
24
|
}
|
|
25
|
+
const { isStatic, result } = contextlessEvaluateFormula(value.attrs[attr]);
|
|
26
|
+
return (
|
|
27
|
+
// Dynamic attributes are considered valid
|
|
28
|
+
!isStatic ||
|
|
29
|
+
// Static attributes must be truthy as falsy values are not rendered
|
|
30
|
+
(isDefined(result) &&
|
|
31
|
+
toBoolean(result) &&
|
|
32
|
+
(allowEmptyString || result !== '')));
|
|
33
|
+
})) {
|
|
34
|
+
return;
|
|
23
35
|
}
|
|
36
|
+
report(path, { tag, attribute: mainAttribute });
|
|
24
37
|
}
|
|
25
38
|
},
|
|
26
39
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createRequiredElementAttributeRule.js","sourceRoot":"","sources":["../../../../src/rules/issues/dom/createRequiredElementAttributeRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAA;
|
|
1
|
+
{"version":3,"file":"createRequiredElementAttributeRule.js","sourceRoot":"","sources":["../../../../src/rules/issues/dom/createRequiredElementAttributeRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAA;AAEtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAA;AAErF;;;;;;GAMG;AACH,MAAM,UAAU,kCAAkC,CAAC,EACjD,GAAG,EACH,SAAS,EACT,KAAK,GAAG,SAAS,EACjB,gBAAgB,GAAG,KAAK,GAMzB;IAIC,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACzE,OAAO;QACL,IAAI,EAAE,4BAA4B;QAClC,KAAK,EAAE,KAAK;QACZ,QAAQ,EAAE,eAAe;QACzB,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;YAC3C,IACE,QAAQ,KAAK,gBAAgB;gBAC7B,KAAK,CAAC,IAAI,KAAK,SAAS;gBACxB,KAAK,CAAC,GAAG,KAAK,GAAG,EACjB,CAAC;gBACD,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;gBACrE,IACE,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;oBACvB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;wBAClC,OAAO,KAAK,CAAA;oBACd,CAAC;oBACD,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,0BAA0B,CACrD,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAClB,CAAA;oBACD,OAAO;oBACL,0CAA0C;oBAC1C,CAAC,QAAQ;wBACT,oEAAoE;wBACpE,CAAC,SAAS,CAAC,MAAM,CAAC;4BAChB,SAAS,CAAC,MAAM,CAAC;4BACjB,CAAC,gBAAgB,IAAI,MAAM,KAAK,EAAE,CAAC,CAAC,CACvC,CAAA;gBACH,CAAC,CAAC,EACF,CAAC;oBACD,OAAM;gBACR,CAAC;gBAED,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAA;YACjD,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -144,5 +144,98 @@ describe('requiredElementAttributeRule', () => {
|
|
|
144
144
|
}));
|
|
145
145
|
expect(problems).toHaveLength(0);
|
|
146
146
|
});
|
|
147
|
+
test('should report if attribute is false or null, as such attributes are not rendered', () => {
|
|
148
|
+
const problems = Array.from(searchProject({
|
|
149
|
+
files: {
|
|
150
|
+
formulas: {},
|
|
151
|
+
components: {
|
|
152
|
+
test: {
|
|
153
|
+
name: 'test',
|
|
154
|
+
nodes: {
|
|
155
|
+
root: {
|
|
156
|
+
type: 'element',
|
|
157
|
+
attrs: {
|
|
158
|
+
alt: { type: 'value', value: null },
|
|
159
|
+
},
|
|
160
|
+
classes: {},
|
|
161
|
+
events: {},
|
|
162
|
+
tag: 'img',
|
|
163
|
+
children: [],
|
|
164
|
+
style: {},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
formulas: {},
|
|
168
|
+
apis: {},
|
|
169
|
+
attributes: {},
|
|
170
|
+
variables: {},
|
|
171
|
+
},
|
|
172
|
+
test2: {
|
|
173
|
+
name: 'test2',
|
|
174
|
+
nodes: {
|
|
175
|
+
root: {
|
|
176
|
+
type: 'element',
|
|
177
|
+
attrs: {
|
|
178
|
+
alt: { type: 'value', value: false },
|
|
179
|
+
},
|
|
180
|
+
classes: {},
|
|
181
|
+
events: {},
|
|
182
|
+
tag: 'img',
|
|
183
|
+
children: [],
|
|
184
|
+
style: {},
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
formulas: {},
|
|
188
|
+
apis: {},
|
|
189
|
+
attributes: {},
|
|
190
|
+
variables: {},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
rules: [
|
|
195
|
+
createRequiredElementAttributeRule({ tag: 'img', attribute: 'alt' }),
|
|
196
|
+
],
|
|
197
|
+
}));
|
|
198
|
+
expect(problems).toHaveLength(2);
|
|
199
|
+
expect(problems[0].code).toBe('required element attribute');
|
|
200
|
+
expect(problems[0].path).toEqual(['components', 'test', 'nodes', 'root']);
|
|
201
|
+
expect(problems[1].code).toBe('required element attribute');
|
|
202
|
+
expect(problems[1].path).toEqual(['components', 'test2', 'nodes', 'root']);
|
|
203
|
+
});
|
|
204
|
+
test('should handle multiple acceptable attributes', () => {
|
|
205
|
+
const problems = Array.from(searchProject({
|
|
206
|
+
files: {
|
|
207
|
+
formulas: {},
|
|
208
|
+
components: {
|
|
209
|
+
test: {
|
|
210
|
+
name: 'test',
|
|
211
|
+
nodes: {
|
|
212
|
+
root: {
|
|
213
|
+
type: 'element',
|
|
214
|
+
attrs: {
|
|
215
|
+
'aria-hidden': { type: 'value', value: 'true' },
|
|
216
|
+
},
|
|
217
|
+
classes: {},
|
|
218
|
+
events: {},
|
|
219
|
+
tag: 'a',
|
|
220
|
+
children: [],
|
|
221
|
+
style: {},
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
formulas: {},
|
|
225
|
+
apis: {},
|
|
226
|
+
attributes: {},
|
|
227
|
+
variables: {},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
rules: [
|
|
232
|
+
createRequiredElementAttributeRule({
|
|
233
|
+
tag: 'a',
|
|
234
|
+
attribute: ['alt', 'aria-hidden'],
|
|
235
|
+
}),
|
|
236
|
+
],
|
|
237
|
+
}));
|
|
238
|
+
expect(problems).toHaveLength(0);
|
|
239
|
+
});
|
|
147
240
|
});
|
|
148
241
|
//# sourceMappingURL=createRequiredElementAttributeRule.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createRequiredElementAttributeRule.test.js","sourceRoot":"","sources":["../../../../src/rules/issues/dom/createRequiredElementAttributeRule.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createRequiredElementAttributeRule.test.js","sourceRoot":"","sources":["../../../../src/rules/issues/dom/createRequiredElementAttributeRule.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domRules.index.js","sourceRoot":"","sources":["../../../../src/rules/issues/dom/domRules.index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAA;AAC/E,OAAO,EAAE,8BAA8B,EAAE,MAAM,kCAAkC,CAAA;AACjF,OAAO,EAAE,kCAAkC,EAAE,MAAM,sCAAsC,CAAA;AACzF,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AACvE,OAAO,EAAE,oCAAoC,EAAE,MAAM,wCAAwC,CAAA;AAC7F,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAA;AAEnE,eAAe;IACb,uBAAuB;IACvB,kCAAkC,CAAC;QACjC,GAAG,EAAE,GAAG;QACR,SAAS,EAAE,MAAM;KAClB,CAAC;IACF,kCAAkC,CAAC;QACjC,GAAG,EAAE,KAAK;QACV,SAAS,EAAE,KAAK;
|
|
1
|
+
{"version":3,"file":"domRules.index.js","sourceRoot":"","sources":["../../../../src/rules/issues/dom/domRules.index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAA;AAC/E,OAAO,EAAE,8BAA8B,EAAE,MAAM,kCAAkC,CAAA;AACjF,OAAO,EAAE,kCAAkC,EAAE,MAAM,sCAAsC,CAAA;AACzF,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AACvE,OAAO,EAAE,oCAAoC,EAAE,MAAM,wCAAwC,CAAA;AAC7F,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAA;AAEnE,eAAe;IACb,uBAAuB;IACvB,kCAAkC,CAAC;QACjC,GAAG,EAAE,GAAG;QACR,SAAS,EAAE,MAAM;KAClB,CAAC;IACF,kCAAkC,CAAC;QACjC,GAAG,EAAE,KAAK;QACV,SAAS,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC;QACjC,gBAAgB,EAAE,IAAI;KACvB,CAAC;IACF,kCAAkC,CAAC;QACjC,GAAG,EAAE,KAAK;QACV,SAAS,EAAE,KAAK;KACjB,CAAC;IACF,yBAAyB,CAAC,aAAa,CAAC;IACxC,yBAAyB,CAAC,OAAO,CAAC;IAClC,6BAA6B,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IACzE,8BAA8B,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IACpD,oFAAoF;IACpF,6BAA6B,CAC3B,CAAC,OAAO,CAAC,EACT,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CACzD;IACD,oFAAoF;IACpF,oFAAoF;IACpF,oFAAoF;IACpF,8BAA8B,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACtE,iFAAiF;IACjF,6BAA6B,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IACzE,iFAAiF;IACjF,iFAAiF;IACjF,8BAA8B,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACpD,qFAAqF;IACrF,6BAA6B,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;IACvE,uFAAuF;IACvF,6BAA6B,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IACvD,qFAAqF;IACrF,8BAA8B,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IACxD,iFAAiF;IACjF,6BAA6B,CAC3B,CAAC,IAAI,CAAC,EACN,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,CAAC,CAC1C;IACD,oCAAoC;IACpC,yBAAyB;CAC1B,CAAA"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { isDefined } from '@nordcraft/core/dist/utils/util';
|
|
2
|
+
import { contextlessEvaluateFormula } from '../../../util/contextlessEvaluateFormula';
|
|
3
|
+
const nonStaticDimensionKeywords = ['', 'auto'];
|
|
2
4
|
/**
|
|
3
5
|
* Lighthouse reports a similar issue:
|
|
4
6
|
* https://web.dev/articles/optimize-cls?utm_source=lighthouse&utm_medium=devtools#images_without_dimensions
|
|
@@ -13,28 +15,44 @@ export const imageWithoutDimensionRule = {
|
|
|
13
15
|
!['img', 'source'].includes(value.tag)) {
|
|
14
16
|
return;
|
|
15
17
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
let hasValidWidth = false;
|
|
19
|
+
let hasValidHeight = false;
|
|
20
|
+
let hasValidAspectRatio = false;
|
|
21
|
+
if (isDefined(value.attrs.width)) {
|
|
22
|
+
const widthEval = contextlessEvaluateFormula(value.attrs.width);
|
|
23
|
+
// If dynamic, we assume it is valid
|
|
24
|
+
hasValidWidth ||= !widthEval.isStatic || checkValue(widthEval.result);
|
|
25
|
+
}
|
|
26
|
+
if (isDefined(value.attrs.height)) {
|
|
27
|
+
const heightEval = contextlessEvaluateFormula(value.attrs.height);
|
|
28
|
+
// If dynamic, we assume it is valid
|
|
29
|
+
hasValidHeight ||= !heightEval.isStatic || checkValue(heightEval.result);
|
|
19
30
|
}
|
|
20
|
-
|
|
31
|
+
;
|
|
32
|
+
[
|
|
21
33
|
value.style,
|
|
22
|
-
// We don't know the circumstances under which the style is applied, so we assume it is
|
|
34
|
+
// We don't know the circumstances under which the style is applied, so we assume it is fine if just one of the variants has correct dimensions
|
|
23
35
|
...(value.variants?.map((variant) => variant.style) ?? []),
|
|
24
|
-
].
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
return false;
|
|
34
|
-
})) {
|
|
36
|
+
].forEach((style) => {
|
|
37
|
+
hasValidWidth ||= checkValue(style?.width);
|
|
38
|
+
hasValidHeight ||= checkValue(style?.height);
|
|
39
|
+
hasValidAspectRatio ||= checkValue(style?.['aspect-ratio']);
|
|
40
|
+
});
|
|
41
|
+
// If two of the three values are truthy, the third can be derived
|
|
42
|
+
if ([hasValidWidth, hasValidHeight, hasValidAspectRatio].filter(Boolean)
|
|
43
|
+
.length >= 2) {
|
|
35
44
|
return;
|
|
36
45
|
}
|
|
37
46
|
report(path);
|
|
38
47
|
},
|
|
39
48
|
};
|
|
49
|
+
function checkValue(value) {
|
|
50
|
+
if (!isDefined(value)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (nonStaticDimensionKeywords.includes(value)) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
40
58
|
//# sourceMappingURL=imageWithoutDimensionRule.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imageWithoutDimensionRule.js","sourceRoot":"","sources":["../../../../src/rules/issues/dom/imageWithoutDimensionRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAA;
|
|
1
|
+
{"version":3,"file":"imageWithoutDimensionRule.js","sourceRoot":"","sources":["../../../../src/rules/issues/dom/imageWithoutDimensionRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAA;AAE3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAA;AAErF,MAAM,0BAA0B,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;AAC/C;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAS;IAC7C,IAAI,EAAE,yBAAyB;IAC/B,KAAK,EAAE,SAAS;IAChB,QAAQ,EAAE,aAAa;IACvB,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;QAC3C,IACE,QAAQ,KAAK,gBAAgB;YAC7B,KAAK,CAAC,IAAI,KAAK,SAAS;YACxB,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EACtC,CAAC;YACD,OAAM;QACR,CAAC;QAED,IAAI,aAAa,GAAG,KAAK,CAAA;QACzB,IAAI,cAAc,GAAG,KAAK,CAAA;QAC1B,IAAI,mBAAmB,GAAG,KAAK,CAAA;QAE/B,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACjC,MAAM,SAAS,GAAG,0BAA0B,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAC/D,oCAAoC;YACpC,aAAa,KAAK,CAAC,SAAS,CAAC,QAAQ,IAAI,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QACvE,CAAC;QAED,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YAClC,MAAM,UAAU,GAAG,0BAA0B,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;YACjE,oCAAoC;YACpC,cAAc,KAAK,CAAC,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;QAC1E,CAAC;QAED,CAAC;QAAA;YACC,KAAK,CAAC,KAAK;YACX,+IAA+I;YAC/I,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC3D,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YAClB,aAAa,KAAK,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;YAC1C,cAAc,KAAK,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;YAC5C,mBAAmB,KAAK,UAAU,CAAC,KAAK,EAAE,CAAC,cAAc,CAAC,CAAC,CAAA;QAC7D,CAAC,CAAC,CAAA;QAEF,kEAAkE;QAClE,IACE,CAAC,aAAa,EAAE,cAAc,EAAE,mBAAmB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;aACjE,MAAM,IAAI,CAAC,EACd,CAAC;YACD,OAAM;QACR,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,CAAA;IACd,CAAC;CACF,CAAA;AAED,SAAS,UAAU,CAAC,KAAsB;IACxC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,0BAA0B,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -143,5 +143,204 @@ describe('imageWithoutDimensionRule', () => {
|
|
|
143
143
|
expect(problems[0].code).toBe('image without dimension');
|
|
144
144
|
expect(problems[0].path).toEqual(['components', 'test', 'nodes', 'root']);
|
|
145
145
|
});
|
|
146
|
+
test('should report if only aspect-ratio is set', () => {
|
|
147
|
+
const problems = Array.from(searchProject({
|
|
148
|
+
files: {
|
|
149
|
+
formulas: {},
|
|
150
|
+
components: {
|
|
151
|
+
test: {
|
|
152
|
+
name: 'test',
|
|
153
|
+
nodes: {
|
|
154
|
+
root: {
|
|
155
|
+
type: 'element',
|
|
156
|
+
attrs: {},
|
|
157
|
+
classes: {},
|
|
158
|
+
events: {},
|
|
159
|
+
tag: 'source',
|
|
160
|
+
children: [],
|
|
161
|
+
style: {
|
|
162
|
+
'aspect-ratio': '16/9',
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
formulas: {},
|
|
167
|
+
apis: {},
|
|
168
|
+
attributes: {},
|
|
169
|
+
variables: {},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
rules: [imageWithoutDimensionRule],
|
|
174
|
+
}));
|
|
175
|
+
expect(problems).toHaveLength(1);
|
|
176
|
+
expect(problems[0].code).toBe('image without dimension');
|
|
177
|
+
expect(problems[0].path).toEqual(['components', 'test', 'nodes', 'root']);
|
|
178
|
+
});
|
|
179
|
+
test('should not report if aspect-ratio and one dimension is set', () => {
|
|
180
|
+
const problems = Array.from(searchProject({
|
|
181
|
+
files: {
|
|
182
|
+
formulas: {},
|
|
183
|
+
components: {
|
|
184
|
+
test: {
|
|
185
|
+
name: 'test',
|
|
186
|
+
nodes: {
|
|
187
|
+
root: {
|
|
188
|
+
type: 'element',
|
|
189
|
+
attrs: {
|
|
190
|
+
width: {
|
|
191
|
+
type: 'value',
|
|
192
|
+
value: '100',
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
classes: {},
|
|
196
|
+
events: {},
|
|
197
|
+
tag: 'img',
|
|
198
|
+
children: [],
|
|
199
|
+
style: {
|
|
200
|
+
'aspect-ratio': '16/9',
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
other: {
|
|
204
|
+
type: 'element',
|
|
205
|
+
attrs: {},
|
|
206
|
+
classes: {},
|
|
207
|
+
events: {},
|
|
208
|
+
tag: 'img',
|
|
209
|
+
children: [],
|
|
210
|
+
style: {
|
|
211
|
+
height: '200px',
|
|
212
|
+
'aspect-ratio': '4/3',
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
formulas: {},
|
|
217
|
+
apis: {},
|
|
218
|
+
attributes: {},
|
|
219
|
+
variables: {},
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
rules: [imageWithoutDimensionRule],
|
|
224
|
+
}));
|
|
225
|
+
expect(problems).toHaveLength(0);
|
|
226
|
+
});
|
|
227
|
+
test('should not report if dimensions are dynamic', () => {
|
|
228
|
+
const problems = Array.from(searchProject({
|
|
229
|
+
files: {
|
|
230
|
+
formulas: {},
|
|
231
|
+
components: {
|
|
232
|
+
test: {
|
|
233
|
+
name: 'test',
|
|
234
|
+
nodes: {
|
|
235
|
+
root: {
|
|
236
|
+
type: 'element',
|
|
237
|
+
attrs: {
|
|
238
|
+
width: {
|
|
239
|
+
type: 'path',
|
|
240
|
+
path: ['Variables', 'imageWidth'],
|
|
241
|
+
},
|
|
242
|
+
height: {
|
|
243
|
+
type: 'path',
|
|
244
|
+
path: ['Variables', 'imageHeight'],
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
classes: {},
|
|
248
|
+
events: {},
|
|
249
|
+
tag: 'img',
|
|
250
|
+
children: [],
|
|
251
|
+
style: {},
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
formulas: {},
|
|
255
|
+
apis: {},
|
|
256
|
+
attributes: {},
|
|
257
|
+
variables: {},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
rules: [imageWithoutDimensionRule],
|
|
262
|
+
}));
|
|
263
|
+
expect(problems).toHaveLength(0);
|
|
264
|
+
});
|
|
265
|
+
test('should not report non-image elements', () => {
|
|
266
|
+
const problems = Array.from(searchProject({
|
|
267
|
+
files: {
|
|
268
|
+
formulas: {},
|
|
269
|
+
components: {
|
|
270
|
+
test: {
|
|
271
|
+
name: 'test',
|
|
272
|
+
nodes: {
|
|
273
|
+
root: {
|
|
274
|
+
type: 'element',
|
|
275
|
+
attrs: {},
|
|
276
|
+
classes: {},
|
|
277
|
+
events: {},
|
|
278
|
+
tag: 'div',
|
|
279
|
+
children: [],
|
|
280
|
+
style: {},
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
formulas: {},
|
|
284
|
+
apis: {},
|
|
285
|
+
attributes: {},
|
|
286
|
+
variables: {},
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
rules: [imageWithoutDimensionRule],
|
|
291
|
+
}));
|
|
292
|
+
expect(problems).toHaveLength(0);
|
|
293
|
+
});
|
|
294
|
+
test('should report if dimensions are set to non-static keywords (auto | empty string)', () => {
|
|
295
|
+
const problems = Array.from(searchProject({
|
|
296
|
+
files: {
|
|
297
|
+
formulas: {},
|
|
298
|
+
components: {
|
|
299
|
+
test: {
|
|
300
|
+
name: 'test',
|
|
301
|
+
nodes: {
|
|
302
|
+
root: {
|
|
303
|
+
type: 'element',
|
|
304
|
+
attrs: {
|
|
305
|
+
width: {
|
|
306
|
+
type: 'value',
|
|
307
|
+
value: 'auto',
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
classes: {},
|
|
311
|
+
events: {},
|
|
312
|
+
tag: 'img',
|
|
313
|
+
children: [],
|
|
314
|
+
style: {
|
|
315
|
+
height: '',
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
other: {
|
|
319
|
+
type: 'element',
|
|
320
|
+
attrs: {},
|
|
321
|
+
classes: {},
|
|
322
|
+
events: {},
|
|
323
|
+
tag: 'source',
|
|
324
|
+
children: [],
|
|
325
|
+
style: {
|
|
326
|
+
width: '100%',
|
|
327
|
+
'aspect-ratio': 'auto',
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
formulas: {},
|
|
332
|
+
apis: {},
|
|
333
|
+
attributes: {},
|
|
334
|
+
variables: {},
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
rules: [imageWithoutDimensionRule],
|
|
339
|
+
}));
|
|
340
|
+
expect(problems).toHaveLength(2);
|
|
341
|
+
expect(problems[0].code).toBe('image without dimension');
|
|
342
|
+
expect(problems[0].path).toEqual(['components', 'test', 'nodes', 'root']);
|
|
343
|
+
expect(problems[1].path).toEqual(['components', 'test', 'nodes', 'other']);
|
|
344
|
+
});
|
|
146
345
|
});
|
|
147
346
|
//# sourceMappingURL=imageWithoutDimensionRule.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imageWithoutDimensionRule.test.js","sourceRoot":"","sources":["../../../../src/rules/issues/dom/imageWithoutDimensionRule.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA;AAEvE,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,IAAI,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAClD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CACzB,aAAa,CAAC;YACZ,KAAK,EAAE;gBACL,QAAQ,EAAE,EAAE;gBACZ,UAAU,EAAE;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,MAAM;wBACZ,KAAK,EAAE;4BACL,IAAI,EAAE;gCACJ,IAAI,EAAE,SAAS;gCACf,KAAK,EAAE,EAAE;gCACT,OAAO,EAAE,EAAE;gCACX,MAAM,EAAE,EAAE;gCACV,GAAG,EAAE,KAAK;gCACV,QAAQ,EAAE,EAAE;gCACZ,KAAK,EAAE,EAAE;6BACV;yBACF;wBACD,QAAQ,EAAE,EAAE;wBACZ,IAAI,EAAE,EAAE;wBACR,UAAU,EAAE,EAAE;wBACd,SAAS,EAAE,EAAE;qBACd;iBACF;aACF;YACD,KAAK,EAAE,CAAC,yBAAyB,CAAC;SACnC,CAAC,CACH,CAAA;QAED,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAChC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAA;QACxD,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAChE,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CACzB,aAAa,CAAC;YACZ,KAAK,EAAE;gBACL,QAAQ,EAAE,EAAE;gBACZ,UAAU,EAAE;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,MAAM;wBACZ,KAAK,EAAE;4BACL,IAAI,EAAE;gCACJ,IAAI,EAAE,SAAS;gCACf,KAAK,EAAE;oCACL,KAAK,EAAE;wCACL,IAAI,EAAE,OAAO;wCACb,KAAK,EAAE,KAAK;qCACb;oCACD,MAAM,EAAE;wCACN,IAAI,EAAE,OAAO;wCACb,KAAK,EAAE,KAAK;qCACb;iCACF;gCACD,OAAO,EAAE,EAAE;gCACX,MAAM,EAAE,EAAE;gCACV,GAAG,EAAE,KAAK;gCACV,QAAQ,EAAE,EAAE;gCACZ,KAAK,EAAE,EAAE;6BACV;yBACF;wBACD,QAAQ,EAAE,EAAE;wBACZ,IAAI,EAAE,EAAE;wBACR,UAAU,EAAE,EAAE;wBACd,SAAS,EAAE,EAAE;qBACd;iBACF;aACF;YACD,KAAK,EAAE,CAAC,yBAAyB,CAAC;SACnC,CAAC,CACH,CAAA;QAED,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,gDAAgD,EAAE,GAAG,EAAE;QAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CACzB,aAAa,CAAC;YACZ,KAAK,EAAE;gBACL,QAAQ,EAAE,EAAE;gBACZ,UAAU,EAAE;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,MAAM;wBACZ,KAAK,EAAE;4BACL,IAAI,EAAE;gCACJ,IAAI,EAAE,SAAS;gCACf,KAAK,EAAE;oCACL,KAAK,EAAE;wCACL,IAAI,EAAE,OAAO;wCACb,KAAK,EAAE,KAAK;qCACb;iCACF;gCACD,OAAO,EAAE,EAAE;gCACX,MAAM,EAAE,EAAE;gCACV,GAAG,EAAE,QAAQ;gCACb,QAAQ,EAAE,EAAE;gCACZ,KAAK,EAAE,EAAE;6BACV;yBACF;wBACD,QAAQ,EAAE,EAAE;wBACZ,IAAI,EAAE,EAAE;wBACR,UAAU,EAAE,EAAE;wBACd,SAAS,EAAE,EAAE;qBACd;iBACF;aACF;YACD,KAAK,EAAE,CAAC,yBAAyB,CAAC;SACnC,CAAC,CACH,CAAA;QAED,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAChC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAA;QACxD,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,gDAAgD,EAAE,GAAG,EAAE;QAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CACzB,aAAa,CAAC;YACZ,KAAK,EAAE;gBACL,QAAQ,EAAE,EAAE;gBACZ,UAAU,EAAE;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,MAAM;wBACZ,KAAK,EAAE;4BACL,IAAI,EAAE;gCACJ,IAAI,EAAE,SAAS;gCACf,KAAK,EAAE;oCACL,MAAM,EAAE;wCACN,IAAI,EAAE,OAAO;wCACb,KAAK,EAAE,KAAK;qCACb;iCACF;gCACD,OAAO,EAAE,EAAE;gCACX,MAAM,EAAE,EAAE;gCACV,GAAG,EAAE,QAAQ;gCACb,QAAQ,EAAE,EAAE;gCACZ,KAAK,EAAE,EAAE;6BACV;yBACF;wBACD,QAAQ,EAAE,EAAE;wBACZ,IAAI,EAAE,EAAE;wBACR,UAAU,EAAE,EAAE;wBACd,SAAS,EAAE,EAAE;qBACd;iBACF;aACF;YACD,KAAK,EAAE,CAAC,yBAAyB,CAAC;SACnC,CAAC,CACH,CAAA;QAED,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAChC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAA;QACxD,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
1
|
+
{"version":3,"file":"imageWithoutDimensionRule.test.js","sourceRoot":"","sources":["../../../../src/rules/issues/dom/imageWithoutDimensionRule.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/nordcraftengine/nordcraft",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@nordcraft/ssr": "1.0.
|
|
9
|
-
"@nordcraft/core": "1.0.
|
|
8
|
+
"@nordcraft/ssr": "1.0.61",
|
|
9
|
+
"@nordcraft/core": "1.0.61",
|
|
10
10
|
"jsondiffpatch": "0.7.3",
|
|
11
11
|
"postcss": "8.5.6"
|
|
12
12
|
},
|
|
@@ -20,5 +20,5 @@
|
|
|
20
20
|
"test:watch:only": "bun test --watch --only"
|
|
21
21
|
},
|
|
22
22
|
"files": ["dist", "src"],
|
|
23
|
-
"version": "1.0.
|
|
23
|
+
"version": "1.0.61"
|
|
24
24
|
}
|
|
@@ -157,4 +157,105 @@ describe('requiredElementAttributeRule', () => {
|
|
|
157
157
|
|
|
158
158
|
expect(problems).toHaveLength(0)
|
|
159
159
|
})
|
|
160
|
+
|
|
161
|
+
test('should report if attribute is false or null, as such attributes are not rendered', () => {
|
|
162
|
+
const problems = Array.from(
|
|
163
|
+
searchProject({
|
|
164
|
+
files: {
|
|
165
|
+
formulas: {},
|
|
166
|
+
components: {
|
|
167
|
+
test: {
|
|
168
|
+
name: 'test',
|
|
169
|
+
nodes: {
|
|
170
|
+
root: {
|
|
171
|
+
type: 'element',
|
|
172
|
+
attrs: {
|
|
173
|
+
alt: { type: 'value', value: null },
|
|
174
|
+
},
|
|
175
|
+
classes: {},
|
|
176
|
+
events: {},
|
|
177
|
+
tag: 'img',
|
|
178
|
+
children: [],
|
|
179
|
+
style: {},
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
formulas: {},
|
|
183
|
+
apis: {},
|
|
184
|
+
attributes: {},
|
|
185
|
+
variables: {},
|
|
186
|
+
},
|
|
187
|
+
test2: {
|
|
188
|
+
name: 'test2',
|
|
189
|
+
nodes: {
|
|
190
|
+
root: {
|
|
191
|
+
type: 'element',
|
|
192
|
+
attrs: {
|
|
193
|
+
alt: { type: 'value', value: false },
|
|
194
|
+
},
|
|
195
|
+
classes: {},
|
|
196
|
+
events: {},
|
|
197
|
+
tag: 'img',
|
|
198
|
+
children: [],
|
|
199
|
+
style: {},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
formulas: {},
|
|
203
|
+
apis: {},
|
|
204
|
+
attributes: {},
|
|
205
|
+
variables: {},
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
rules: [
|
|
210
|
+
createRequiredElementAttributeRule({ tag: 'img', attribute: 'alt' }),
|
|
211
|
+
],
|
|
212
|
+
}),
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
expect(problems).toHaveLength(2)
|
|
216
|
+
expect(problems[0].code).toBe('required element attribute')
|
|
217
|
+
expect(problems[0].path).toEqual(['components', 'test', 'nodes', 'root'])
|
|
218
|
+
expect(problems[1].code).toBe('required element attribute')
|
|
219
|
+
expect(problems[1].path).toEqual(['components', 'test2', 'nodes', 'root'])
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
test('should handle multiple acceptable attributes', () => {
|
|
223
|
+
const problems = Array.from(
|
|
224
|
+
searchProject({
|
|
225
|
+
files: {
|
|
226
|
+
formulas: {},
|
|
227
|
+
components: {
|
|
228
|
+
test: {
|
|
229
|
+
name: 'test',
|
|
230
|
+
nodes: {
|
|
231
|
+
root: {
|
|
232
|
+
type: 'element',
|
|
233
|
+
attrs: {
|
|
234
|
+
'aria-hidden': { type: 'value', value: 'true' },
|
|
235
|
+
},
|
|
236
|
+
classes: {},
|
|
237
|
+
events: {},
|
|
238
|
+
tag: 'a',
|
|
239
|
+
children: [],
|
|
240
|
+
style: {},
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
formulas: {},
|
|
244
|
+
apis: {},
|
|
245
|
+
attributes: {},
|
|
246
|
+
variables: {},
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
rules: [
|
|
251
|
+
createRequiredElementAttributeRule({
|
|
252
|
+
tag: 'a',
|
|
253
|
+
attribute: ['alt', 'aria-hidden'],
|
|
254
|
+
}),
|
|
255
|
+
],
|
|
256
|
+
}),
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
expect(problems).toHaveLength(0)
|
|
260
|
+
})
|
|
160
261
|
})
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import { isDefined } from '@nordcraft/core/dist/utils/util'
|
|
1
|
+
import { isDefined, toBoolean } from '@nordcraft/core/dist/utils/util'
|
|
2
2
|
import type { Level, Rule } from '../../../types'
|
|
3
|
+
import { contextlessEvaluateFormula } from '../../../util/contextlessEvaluateFormula'
|
|
3
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @param tag - The HTML tag of the element to check (e.g., 'img', 'a').
|
|
7
|
+
* @param attribute - The required attribute that must be present on the element (e.g., 'alt', 'href'). Can also be an array of attributes to check where any one being present is sufficient. Only the first attribute will be reported in the issue details.
|
|
8
|
+
* @param level - The severity level of the issue ('warning' by default).
|
|
9
|
+
* @param allowEmptyString - Whether to allow the attribute to be an empty string (false by default).
|
|
10
|
+
* @returns An issue rule that reports when an element of the specified tag is missing the specified attribute.
|
|
11
|
+
*/
|
|
4
12
|
export function createRequiredElementAttributeRule({
|
|
5
13
|
tag,
|
|
6
14
|
attribute,
|
|
@@ -8,13 +16,14 @@ export function createRequiredElementAttributeRule({
|
|
|
8
16
|
allowEmptyString = false,
|
|
9
17
|
}: {
|
|
10
18
|
tag: string
|
|
11
|
-
attribute: string
|
|
19
|
+
attribute: string | string[]
|
|
12
20
|
level?: Level
|
|
13
21
|
allowEmptyString?: boolean
|
|
14
22
|
}): Rule<{
|
|
15
23
|
tag: string
|
|
16
24
|
attribute: string
|
|
17
25
|
}> {
|
|
26
|
+
const mainAttribute = Array.isArray(attribute) ? attribute[0] : attribute
|
|
18
27
|
return {
|
|
19
28
|
code: 'required element attribute',
|
|
20
29
|
level: level,
|
|
@@ -25,19 +34,29 @@ export function createRequiredElementAttributeRule({
|
|
|
25
34
|
value.type === 'element' &&
|
|
26
35
|
value.tag === tag
|
|
27
36
|
) {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
const attributes = Array.isArray(attribute) ? attribute : [attribute]
|
|
38
|
+
if (
|
|
39
|
+
attributes.some((attr) => {
|
|
40
|
+
if (!isDefined(value.attrs[attr])) {
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
const { isStatic, result } = contextlessEvaluateFormula(
|
|
44
|
+
value.attrs[attr],
|
|
45
|
+
)
|
|
46
|
+
return (
|
|
47
|
+
// Dynamic attributes are considered valid
|
|
48
|
+
!isStatic ||
|
|
49
|
+
// Static attributes must be truthy as falsy values are not rendered
|
|
50
|
+
(isDefined(result) &&
|
|
51
|
+
toBoolean(result) &&
|
|
52
|
+
(allowEmptyString || result !== ''))
|
|
53
|
+
)
|
|
54
|
+
})
|
|
55
|
+
) {
|
|
56
|
+
return
|
|
40
57
|
}
|
|
58
|
+
|
|
59
|
+
report(path, { tag, attribute: mainAttribute })
|
|
41
60
|
}
|
|
42
61
|
},
|
|
43
62
|
}
|
|
@@ -159,4 +159,223 @@ describe('imageWithoutDimensionRule', () => {
|
|
|
159
159
|
expect(problems[0].code).toBe('image without dimension')
|
|
160
160
|
expect(problems[0].path).toEqual(['components', 'test', 'nodes', 'root'])
|
|
161
161
|
})
|
|
162
|
+
|
|
163
|
+
test('should report if only aspect-ratio is set', () => {
|
|
164
|
+
const problems = Array.from(
|
|
165
|
+
searchProject({
|
|
166
|
+
files: {
|
|
167
|
+
formulas: {},
|
|
168
|
+
components: {
|
|
169
|
+
test: {
|
|
170
|
+
name: 'test',
|
|
171
|
+
nodes: {
|
|
172
|
+
root: {
|
|
173
|
+
type: 'element',
|
|
174
|
+
attrs: {},
|
|
175
|
+
classes: {},
|
|
176
|
+
events: {},
|
|
177
|
+
tag: 'source',
|
|
178
|
+
children: [],
|
|
179
|
+
style: {
|
|
180
|
+
'aspect-ratio': '16/9',
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
formulas: {},
|
|
185
|
+
apis: {},
|
|
186
|
+
attributes: {},
|
|
187
|
+
variables: {},
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
rules: [imageWithoutDimensionRule],
|
|
192
|
+
}),
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
expect(problems).toHaveLength(1)
|
|
196
|
+
expect(problems[0].code).toBe('image without dimension')
|
|
197
|
+
expect(problems[0].path).toEqual(['components', 'test', 'nodes', 'root'])
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
test('should not report if aspect-ratio and one dimension is set', () => {
|
|
201
|
+
const problems = Array.from(
|
|
202
|
+
searchProject({
|
|
203
|
+
files: {
|
|
204
|
+
formulas: {},
|
|
205
|
+
components: {
|
|
206
|
+
test: {
|
|
207
|
+
name: 'test',
|
|
208
|
+
nodes: {
|
|
209
|
+
root: {
|
|
210
|
+
type: 'element',
|
|
211
|
+
attrs: {
|
|
212
|
+
width: {
|
|
213
|
+
type: 'value',
|
|
214
|
+
value: '100',
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
classes: {},
|
|
218
|
+
events: {},
|
|
219
|
+
tag: 'img',
|
|
220
|
+
children: [],
|
|
221
|
+
style: {
|
|
222
|
+
'aspect-ratio': '16/9',
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
other: {
|
|
226
|
+
type: 'element',
|
|
227
|
+
attrs: {},
|
|
228
|
+
classes: {},
|
|
229
|
+
events: {},
|
|
230
|
+
tag: 'img',
|
|
231
|
+
children: [],
|
|
232
|
+
style: {
|
|
233
|
+
height: '200px',
|
|
234
|
+
'aspect-ratio': '4/3',
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
formulas: {},
|
|
239
|
+
apis: {},
|
|
240
|
+
attributes: {},
|
|
241
|
+
variables: {},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
rules: [imageWithoutDimensionRule],
|
|
246
|
+
}),
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
expect(problems).toHaveLength(0)
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
test('should not report if dimensions are dynamic', () => {
|
|
253
|
+
const problems = Array.from(
|
|
254
|
+
searchProject({
|
|
255
|
+
files: {
|
|
256
|
+
formulas: {},
|
|
257
|
+
components: {
|
|
258
|
+
test: {
|
|
259
|
+
name: 'test',
|
|
260
|
+
nodes: {
|
|
261
|
+
root: {
|
|
262
|
+
type: 'element',
|
|
263
|
+
attrs: {
|
|
264
|
+
width: {
|
|
265
|
+
type: 'path',
|
|
266
|
+
path: ['Variables', 'imageWidth'],
|
|
267
|
+
},
|
|
268
|
+
height: {
|
|
269
|
+
type: 'path',
|
|
270
|
+
path: ['Variables', 'imageHeight'],
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
classes: {},
|
|
274
|
+
events: {},
|
|
275
|
+
tag: 'img',
|
|
276
|
+
children: [],
|
|
277
|
+
style: {},
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
formulas: {},
|
|
281
|
+
apis: {},
|
|
282
|
+
attributes: {},
|
|
283
|
+
variables: {},
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
rules: [imageWithoutDimensionRule],
|
|
288
|
+
}),
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
expect(problems).toHaveLength(0)
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
test('should not report non-image elements', () => {
|
|
295
|
+
const problems = Array.from(
|
|
296
|
+
searchProject({
|
|
297
|
+
files: {
|
|
298
|
+
formulas: {},
|
|
299
|
+
components: {
|
|
300
|
+
test: {
|
|
301
|
+
name: 'test',
|
|
302
|
+
nodes: {
|
|
303
|
+
root: {
|
|
304
|
+
type: 'element',
|
|
305
|
+
attrs: {},
|
|
306
|
+
classes: {},
|
|
307
|
+
events: {},
|
|
308
|
+
tag: 'div',
|
|
309
|
+
children: [],
|
|
310
|
+
style: {},
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
formulas: {},
|
|
314
|
+
apis: {},
|
|
315
|
+
attributes: {},
|
|
316
|
+
variables: {},
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
rules: [imageWithoutDimensionRule],
|
|
321
|
+
}),
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
expect(problems).toHaveLength(0)
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
test('should report if dimensions are set to non-static keywords (auto | empty string)', () => {
|
|
328
|
+
const problems = Array.from(
|
|
329
|
+
searchProject({
|
|
330
|
+
files: {
|
|
331
|
+
formulas: {},
|
|
332
|
+
components: {
|
|
333
|
+
test: {
|
|
334
|
+
name: 'test',
|
|
335
|
+
nodes: {
|
|
336
|
+
root: {
|
|
337
|
+
type: 'element',
|
|
338
|
+
attrs: {
|
|
339
|
+
width: {
|
|
340
|
+
type: 'value',
|
|
341
|
+
value: 'auto',
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
classes: {},
|
|
345
|
+
events: {},
|
|
346
|
+
tag: 'img',
|
|
347
|
+
children: [],
|
|
348
|
+
style: {
|
|
349
|
+
height: '',
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
other: {
|
|
353
|
+
type: 'element',
|
|
354
|
+
attrs: {},
|
|
355
|
+
classes: {},
|
|
356
|
+
events: {},
|
|
357
|
+
tag: 'source',
|
|
358
|
+
children: [],
|
|
359
|
+
style: {
|
|
360
|
+
width: '100%',
|
|
361
|
+
'aspect-ratio': 'auto',
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
formulas: {},
|
|
366
|
+
apis: {},
|
|
367
|
+
attributes: {},
|
|
368
|
+
variables: {},
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
rules: [imageWithoutDimensionRule],
|
|
373
|
+
}),
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
expect(problems).toHaveLength(2)
|
|
377
|
+
expect(problems[0].code).toBe('image without dimension')
|
|
378
|
+
expect(problems[0].path).toEqual(['components', 'test', 'nodes', 'root'])
|
|
379
|
+
expect(problems[1].path).toEqual(['components', 'test', 'nodes', 'other'])
|
|
380
|
+
})
|
|
162
381
|
})
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { isDefined } from '@nordcraft/core/dist/utils/util'
|
|
2
2
|
import type { Rule } from '../../../types'
|
|
3
|
+
import { contextlessEvaluateFormula } from '../../../util/contextlessEvaluateFormula'
|
|
3
4
|
|
|
5
|
+
const nonStaticDimensionKeywords = ['', 'auto']
|
|
4
6
|
/**
|
|
5
7
|
* Lighthouse reports a similar issue:
|
|
6
8
|
* https://web.dev/articles/optimize-cls?utm_source=lighthouse&utm_medium=devtools#images_without_dimensions
|
|
@@ -18,29 +20,36 @@ export const imageWithoutDimensionRule: Rule = {
|
|
|
18
20
|
return
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
let hasValidWidth = false
|
|
24
|
+
let hasValidHeight = false
|
|
25
|
+
let hasValidAspectRatio = false
|
|
26
|
+
|
|
27
|
+
if (isDefined(value.attrs.width)) {
|
|
28
|
+
const widthEval = contextlessEvaluateFormula(value.attrs.width)
|
|
29
|
+
// If dynamic, we assume it is valid
|
|
30
|
+
hasValidWidth ||= !widthEval.isStatic || checkValue(widthEval.result)
|
|
24
31
|
}
|
|
25
32
|
|
|
33
|
+
if (isDefined(value.attrs.height)) {
|
|
34
|
+
const heightEval = contextlessEvaluateFormula(value.attrs.height)
|
|
35
|
+
// If dynamic, we assume it is valid
|
|
36
|
+
hasValidHeight ||= !heightEval.isStatic || checkValue(heightEval.result)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
;[
|
|
40
|
+
value.style,
|
|
41
|
+
// We don't know the circumstances under which the style is applied, so we assume it is fine if just one of the variants has correct dimensions
|
|
42
|
+
...(value.variants?.map((variant) => variant.style) ?? []),
|
|
43
|
+
].forEach((style) => {
|
|
44
|
+
hasValidWidth ||= checkValue(style?.width)
|
|
45
|
+
hasValidHeight ||= checkValue(style?.height)
|
|
46
|
+
hasValidAspectRatio ||= checkValue(style?.['aspect-ratio'])
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
// If two of the three values are truthy, the third can be derived
|
|
26
50
|
if (
|
|
27
|
-
[
|
|
28
|
-
|
|
29
|
-
// We don't know the circumstances under which the style is applied, so we assume it is Okay if just one of the variants has correct style
|
|
30
|
-
...(value.variants?.map((variant) => variant.style) ?? []),
|
|
31
|
-
].some((style) => {
|
|
32
|
-
// Aspect ratio is not required if width and height are fixed
|
|
33
|
-
if (isDefined(style.width) && isDefined(style.height)) {
|
|
34
|
-
return true
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Aspect ratio is set explicitly
|
|
38
|
-
if (isDefined(style['aspect-ratio'])) {
|
|
39
|
-
return true
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return false
|
|
43
|
-
})
|
|
51
|
+
[hasValidWidth, hasValidHeight, hasValidAspectRatio].filter(Boolean)
|
|
52
|
+
.length >= 2
|
|
44
53
|
) {
|
|
45
54
|
return
|
|
46
55
|
}
|
|
@@ -48,3 +57,15 @@ export const imageWithoutDimensionRule: Rule = {
|
|
|
48
57
|
report(path)
|
|
49
58
|
},
|
|
50
59
|
}
|
|
60
|
+
|
|
61
|
+
function checkValue(value: any | undefined): boolean {
|
|
62
|
+
if (!isDefined(value)) {
|
|
63
|
+
return false
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (nonStaticDimensionKeywords.includes(value)) {
|
|
67
|
+
return false
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return true
|
|
71
|
+
}
|