Skip to content

Commit bb8c181

Browse files
authored
Merge branch 'master' into ross-fix-sort-props-test-cases
2 parents 2cc1d30 + 5baa3e0 commit bb8c181

7 files changed

+92
-8
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,19 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
88
### Fixed
99
* [`no-unknown-property`]: add `dialog` attributes ([#3436][] @ljharb)
1010
* [`no-arrow-function-lifecycle`]: when converting from an arrow, remove the semi and wrapping parens ([#3337][] @ljharb)
11+
* [`jsx-key`]: Ignore elements inside `React.Children.toArray()` ([#1591][] @silvenon)
12+
* [`jsx-no-constructed-context-values`]: fix false positive for usage in non-components ([#3448][] @golopot)
1113

14+
### Changed
15+
* [Docs] [`no-unknown-property`]: fix typo in link ([#3445][] @denkristoffer)
16+
* [Perf] component detection: improve performance by optimizing getId ([#3451][] @golopot)
17+
18+
[#3451]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3451
19+
[#3448]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3448
20+
[#3445]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3445
1221
[#3436]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3436
1322
[#3337]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3337
23+
[#1591]: https://github.com/jsx-eslint/eslint-plugin-react/pull/1591
1424

1525
## [7.31.8] - 2022.09.08
1626

docs/rules/no-unknown-property.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ var AtomPanel = <atom-panel class="foo"></atom-panel>;
5858

5959
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.
6060

61-
For example, if you use [emotion](https://emotion.sh/docs/introduction) and its [`css` prop](https://emotion.sh/docs/css-prop)),
61+
For example, if you use [emotion](https://emotion.sh/docs/introduction) and its [`css` prop](https://emotion.sh/docs/css-prop),
6262
add the following to your `.eslintrc` config file:
6363

6464
```js

lib/rules/jsx-key.js

+32-1
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,33 @@ module.exports = {
155155
}
156156
}
157157

158+
const childrenToArraySelector = `:matches(
159+
CallExpression
160+
[callee.object.object.name=${reactPragma}]
161+
[callee.object.property.name=Children]
162+
[callee.property.name=toArray],
163+
CallExpression
164+
[callee.object.name=Children]
165+
[callee.property.name=toArray]
166+
)`.replace(/\s/g, '');
167+
let isWithinChildrenToArray = false;
168+
158169
const seen = new WeakSet();
159170

160171
return {
172+
[childrenToArraySelector]() {
173+
isWithinChildrenToArray = true;
174+
},
175+
176+
[`${childrenToArraySelector}:exit`]() {
177+
isWithinChildrenToArray = false;
178+
},
179+
161180
'ArrayExpression, JSXElement > JSXElement'(node) {
181+
if (isWithinChildrenToArray) {
182+
return;
183+
}
184+
162185
const jsx = (node.type === 'ArrayExpression' ? node.elements : node.parent.children).filter((x) => x && x.type === 'JSXElement');
163186
if (jsx.length === 0) {
164187
return;
@@ -205,7 +228,7 @@ module.exports = {
205228
},
206229

207230
JSXFragment(node) {
208-
if (!checkFragmentShorthand) {
231+
if (!checkFragmentShorthand || isWithinChildrenToArray) {
209232
return;
210233
}
211234

@@ -226,6 +249,10 @@ module.exports = {
226249
CallExpression[callee.type="OptionalMemberExpression"][callee.property.name="map"],\
227250
OptionalCallExpression[callee.type="MemberExpression"][callee.property.name="map"],\
228251
OptionalCallExpression[callee.type="OptionalMemberExpression"][callee.property.name="map"]'(node) {
252+
if (isWithinChildrenToArray) {
253+
return;
254+
}
255+
229256
const fn = node.arguments.length > 0 && node.arguments[0];
230257
if (!fn || !astUtil.isFunctionLikeExpression(fn)) {
231258
return;
@@ -238,6 +265,10 @@ module.exports = {
238265

239266
// Array.from
240267
'CallExpression[callee.type="MemberExpression"][callee.property.name="from"]'(node) {
268+
if (isWithinChildrenToArray) {
269+
return;
270+
}
271+
241272
const fn = node.arguments.length > 1 && node.arguments[1];
242273
if (!astUtil.isFunctionLikeExpression(fn)) {
243274
return;

lib/rules/jsx-no-constructed-context-values.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
'use strict';
88

9+
const Components = require('../util/Components');
910
const docsUrl = require('../util/docsUrl');
1011
const report = require('../util/report');
1112

@@ -139,7 +140,8 @@ module.exports = {
139140
messages,
140141
},
141142

142-
create(context) {
143+
// eslint-disable-next-line arrow-body-style
144+
create: Components.detect((context, components, utils) => {
143145
return {
144146
JSXOpeningElement(node) {
145147
const openingElementName = node.name;
@@ -184,6 +186,10 @@ module.exports = {
184186
return;
185187
}
186188

189+
if (!utils.getParentComponent(node)) {
190+
return;
191+
}
192+
187193
// Report found error
188194
const constructType = constructInfo.type;
189195
const constructNode = constructInfo.node;
@@ -214,5 +220,5 @@ module.exports = {
214220
});
215221
},
216222
};
217-
},
223+
}),
218224
};

lib/util/Components.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const isFirstLetterCapitalized = require('./isFirstLetterCapitalized');
2121
const isDestructuredFromPragmaImport = require('./isDestructuredFromPragmaImport');
2222

2323
function getId(node) {
24-
return node && node.range.join(':');
24+
return node ? `${node.range[0]}:${node.range[1]}` : '';
2525
}
2626

2727
function usedPropTypesAreEquivalent(propA, propB) {

tests/lib/rules/jsx-key.js

+27
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,33 @@ ruleTester.run('jsx-key', rule, {
176176
`,
177177
features: ['types', 'no-babel-old'],
178178
},
179+
{ code: 'React.Children.toArray([1, 2 ,3].map(x => <App />));' },
180+
{
181+
code: `
182+
import { Children } from "react";
183+
Children.toArray([1, 2 ,3].map(x => <App />));
184+
`,
185+
},
186+
{
187+
// TODO: uncomment the commented lines below
188+
code: `
189+
import Act from 'react';
190+
import { Children as ReactChildren } from 'react';
191+
192+
const { Children } = Act;
193+
const { toArray } = Children;
194+
195+
Act.Children.toArray([1, 2 ,3].map(x => <App />));
196+
Act.Children.toArray(Array.from([1, 2 ,3], x => <App />));
197+
Children.toArray([1, 2 ,3].map(x => <App />));
198+
Children.toArray(Array.from([1, 2 ,3], x => <App />));
199+
// ReactChildren.toArray([1, 2 ,3].map(x => <App />));
200+
// ReactChildren.toArray(Array.from([1, 2 ,3], x => <App />));
201+
// toArray([1, 2 ,3].map(x => <App />));
202+
// toArray(Array.from([1, 2 ,3], x => <App />));
203+
`,
204+
settings,
205+
},
179206
]),
180207
invalid: parsers.all([
181208
{

tests/lib/rules/jsx-no-constructed-context-values.js

+13-3
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ const ruleTester = new RuleTester({ parserOptions });
3131
ruleTester.run('react-no-constructed-context-values', rule, {
3232
valid: parsers.all([
3333
{
34-
code: '<Context.Provider value={props}></Context.Provider>',
34+
code: 'const Component = () => <Context.Provider value={props}></Context.Provider>',
3535
},
3636
{
37-
code: '<Context.Provider value={100}></Context.Provider>',
37+
code: 'const Component = () => <Context.Provider value={100}></Context.Provider>',
3838
},
3939
{
40-
code: '<Context.Provider value="Some string"></Context.Provider>',
40+
code: 'const Component = () => <Context.Provider value="Some string"></Context.Provider>',
4141
},
4242
{
4343
code: 'function Component() { const foo = useMemo(() => { return {} }, []); return (<Context.Provider value={foo}></Context.Provider>)}',
@@ -137,6 +137,16 @@ ruleTester.run('react-no-constructed-context-values', rule, {
137137
}
138138
`,
139139
},
140+
{
141+
code: `
142+
const root = ReactDOM.createRoot(document.getElementById('root'));
143+
root.render(
144+
<AppContext.Provider value={{}}>
145+
<AppView />
146+
</AppContext.Provider>
147+
);
148+
`,
149+
},
140150
]),
141151
invalid: parsers.all([
142152
{

0 commit comments

Comments
 (0)