Skip to content

Commit 597553d

Browse files
akulsr0ljharb
authored andcommitted
[New] no-danger: add customComponentNames option
1 parent c58f04b commit 597553d

File tree

4 files changed

+126
-4
lines changed

4 files changed

+126
-4
lines changed

CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
1313
* [`jsx-handler-names`]: support ignoring component names ([#3772][] @akulsr0)
1414
* version settings: Allow react defaultVersion to be configurable ([#3771][] @onlywei)
1515
* [`jsx-closing-tag-location`]: add `line-aligned` option ([#3777] @kimtaejin3)
16+
* [`no-danger`]: add `customComponentNames` option ([#3748][] @akulsr0)
1617

1718
### Changed
1819
* [Refactor] `variableUtil`: Avoid creating a single flat variable scope for each lookup ([#3782][] @DanielRosenwasser)
1920

20-
e[#3782]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3782
21+
[#3782]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3782
2122
[#3777]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3777
2223
[#3774]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3774
2324
[#3772]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3772
2425
[#3771]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3771
2526
[#3759]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3759
27+
[#3748]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3748
2628
[#3724]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3724
2729
[#3694]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3694
2830

@@ -60,7 +62,7 @@ e[#3782]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3782
6062

6163
### Fixed
6264
* [`boolean-prop-naming`]: avoid a crash with a non-TSTypeReference type ([#3718][] @developer-bandi)
63-
* [`jsx-no-leaked-render`]: invalid report if left side is boolean ([#3746][] @akulsr0)
65+
* [`jsx-no-leaked-render`]: invalid report if left eside is boolean ([#3746][] @akulsr0)
6466
* [`jsx-closing-bracket-location`]: message shows `{{details}}` when there are no details ([#3759][] @mdjermanovic)
6567
* [`no-invalid-html-attribute`]: ensure error messages are correct ([#3759][] @mdjermanovic, @ljharb)
6668

docs/rules/no-danger.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@ var React = require('react');
2424
var Hello = <div>Hello World</div>;
2525
```
2626

27+
## Rule Options
28+
29+
```js
30+
...
31+
"react/no-danger": [<enabled>, {
32+
"customComponentNames": Array<string>,
33+
}]
34+
...
35+
```
36+
37+
### customComponentNames
38+
39+
Defaults to `[]`, if you want to enable this rule for all custom components you can pass `customComponentNames` as `['*']`, or else you can pass specific components name to the array.
40+
2741
## When Not To Use It
2842

2943
If you are certain the content passed to dangerouslySetInnerHTML is sanitized HTML you can disable this rule.

lib/rules/no-danger.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
const has = require('hasown');
99
const fromEntries = require('object.fromentries/polyfill')();
10+
const minimatch = require('minimatch');
1011

1112
const docsUrl = require('../util/docsUrl');
1213
const jsxUtil = require('../util/jsx');
@@ -55,13 +56,32 @@ module.exports = {
5556

5657
messages,
5758

58-
schema: [],
59+
schema: [{
60+
type: 'object',
61+
properties: {
62+
customComponentNames: {
63+
items: {
64+
type: 'string',
65+
},
66+
minItems: 0,
67+
type: 'array',
68+
uniqueItems: true,
69+
},
70+
},
71+
}],
5972
},
6073

6174
create(context) {
75+
const configuration = context.options[0] || {};
76+
const customComponentNames = configuration.customComponentNames || [];
77+
6278
return {
6379
JSXAttribute(node) {
64-
if (jsxUtil.isDOMComponent(node.parent) && isDangerous(node.name.name)) {
80+
const functionName = node.parent.name.name;
81+
82+
const enableCheckingCustomComponent = customComponentNames.some((name) => minimatch(functionName, name));
83+
84+
if ((enableCheckingCustomComponent || jsxUtil.isDOMComponent(node.parent)) && isDangerous(node.name.name)) {
6585
report(context, messages.dangerousProp, 'dangerousProp', {
6686
node,
6787
data: {

tests/lib/rules/no-danger.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,26 @@ ruleTester.run('no-danger', rule, {
3232
{ code: '<App />;' },
3333
{ code: '<App dangerouslySetInnerHTML={{ __html: "" }} />;' },
3434
{ code: '<div className="bar"></div>;' },
35+
{
36+
code: '<div className="bar"></div>;',
37+
options: [{ customComponentNames: ['*'] }],
38+
},
39+
{
40+
code: `
41+
function App() {
42+
return <Title dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;
43+
}
44+
`,
45+
options: [{ customComponentNames: ['Home'] }],
46+
},
47+
{
48+
code: `
49+
function App() {
50+
return <TextMUI dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;
51+
}
52+
`,
53+
options: [{ customComponentNames: ['MUI*'] }],
54+
},
3555
]),
3656
invalid: parsers.all([
3757
{
@@ -43,5 +63,71 @@ ruleTester.run('no-danger', rule, {
4363
},
4464
],
4565
},
66+
{
67+
code: '<App dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;',
68+
options: [{ customComponentNames: ['*'] }],
69+
errors: [
70+
{
71+
messageId: 'dangerousProp',
72+
data: { name: 'dangerouslySetInnerHTML' },
73+
},
74+
],
75+
},
76+
{
77+
code: `
78+
function App() {
79+
return <Title dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;
80+
}
81+
`,
82+
options: [{ customComponentNames: ['Title'] }],
83+
errors: [
84+
{
85+
messageId: 'dangerousProp',
86+
data: { name: 'dangerouslySetInnerHTML' },
87+
},
88+
],
89+
},
90+
{
91+
code: `
92+
function App() {
93+
return <TextFoo dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;
94+
}
95+
`,
96+
options: [{ customComponentNames: ['*Foo'] }],
97+
errors: [
98+
{
99+
messageId: 'dangerousProp',
100+
data: { name: 'dangerouslySetInnerHTML' },
101+
},
102+
],
103+
},
104+
{
105+
code: `
106+
function App() {
107+
return <FooText dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;
108+
}
109+
`,
110+
options: [{ customComponentNames: ['Foo*'] }],
111+
errors: [
112+
{
113+
messageId: 'dangerousProp',
114+
data: { name: 'dangerouslySetInnerHTML' },
115+
},
116+
],
117+
},
118+
{
119+
code: `
120+
function App() {
121+
return <TextMUI dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;
122+
}
123+
`,
124+
options: [{ customComponentNames: ['*MUI'] }],
125+
errors: [
126+
{
127+
messageId: 'dangerousProp',
128+
data: { name: 'dangerouslySetInnerHTML' },
129+
},
130+
],
131+
},
46132
]),
47133
});

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy