Skip to content

Commit 42c7e60

Browse files
authored
fix: allow some case-sensitive svg attributes in lowercase rule (#178)
1 parent 4399086 commit 42c7e60

File tree

5 files changed

+162
-11
lines changed

5 files changed

+162
-11
lines changed

.cspell.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"**/coverage/**",
1010
"**/out/**",
1111
"**/node_modules/**",
12-
"packages/website/**"
12+
"packages/website/**",
13+
"packages/eslint-plugin/types/**"
1314
],
1415
"words": [
1516
"rehype",
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
module.exports = [
2+
"allowReorder",
3+
"attributeName",
4+
"attributeType",
5+
"autoReverse",
6+
"baseFrequency",
7+
"baseProfile",
8+
"calcMode",
9+
"clipPath",
10+
"clipPathUnits",
11+
"contentScriptType",
12+
"contentStyleType",
13+
"diffuseConstant",
14+
"edgeMode",
15+
"externalResourcesRequired",
16+
"filterRes",
17+
"filterUnits",
18+
"glyphRef",
19+
"gradientTransform",
20+
"gradientUnits",
21+
"kernelMatrix",
22+
"kernelUnitLength",
23+
"keyPoints",
24+
"keySplines",
25+
"keyTimes",
26+
"lengthAdjust",
27+
"limitingConeAngle",
28+
"markerHeight",
29+
"markerUnits",
30+
"markerWidth",
31+
"maskContentUnits",
32+
"maskUnits",
33+
"numOctaves",
34+
"onBlur",
35+
"onChange",
36+
"onClick",
37+
"onFocus",
38+
"onKeyUp",
39+
"onLoad",
40+
"pathLength",
41+
"patternContentUnits",
42+
"patternTransform",
43+
"patternUnits",
44+
"pointsAtX",
45+
"pointsAtY",
46+
"pointsAtZ",
47+
"preserveAlpha",
48+
"preserveAspectRatio",
49+
"primitiveUnits",
50+
"refX",
51+
"refY",
52+
"repeatCount",
53+
"repeatDur",
54+
"requiredExtensions",
55+
"requiredFeatures",
56+
"specularConstant",
57+
"specularExponent",
58+
"spreadMethod",
59+
"startOffset",
60+
"stdDeviation",
61+
"stitchTiles",
62+
"surfaceScale",
63+
"systemLanguage",
64+
"tableValues",
65+
"targetX",
66+
"targetY",
67+
"textLength",
68+
"viewBox",
69+
"viewTarget",
70+
"xChannelSelector",
71+
"yChannelSelector",
72+
"zoomAndPan",
73+
];

packages/eslint-plugin/lib/rules/lowercase.js

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
const { NODE_TYPES } = require("@html-eslint/parser");
99
const { RULE_CATEGORY } = require("../constants");
10+
const SVG_CAMEL_CASE_ATTRIBUTES = require("../constants/svg-camel-case-attributes");
1011

1112
const MESSAGE_IDS = {
1213
UNEXPECTED: "unexpected",
@@ -33,6 +34,31 @@ module.exports = {
3334
},
3435

3536
create(context) {
37+
const allowedAttrKeySet = new Set(SVG_CAMEL_CASE_ATTRIBUTES);
38+
/**
39+
* @type {TagNode[]}
40+
*/
41+
const svgStack = [];
42+
43+
/**
44+
* @param {TagNode} node
45+
*/
46+
function enterSvg(node) {
47+
svgStack.push(node);
48+
}
49+
50+
function exitSvg() {
51+
svgStack.pop();
52+
}
53+
54+
/**
55+
* @param {string} key
56+
* @returns {boolean}
57+
*/
58+
function isAllowedAttributeKey(key) {
59+
return !!svgStack.length && allowedAttrKeySet.has(key);
60+
}
61+
3662
/**
3763
* @param {TagNode | StyleTagNode | ScriptTagNode} node
3864
*/
@@ -72,6 +98,9 @@ module.exports = {
7298
}
7399
if (node.attributes && node.attributes.length) {
74100
node.attributes.forEach((attribute) => {
101+
if (isAllowedAttributeKey(attribute.key.value)) {
102+
return;
103+
}
75104
if (attribute.key.value !== attribute.key.value.toLowerCase()) {
76105
context.report({
77106
node: attribute.key,
@@ -92,7 +121,20 @@ module.exports = {
92121
}
93122

94123
return {
95-
Tag: check,
124+
Tag(node) {
125+
if (node.name.toLocaleLowerCase() === "svg") {
126+
enterSvg(node);
127+
}
128+
check(node);
129+
},
130+
/**
131+
* @param {TagNode} node
132+
*/
133+
"Tag:exit"(node) {
134+
if (node.name.toLocaleLowerCase() === "svg") {
135+
exitSvg();
136+
}
137+
},
96138
StyleTag: check,
97139
ScriptTag: check,
98140
};

packages/eslint-plugin/tests/rules/lowercase.test.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,32 @@ ruleTester.run("lowercase", rule, {
1717
{
1818
code: "<style></style>",
1919
},
20+
// svg
21+
{
22+
code: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"></svg>`,
23+
},
24+
{
25+
code: `<svg viewBox="0 0 220 150" xmlns="http://www.w3.org/2000/svg">
26+
<rect x="0" y="0" width="100" height="100">
27+
<animate
28+
attributeType="XML"
29+
attributeName="y"
30+
from="0"
31+
to="50"
32+
dur="1s"
33+
repeatCount="5" />
34+
</rect>
35+
<rect x="120" y="0" width="100" height="100">
36+
<animate
37+
attributeType="XML"
38+
attributeName="y"
39+
from="0"
40+
to="50"
41+
dur="1s"
42+
repeatCount="indefinite" />
43+
</rect>
44+
</svg>`,
45+
},
2046
],
2147
invalid: [
2248
{
@@ -64,5 +90,14 @@ ruleTester.run("lowercase", rule, {
6490
},
6591
],
6692
},
93+
{
94+
code: `<svg xmlns="http://www.w3.org/2000/svg" STYLE="" viewBox="0 0 200 200"></svg>`,
95+
output: `<svg xmlns="http://www.w3.org/2000/svg" style="" viewBox="0 0 200 200"></svg>`,
96+
errors: [
97+
{
98+
message: "'STYLE' is not in lowercase.",
99+
},
100+
],
101+
},
67102
],
68103
});

yarn.lock

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,8 +1055,8 @@ __metadata:
10551055
version: 0.0.0-use.local
10561056
resolution: "@html-eslint/cli@workspace:packages/cli"
10571057
dependencies:
1058-
"@html-eslint/eslint-plugin": "npm:^0.22.0"
1059-
"@html-eslint/parser": "npm:^0.22.0"
1058+
"@html-eslint/eslint-plugin": "npm:^0.23.0"
1059+
"@html-eslint/parser": "npm:^0.23.0"
10601060
axios: "npm:^1.6.2"
10611061
chalk: "npm:^4.1.1"
10621062
eslint: "npm:^7.27.0"
@@ -1066,11 +1066,11 @@ __metadata:
10661066
languageName: unknown
10671067
linkType: soft
10681068

1069-
"@html-eslint/eslint-plugin@npm:^0.22.0, @html-eslint/eslint-plugin@workspace:packages/eslint-plugin":
1069+
"@html-eslint/eslint-plugin@npm:^0.23.0, @html-eslint/eslint-plugin@workspace:packages/eslint-plugin":
10701070
version: 0.0.0-use.local
10711071
resolution: "@html-eslint/eslint-plugin@workspace:packages/eslint-plugin"
10721072
dependencies:
1073-
"@html-eslint/parser": "npm:^0.22.0"
1073+
"@html-eslint/parser": "npm:^0.23.0"
10741074
"@types/eslint": "npm:^8.56.2"
10751075
"@types/estree": "npm:^0.0.47"
10761076
es-html-parser: "npm:^0.0.8"
@@ -1096,7 +1096,7 @@ __metadata:
10961096
languageName: unknown
10971097
linkType: soft
10981098

1099-
"@html-eslint/parser@npm:^0.22.0, @html-eslint/parser@workspace:packages/parser":
1099+
"@html-eslint/parser@npm:^0.23.0, @html-eslint/parser@workspace:packages/parser":
11001100
version: 0.0.0-use.local
11011101
resolution: "@html-eslint/parser@workspace:packages/parser"
11021102
dependencies:
@@ -1105,7 +1105,7 @@ __metadata:
11051105
languageName: unknown
11061106
linkType: soft
11071107

1108-
"@html-eslint/web-linter@npm:^0.22.0, @html-eslint/web-linter@workspace:packages/web-linter":
1108+
"@html-eslint/web-linter@npm:^0.23.0, @html-eslint/web-linter@workspace:packages/web-linter":
11091109
version: 0.0.0-use.local
11101110
resolution: "@html-eslint/web-linter@workspace:packages/web-linter"
11111111
dependencies:
@@ -15743,9 +15743,9 @@ __metadata:
1574315743
version: 0.0.0-use.local
1574415744
resolution: "website@workspace:packages/website"
1574515745
dependencies:
15746-
"@html-eslint/eslint-plugin": "npm:^0.22.0"
15747-
"@html-eslint/parser": "npm:^0.22.0"
15748-
"@html-eslint/web-linter": "npm:^0.22.0"
15746+
"@html-eslint/eslint-plugin": "npm:^0.23.0"
15747+
"@html-eslint/parser": "npm:^0.23.0"
15748+
"@html-eslint/web-linter": "npm:^0.23.0"
1574915749
"@parcel/transformer-sass": "npm:2.10.3"
1575015750
"@types/codemirror": "npm:^5.60.5"
1575115751
"@types/eslint": "npm:^8.56.2"

0 commit comments

Comments
 (0)