Skip to content

Commit 70e6019

Browse files
HermanBilousljharb
authored andcommitted
[New] no-unknown-property: add requireDataLowercase option
Fixes #3643
1 parent ca30f77 commit 70e6019

File tree

4 files changed

+63
-2
lines changed

4 files changed

+63
-2
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
88
### Added
99
* [`sort-prop-types`]: give errors on TS types ([#3615][] @akulsr0)
1010
* [`no-invalid-html-attribute`]: add support for `apple-touch-startup-image` `rel` attributes in `link` tags ([#3638][] @thomashockaday)
11+
* [`no-unknown-property`]: add requireDataLowercase option ([#3645][] @HermanBilous)
1112

1213
### Fixed
1314
* [`jsx-no-leaked-render`]: preserve RHS parens for multiline jsx elements while fixing ([#3623][] @akulsr0)
@@ -20,6 +21,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
2021
* [Refactor] [`function-component-definition`]: exit early if no type params ([#3634][] @HenryBrown0)
2122
* [Refactor] [`jsx-props-no-multi-spaces`]: extract type parameters to var ([#3634][] @HenryBrown0)
2223

24+
[#3645]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3645
2325
[#3638]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3638
2426
[#3634]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3634
2527
[#3633]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3633

docs/rules/no-unknown-property.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,13 @@ var AtomPanel = <atom-panel class="foo"></atom-panel>;
5151

5252
```js
5353
...
54-
"react/no-unknown-property": [<enabled>, { ignore: <ignore> }]
54+
"react/no-unknown-property": [<enabled>, { ignore: <ignore>, requireDataLowercase: <requireDataLowercase> }]
5555
...
5656
```
5757

5858
- `enabled`: for enabling the rule. 0=off, 1=warn, 2=error. Defaults to 0.
5959
- `ignore`: optional array of property and attribute names to ignore during validation.
60+
- `requireDataLowercase`: optional (default: `false`), require data-\* attributes to contain only lowercase characters. React will issue a warning when data-\* attributes contain uppercase characters. In order to catch such attributes, set the `requireDataLowercase` option to `true`.
6061

6162
If you are using a library that passes something as a prop to JSX elements, it is recommended to add those props to the ignored properties.
6263

lib/rules/no-unknown-property.js

+35-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const report = require('../util/report');
1616

1717
const DEFAULTS = {
1818
ignore: [],
19+
requireDataLowercase: false,
1920
};
2021

2122
const DOM_ATTRIBUTE_NAMES = {
@@ -429,6 +430,16 @@ function isValidDataAttribute(name) {
429430
return /^data(-[^:]*)*$/.test(name) && !/^data-xml/i.test(name);
430431
}
431432

433+
/**
434+
* Checks if an attribute name has at least one uppercase characters
435+
*
436+
* @param {String} name
437+
* @returns {boolean} Result
438+
*/
439+
function hasUpperCaseCharacter(name) {
440+
return name.toLowerCase() !== name;
441+
}
442+
432443
/**
433444
* Checks if an attribute name is a standard aria attribute by compering it to a list
434445
* of standard aria property names
@@ -493,6 +504,7 @@ const messages = {
493504
invalidPropOnTag: 'Invalid property \'{{name}}\' found on tag \'{{tagName}}\', but it is only allowed on: {{allowedTags}}',
494505
unknownPropWithStandardName: 'Unknown property \'{{name}}\' found, use \'{{standardName}}\' instead',
495506
unknownProp: 'Unknown property \'{{name}}\' found',
507+
dataLowercaseRequired: 'React does not recognize data-* props with uppercase characters on a DOM element. Found \'{{name}}\', use \'{{lowerCaseName}}\' instead',
496508
};
497509

498510
module.exports = {
@@ -516,6 +528,10 @@ module.exports = {
516528
type: 'string',
517529
},
518530
},
531+
requireDataLowercase: {
532+
type: 'boolean',
533+
default: false,
534+
},
519535
},
520536
additionalProperties: false,
521537
}],
@@ -526,6 +542,12 @@ module.exports = {
526542
return (context.options[0] && context.options[0].ignore) || DEFAULTS.ignore;
527543
}
528544

545+
function getRequireDataLowercase() {
546+
return (context.options[0] && typeof context.options[0].requireDataLowercase !== 'undefined')
547+
? !!context.options[0].requireDataLowercase
548+
: DEFAULTS.requireDataLowercase;
549+
}
550+
529551
return {
530552
JSXAttribute(node) {
531553
const ignoreNames = getIgnoreConfig();
@@ -540,7 +562,19 @@ module.exports = {
540562
return;
541563
}
542564

543-
if (isValidDataAttribute(name)) { return; }
565+
if (isValidDataAttribute(name)) {
566+
if (getRequireDataLowercase() && hasUpperCaseCharacter(name)) {
567+
report(context, messages.dataLowercaseRequired, 'dataLowercaseRequired', {
568+
node,
569+
data: {
570+
name: actualName,
571+
lowerCaseName: actualName.toLowerCase(),
572+
},
573+
});
574+
}
575+
576+
return;
577+
}
544578

545579
if (isValidAriaAttribute(name)) { return; }
546580

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

+24
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ ruleTester.run('no-unknown-property', rule, {
9999
{ code: '<div data-index-number="1234"></div>;' },
100100
{ code: '<div data-e2e-id="5678"></div>;' },
101101
{ code: '<div data-testID="bar" data-under_sCoRe="bar" />;' },
102+
{
103+
code: '<div data-testID="bar" data-under_sCoRe="bar" />;',
104+
options: [{ requireDataLowercase: false }],
105+
},
102106
// Ignoring should work
103107
{
104108
code: '<div class="bar"></div>;',
@@ -573,6 +577,26 @@ ruleTester.run('no-unknown-property', rule, {
573577
},
574578
],
575579
},
580+
{
581+
code: '<div data-testID="bar" data-under_sCoRe="bar" />;',
582+
errors: [
583+
{
584+
messageId: 'dataLowercaseRequired',
585+
data: {
586+
name: 'data-testID',
587+
lowerCaseName: 'data-testid',
588+
},
589+
},
590+
{
591+
messageId: 'dataLowercaseRequired',
592+
data: {
593+
name: 'data-under_sCoRe',
594+
lowerCaseName: 'data-under_score',
595+
},
596+
},
597+
],
598+
options: [{ requireDataLowercase: true }],
599+
},
576600
{
577601
code: '<div abbr="abbr" />',
578602
errors: [

0 commit comments

Comments
 (0)