Skip to content

Commit 4da7451

Browse files
julienwljharb
authored andcommitted
[Fix] no-unknown-property: check attributes with any input case
1 parent facb65b commit 4da7451

File tree

3 files changed

+19
-9
lines changed

3 files changed

+19
-9
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
2121
* [`jsx-handler-names`]: false positive when handler name begins with number ([#1689][] @jsphstls)
2222
* [`prop-types`]: Detect JSX returned by sequential expression ([#2801][] @mikol)
2323
* [`jsx-props-no-multi-spaces`]: "Expected no line gap between" false positive ([#2792][] @karolina-benitez)
24+
* [`no-unknown-property`]: check attributes with any input case ([#2790][] @julienw)
2425

2526
### Changed
2627
* [Tests] [`jsx-one-expression-per-line`]: add passing tests ([#2799][] @TaLeaMonet)
@@ -30,6 +31,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
3031
[#2796]: https://github.com/yannickcr/eslint-plugin-react/pull/2796
3132
[#2792]: https://github.com/yannickcr/eslint-plugin-react/pull/2792
3233
[#2791]: https://github.com/yannickcr/eslint-plugin-react/pull/2791
34+
[#2790]: https://github.com/yannickcr/eslint-plugin-react/pull/2790
3335
[#2789]: https://github.com/yannickcr/eslint-plugin-react/pull/2789
3436
[#2782]: https://github.com/yannickcr/eslint-plugin-react/pull/2782
3537
[#2780]: https://github.com/yannickcr/eslint-plugin-react/pull/2780

lib/rules/no-unknown-property.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ function getDOMPropertyNames(context) {
147147
// ------------------------------------------------------------------------------
148148

149149
/**
150-
* Checks if a node matches the JSX tag convention.
150+
* Checks if a node matches the JSX tag convention. This also checks if a node
151+
* is extended as a webcomponent using the attribute "is".
151152
* @param {Object} node - JSX element being tested.
152153
* @returns {boolean} Whether or not the node name match the JSX tag convention.
153154
*/
@@ -194,7 +195,7 @@ function tagNameHasDot(node) {
194195
* Get the standard name of the attribute.
195196
* @param {String} name - Name of the attribute.
196197
* @param {String} context - eslint context
197-
* @returns {String} The standard name of the attribute.
198+
* @returns {String | undefined} The standard name of the attribute, or undefined if no standard name was found.
198199
*/
199200
function getStandardName(name, context) {
200201
if (DOM_ATTRIBUTE_NAMES[name]) {
@@ -203,13 +204,9 @@ function getStandardName(name, context) {
203204
if (SVGDOM_ATTRIBUTE_NAMES[name]) {
204205
return SVGDOM_ATTRIBUTE_NAMES[name];
205206
}
206-
let i = -1;
207207
const names = getDOMPropertyNames(context);
208-
const found = names.some((element, index) => {
209-
i = index;
210-
return element.toLowerCase() === name;
211-
});
212-
return found ? names[i] : null;
208+
// Let's find a possible attribute match with a case-insensitive search.
209+
return names.find((element) => element.toLowerCase() === name.toLowerCase());
213210
}
214211

215212
// ------------------------------------------------------------------------------
@@ -259,6 +256,8 @@ module.exports = {
259256
}
260257

261258
const tagName = getTagName(node);
259+
260+
// 1. Some attributes are allowed on some tags only.
262261
const allowedTags = ATTRIBUTE_TAGS_MAP[name];
263262
if (tagName && allowedTags && /[^A-Z]/.test(tagName.charAt(0)) && allowedTags.indexOf(tagName) === -1) {
264263
context.report({
@@ -272,8 +271,12 @@ module.exports = {
272271
});
273272
}
274273

274+
// 2. Otherwise, we'll try to find if the attribute is a close version
275+
// of what we should normally have with React. If yes, we'll report an
276+
// error. We don't want to report if the input attribute name is the
277+
// standard name though!
275278
const standardName = getStandardName(name, context);
276-
if (!isTagName(node) || !standardName) {
279+
if (!isTagName(node) || !standardName || standardName === name) {
277280
return;
278281
}
279282
context.report({

tests/lib/rules/no-unknown-property.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ ruleTester.run('no-unknown-property', rule, {
3737
{code: '<App xlink:href="bar" />;'},
3838
{code: '<App clip-path="bar" />;'},
3939
{code: '<div className="bar"></div>;'},
40+
{code: '<div onMouseDown={this._onMouseDown}></div>;'},
4041
{code: '<div data-foo="bar"></div>;'},
4142
{code: '<div class="foo" is="my-elem"></div>;'},
4243
{code: '<div {...this.props} class="foo" is="my-elem"></div>;'},
@@ -75,6 +76,10 @@ ruleTester.run('no-unknown-property', rule, {
7576
code: '<div onmousedown="bar"></div>;',
7677
output: '<div onMouseDown="bar"></div>;',
7778
errors: [{message: 'Unknown property \'onmousedown\' found, use \'onMouseDown\' instead'}]
79+
}, {
80+
code: '<div onMousedown="bar"></div>;',
81+
output: '<div onMouseDown="bar"></div>;',
82+
errors: [{message: 'Unknown property \'onMousedown\' found, use \'onMouseDown\' instead'}]
7883
}, {
7984
code: '<use xlink:href="bar" />;',
8085
output: '<use xlinkHref="bar" />;',

0 commit comments

Comments
 (0)