Skip to content

Commit

Permalink
[New] no-danger: add customComponentNames option
Browse files Browse the repository at this point in the history
  • Loading branch information
akulsr0 authored and ljharb committed May 6, 2024
1 parent c58f04b commit 597553d
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 4 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,18 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
* [`jsx-handler-names`]: support ignoring component names ([#3772][] @akulsr0)
* version settings: Allow react defaultVersion to be configurable ([#3771][] @onlywei)
* [`jsx-closing-tag-location`]: add `line-aligned` option ([#3777] @kimtaejin3)
* [`no-danger`]: add `customComponentNames` option ([#3748][] @akulsr0)

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

e[#3782]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3782
[#3782]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3782
[#3777]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3777
[#3774]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3774
[#3772]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3772
[#3771]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3771
[#3759]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3759
[#3748]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3748
[#3724]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3724
[#3694]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3694

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

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

Expand Down
14 changes: 14 additions & 0 deletions docs/rules/no-danger.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ var React = require('react');
var Hello = <div>Hello World</div>;
```

## Rule Options

```js
...
"react/no-danger": [<enabled>, {
"customComponentNames": Array<string>,
}]
...
```

### customComponentNames

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.

## When Not To Use It

If you are certain the content passed to dangerouslySetInnerHTML is sanitized HTML you can disable this rule.
24 changes: 22 additions & 2 deletions lib/rules/no-danger.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

const has = require('hasown');
const fromEntries = require('object.fromentries/polyfill')();
const minimatch = require('minimatch');

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

messages,

schema: [],
schema: [{
type: 'object',
properties: {
customComponentNames: {
items: {
type: 'string',
},
minItems: 0,
type: 'array',
uniqueItems: true,
},
},
}],
},

create(context) {
const configuration = context.options[0] || {};
const customComponentNames = configuration.customComponentNames || [];

return {
JSXAttribute(node) {
if (jsxUtil.isDOMComponent(node.parent) && isDangerous(node.name.name)) {
const functionName = node.parent.name.name;

const enableCheckingCustomComponent = customComponentNames.some((name) => minimatch(functionName, name));

if ((enableCheckingCustomComponent || jsxUtil.isDOMComponent(node.parent)) && isDangerous(node.name.name)) {
report(context, messages.dangerousProp, 'dangerousProp', {
node,
data: {
Expand Down
86 changes: 86 additions & 0 deletions tests/lib/rules/no-danger.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,26 @@ ruleTester.run('no-danger', rule, {
{ code: '<App />;' },
{ code: '<App dangerouslySetInnerHTML={{ __html: "" }} />;' },
{ code: '<div className="bar"></div>;' },
{
code: '<div className="bar"></div>;',
options: [{ customComponentNames: ['*'] }],
},
{
code: `
function App() {
return <Title dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;
}
`,
options: [{ customComponentNames: ['Home'] }],
},
{
code: `
function App() {
return <TextMUI dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;
}
`,
options: [{ customComponentNames: ['MUI*'] }],
},
]),
invalid: parsers.all([
{
Expand All @@ -43,5 +63,71 @@ ruleTester.run('no-danger', rule, {
},
],
},
{
code: '<App dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;',
options: [{ customComponentNames: ['*'] }],
errors: [
{
messageId: 'dangerousProp',
data: { name: 'dangerouslySetInnerHTML' },
},
],
},
{
code: `
function App() {
return <Title dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;
}
`,
options: [{ customComponentNames: ['Title'] }],
errors: [
{
messageId: 'dangerousProp',
data: { name: 'dangerouslySetInnerHTML' },
},
],
},
{
code: `
function App() {
return <TextFoo dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;
}
`,
options: [{ customComponentNames: ['*Foo'] }],
errors: [
{
messageId: 'dangerousProp',
data: { name: 'dangerouslySetInnerHTML' },
},
],
},
{
code: `
function App() {
return <FooText dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;
}
`,
options: [{ customComponentNames: ['Foo*'] }],
errors: [
{
messageId: 'dangerousProp',
data: { name: 'dangerouslySetInnerHTML' },
},
],
},
{
code: `
function App() {
return <TextMUI dangerouslySetInnerHTML={{ __html: "<span>hello</span>" }} />;
}
`,
options: [{ customComponentNames: ['*MUI'] }],
errors: [
{
messageId: 'dangerousProp',
data: { name: 'dangerouslySetInnerHTML' },
},
],
},
]),
});

0 comments on commit 597553d

Please sign in to comment.