Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix no-unknown-property: check attributes with any input case #2790

Merged
merged 1 commit into from Sep 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -21,6 +21,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
* [`jsx-handler-names`]: false positive when handler name begins with number ([#1689][] @jsphstls)
* [`prop-types`]: Detect JSX returned by sequential expression ([#2801][] @mikol)
* [`jsx-props-no-multi-spaces`]: "Expected no line gap between" false positive ([#2792][] @karolina-benitez)
* [`no-unknown-property`]: check attributes with any input case ([#2790][] @julienw)

### Changed
* [Tests] [`jsx-one-expression-per-line`]: add passing tests ([#2799][] @TaLeaMonet)
Expand All @@ -30,6 +31,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
[#2796]: https://github.com/yannickcr/eslint-plugin-react/pull/2796
[#2792]: https://github.com/yannickcr/eslint-plugin-react/pull/2792
[#2791]: https://github.com/yannickcr/eslint-plugin-react/pull/2791
[#2790]: https://github.com/yannickcr/eslint-plugin-react/pull/2790
[#2789]: https://github.com/yannickcr/eslint-plugin-react/pull/2789
[#2782]: https://github.com/yannickcr/eslint-plugin-react/pull/2782
[#2780]: https://github.com/yannickcr/eslint-plugin-react/pull/2780
Expand Down
21 changes: 12 additions & 9 deletions lib/rules/no-unknown-property.js
Expand Up @@ -147,7 +147,8 @@ function getDOMPropertyNames(context) {
// ------------------------------------------------------------------------------

/**
* Checks if a node matches the JSX tag convention.
* Checks if a node matches the JSX tag convention. This also checks if a node
* is extended as a webcomponent using the attribute "is".
* @param {Object} node - JSX element being tested.
* @returns {boolean} Whether or not the node name match the JSX tag convention.
*/
Expand Down Expand Up @@ -194,7 +195,7 @@ function tagNameHasDot(node) {
* Get the standard name of the attribute.
* @param {String} name - Name of the attribute.
* @param {String} context - eslint context
* @returns {String} The standard name of the attribute.
* @returns {String | undefined} The standard name of the attribute, or undefined if no standard name was found.
*/
function getStandardName(name, context) {
if (DOM_ATTRIBUTE_NAMES[name]) {
Expand All @@ -203,13 +204,9 @@ function getStandardName(name, context) {
if (SVGDOM_ATTRIBUTE_NAMES[name]) {
return SVGDOM_ATTRIBUTE_NAMES[name];
}
let i = -1;
const names = getDOMPropertyNames(context);
const found = names.some((element, index) => {
i = index;
return element.toLowerCase() === name;
});
return found ? names[i] : null;
// Let's find a possible attribute match with a case-insensitive search.
return names.find((element) => element.toLowerCase() === name.toLowerCase());
}

// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -259,6 +256,8 @@ module.exports = {
}

const tagName = getTagName(node);

// 1. Some attributes are allowed on some tags only.
const allowedTags = ATTRIBUTE_TAGS_MAP[name];
if (tagName && allowedTags && /[^A-Z]/.test(tagName.charAt(0)) && allowedTags.indexOf(tagName) === -1) {
context.report({
Expand All @@ -272,8 +271,12 @@ module.exports = {
});
}

// 2. Otherwise, we'll try to find if the attribute is a close version
// of what we should normally have with React. If yes, we'll report an
// error. We don't want to report if the input attribute name is the
// standard name though!
const standardName = getStandardName(name, context);
if (!isTagName(node) || !standardName) {
if (!isTagName(node) || !standardName || standardName === name) {
return;
}
context.report({
Expand Down
5 changes: 5 additions & 0 deletions tests/lib/rules/no-unknown-property.js
Expand Up @@ -37,6 +37,7 @@ ruleTester.run('no-unknown-property', rule, {
{code: '<App xlink:href="bar" />;'},
{code: '<App clip-path="bar" />;'},
{code: '<div className="bar"></div>;'},
{code: '<div onMouseDown={this._onMouseDown}></div>;'},
{code: '<div data-foo="bar"></div>;'},
{code: '<div class="foo" is="my-elem"></div>;'},
{code: '<div {...this.props} class="foo" is="my-elem"></div>;'},
Expand Down Expand Up @@ -75,6 +76,10 @@ ruleTester.run('no-unknown-property', rule, {
code: '<div onmousedown="bar"></div>;',
output: '<div onMouseDown="bar"></div>;',
errors: [{message: 'Unknown property \'onmousedown\' found, use \'onMouseDown\' instead'}]
}, {
code: '<div onMousedown="bar"></div>;',
output: '<div onMouseDown="bar"></div>;',
errors: [{message: 'Unknown property \'onMousedown\' found, use \'onMouseDown\' instead'}]
}, {
code: '<use xlink:href="bar" />;',
output: '<use xlinkHref="bar" />;',
Expand Down