Skip to content

Commit 01ac0a2

Browse files
authored
Merge branch 'master' into issue-3686
2 parents 40beeb5 + 9668ee0 commit 01ac0a2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1946
-282
lines changed

.github/workflows/node-18+.yml

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,64 @@ jobs:
3838
- 10
3939
- 9
4040
- 8
41+
typescript-eslint:
42+
- 5
43+
- 6
44+
- 7
45+
- 8
46+
exclude:
47+
- eslint: 3
48+
babel-eslint: 10
49+
- eslint: 3
50+
typescript-eslint: 5
51+
- eslint: 4
52+
typescript-eslint: 5
53+
- eslint: 4.14
54+
typescript-eslint: 5
55+
- eslint: 5
56+
typescript-eslint: 5
57+
- eslint: 3
58+
typescript-eslint: 6
59+
- eslint: 4
60+
typescript-eslint: 6
61+
- eslint: 4.14
62+
typescript-eslint: 6
63+
- eslint: 5
64+
typescript-eslint: 6
65+
- eslint: 6
66+
typescript-eslint: 6
67+
- eslint: 9
68+
typescript-eslint: 6
69+
- eslint: 3
70+
typescript-eslint: 7
71+
- eslint: 4
72+
typescript-eslint: 7
73+
- eslint: 4.14
74+
typescript-eslint: 7
75+
- eslint: 5
76+
typescript-eslint: 7
77+
- eslint: 6
78+
typescript-eslint: 7
79+
- eslint: 7
80+
typescript-eslint: 7
81+
- eslint: 9
82+
typescript-eslint: 7
83+
- eslint: 3
84+
typescript-eslint: 8
85+
- eslint: 4
86+
typescript-eslint: 8
87+
- eslint: 4.14
88+
typescript-eslint: 8
89+
- eslint: 5
90+
typescript-eslint: 8
91+
- eslint: 6
92+
typescript-eslint: 8
93+
- eslint: 7
94+
typescript-eslint: 8
95+
- eslint: 9
96+
typescript-eslint: 5
97+
- node-version: 19
98+
typescript-eslint: 7
4199

42100
steps:
43101
- uses: actions/checkout@v4
@@ -46,9 +104,9 @@ jobs:
46104
with:
47105
node-version: ${{ matrix.node-version }}
48106
after_install: |
49-
npm install --no-save "eslint@${{ matrix.eslint }}" "@typescript-eslint/parser@5" "babel-eslint@${{ matrix.babel-eslint }}"
107+
npm install --no-save "eslint@${{ matrix.eslint }}" "@typescript-eslint/parser@${{ matrix.typescript-eslint }}" "babel-eslint@${{ matrix.babel-eslint }}"
50108
env:
51-
NPM_CONFIG_LEGACY_PEER_DEPS: true
109+
NPM_CONFIG_LEGACY_PEER_DEPS: "${{ matrix.typescript-eslint >= 6 && 'false' || 'true' }}"
52110
- run: npx ls-engines
53111
- run: npm run unit-test
54112
- uses: codecov/[email protected]

.github/workflows/node-minors.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ jobs:
100100
with:
101101
node-version: ${{ matrix.node-version }}
102102
after_install: |
103-
npm install --no-save "eslint@${{ matrix.eslint }}" "@typescript-eslint/parser@${{ matrix.node-version >= 14 && '5' || (matrix.node-version >= 12 && '4' || (matrix.node-version >= 10 && '4.0' || (matrix.node-version >= 8 && '3' || '2'))) }}" "babel-eslint@${{ matrix.babel-eslint }}"
103+
npm install --no-save "eslint@${{ matrix.eslint }}" "@typescript-eslint/parser@${{ matrix.node-version >= 18 && matrix.eslint >= 8 && '8' || (matrix.node-version >= 16 && matrix.eslint >= 7 && '6' || (matrix.node-version >= 14 && '5' || (matrix.node-version >= 12 && '4' || (matrix.node-version >= 10 && '4.0' || (matrix.node-version >= 8 && '3' || '2'))))) }}" "babel-eslint@${{ matrix.babel-eslint }}"
104104
skip-ls-check: ${{ matrix.node-version < 10 && true || false }}
105105
env:
106-
NPM_CONFIG_LEGACY_PEER_DEPS: true
106+
NPM_CONFIG_LEGACY_PEER_DEPS: "${{ matrix.node-version >= 16 && matrix.eslint >= 7 && 'false' || 'true' }}"
107107
- run: npx ls-engines
108108
if: ${{ matrix.node-version >= 12 }}
109109
- run: npm run unit-test

.github/workflows/release.yml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,29 @@ jobs:
3737
id: changelog
3838
run: |
3939
# Parse the changelog for common links
40-
_links="$(grep -P '^\[.*]:.+' ${GITHUB_WORKSPACE}/CHANGELOG.md | sort -u)"
40+
_links="$(egrep '^\[.*]:.+' ${GITHUB_WORKSPACE:-.}/CHANGELOG.md | sort -u)"
4141
_links="${_links//'%'/'%25'}"
42-
_links="${_links//$'\n'/'%0A'}"
42+
# _links="${_links//$'\n'/'%0A'}"
4343
_links="${_links//$'\r'/'%0D'}"
4444
# Set output 'links' to $_links
4545
DELIMITER=$(uuidgen)
4646
echo "links<<${DELIMITER}" >> "${GITHUB_OUTPUT}"
4747
echo "$_links" >> "${GITHUB_OUTPUT}"
4848
echo "${DELIMITER}" >> "${GITHUB_OUTPUT}"
4949
50-
- uses: softprops/action-gh-release@v1
50+
- id: prune-footnotes
51+
run: |
52+
cat << 'EOF' > tmp.md
53+
${{ steps.changelog_reader.outputs.changes }}
54+
${{ steps.changelog.outputs.links }}
55+
EOF
56+
57+
DELIMITER=$(uuidgen)
58+
echo "body<<${DELIMITER}" >> "${GITHUB_OUTPUT}"
59+
npx gfm-footnotes -i tmp.md > "${GITHUB_OUTPUT}"
60+
echo "${DELIMITER}" >> "${GITHUB_OUTPUT}"
61+
62+
- uses: softprops/action-gh-release@v2
5163
with:
5264
body: |
53-
${{ steps.changelog_reader.outputs.changes }}
54-
${{ steps.changelog.outputs.links }}
65+
${{ steps.prune-footnotes.outputs.body }}

CHANGELOG.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,64 @@
11
# Change Log
2+
23
All notable changes to this project will be documented in this file.
34
This project adheres to [Semantic Versioning](https://semver.org/).
45
This change log adheres to standards from [Keep a CHANGELOG](https://keepachangelog.com).
56

67
## Unreleased
78

9+
## [7.36.1] - 2024.09.12
10+
11+
### Fixed
12+
* [`no-is-mounted`]: fix logic in method name check ([#3821][] @Mathias-S)
13+
* [`jsx-no-literals`]: Avoid crashing on valueless boolean props ([#3823][] @reosarevok)
14+
15+
[7.36.1]: https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.36.0...v7.36.1
16+
[#3823]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3823
17+
[#3821]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3821
18+
19+
## [7.36.0] - 2024.09.12
20+
21+
### Added
22+
* [`no-string-refs`]: allow this.refs in > 18.3.0 ([#3807][] @henryqdineen)
23+
* [`jsx-no-literals`] Add `elementOverrides` option and the ability to ignore this rule on specific elements ([#3812][] @Pearce-Ropion)
24+
* [`forward-ref-uses-ref`]: add rule for checking ref parameter is added ([#3667][] @NotWoods)
25+
26+
### Fixed
27+
* [`function-component-definition`], [`boolean-prop-naming`], [`jsx-first-prop-new-line`], [`jsx-props-no-multi-spaces`], `propTypes`: use type args ([#3629][] @HenryBrown0)
28+
* JSX pragma: fail gracefully ([#3632][] @ljharb)
29+
* [`jsx-props-no-spreading`]: add `explicitSpread` option to schema ([#3799][] @ljharb)
30+
31+
### Changed
32+
* [Tests] add @typescript-eslint/parser v6 ([#3629][] @HenryBrown0)
33+
* [Tests] add @typescript-eslint/parser v7 and v8 ([#3629][] @hampustagerud)
34+
* [Docs] [`no-danger`]: update broken link ([#3817][] @lucasrmendonca)
35+
* [types] add jsdoc type annotations ([#3731][] @y-hsgw)
36+
* [Tests] `button-has-type`: add test case with spread ([#3731][] @y-hsgw)
37+
38+
[7.36.0]: https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.35.2...v7.36.0
39+
[#3799]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3799
40+
[#3632]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3632
41+
[#3812]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3812
42+
[#3731]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3731
43+
[#3694]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3667
44+
[#3629]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3629
45+
[#3817]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3817
46+
[#3807]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3807
47+
48+
## [7.35.2] - 2024.09.03
49+
50+
### Fixed
51+
* [`jsx-curly-brace-presence`]: avoid autofixing attributes with double quotes to a double quoted attribute ([#3814][] @ljharb)
52+
53+
[7.35.2]: https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.35.1...v7.35.2
54+
[#3814]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3814
55+
56+
## [7.35.1] - 2024.09.02
57+
858
### Fixed
959
* [`jsx-curly-brace-presence`]: do not trigger on strings containing a quote character ([#3798][] @akulsr0)
1060

61+
[7.35.1]: https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.35.0...v7.35.1
1162
[#3798]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3798
1263

1364
## [7.35.0] - 2024.07.19
@@ -4266,6 +4317,7 @@ If you're still not using React 15 you can keep the old behavior by setting the
42664317
[`forbid-elements`]: docs/rules/forbid-elements.md
42674318
[`forbid-foreign-prop-types`]: docs/rules/forbid-foreign-prop-types.md
42684319
[`forbid-prop-types`]: docs/rules/forbid-prop-types.md
4320+
[`forward-ref-uses-ref`]: docs/rules/forward-ref-uses-ref.md
42694321
[`function-component-definition`]: docs/rules/function-component-definition.md
42704322
[`hook-use-state`]: docs/rules/hook-use-state.md
42714323
[`iframe-missing-sandbox`]: docs/rules/iframe-missing-sandbox.md

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ module.exports = [
301301
| [forbid-elements](docs/rules/forbid-elements.md) | Disallow certain elements | | | | | |
302302
| [forbid-foreign-prop-types](docs/rules/forbid-foreign-prop-types.md) | Disallow using another component's propTypes | | | | | |
303303
| [forbid-prop-types](docs/rules/forbid-prop-types.md) | Disallow certain propTypes | | | | | |
304+
| [forward-ref-uses-ref](docs/rules/forward-ref-uses-ref.md) | Require all forwardRef components include a ref parameter | | | | 💡 | |
304305
| [function-component-definition](docs/rules/function-component-definition.md) | Enforce a specific function type for function components | | | 🔧 | | |
305306
| [hook-use-state](docs/rules/hook-use-state.md) | Ensure destructuring and symmetric naming of useState hook value and setter variables | | | | 💡 | |
306307
| [iframe-missing-sandbox](docs/rules/iframe-missing-sandbox.md) | Enforce sandbox attribute on iframe elements | | | | | |

docs/rules/forward-ref-uses-ref.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Require all forwardRef components include a ref parameter (`react/forward-ref-uses-ref`)
2+
3+
💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
4+
5+
<!-- end auto-generated rule header -->
6+
7+
Requires that components wrapped with `forwardRef` must have a `ref` parameter. Omitting the `ref` argument is usually a bug, and components not using `ref` don't need to be wrapped by `forwardRef`.
8+
9+
See <https://react.dev/reference/react/forwardRef>
10+
11+
## Rule Details
12+
13+
This rule checks all React components using `forwardRef` and verifies that there is a second parameter.
14+
15+
The following patterns are considered warnings:
16+
17+
```jsx
18+
var React = require('react');
19+
20+
var Component = React.forwardRef((props) => (
21+
<div />
22+
));
23+
```
24+
25+
The following patterns are **not** considered warnings:
26+
27+
```jsx
28+
var React = require('react');
29+
30+
var Component = React.forwardRef((props, ref) => (
31+
<div ref={ref} />
32+
));
33+
34+
var Component = React.forwardRef((props, ref) => (
35+
<div />
36+
));
37+
38+
function Component(props) {
39+
return <div />;
40+
};
41+
```
42+
43+
## When not to use
44+
45+
If you don't want to enforce that components using `forwardRef` utilize the forwarded ref.

docs/rules/jsx-no-literals.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,61 @@ The supported options are:
3434
- `allowedStrings` - An array of unique string values that would otherwise warn, but will be ignored.
3535
- `ignoreProps` (default: `false`) - When `true` the rule ignores literals used in props, wrapped or unwrapped.
3636
- `noAttributeStrings` (default: `false`) - Enforces no string literals used in attributes when set to `true`.
37+
- `elementOverrides` - An object where the keys are the element names and the values are objects with the same options as above. This allows you to specify different options for different elements.
38+
39+
### `elementOverrides`
40+
41+
The `elementOverrides` option allows you to specify different options for different elements. This is useful when you want to enforce different rules for different elements. For example, you may want to allow string literals in `Button` elements, but not in the rest of your application.
42+
43+
The element name only accepts component names.
44+
HTML element tag names are not supported. Component names are case-sensitive and should exactly match the name of the component as it is used in the JSX.
45+
It can also be the name of a compound component (ie. `Modal.Button`).
46+
47+
Specifying options creates a new context for the rule, so the rule will only apply the new options to the specified element and its children (if `applyToNestedElements` is `true` - see below).
48+
This means that the root rule options will not apply to the specified element.
49+
50+
In addition to the options above (`noStrings`, `allowedStrings`, `noAttributeStrings` and `ignoreProps`), you can also specify the the following options that are specific to `elementOverrides`:
51+
52+
- `allowElement` (default: `false`) - When `true` the rule will allow the specified element to have string literals as children, wrapped or unwrapped without warning.
53+
- `applyToNestedElements` (default: `true`) - When `false` the rule will not apply the current options set to nested elements. This is useful when you want to apply the rule to a specific element, but not to its children.
54+
55+
**Note**: As this rule has no way of differentiating between different componets with the same name, it is recommended to use this option with specific components that are unique to your application.
56+
57+
#### `elementOverrides` Examples
58+
59+
The following are **correct** examples that demonstrate how to use the `elementOverrides` option:
60+
61+
```js
62+
// "react/jsx-no-literals": [<enabled>, {"elementOverrides": { "Button": {"allowElement": true} }}]
63+
64+
var Hello = <div>{'test'}</div>;
65+
var World = <Button>test</Button>;
66+
```
67+
68+
```js
69+
// "react/jsx-no-literals": [<enabled>, {"elementOverrides": { "Text": {"allowElement": true} }}]
70+
71+
var World = <Text>Hello <a href="a">world</a></Text>;
72+
```
73+
74+
```js
75+
// "react/jsx-no-literals": [<enabled>, {"elementOverrides": { "Text": {"allowElement": true, "applyToNestedElements": false} }}]
76+
77+
var linkText = 'world';
78+
var World = <Text>Hello <a href="a">{linkText}</a></Text>;
79+
```
80+
81+
```js
82+
// "react/jsx-no-literals": [<enabled>, {"noStrings": true, "elementOverrides": { "Button": {"noStrings": false} }}]
83+
// OR
84+
// "react/jsx-no-literals": [<enabled>, {"noStrings": true, "elementOverrides": { "Button": {} }}]
85+
86+
var test = 'test'
87+
var Hello = <div>{test}</div>;
88+
var World = <Button>{'test'}</Button>;
89+
```
90+
91+
## Examples
3792

3893
To use, you can specify as follows:
3994

docs/rules/no-danger.md

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

33
<!-- end auto-generated rule header -->
44

5-
Dangerous properties in React are those whose behavior is known to be a common source of application vulnerabilities. The properties names clearly indicate they are dangerous and should be avoided unless great care is taken.
5+
Dangerous properties in React are those whose behavior is known to be a common source of application vulnerabilities. The properties' names clearly indicate they are dangerous and should be avoided unless great care is taken.
66

7-
See <https://facebook.github.io/react/tips/dangerously-set-inner-html.html>
7+
See <https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html>
88

99
## Rule Details
1010

lib/rules/boolean-prop-naming.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,14 +259,16 @@ module.exports = {
259259
return;
260260
}
261261

262-
const annotationTypeParams = component.node.parent.id.typeAnnotation.typeAnnotation.typeParameters;
262+
const annotationTypeArguments = propsUtil.getTypeArguments(
263+
component.node.parent.id.typeAnnotation.typeAnnotation
264+
);
263265
if (
264-
annotationTypeParams && (
265-
annotationTypeParams.type === 'TSTypeParameterInstantiation'
266-
|| annotationTypeParams.type === 'TypeParameterInstantiation'
266+
annotationTypeArguments && (
267+
annotationTypeArguments.type === 'TSTypeParameterInstantiation'
268+
|| annotationTypeArguments.type === 'TypeParameterInstantiation'
267269
)
268270
) {
269-
return annotationTypeParams.params.find(
271+
return annotationTypeArguments.params.find(
270272
(param) => param.type === 'TSTypeReference' || param.type === 'GenericTypeAnnotation'
271273
);
272274
}

lib/rules/button-has-type.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const messages = {
2828
forbiddenValue: '"{{value}}" is an invalid value for button type attribute',
2929
};
3030

31+
/** @type {import('eslint').Rule.RuleModule} */
3132
module.exports = {
3233
meta: {
3334
docs: {
@@ -149,14 +150,19 @@ module.exports = {
149150
}
150151

151152
const props = node.arguments[1].properties;
152-
const typeProp = props.find((prop) => prop.key && prop.key.name === 'type');
153+
const typeProp = props.find((prop) => (
154+
'key' in prop
155+
&& prop.key
156+
&& 'name' in prop.key
157+
&& prop.key.name === 'type'
158+
));
153159

154160
if (!typeProp) {
155161
reportMissing(node);
156162
return;
157163
}
158164

159-
checkExpression(node, typeProp.value);
165+
checkExpression(node, 'value' in typeProp ? typeProp.value : undefined);
160166
},
161167
};
162168
},

0 commit comments

Comments
 (0)