From 5696f99930897cb049d30303293818d3e8f182ee Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 22 Oct 2024 12:49:51 -0700 Subject: [PATCH 01/40] [Dev Deps] update `@babel/core`, `@babel/eslint-parser`, `@babel/plugin-syntax-decorators`, `@babel/plugin-syntax-do-expressions`, `@babel/plugin-syntax-function-bind`, `@babel/preset-react` --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 5122692c22..5fc051131f 100644 --- a/package.json +++ b/package.json @@ -49,12 +49,12 @@ "string.prototype.repeat": "^1.0.0" }, "devDependencies": { - "@babel/core": "^7.25.8", - "@babel/eslint-parser": "^7.25.8", - "@babel/plugin-syntax-decorators": "^7.25.7", - "@babel/plugin-syntax-do-expressions": "^7.25.7", - "@babel/plugin-syntax-function-bind": "^7.25.7", - "@babel/preset-react": "^7.25.7", + "@babel/core": "^7.25.9", + "@babel/eslint-parser": "^7.25.9", + "@babel/plugin-syntax-decorators": "^7.25.9", + "@babel/plugin-syntax-do-expressions": "^7.25.9", + "@babel/plugin-syntax-function-bind": "^7.25.9", + "@babel/preset-react": "^7.25.9", "@types/eslint": "=7.2.10", "@types/estree": "0.0.52", "@types/node": "^4.9.5", From 33db656bfb1bf42eac1fbc72ed1f63f9fa655a8c Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 22 Oct 2024 12:50:14 -0700 Subject: [PATCH 02/40] [Deps] update `es-iterator-helpers` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5fc051131f..dcaca108b4 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "array.prototype.flatmap": "^1.3.2", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.19", + "es-iterator-helpers": "^1.1.0", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", From 256cf74fbd662e183ecd1fca90d6aba82bac8918 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 22 Oct 2024 12:51:22 -0700 Subject: [PATCH 03/40] Update CHANGELOG and bump version --- CHANGELOG.md | 6 +++++- package.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f62ad8605e..26389bca1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,15 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ## Unreleased +## [7.37.2] - 2024.10.22 + ### Fixed * [`destructuring-assignment`]: fix false negative when using `typeof props.a` ([#3835][] @golopot) ### Changed * [Refactor] [`destructuring-assignment`]: use `getParentStatelessComponent` ([#3835][] @golopot) +[7.37.2]: https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.37.1...v7.37.2 [#3835]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3835 ## [7.37.1] - 2024.10.01 @@ -22,6 +25,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Changed * [readme] Fix shared settings link ([#3834][] @MgenGlder) +[7.37.1]: https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.37.0...v7.37.1 [#3836]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3836 [#3834]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3834 @@ -36,7 +40,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Changed * [readme] flat config example for react 17+ ([#3824][] @GabenGar) -[7.36.2]: https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.36.1...v7.36.2 +[7.37.0]: https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.36.1...v7.37.0 [#3831]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3831 [#3830]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3830 [#3826]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3826 diff --git a/package.json b/package.json index dcaca108b4..510549d6a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-react", - "version": "7.37.1", + "version": "7.37.2", "author": "Yannick Croissant ", "description": "React specific linting rules for ESLint", "main": "index.js", From b2446381efb7ac76b4d7e8efdba2fa07d46e9db6 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 22 Oct 2024 16:49:58 -0700 Subject: [PATCH 04/40] [actions] publish action: hopefully clarify failure reasons --- .github/workflows/npm-publish.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 8ed3becf6b..b0a4b060c7 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -63,7 +63,10 @@ jobs: const pending = checkSuites.filter(({ status }) => status !== 'completed') if (pending.length > 0) { - core.setFailed(`Some workflows for ${context.payload.inputs.tag} are still in-progress: ${JSON.stringify(pending)}`); + core.setFailed(`Some workflows for ${context.payload.inputs.tag} are still in-progress`); + pending.forEach(({ pull_requests, ...x }) => { + core.debug(JSON.stringify(x)); + }); } const result = await Promise.all( From 1c3621a7e7fc4ff5e426f6e6f1fdac64c54630a9 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 22 Oct 2024 22:36:39 -0700 Subject: [PATCH 05/40] [Fix] `no-danger`: avoid a crash on a nested component name Fixes #3833 --- CHANGELOG.md | 5 ++++ lib/rules/no-danger.js | 3 ++- tests/lib/rules/no-danger.js | 44 ++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26389bca1e..94d723c668 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ## Unreleased +### Fixed +* [`no-danger`]: avoid a crash on a nested component name ([#3833][] @ljharb) + +[#3833]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3833 + ## [7.37.2] - 2024.10.22 ### Fixed diff --git a/lib/rules/no-danger.js b/lib/rules/no-danger.js index fb70263208..54dbed49cf 100644 --- a/lib/rules/no-danger.js +++ b/lib/rules/no-danger.js @@ -77,7 +77,8 @@ module.exports = { return { JSXAttribute(node) { - const functionName = node.parent.name.name; + const nodeName = node.parent.name; + const functionName = nodeName.name || `${nodeName.object.name}.${nodeName.property.name}`; const enableCheckingCustomComponent = customComponentNames.some((name) => minimatch(functionName, name)); diff --git a/tests/lib/rules/no-danger.js b/tests/lib/rules/no-danger.js index e354ad28bd..9403a220bf 100644 --- a/tests/lib/rules/no-danger.js +++ b/tests/lib/rules/no-danger.js @@ -129,5 +129,49 @@ ruleTester.run('no-danger', rule, { }, ], }, + { + code: ` + import type { ComponentProps } from "react"; + + const Comp = "div"; + const Component = () => <>; + + const NestedComponent = (_props: ComponentProps<"div">) => <>; + + Component.NestedComponent = NestedComponent; + + function App() { + return ( + <> +
aaa
" }} /> + aaa" }} /> + + aaa' }} + /> + + ); + } + `, + features: ['fragment', 'types'], + options: [{ customComponentNames: ['*'] }], + errors: [ + { + messageId: 'dangerousProp', + data: { name: 'dangerouslySetInnerHTML' }, + line: 14, + }, + { + messageId: 'dangerousProp', + data: { name: 'dangerouslySetInnerHTML' }, + line: 15, + }, + { + messageId: 'dangerousProp', + data: { name: 'dangerouslySetInnerHTML' }, + line: 18, + }, + ], + }, ]), }); From d1556a3d2f95f56cfb6e7c0a341af16742f64033 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 22 Oct 2024 22:39:30 -0700 Subject: [PATCH 06/40] [eslint] ignore d.ts files --- .eslintrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintrc b/.eslintrc index fd3ae2193c..894df7caa9 100644 --- a/.eslintrc +++ b/.eslintrc @@ -17,7 +17,8 @@ "coverage/", ".nyc_output/", "test-published-types/", - "tests/fixtures/flat-config/" + "tests/fixtures/flat-config/", + "**/*/*.d.ts", ], "rules": { "comma-dangle": [2, "always-multiline"], From 4ef92b49ab70eacb913afa394209ac5a24522fad Mon Sep 17 00:00:00 2001 From: Radu Baston Date: Mon, 4 Nov 2024 17:20:27 +0200 Subject: [PATCH 07/40] [Tests] `jsx-no-script-url`: Improve tests --- CHANGELOG.md | 4 ++++ tests/lib/rules/jsx-no-script-url.js | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94d723c668..638e053935 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Fixed * [`no-danger`]: avoid a crash on a nested component name ([#3833][] @ljharb) +### Changed +* [Tests] [`jsx-no-script-url`]: Improve tests ([#3849][] @radu2147) + +[#3849]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3849 [#3833]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3833 ## [7.37.2] - 2024.10.22 diff --git a/tests/lib/rules/jsx-no-script-url.js b/tests/lib/rules/jsx-no-script-url.js index 2a2ff394bd..b97c9ce567 100644 --- a/tests/lib/rules/jsx-no-script-url.js +++ b/tests/lib/rules/jsx-no-script-url.js @@ -38,6 +38,10 @@ ruleTester.run('jsx-no-script-url', rule, { { code: '' }, { code: '' }, { code: '' }, + { + code: '', + options: [[{ name: 'Foo', props: ['to', 'href'] }]], + }, { code: '', settings: { @@ -51,6 +55,13 @@ ruleTester.run('jsx-no-script-url', rule, { linkComponents: [{ name: 'Foo', linkAttribute: ['to', 'href'] }], }, }, + { + code: '', + options: [[], { includeFromSettings: true }], + settings: { + linkComponents: [{ name: 'Foo', linkAttribute: ['to', 'href'] }], + }, + }, ]), invalid: parsers.all([ // defaults From e80def4259c16855e2202f20af9f401c61c0b7ba Mon Sep 17 00:00:00 2001 From: ocavue Date: Sat, 12 Oct 2024 11:05:34 +1100 Subject: [PATCH 08/40] [Fix] types: correct generated type declaration - Add types/rules/jsx-no-literals.d.ts to avoid error TS2309: An export assignment cannot be used in a module with other exported elements. --- .github/workflows/type-check.yml | 20 ++++++- CHANGELOG.md | 2 + index.js | 54 ++++++++++--------- lib/rules/forbid-foreign-prop-types.js | 2 +- lib/rules/forbid-prop-types.js | 1 + lib/rules/forward-ref-uses-ref.js | 1 + lib/rules/index.js | 4 +- lib/rules/jsx-fragments.js | 7 ++- lib/rules/jsx-no-literals.js | 66 +++++++----------------- lib/rules/jsx-props-no-spread-multi.js | 1 + lib/rules/jsx-space-before-closing.js | 2 +- lib/rules/no-access-state-in-setstate.js | 4 +- lib/rules/no-deprecated.js | 2 +- lib/rules/no-unused-state.js | 2 +- test-published-types/index.js | 4 +- test-published-types/package.json | 3 +- test-published-types/tsconfig.json | 3 +- tsconfig.json | 2 +- types/rules/jsx-no-literals.d.ts | 50 ++++++++++++++++++ types/string.prototype.repeat/index.d.ts | 3 +- 20 files changed, 144 insertions(+), 89 deletions(-) create mode 100644 types/rules/jsx-no-literals.d.ts diff --git a/.github/workflows/type-check.yml b/.github/workflows/type-check.yml index c0e6b4d033..0aaca2cb00 100644 --- a/.github/workflows/type-check.yml +++ b/.github/workflows/type-check.yml @@ -44,18 +44,34 @@ jobs: - name: build types run: npm run build-types + # Pack the lib into a tarball so that when we install the lib later in the + # test-published-types directory, it's only install `dependencies` of the + # lib. + - name: pack the lib + run: npm pack --pack-destination /tmp/ + + - name: find the packed lib + run: echo "ESLINT_PLUGIN_REACT_PATH=$(ls /tmp/eslint-plugin-react*.tgz | tail -n 1)" >> $GITHUB_ENV + + - name: show the path to the packed lib + run: echo "$ESLINT_PLUGIN_REACT_PATH" + - name: npm install working directory run: npm install working-directory: test-published-types - - name: install typescript version ${{ matrix.ts_version }} - run: npm install --no-save typescript@${{ matrix.ts_version }} + - name: install eslint-plugin-react and typescript version ${{ matrix.ts_version }} + run: npm install --no-save "$ESLINT_PLUGIN_REACT_PATH" typescript@${{ matrix.ts_version }} working-directory: test-published-types - name: show installed typescript version run: npm list typescript --depth=0 working-directory: test-published-types + - name: show installed eslint-plugin-react version + run: npm list eslint-plugin-react --depth=0 + working-directory: test-published-types + - name: check types with lib "${{ matrix.ts_lib }}" run: npx tsc --lib ${{ matrix.ts_lib }} working-directory: test-published-types diff --git a/CHANGELOG.md b/CHANGELOG.md index 638e053935..ff0bedbc3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,13 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Fixed * [`no-danger`]: avoid a crash on a nested component name ([#3833][] @ljharb) +* [Fix] types: correct generated type declaration ([#3840][] @ocavue) ### Changed * [Tests] [`jsx-no-script-url`]: Improve tests ([#3849][] @radu2147) [#3849]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3849 +[#3840]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3840 [#3833]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3833 ## [7.37.2] - 2024.10.22 diff --git a/index.js b/index.js index 8426993e5b..365f17446c 100644 --- a/index.js +++ b/index.js @@ -11,7 +11,7 @@ function filterRules(rules, predicate) { /** * @param {object} rules - rules object mapping rule name to rule module - * @returns {Record} + * @returns {Record} */ function configureAsError(rules) { return fromEntries(Object.keys(rules).map((key) => [`react/${key}`, 2])); @@ -31,6 +31,10 @@ const plugins = [ 'react', ]; +// TODO: with TS 4.5+, inline this +const SEVERITY_ERROR = /** @type {2} */ (2); +const SEVERITY_OFF = /** @type {0} */ (0); + const configs = { recommended: { plugins, @@ -40,28 +44,28 @@ const configs = { }, }, rules: { - 'react/display-name': 2, - 'react/jsx-key': 2, - 'react/jsx-no-comment-textnodes': 2, - 'react/jsx-no-duplicate-props': 2, - 'react/jsx-no-target-blank': 2, - 'react/jsx-no-undef': 2, - 'react/jsx-uses-react': 2, - 'react/jsx-uses-vars': 2, - 'react/no-children-prop': 2, - 'react/no-danger-with-children': 2, - 'react/no-deprecated': 2, - 'react/no-direct-mutation-state': 2, - 'react/no-find-dom-node': 2, - 'react/no-is-mounted': 2, - 'react/no-render-return-value': 2, - 'react/no-string-refs': 2, - 'react/no-unescaped-entities': 2, - 'react/no-unknown-property': 2, - 'react/no-unsafe': 0, - 'react/prop-types': 2, - 'react/react-in-jsx-scope': 2, - 'react/require-render-return': 2, + 'react/display-name': SEVERITY_ERROR, + 'react/jsx-key': SEVERITY_ERROR, + 'react/jsx-no-comment-textnodes': SEVERITY_ERROR, + 'react/jsx-no-duplicate-props': SEVERITY_ERROR, + 'react/jsx-no-target-blank': SEVERITY_ERROR, + 'react/jsx-no-undef': SEVERITY_ERROR, + 'react/jsx-uses-react': SEVERITY_ERROR, + 'react/jsx-uses-vars': SEVERITY_ERROR, + 'react/no-children-prop': SEVERITY_ERROR, + 'react/no-danger-with-children': SEVERITY_ERROR, + 'react/no-deprecated': SEVERITY_ERROR, + 'react/no-direct-mutation-state': SEVERITY_ERROR, + 'react/no-find-dom-node': SEVERITY_ERROR, + 'react/no-is-mounted': SEVERITY_ERROR, + 'react/no-render-return-value': SEVERITY_ERROR, + 'react/no-string-refs': SEVERITY_ERROR, + 'react/no-unescaped-entities': SEVERITY_ERROR, + 'react/no-unknown-property': SEVERITY_ERROR, + 'react/no-unsafe': SEVERITY_OFF, + 'react/prop-types': SEVERITY_ERROR, + 'react/react-in-jsx-scope': SEVERITY_ERROR, + 'react/require-render-return': SEVERITY_ERROR, }, }, all: { @@ -82,8 +86,8 @@ const configs = { jsxPragma: null, // for @typescript/eslint-parser }, rules: { - 'react/react-in-jsx-scope': 0, - 'react/jsx-uses-react': 0, + 'react/react-in-jsx-scope': SEVERITY_OFF, + 'react/jsx-uses-react': SEVERITY_OFF, }, }, }; diff --git a/lib/rules/forbid-foreign-prop-types.js b/lib/rules/forbid-foreign-prop-types.js index 7724049af4..20d191d264 100644 --- a/lib/rules/forbid-foreign-prop-types.js +++ b/lib/rules/forbid-foreign-prop-types.js @@ -109,7 +109,7 @@ module.exports = { && !ast.isAssignmentLHS(node) && !isAllowedAssignment(node) )) || ( - // @ts-expect-error The JSXText type is not present in the estree type definitions + // @ts-expect-error: The JSXText type is not present in the estree type definitions (node.property.type === 'Literal' || node.property.type === 'JSXText') && 'value' in node.property && node.property.value === 'propTypes' diff --git a/lib/rules/forbid-prop-types.js b/lib/rules/forbid-prop-types.js index df40706d00..44de1fa023 100644 --- a/lib/rules/forbid-prop-types.js +++ b/lib/rules/forbid-prop-types.js @@ -195,6 +195,7 @@ module.exports = { const propTypesSpecifier = node.specifiers.find((specifier) => ( 'imported' in specifier && specifier.imported + && 'name' in specifier.imported && specifier.imported.name === 'PropTypes' )); if (propTypesSpecifier) { diff --git a/lib/rules/forward-ref-uses-ref.js b/lib/rules/forward-ref-uses-ref.js index aeedeb82df..3a0b7de4c9 100644 --- a/lib/rules/forward-ref-uses-ref.js +++ b/lib/rules/forward-ref-uses-ref.js @@ -41,6 +41,7 @@ const messages = { removeForwardRef: 'Remove forwardRef wrapper', }; +/** @type {import('eslint').Rule.RuleModule} */ module.exports = { meta: { docs: { diff --git a/lib/rules/index.js b/lib/rules/index.js index 1e010b677b..0e73ab1a3f 100644 --- a/lib/rules/index.js +++ b/lib/rules/index.js @@ -3,7 +3,7 @@ /* eslint global-require: 0 */ /** @satisfies {Record} */ -module.exports = { +const rules = { 'boolean-prop-naming': require('./boolean-prop-naming'), 'button-has-type': require('./button-has-type'), 'checked-requires-onchange-or-readonly': require('./checked-requires-onchange-or-readonly'), @@ -108,3 +108,5 @@ module.exports = { 'style-prop-object': require('./style-prop-object'), 'void-dom-elements-no-children': require('./void-dom-elements-no-children'), }; + +module.exports = rules; diff --git a/lib/rules/jsx-fragments.js b/lib/rules/jsx-fragments.js index 6835331025..b4a545846e 100644 --- a/lib/rules/jsx-fragments.js +++ b/lib/rules/jsx-fragments.js @@ -170,7 +170,12 @@ module.exports = { ImportDeclaration(node) { if (node.source && node.source.value === 'react') { node.specifiers.forEach((spec) => { - if ('imported' in spec && spec.imported && spec.imported.name === fragmentPragma) { + if ( + 'imported' in spec + && spec.imported + && 'name' in spec.imported + && spec.imported.name === fragmentPragma + ) { if (spec.local) { fragmentNames.add(spec.local.name); } diff --git a/lib/rules/jsx-no-literals.js b/lib/rules/jsx-no-literals.js index 230d33a18d..45c9a54c48 100644 --- a/lib/rules/jsx-no-literals.js +++ b/lib/rules/jsx-no-literals.js @@ -17,6 +17,14 @@ const docsUrl = require('../util/docsUrl'); const report = require('../util/report'); const getText = require('../util/eslint').getText; +/** @typedef {import('eslint').Rule.RuleModule} RuleModule */ + +/** @typedef {import('../../types/rules/jsx-no-literals').Config} Config */ +/** @typedef {import('../../types/rules/jsx-no-literals').RawConfig} RawConfig */ +/** @typedef {import('../../types/rules/jsx-no-literals').ResolvedConfig} ResolvedConfig */ +/** @typedef {import('../../types/rules/jsx-no-literals').OverrideConfig} OverrideConfig */ +/** @typedef {import('../../types/rules/jsx-no-literals').ElementConfig} ElementConfig */ + // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ @@ -45,7 +53,7 @@ const messages = { literalNotInJSXExpressionInElement: 'Missing JSX expression container around literal string: "{{text}}" in {{element}}', }; -/** @type {Exclude['properties']} */ +/** @type {Exclude['properties']} */ const commonPropertiesSchema = { noStrings: { type: 'boolean', @@ -65,52 +73,7 @@ const commonPropertiesSchema = { }, }; -/** - * @typedef RawElementConfigProperties - * @property {boolean} [noStrings] - * @property {string[]} [allowedStrings] - * @property {boolean} [ignoreProps] - * @property {boolean} [noAttributeStrings] - * - * @typedef RawOverrideConfigProperties - * @property {boolean} [allowElement] - * @property {boolean} [applyToNestedElements=true] - * - * @typedef {RawElementConfigProperties} RawElementConfig - * @typedef {RawElementConfigProperties & RawElementConfigProperties} RawOverrideConfig - * - * @typedef RawElementOverrides - * @property {Record} [elementOverrides] - * - * @typedef {RawElementConfig & RawElementOverrides} RawConfig - * - * ---------------------------------------------------------------------- - * - * @typedef ElementConfigType - * @property {'element'} type - * - * @typedef ElementConfigProperties - * @property {boolean} noStrings - * @property {Set} allowedStrings - * @property {boolean} ignoreProps - * @property {boolean} noAttributeStrings - * - * @typedef OverrideConfigProperties - * @property {'override'} type - * @property {string} name - * @property {boolean} allowElement - * @property {boolean} applyToNestedElements - * - * @typedef {ElementConfigType & ElementConfigProperties} ElementConfig - * @typedef {OverrideConfigProperties & ElementConfigProperties} OverrideConfig - * - * @typedef ElementOverrides - * @property {Record} elementOverrides - * - * @typedef {ElementConfig & ElementOverrides} Config - * @typedef {Config | OverrideConfig} ResolvedConfig - */ - +// eslint-disable-next-line valid-jsdoc /** * Normalizes the element portion of the config * @param {RawConfig} config @@ -128,6 +91,7 @@ function normalizeElementConfig(config) { }; } +// eslint-disable-next-line valid-jsdoc /** * Normalizes the config and applies default values to all config options * @param {RawConfig} config @@ -182,8 +146,9 @@ const elementOverrides = { }, }; +/** @type {RuleModule} */ module.exports = { - meta: /** @type {import('eslint').Rule.RuleModule["meta"]} */ ({ + meta: /** @type {RuleModule['meta']} */ ({ docs: { description: 'Disallow usage of string literals in JSX', category: 'Stylistic Issues', @@ -339,6 +304,7 @@ module.exports = { return some(iterFrom([ancestors.parent, ancestors.grandParent]), (parent) => jsxElementTypes.has(parent.type)); } + // eslint-disable-next-line valid-jsdoc /** * Determines whether a given node's value and its immediate parent are * viable text nodes that can/should be reported on @@ -370,6 +336,7 @@ module.exports = { return isStandardJSXNode && parent.type !== 'JSXExpressionContainer'; } + // eslint-disable-next-line valid-jsdoc /** * Gets an override config for a given node. For any given node, we also * need to traverse the ancestor tree to determine if an ancestor's config @@ -408,6 +375,7 @@ module.exports = { } } + // eslint-disable-next-line valid-jsdoc /** * @param {ResolvedConfig} resolvedConfig * @returns {boolean} @@ -416,6 +384,7 @@ module.exports = { return resolvedConfig.type === 'override' && 'allowElement' in resolvedConfig && !!resolvedConfig.allowElement; } + // eslint-disable-next-line valid-jsdoc /** * @param {boolean} ancestorIsJSXElement * @param {ResolvedConfig} resolvedConfig @@ -433,6 +402,7 @@ module.exports = { return resolvedConfig.type === 'override' ? 'literalNotInJSXExpressionInElement' : 'literalNotInJSXExpression'; } + // eslint-disable-next-line valid-jsdoc /** * @param {ASTNode} node * @param {string} messageId diff --git a/lib/rules/jsx-props-no-spread-multi.js b/lib/rules/jsx-props-no-spread-multi.js index 2eeed0be49..3103be86da 100644 --- a/lib/rules/jsx-props-no-spread-multi.js +++ b/lib/rules/jsx-props-no-spread-multi.js @@ -16,6 +16,7 @@ const messages = { noMultiSpreading: 'Spreading the same expression multiple times is forbidden', }; +/** @type {import('eslint').Rule.RuleModule} */ module.exports = { meta: { docs: { diff --git a/lib/rules/jsx-space-before-closing.js b/lib/rules/jsx-space-before-closing.js index ffcc357d8b..2cef238841 100644 --- a/lib/rules/jsx-space-before-closing.js +++ b/lib/rules/jsx-space-before-closing.js @@ -59,7 +59,7 @@ module.exports = { const sourceCode = getSourceCode(context); const leftToken = getTokenBeforeClosingBracket(node); - const closingSlash = /** @type {import("eslint").AST.Token} */ (sourceCode.getTokenAfter(leftToken)); + const closingSlash = /** @type {import('eslint').AST.Token} */ (sourceCode.getTokenAfter(leftToken)); if (leftToken.loc.end.line !== closingSlash.loc.start.line) { return; diff --git a/lib/rules/no-access-state-in-setstate.js b/lib/rules/no-access-state-in-setstate.js index 7126517112..1b23dd88ee 100644 --- a/lib/rules/no-access-state-in-setstate.js +++ b/lib/rules/no-access-state-in-setstate.js @@ -116,7 +116,7 @@ module.exports = { && node.object.type === 'ThisExpression' && isClassComponent(node) ) { - /** @type {import("eslint").Rule.Node} */ + /** @type {import('eslint').Rule.Node} */ let current = node; while (current.type !== 'Program') { // Reporting if this.state is directly within this.setState @@ -163,7 +163,7 @@ module.exports = { Identifier(node) { // Checks if the identifier is a variable within an object - /** @type {import("eslint").Rule.Node} */ + /** @type {import('eslint').Rule.Node} */ let current = node; while (current.parent.type === 'BinaryExpression') { current = current.parent; diff --git a/lib/rules/no-deprecated.js b/lib/rules/no-deprecated.js index 9f5ddf7082..0c5931345f 100644 --- a/lib/rules/no-deprecated.js +++ b/lib/rules/no-deprecated.js @@ -229,7 +229,7 @@ module.exports = { } node.specifiers.filter(((s) => 'imported' in s && s.imported)).forEach((specifier) => { // TODO, semver-major: remove `in` check as part of jsdoc->tsdoc migration - checkDeprecation(node, 'imported' in specifier && `${MODULES[node.source.value][0]}.${specifier.imported.name}`, specifier); + checkDeprecation(node, 'imported' in specifier && 'name' in specifier.imported && `${MODULES[node.source.value][0]}.${specifier.imported.name}`, specifier); }); }, diff --git a/lib/rules/no-unused-state.js b/lib/rules/no-unused-state.js index a71d63ebeb..c1986755c4 100644 --- a/lib/rules/no-unused-state.js +++ b/lib/rules/no-unused-state.js @@ -468,7 +468,7 @@ module.exports = { && unwrappedRight.type === 'ObjectExpression' ) { // Find the nearest function expression containing this assignment. - /** @type {import("eslint").Rule.Node} */ + /** @type {import('eslint').Rule.Node} */ let fn = node; while (fn.type !== 'FunctionExpression' && fn.parent) { fn = fn.parent; diff --git a/test-published-types/index.js b/test-published-types/index.js index 31e6005985..010d658041 100644 --- a/test-published-types/index.js +++ b/test-published-types/index.js @@ -3,10 +3,12 @@ const react = require('eslint-plugin-react'); /** @type {import('eslint').Linter.Config[]} */ -module.exports = [ +const config = [ { plugins: { react, }, }, ]; + +module.exports = config; diff --git a/test-published-types/package.json b/test-published-types/package.json index ab8a7160c6..80953c53ab 100644 --- a/test-published-types/package.json +++ b/test-published-types/package.json @@ -3,7 +3,6 @@ "private": true, "version": "0.0.0", "dependencies": { - "eslint": "^9.11.1", - "eslint-plugin-react": "file:.." + "eslint": "^9.11.1" } } diff --git a/test-published-types/tsconfig.json b/test-published-types/tsconfig.json index 7fc1500df3..2ce0bd816e 100644 --- a/test-published-types/tsconfig.json +++ b/test-published-types/tsconfig.json @@ -7,6 +7,7 @@ "compilerOptions": { "lib": ["esnext"], - "types": ["node"] + "types": ["node"], + "skipLibCheck": true } } diff --git a/tsconfig.json b/tsconfig.json index 39187b7f32..8772fab53d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,5 +19,5 @@ "alwaysStrict": false, /* Parse in strict mode and emit "use strict" for each source file. */ "resolveJsonModule": true }, - "include": ["lib"], + "include": ["lib", "types"], } diff --git a/types/rules/jsx-no-literals.d.ts b/types/rules/jsx-no-literals.d.ts new file mode 100644 index 0000000000..c1b9638958 --- /dev/null +++ b/types/rules/jsx-no-literals.d.ts @@ -0,0 +1,50 @@ +type RawElementConfig = { + noStrings?: boolean; + allowedStrings?: string[]; + ignoreProps?: boolean; + noAttributeStrings?: boolean; +}; + +type RawOverrideConfig = { + allowElement?: boolean; + applyToNestedElements?: boolean; +}; + +interface RawElementOverrides { + elementOverrides?: Record; +} + +export type RawConfig = RawElementConfig & RawElementOverrides; + +interface ElementConfigType { + type: 'element'; +} + +interface ElementConfigProperties { + noStrings: boolean; + allowedStrings: Set; + ignoreProps: boolean; + noAttributeStrings: boolean; +} + +interface OverrideConfigProperties { + type: 'override'; + name: string; + allowElement: boolean; + applyToNestedElements: boolean; +} + +export type ElementConfig = { + type: 'element'; +} & ElementConfigProperties; + +export type OverrideConfig = OverrideConfigProperties & ElementConfigProperties; + +interface ElementOverrides { + elementOverrides: Record; +} + +export type Config = ElementConfig & ElementOverrides; + +export type ResolvedConfig = Config | OverrideConfig; + diff --git a/types/string.prototype.repeat/index.d.ts b/types/string.prototype.repeat/index.d.ts index f240d9301f..b2e5992712 100644 --- a/types/string.prototype.repeat/index.d.ts +++ b/types/string.prototype.repeat/index.d.ts @@ -1,3 +1,4 @@ declare module 'string.prototype.repeat' { - export = typeof Function.call.bind(String.prototype.repeat); + function repeat(text: string, count: number): string; + export = repeat; } From 4bf30c3f7f2dc718a60e1056ba0757b9a3b5ef78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Nov 2024 08:03:23 +0000 Subject: [PATCH 09/40] [actions] update step-security/harden-runner from v1 to v2 Bumps [step-security/harden-runner](https://github.com/step-security/harden-runner) from 1 to 2.10.2. - [Release notes](https://github.com/step-security/harden-runner/releases) - [Commits](https://github.com/step-security/harden-runner/compare/v1...v2.10.2) --- updated-dependencies: - dependency-name: step-security/harden-runner dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/npm-publish.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index b0a4b060c7..004c88360e 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -97,7 +97,7 @@ jobs: contents: read id-token: write steps: - - uses: step-security/harden-runner@v1 + - uses: step-security/harden-runner@v2 with: egress-policy: block allowed-endpoints: > diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3a957f007c..3ea4e63f84 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: contents: write steps: - - uses: step-security/harden-runner@v1 + - uses: step-security/harden-runner@v2 with: allowed-endpoints: api.github.com:443 From efb29939fb34aaff10f09adbbae306593116bb3d Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Fri, 29 Nov 2024 10:24:59 -0800 Subject: [PATCH 10/40] [Refactor] some cleanups --- lib/rules/jsx-handler-names.js | 24 ++++++++++++------------ lib/util/version.js | 9 +++------ 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/rules/jsx-handler-names.js b/lib/rules/jsx-handler-names.js index 652e125d6e..f89f24413e 100644 --- a/lib/rules/jsx-handler-names.js +++ b/lib/rules/jsx-handler-names.js @@ -19,6 +19,14 @@ const messages = { badPropKey: 'Prop key for {{propValue}} must begin with \'{{handlerPropPrefix}}\'', }; +function isPrefixDisabled(prefix) { + return prefix === false; +} + +function isInlineHandler(node) { + return node.value.expression.type === 'ArrowFunctionExpression'; +} + /** @type {import('eslint').Rule.RuleModule} */ module.exports = { meta: { @@ -109,14 +117,6 @@ module.exports = { }, create(context) { - function isPrefixDisabled(prefix) { - return prefix === false; - } - - function isInlineHandler(node) { - return node.value.expression.type === 'ArrowFunctionExpression'; - } - const configuration = context.options[0] || {}; const eventHandlerPrefix = isPrefixDisabled(configuration.eventHandlerPrefix) @@ -143,10 +143,10 @@ module.exports = { JSXAttribute(node) { const componentName = node.parent.name.name; - const isComponentNameIgnored = ignoreComponentNames.some((ignoredComponentNamePattern) => { - const isIgnored = minimatch(componentName, ignoredComponentNamePattern); - return isIgnored; - }); + const isComponentNameIgnored = ignoreComponentNames.some((ignoredComponentNamePattern) => minimatch( + componentName, + ignoredComponentNamePattern + )); if ( !node.value diff --git a/lib/util/version.js b/lib/util/version.js index 9db44dbee2..c9dc683b7d 100644 --- a/lib/util/version.js +++ b/lib/util/version.js @@ -62,8 +62,7 @@ function readDefaultReactVersionFromContext(context) { if (context.settings && context.settings.react && context.settings.react.defaultVersion) { let settingsDefaultVersion = context.settings.react.defaultVersion; if (typeof settingsDefaultVersion !== 'string') { - error('Warning: default React version specified in eslint-pluigin-react-settings must be a string; ' - + `got "${typeof settingsDefaultVersion}"`); + error(`Warning: default React version specified in eslint-pluigin-react-settings must be a string; got "${typeof settingsDefaultVersion}"`); } settingsDefaultVersion = String(settingsDefaultVersion); const result = convertConfVerToSemver(settingsDefaultVersion); @@ -117,13 +116,11 @@ function getReactVersionFromContext(context) { settingsVersion = detectReactVersion(context); } if (typeof settingsVersion !== 'string') { - error('Warning: React version specified in eslint-plugin-react-settings must be a string; ' - + `got “${typeof settingsVersion}”`); + error(`Warning: React version specified in eslint-plugin-react-settings must be a string; got “${typeof settingsVersion}”`); } confVer = String(settingsVersion); } else if (!warnedForMissingVersion) { - error('Warning: React version not specified in eslint-plugin-react settings. ' - + 'See https://github.com/jsx-eslint/eslint-plugin-react#configuration .'); + error('Warning: React version not specified in eslint-plugin-react settings. See https://github.com/jsx-eslint/eslint-plugin-react#configuration .'); warnedForMissingVersion = true; } From 17e1a84d697eccbbbadf5639f9cb717aa52749f4 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Fri, 29 Nov 2024 10:26:54 -0800 Subject: [PATCH 11/40] [Dev Deps] update `@babel/core` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 510549d6a8..d951d4f68a 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "string.prototype.repeat": "^1.0.0" }, "devDependencies": { - "@babel/core": "^7.25.9", + "@babel/core": "^7.26.0", "@babel/eslint-parser": "^7.25.9", "@babel/plugin-syntax-decorators": "^7.25.9", "@babel/plugin-syntax-do-expressions": "^7.25.9", From d5da0a6cfae70fbef4d30b5161701d4b64cfff73 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Fri, 29 Nov 2024 10:27:16 -0800 Subject: [PATCH 12/40] [Deps] update `es-iterator-helpers` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d951d4f68a..9cb8e60abb 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "array.prototype.flatmap": "^1.3.2", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.1.0", + "es-iterator-helpers": "^1.2.0", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", From 2c0b10cbff8e5395a80b337d929d66d20de929c9 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 9 Dec 2024 11:02:32 -0800 Subject: [PATCH 13/40] [Tests] pin `@typescript-eslint/parser to < 8.18, due to a breaking change See https://github.com/typescript-eslint/typescript-eslint/issues/10480 --- .github/workflows/node-18+.yml | 2 +- .github/workflows/node-minors.yml | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/node-18+.yml b/.github/workflows/node-18+.yml index ee7d126939..5a48b15a88 100644 --- a/.github/workflows/node-18+.yml +++ b/.github/workflows/node-18+.yml @@ -104,7 +104,7 @@ jobs: with: node-version: ${{ matrix.node-version }} after_install: | - npm install --no-save "eslint@${{ matrix.eslint }}" "@typescript-eslint/parser@${{ matrix.typescript-eslint }}" "babel-eslint@${{ matrix.babel-eslint }}" + npm install --no-save "eslint@${{ matrix.eslint }}" "@typescript-eslint/parser@${{ matrix.typescript-eslint == 8 && 8.17 || matrix.typescript-eslint }}" "babel-eslint@${{ matrix.babel-eslint }}" env: NPM_CONFIG_LEGACY_PEER_DEPS: "${{ matrix.typescript-eslint >= 6 && 'false' || 'true' }}" - run: npx ls-engines diff --git a/.github/workflows/node-minors.yml b/.github/workflows/node-minors.yml index 69f92684ea..9e227f2b89 100644 --- a/.github/workflows/node-minors.yml +++ b/.github/workflows/node-minors.yml @@ -100,7 +100,7 @@ jobs: with: node-version: ${{ matrix.node-version }} after_install: | - 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 }}" + npm install --no-save "eslint@${{ matrix.eslint }}" "@typescript-eslint/parser@${{ matrix.node-version >= 18 && matrix.eslint >= 8 && '8.17' || (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 }}" skip-ls-check: ${{ matrix.node-version < 10 && true || false }} env: NPM_CONFIG_LEGACY_PEER_DEPS: "${{ matrix.node-version >= 16 && matrix.eslint >= 7 && 'false' || 'true' }}" diff --git a/package.json b/package.json index 9cb8e60abb..97279330df 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@types/eslint": "=7.2.10", "@types/estree": "0.0.52", "@types/node": "^4.9.5", - "@typescript-eslint/parser": "^2.34.0 || ^3.10.1 || ^4 || ^5 || ^6.20 || ^7.14.1 || ^8.4", + "@typescript-eslint/parser": "^2.34.0 || ^3.10.1 || ^4 || ^5 || ^6.20 || ^7.14.1 || 8.4 - 8.17", "babel-eslint": "^8 || ^9 || ^10.1.0", "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint-config-airbnb-base": "^15.0.0", From 958954de7422c5c78e8758fa02fc8b6aa2db67ec Mon Sep 17 00:00:00 2001 From: Bastien Dumont <32489032+bastiendmt@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:13:12 +0200 Subject: [PATCH 14/40] [Docs] fix broken links: - `default-props-match-prop-types` - `jsx-boolean-value` - `jsx-curly-brace-presence` - `jsx-no-bind` - `no-array-index-key` - `no-is-mounted` - `no-render-return-value` - `require-default-props` --- CHANGELOG.md | 3 +++ docs/rules/default-props-match-prop-types.md | 2 +- docs/rules/jsx-boolean-value.md | 2 +- docs/rules/jsx-curly-brace-presence.md | 2 +- docs/rules/jsx-no-bind.md | 6 +++--- docs/rules/no-array-index-key.md | 2 +- docs/rules/no-is-mounted.md | 2 +- docs/rules/no-render-return-value.md | 4 ++-- docs/rules/require-default-props.md | 2 +- 9 files changed, 14 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff0bedbc3a..3b2b5bcf38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ + # Change Log All notable changes to this project will be documented in this file. @@ -12,8 +13,10 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Changed * [Tests] [`jsx-no-script-url`]: Improve tests ([#3849][] @radu2147) +* [Docs] fix broken links: [`default-props-match-prop-types`], [`jsx-boolean-value`], [`jsx-curly-brace-presence`], [`jsx-no-bind`], [`no-array-index-key`], [`no-is-mounted`], [`no-render-return-value`], [`require-default-props`] ([#3841][] @bastiendmt) [#3849]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3849 +[#3841]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3841 [#3840]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3840 [#3833]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3833 diff --git a/docs/rules/default-props-match-prop-types.md b/docs/rules/default-props-match-prop-types.md index f5641c44aa..d8773046f2 100644 --- a/docs/rules/default-props-match-prop-types.md +++ b/docs/rules/default-props-match-prop-types.md @@ -196,7 +196,7 @@ If you don't care about stray `defaultsProps` in your components, you can disabl ## Resources -- [Official React documentation on defaultProps](https://facebook.github.io/react/docs/typechecking-with-proptypes.html#default-prop-values) +- [Official React documentation on defaultProps](https://legacy.reactjs.org/docs/typechecking-with-proptypes.html#default-prop-values) [PropTypes]: https://reactjs.org/docs/typechecking-with-proptypes.html [TypeScript]: https://www.typescriptlang.org/ diff --git a/docs/rules/jsx-boolean-value.md b/docs/rules/jsx-boolean-value.md index 1a0c2bde17..6bebe31137 100644 --- a/docs/rules/jsx-boolean-value.md +++ b/docs/rules/jsx-boolean-value.md @@ -4,7 +4,7 @@ -[When using a boolean attribute in JSX](https://facebook.github.io/react/docs/jsx-in-depth.html#boolean-attributes), you can set the attribute value to `true` or omit the value. +When using a [boolean attribute in JSX](https://web.archive.org/web/20160607204033/http://facebook.github.io/react/docs/jsx-in-depth.html#boolean-attributes), you can set the attribute value to `true` or omit the value. ## Rule Details diff --git a/docs/rules/jsx-curly-brace-presence.md b/docs/rules/jsx-curly-brace-presence.md index ddd296926a..30a00364db 100644 --- a/docs/rules/jsx-curly-brace-presence.md +++ b/docs/rules/jsx-curly-brace-presence.md @@ -6,7 +6,7 @@ This rule allows you to enforce curly braces or disallow unnecessary curly braces in JSX props and/or children. -For situations where JSX expressions are unnecessary, please refer to [the React doc](https://facebook.github.io/react/docs/jsx-in-depth.html) and [this page about JSX gotchas](https://github.com/facebook/react/blob/v15.4.0-rc.3/docs/docs/02.3-jsx-gotchas.md#html-entities). +For situations where JSX expressions are unnecessary, please refer to [the React doc](https://legacy.reactjs.org/docs/jsx-in-depth.html) and [this page about JSX gotchas](https://github.com/facebook/react/blob/v15.4.0-rc.3/docs/docs/02.3-jsx-gotchas.md#html-entities). ## Rule Details diff --git a/docs/rules/jsx-no-bind.md b/docs/rules/jsx-no-bind.md index 10141656a6..2becfef8a0 100644 --- a/docs/rules/jsx-no-bind.md +++ b/docs/rules/jsx-no-bind.md @@ -153,7 +153,7 @@ This will speed up rendering, as it avoids the need to create new functions (thr ### ES6 Classes -Unfortunately [React ES6 classes](https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#es6-classes) do not autobind their methods like components created with the older `createReactClass` syntax. There are several approaches to binding methods for ES6 classes. A basic approach is to just manually bind the methods in the constructor: +Unfortunately [React ES6 classes](https://legacy.reactjs.org/blog/2015/01/27/react-v0.13.0-beta-1.html#es6-classes) do not autobind their methods like components created with the older `createReactClass` syntax. There are several approaches to binding methods for ES6 classes. A basic approach is to just manually bind the methods in the constructor: ```jsx class Foo extends React.Component { @@ -174,7 +174,7 @@ class Foo extends React.Component { } ``` -A more sophisticated approach would be to use something like an [autobind ES7 decorator](https://www.npmjs.com/package/core-decorators#autobind) or [property initializers](https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding). +A more sophisticated approach would be to use something like an [autobind ES7 decorator](https://www.npmjs.com/package/core-decorators#autobind) or [property initializers](https://legacy.reactjs.org/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding). ### React Hooks @@ -191,7 +191,7 @@ const Button = () => { }; ``` -Otherwise, the idiomatic way to avoid redefining callbacks on every render would be to memoize them using the [`useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback) hook: +Otherwise, the idiomatic way to avoid redefining callbacks on every render would be to memoize them using the [`useCallback`](https://legacy.reactjs.org/docs/hooks-reference.html#usecallback) hook: ```jsx const Button = () => { diff --git a/docs/rules/no-array-index-key.md b/docs/rules/no-array-index-key.md index 37f2652d93..4fc4f928ad 100644 --- a/docs/rules/no-array-index-key.md +++ b/docs/rules/no-array-index-key.md @@ -4,7 +4,7 @@ Warn if an element uses an Array index in its `key`. -The `key` is used by React to [identify which items have changed, are added, or are removed and should be stable](https://facebook.github.io/react/docs/lists-and-keys.html#keys). +The `key` is used by React to [identify which items have changed, are added, or are removed and should be stable](https://react.dev/learn/rendering-lists#why-does-react-need-keys). It's a bad idea to use the array index since it doesn't uniquely identify your elements. In cases where the array is sorted or an element is added to the beginning of the array, the index will be changed even though the element representing that index may be the same. This results in unnecessary renders. diff --git a/docs/rules/no-is-mounted.md b/docs/rules/no-is-mounted.md index e38be740bc..ce06311545 100644 --- a/docs/rules/no-is-mounted.md +++ b/docs/rules/no-is-mounted.md @@ -6,7 +6,7 @@ [`isMounted` is an anti-pattern][anti-pattern], is not available when using ES6 classes, and it is on its way to being officially deprecated. -[anti-pattern]: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html +[anti-pattern]: https://legacy.reactjs.org/blog/2015/12/16/ismounted-antipattern.html ## Rule Details diff --git a/docs/rules/no-render-return-value.md b/docs/rules/no-render-return-value.md index 2042ba9f57..1859f75231 100644 --- a/docs/rules/no-render-return-value.md +++ b/docs/rules/no-render-return-value.md @@ -4,9 +4,9 @@ -> `ReactDOM.render()` currently returns a reference to the root `ReactComponent` instance. However, using this return value is legacy and should be avoided because future versions of React may render components asynchronously in some cases. If you need a reference to the root `ReactComponent` instance, the preferred solution is to attach a [callback ref](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs) to the root element. +> `ReactDOM.render()` currently returns a reference to the root `ReactComponent` instance. However, using this return value is legacy and should be avoided because future versions of React may render components asynchronously in some cases. If you need a reference to the root `ReactComponent` instance, the preferred solution is to attach a [callback ref](https://legacy.reactjs.org/docs/refs-and-the-dom.html#callback-refs) to the root element. -Source: [ReactDOM documentation](https://facebook.github.io/react/docs/react-dom.html#render) +Source: [ReactDOM documentation](https://legacy.reactjs.org/docs/react-dom.html#render) ## Rule Details diff --git a/docs/rules/require-default-props.md b/docs/rules/require-default-props.md index f083aaf7ff..ea4e69e086 100644 --- a/docs/rules/require-default-props.md +++ b/docs/rules/require-default-props.md @@ -476,7 +476,7 @@ If you don't care about using `defaultProps` for your component's props that are ## Resources -- [Official React documentation on defaultProps](https://facebook.github.io/react/docs/typechecking-with-proptypes.html#default-prop-values) +- [Official React documentation on defaultProps](https://legacy.reactjs.org/docs/typechecking-with-proptypes.html#default-prop-values) [PropTypes]: https://reactjs.org/docs/typechecking-with-proptypes.html [TypeScript]: https://www.typescriptlang.org/ From 233d442a8af56bd6b362b4b979a73c1290e7885d Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 9 Dec 2024 13:04:38 -0800 Subject: [PATCH 15/40] [Dev Deps] update `@babel/preset-react` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 97279330df..da508d3131 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@babel/plugin-syntax-decorators": "^7.25.9", "@babel/plugin-syntax-do-expressions": "^7.25.9", "@babel/plugin-syntax-function-bind": "^7.25.9", - "@babel/preset-react": "^7.25.9", + "@babel/preset-react": "^7.26.3", "@types/eslint": "=7.2.10", "@types/estree": "0.0.52", "@types/node": "^4.9.5", From 66ae4c14b109082294022931ca21e8816fa0c912 Mon Sep 17 00:00:00 2001 From: Andrew Patton Date: Thu, 19 Sep 2024 16:31:41 +0000 Subject: [PATCH 16/40] [Fix] `no-unknown-property`: support `precedence` prop in react 19 Fixes #3827 --- CHANGELOG.md | 2 ++ lib/rules/no-unknown-property.js | 29 +++++++++++++++++--------- tests/lib/rules/no-unknown-property.js | 6 ++++++ 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b2b5bcf38..8497f49c61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Fixed * [`no-danger`]: avoid a crash on a nested component name ([#3833][] @ljharb) * [Fix] types: correct generated type declaration ([#3840][] @ocavue) +* [`no-unknown-property`]: support `precedence` prop in react 19 ([#3829][] @acusti) ### Changed * [Tests] [`jsx-no-script-url`]: Improve tests ([#3849][] @radu2147) @@ -19,6 +20,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange [#3841]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3841 [#3840]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3840 [#3833]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3833 +[#3829]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3829 ## [7.37.2] - 2024.10.22 diff --git a/lib/rules/no-unknown-property.js b/lib/rules/no-unknown-property.js index dc5018007a..9a21c96fad 100644 --- a/lib/rules/no-unknown-property.js +++ b/lib/rules/no-unknown-property.js @@ -363,16 +363,24 @@ const REACT_ON_PROPS = [ ]; function getDOMPropertyNames(context) { - const ALL_DOM_PROPERTY_NAMES = DOM_PROPERTY_NAMES_TWO_WORDS.concat(DOM_PROPERTY_NAMES_ONE_WORD); - // this was removed in React v16.1+, see https://github.com/facebook/react/pull/10823 - if (!testReactVersion(context, '>= 16.1.0')) { - return ALL_DOM_PROPERTY_NAMES.concat('allowTransparency'); - } - // these were added in React v16.4.0, see https://reactjs.org/blog/2018/05/23/react-v-16-4.html and https://github.com/facebook/react/pull/12507 - if (testReactVersion(context, '>= 16.4.0')) { - return ALL_DOM_PROPERTY_NAMES.concat(REACT_ON_PROPS); - } - return ALL_DOM_PROPERTY_NAMES; + return [].concat( + DOM_PROPERTY_NAMES_TWO_WORDS, + DOM_PROPERTY_NAMES_ONE_WORD, + + testReactVersion(context, '>= 16.1.0') ? [].concat( + testReactVersion(context, '>= 16.4.0') ? [].concat( + // these were added in React v16.4.0, see https://reactjs.org/blog/2018/05/23/react-v-16-4.html and https://github.com/facebook/react/pull/12507 + REACT_ON_PROPS, + testReactVersion(context, '>= 19') ? [ + // precedence was added in React v19, see https://react.dev/blog/2024/04/25/react-19#support-for-stylesheets + 'precedence', + ] : [] + ) : [] + ) : [ + // this was removed in React v16.1+, see https://github.com/facebook/react/pull/10823 + 'allowTransparency', + ] + ); } // ------------------------------------------------------------------------------ @@ -501,6 +509,7 @@ function getStandardName(name, context) { return SVGDOM_ATTRIBUTE_NAMES[/** @type {keyof SVGDOM_ATTRIBUTE_NAMES} */ (name)]; } const names = getDOMPropertyNames(context); + // Let's find a possible attribute match with a case-insensitive search. return names.find((element) => element.toLowerCase() === name.toLowerCase()); } diff --git a/tests/lib/rules/no-unknown-property.js b/tests/lib/rules/no-unknown-property.js index 32e6c6d6b3..97ae42ea57 100644 --- a/tests/lib/rules/no-unknown-property.js +++ b/tests/lib/rules/no-unknown-property.js @@ -89,6 +89,12 @@ ruleTester.run('no-unknown-property', rule, { { code: '
' }, { code: '' }, { code: '
' }, + { + code: '', + settings: { + react: { version: '19.0.0' }, + }, + }, // Case ignored attributes, for `charset` discussion see https://github.com/jsx-eslint/eslint-plugin-react/pull/1863 { code: ';' }, { code: ';' }, From b713026c48a7292488426f98f5f0b22968033a79 Mon Sep 17 00:00:00 2001 From: Rodrigo Bondoc Date: Mon, 2 Dec 2024 20:17:55 -0800 Subject: [PATCH 17/40] [Fix] `prop-types`: props missing in validation when using generic types from a namespace import --- CHANGELOG.md | 2 + lib/util/propTypes.js | 4 +- tests/lib/rules/prop-types.js | 464 ++++++++++++++++++++++++++++++++++ 3 files changed, 469 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8497f49c61..9de24f1426 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,11 +11,13 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange * [`no-danger`]: avoid a crash on a nested component name ([#3833][] @ljharb) * [Fix] types: correct generated type declaration ([#3840][] @ocavue) * [`no-unknown-property`]: support `precedence` prop in react 19 ([#3829][] @acusti) +* [`prop-types`]: props missing in validation when using generic types from a namespace import ([#3859][] @rbondoc96) ### Changed * [Tests] [`jsx-no-script-url`]: Improve tests ([#3849][] @radu2147) * [Docs] fix broken links: [`default-props-match-prop-types`], [`jsx-boolean-value`], [`jsx-curly-brace-presence`], [`jsx-no-bind`], [`no-array-index-key`], [`no-is-mounted`], [`no-render-return-value`], [`require-default-props`] ([#3841][] @bastiendmt) +[#3859]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3859 [#3849]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3849 [#3841]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3841 [#3840]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3840 diff --git a/lib/util/propTypes.js b/lib/util/propTypes.js index f26a6510c9..3a8cc67f93 100644 --- a/lib/util/propTypes.js +++ b/lib/util/propTypes.js @@ -107,8 +107,10 @@ module.exports = function propTypesInstructions(context, components, utils) { const defaults = { customValidators: [] }; const configuration = Object.assign({}, defaults, context.options[0] || {}); const customValidators = configuration.customValidators; - const allowedGenericTypes = new Set(['forwardRef', 'ForwardRefRenderFunction', 'VFC', 'VoidFunctionComponent', 'PropsWithChildren', 'SFC', 'StatelessComponent', 'FunctionComponent', 'FC']); + const allowedGenericTypes = new Set(['ComponentProps', 'ComponentPropsWithoutRef', 'forwardRef', 'ForwardRefRenderFunction', 'VFC', 'VoidFunctionComponent', 'PropsWithChildren', 'SFC', 'StatelessComponent', 'FunctionComponent', 'FC']); const genericTypeParamIndexWherePropsArePresent = { + ComponentProps: 0, + ComponentPropsWithoutRef: 0, ForwardRefRenderFunction: 1, forwardRef: 1, VoidFunctionComponent: 0, diff --git a/tests/lib/rules/prop-types.js b/tests/lib/rules/prop-types.js index 39dc8bad3c..4a7d05ad6f 100644 --- a/tests/lib/rules/prop-types.js +++ b/tests/lib/rules/prop-types.js @@ -4117,6 +4117,470 @@ ruleTester.run('prop-types', rule, { `, features: ['ts', 'no-babel'], }, + { + code: ` + import {ComponentPropsWithoutRef, forwardRef} from "react"; + + export const FancyButton = forwardRef>( + ({ className, children, ...props }, ref) => ( + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import {ComponentProps, forwardRef} from "react"; + + export const FancyButton = forwardRef>( + ({ className, children, ...props }, ref) => ( + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import {ComponentPropsWithoutRef, ElementRef, forwardRef} from "react"; + + const BaseButton = forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = forwardRef, ComponentPropsWithoutRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import {ComponentProps, ElementRef, forwardRef} from "react"; + + const BaseButton = forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = forwardRef, ComponentProps>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import {ComponentProps, ComponentPropsWithoutRef, ElementRef, forwardRef} from "react"; + + const BaseButton = forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = forwardRef, ComponentPropsWithoutRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import {ComponentProps, ComponentPropsWithoutRef, ElementRef, forwardRef} from "react"; + + const BaseButton = forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = forwardRef, ComponentProps>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React from "react"; + + export const FancyButton = React.forwardRef>( + ({ className, children, ...props }, ref) => ( + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React from "react"; + + export const FancyButton = React.forwardRef>( + ({ className, children, ...props }, ref) => ( + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentProps>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentProps>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import * as React from "react"; + + export const FancyButton = React.forwardRef>( + ({ className, children, ...props }, ref) => ( + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import * as React from "react"; + + export const FancyButton = React.forwardRef>( + ({ className, children, ...props }, ref) => ( + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import * as React from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentProps>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import * as React from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import * as React from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import * as React from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentProps>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React, {ComponentPropsWithoutRef} from "react"; + + export const FancyButton = React.forwardRef>( + ({ className, children, ...props }, ref) => ( + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React, {ComponentProps} from "react"; + + export const FancyButton = React.forwardRef>( + ({ className, children, ...props }, ref) => ( + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React, {ComponentPropsWithoutRef, ElementRef} from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, ComponentPropsWithoutRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React, {ComponentProps, ElementRef} from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, ComponentProps>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React, {ComponentProps, ComponentPropsWithoutRef, ElementRef} from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, ComponentProps>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React, {ComponentProps, ComponentPropsWithoutRef, ElementRef} from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, ComponentPropsWithoutRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, { code: ` import React, { forwardRef } from 'react'; From b4a14f4cdbac6e6ad78f79bd3cec167416ddbc90 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sun, 22 Dec 2024 14:35:56 -0800 Subject: [PATCH 18/40] [meta] add `directories.test` --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index da508d3131..18ceee9d2a 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,9 @@ "type": "git", "url": "https://github.com/jsx-eslint/eslint-plugin-react" }, + "directories": { + "test": ["test", "tests", "test-published-types"] + }, "homepage": "https://github.com/jsx-eslint/eslint-plugin-react", "bugs": "https://github.com/jsx-eslint/eslint-plugin-react/issues", "dependencies": { From 033ad19c6afd4cc6a0777f6c174e7f2dadbd7853 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 23 Dec 2024 13:10:46 -0800 Subject: [PATCH 19/40] [Deps] update `array.prototype.flatmap`, `es-iterator-helpers`, `object.values`, `string.prototype.matchall` --- package.json | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 18ceee9d2a..9870a6037f 100644 --- a/package.json +++ b/package.json @@ -27,28 +27,32 @@ "url": "https://github.com/jsx-eslint/eslint-plugin-react" }, "directories": { - "test": ["test", "tests", "test-published-types"] + "test": [ + "test", + "tests", + "test-published-types" + ] }, "homepage": "https://github.com/jsx-eslint/eslint-plugin-react", "bugs": "https://github.com/jsx-eslint/eslint-plugin-react/issues", "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.2", + "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.2.0", + "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.8", "object.fromentries": "^2.0.8", - "object.values": "^1.2.0", + "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11", + "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "devDependencies": { From ed3b1cf8f398a284353e9f8d41a4ab7b1c31a543 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 23 Dec 2024 13:59:32 -0800 Subject: [PATCH 20/40] [Tests] `jsx-uses-vars`, `jsx-uses-react`: fix `no-unused-vars` tests in eslint v9.17 https://github.com/eslint/eslint/pull/18352 added suggestions to no-unused-vars in eslint v9.17.0 --- tests/index.js | 1 + tests/lib/rules/jsx-uses-react.js | 51 ++++++++++-- tests/lib/rules/jsx-uses-vars.js | 124 ++++++++++++++++++++++++++++-- 3 files changed, 162 insertions(+), 14 deletions(-) diff --git a/tests/index.js b/tests/index.js index 9f7a052943..3539f48136 100644 --- a/tests/index.js +++ b/tests/index.js @@ -10,6 +10,7 @@ const plugin = require('..'); const index = require('../lib/rules'); const ruleFiles = fs.readdirSync(path.resolve(__dirname, '../lib/rules/')) + .filter((f) => f.endsWith('.js')) .map((f) => path.basename(f, '.js')) .filter((f) => f !== 'index'); diff --git a/tests/lib/rules/jsx-uses-react.js b/tests/lib/rules/jsx-uses-react.js index 3a8e39013c..381b44bc89 100644 --- a/tests/lib/rules/jsx-uses-react.js +++ b/tests/lib/rules/jsx-uses-react.js @@ -60,28 +60,67 @@ ruleTester.run('no-unused-vars', rule, { invalid: parsers.all([ { code: '/*eslint react/jsx-uses-react:1*/ var React;', - errors: [{ message: '\'React\' is defined but never used.' }], + errors: [{ + message: '\'React\' is defined but never used.', + suggestions: [{ + messageId: 'removeVar', + output: '/*eslint react/jsx-uses-react:1*/ ', + }], + }], }, { code: '/*eslint react/jsx-uses-react:1*/ /** @jsx Foo */ var React;
;', - errors: [{ message: '\'React\' is defined but never used.' }], + errors: [{ + message: '\'React\' is defined but never used.', + suggestions: [{ + messageId: 'removeVar', + output: '/*eslint react/jsx-uses-react:1*/ /** @jsx Foo */
;', + }], + }], }, { code: '/*eslint react/jsx-uses-react:1*/ var React;
;', - errors: [{ message: '\'React\' is defined but never used.' }], + errors: [{ + message: '\'React\' is defined but never used.', + suggestions: [{ + messageId: 'removeVar', + output: '/*eslint react/jsx-uses-react:1*/
;', + }], + }], settings, }, { code: '/*eslint react/jsx-uses-react:1*/ var Frag; <>;', - errors: [{ message: '\'Frag\' is defined but never used.' }], + errors: [{ + message: '\'Frag\' is defined but never used.', + suggestions: [{ + messageId: 'removeVar', + output: '/*eslint react/jsx-uses-react:1*/ <>;', + }], + }], features: ['fragment'], settings: { react: { fragment: 'Fragment' } }, }, { code: '/*eslint react/jsx-uses-react:1*/ var React; <>;', features: ['fragment'], - errors: [{ message: '\'React\' is defined but never used.' }], + errors: [{ + message: '\'React\' is defined but never used.', + suggestions: [{ + messageId: 'removeVar', + output: '/*eslint react/jsx-uses-react:1*/ <>;', + }], + }], settings, }, - ].map(parsers.disableNewTS)), + ].map(parsers.disableNewTS).map((test) => { + if (!rule.meta.hasSuggestions) { + test.errors = test.errors.map((error) => { + // https://github.com/eslint/eslint/pull/18352 added suggestions to no-unused-vars in eslint v9.17.0 + delete error.suggestions; + return error; + }); + } + return test; + })), }); diff --git a/tests/lib/rules/jsx-uses-vars.js b/tests/lib/rules/jsx-uses-vars.js index 00f801fd65..8b9db2a956 100644 --- a/tests/lib/rules/jsx-uses-vars.js +++ b/tests/lib/rules/jsx-uses-vars.js @@ -10,6 +10,7 @@ // ----------------------------------------------------------------------------- const ruleNoUnusedVars = require('../../helpers/getESLintCoreRule')('no-unused-vars'); + const rulePreferConst = require('../../helpers/getESLintCoreRule')('prefer-const'); const RuleTester = require('../../helpers/ruleTester'); @@ -136,7 +137,13 @@ ruleTester.run('no-unused-vars', ruleNoUnusedVars, { invalid: parsers.all([ { code: '/* eslint react/jsx-uses-vars: 1 */ var App;', - errors: [{ message: '\'App\' is defined but never used.' }], + errors: [{ + message: '\'App\' is defined but never used.', + suggestions: [{ + messageId: 'removeVar', + output: '/* eslint react/jsx-uses-vars: 1 */ ', + }], + }], }, { code: ` @@ -145,7 +152,18 @@ ruleTester.run('no-unused-vars', ruleNoUnusedVars, { var unused; React.render(); `, - errors: [{ message: '\'unused\' is defined but never used.' }], + errors: [{ + message: '\'unused\' is defined but never used.', + suggestions: [{ + messageId: 'removeVar', + output: ` + /* eslint react/jsx-uses-vars: 1 */ + var App; + ${''} + React.render(); + `, + }], + }], }, { code: ` @@ -155,8 +173,30 @@ ruleTester.run('no-unused-vars', ruleNoUnusedVars, { React.render(); `, errors: [ - { message: '\'App\' is defined but never used.' }, - { message: '\'Hello\' is defined but never used.' }, + { + message: '\'App\' is defined but never used.', + suggestions: [{ + messageId: 'removeVar', + output: ` + /* eslint react/jsx-uses-vars: 1 */ + ${''} + var Hello; + React.render(); + `, + }], + }, + { + message: '\'Hello\' is defined but never used.', + suggestions: [{ + messageId: 'removeVar', + output: ` + /* eslint react/jsx-uses-vars: 1 */ + var App; + ${''} + React.render(); + `, + }], + }, ], features: ['jsx namespace'], }, @@ -167,14 +207,34 @@ ruleTester.run('no-unused-vars', ruleNoUnusedVars, { var Input; React.render(); `, - errors: [{ message: '\'Input\' is defined but never used.' }], + errors: [{ + message: '\'Input\' is defined but never used.', + suggestions: [{ + messageId: 'removeVar', + output: ` + /* eslint react/jsx-uses-vars: 1 */ + var Button; + ${''} + React.render(); + `, + }], + }], }, { code: ` /* eslint react/jsx-uses-vars: 1 */ class unused {} `, - errors: [{ message: '\'unused\' is defined but never used.' }], + errors: [{ + message: '\'unused\' is defined but never used.', + suggestions: [{ + messageId: 'removeVar', + output: ` + /* eslint react/jsx-uses-vars: 1 */ + ${''} + `, + }], + }], }, { code: ` @@ -190,6 +250,13 @@ ruleTester.run('no-unused-vars', ruleNoUnusedVars, { { message: '\'HelloMessage\' is defined but never used.', line: 3, + suggestions: [{ + messageId: 'removeVar', + output: ` + /* eslint react/jsx-uses-vars: 1 */ + ${''} + `, + }], }, ], }, @@ -207,6 +274,18 @@ ruleTester.run('no-unused-vars', ruleNoUnusedVars, { { message: '\'Hello\' is defined but never used.', line: 3, + suggestions: [{ + messageId: 'removeVar', + output: ` + /* eslint react/jsx-uses-vars: 1 */ + ${''} + function Greetings() { + const Hello = require('Hello').default; + return ; + } + Greetings(); + `, + }], }, ], }, @@ -216,7 +295,17 @@ ruleTester.run('no-unused-vars', ruleNoUnusedVars, { var lowercase; React.render(); `, - errors: [{ message: '\'lowercase\' is defined but never used.' }], + errors: [{ + message: '\'lowercase\' is defined but never used.', + suggestions: [{ + messageId: 'removeVar', + output: ` + /* eslint react/jsx-uses-vars: 1 */ + ${''} + React.render(); + `, + }], + }], }, { code: ` @@ -230,10 +319,29 @@ ruleTester.run('no-unused-vars', ruleNoUnusedVars, { { message: '\'div\' is defined but never used.', line: 3, + suggestions: [{ + messageId: 'removeVar', + output: ` + /* eslint react/jsx-uses-vars: 1 */ + function Greetings() { + return
; + } + Greetings(); + `, + }], }, ], }, - ]), + ].map((test) => { + if (!ruleNoUnusedVars.meta.hasSuggestions) { + test.errors = test.errors.map((error) => { + // https://github.com/eslint/eslint/pull/18352 added suggestions to no-unused-vars in eslint v9.17.0 + delete error.suggestions; + return error; + }); + } + return test; + })), }); // Check compatibility with eslint prefer-const rule (#716) From bc5b9dda28e37ee2a5dc9daa98868ba4a339839e Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 23 Dec 2024 14:04:14 -0800 Subject: [PATCH 21/40] [actions] release workflow needs some new domains (because less stuff is included by default now) --- .github/workflows/release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3ea4e63f84..d6f97d2e84 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,6 +20,9 @@ jobs: allowed-endpoints: api.github.com:443 github.com:443 + raw.githubusercontent.com:443 + nodejs.org:443 + registry.npmjs.org:443 - name: Get version from tag id: tag_name From 244743a7a974787f60d0afb05dd2cae8f7392064 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 23 Dec 2024 13:11:42 -0800 Subject: [PATCH 22/40] Update CHANGELOG and bump version --- CHANGELOG.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9de24f1426..a7b13f285b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ## Unreleased +## [7.37.3] - 2024.12.23 + ### Fixed * [`no-danger`]: avoid a crash on a nested component name ([#3833][] @ljharb) * [Fix] types: correct generated type declaration ([#3840][] @ocavue) @@ -17,6 +19,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange * [Tests] [`jsx-no-script-url`]: Improve tests ([#3849][] @radu2147) * [Docs] fix broken links: [`default-props-match-prop-types`], [`jsx-boolean-value`], [`jsx-curly-brace-presence`], [`jsx-no-bind`], [`no-array-index-key`], [`no-is-mounted`], [`no-render-return-value`], [`require-default-props`] ([#3841][] @bastiendmt) +[7.37.3]: https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.37.2...v7.37.3 [#3859]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3859 [#3849]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3849 [#3841]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3841 diff --git a/package.json b/package.json index 9870a6037f..9b34448353 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-react", - "version": "7.37.2", + "version": "7.37.3", "author": "Yannick Croissant ", "description": "React specific linting rules for ESLint", "main": "index.js", From 5c816edc1d146767143ce894707bd7284aca400c Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 23 Dec 2024 21:49:15 -0800 Subject: [PATCH 23/40] [actions] publish action: allow additional URL --- .github/workflows/npm-publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 004c88360e..2e654951b6 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -105,6 +105,7 @@ jobs: nodejs.org:443 prod.api.stepsecurity.io:443 registry.npmjs.org:443 + raw.githubusercontent.com:443 - uses: actions/checkout@v4 with: From 82a196a0b2c7c5c91e57f320428b58900cb4a8cf Mon Sep 17 00:00:00 2001 From: Andrew Patton Date: Mon, 9 Dec 2024 18:21:00 -0800 Subject: [PATCH 24/40] [Fix] `no-unknown-property`: support `onBeforeToggle`, `popoverTarget`, `popoverTargetAction` attributes --- CHANGELOG.md | 5 +++++ lib/rules/no-unknown-property.js | 8 +++++--- tests/lib/rules/no-unknown-property.js | 9 +++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7b13f285b..904a29a460 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ## Unreleased +### Fixed +* [`no-unknown-property`]: support `onBeforeToggle`, `popoverTarget`, `popoverTargetAction` attributes ([#3865][] @acusti) + +[#3865]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3865 + ## [7.37.3] - 2024.12.23 ### Fixed diff --git a/lib/rules/no-unknown-property.js b/lib/rules/no-unknown-property.js index 9a21c96fad..b38c588064 100644 --- a/lib/rules/no-unknown-property.js +++ b/lib/rules/no-unknown-property.js @@ -259,8 +259,8 @@ const DOM_PROPERTY_NAMES_TWO_WORDS = [ 'onCompositionUpdate', 'onCut', 'onDoubleClick', 'onDrag', 'onDragEnd', 'onDragEnter', 'onDragExit', 'onDragLeave', 'onError', 'onFocus', 'onInput', 'onKeyDown', 'onKeyPress', 'onKeyUp', 'onLoad', 'onWheel', 'onDragOver', 'onDragStart', 'onDrop', 'onMouseDown', 'onMouseEnter', 'onMouseLeave', 'onMouseMove', 'onMouseOut', 'onMouseOver', - 'onMouseUp', 'onPaste', 'onScroll', 'onSelect', 'onSubmit', 'onToggle', 'onTransitionEnd', 'radioGroup', 'readOnly', 'referrerPolicy', - 'rowSpan', 'srcDoc', 'srcLang', 'srcSet', 'useMap', 'fetchPriority', + 'onMouseUp', 'onPaste', 'onScroll', 'onSelect', 'onSubmit', 'onBeforeToggle', 'onToggle', 'onTransitionEnd', 'radioGroup', + 'readOnly', 'referrerPolicy', 'rowSpan', 'srcDoc', 'srcLang', 'srcSet', 'useMap', 'fetchPriority', // SVG attributes // See https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute 'crossOrigin', 'accentHeight', 'alignmentBaseline', 'arabicForm', 'attributeName', @@ -317,9 +317,11 @@ const DOM_PROPERTY_NAMES_TWO_WORDS = [ 'onMouseMoveCapture', 'onMouseOutCapture', 'onMouseOverCapture', 'onMouseUpCapture', // Video specific 'autoPictureInPicture', 'controlsList', 'disablePictureInPicture', 'disableRemotePlayback', + // popovers + 'popoverTarget', 'popoverTargetAction', ]; -const DOM_PROPERTIES_IGNORE_CASE = ['charset', 'allowFullScreen', 'webkitAllowFullScreen', 'mozAllowFullScreen', 'webkitDirectory']; +const DOM_PROPERTIES_IGNORE_CASE = ['charset', 'allowFullScreen', 'webkitAllowFullScreen', 'mozAllowFullScreen', 'webkitDirectory', 'popoverTarget', 'popoverTargetAction']; const ARIA_PROPERTIES = [ // See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes diff --git a/tests/lib/rules/no-unknown-property.js b/tests/lib/rules/no-unknown-property.js index 97ae42ea57..e746ef56bc 100644 --- a/tests/lib/rules/no-unknown-property.js +++ b/tests/lib/rules/no-unknown-property.js @@ -188,6 +188,15 @@ ruleTester.run('no-unknown-property', rule, {
`, }, + { + code: ` +
+ + +
Greetings, one and all!
+
+ `, + }, ]), invalid: parsers.all([ { From efc021fbece010b3f4a658cd1b05753e9e2776f1 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Fri, 10 Jan 2025 10:24:56 -0800 Subject: [PATCH 25/40] [types] fix types of flat configs Fixes #3874. --- CHANGELOG.md | 2 ++ index.js | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 904a29a460..7bec3e261d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,9 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ### Fixed * [`no-unknown-property`]: support `onBeforeToggle`, `popoverTarget`, `popoverTargetAction` attributes ([#3865][] @acusti) +* [types] fix types of flat configs ([#3874][] @ljharb) +[#3874]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3874 [#3865]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3865 ## [7.37.3] - 2024.12.23 diff --git a/index.js b/index.js index 365f17446c..64ff9bbdc4 100644 --- a/index.js +++ b/index.js @@ -90,19 +90,21 @@ const configs = { 'react/jsx-uses-react': SEVERITY_OFF, }, }, + flat: /** @type {Record} */ ({ + __proto__: null, + }), }; /** @typedef {{ plugins: { react: typeof plugin }, rules: import('eslint').Linter.RulesRecord, languageOptions: { parserOptions: import('eslint').Linter.ParserOptions } }} ReactFlatConfig */ -/** @type {{ deprecatedRules: typeof deprecatedRules, rules: typeof allRules, configs: typeof configs & { flat?: Record }}} */ +/** @type {{ deprecatedRules: typeof deprecatedRules, rules: typeof allRules, configs: typeof configs & { flat: Record }}} */ const plugin = { deprecatedRules, rules: allRules, configs, }; -/** @type {Record} */ -configs.flat = { +Object.assign(configs.flat, { recommended: { plugins: { react: plugin }, rules: configs.recommended.rules, @@ -118,6 +120,6 @@ configs.flat = { rules: configs['jsx-runtime'].rules, languageOptions: { parserOptions: configs['jsx-runtime'].parserOptions }, }, -}; +}); module.exports = plugin; From cfd5edd4f66905ea3300d3ee96289b9fefbbfb5f Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sun, 12 Jan 2025 13:23:16 -0800 Subject: [PATCH 26/40] [Dev Deps] update `@babel/eslint-parser` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9b34448353..45c0830f8c 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ }, "devDependencies": { "@babel/core": "^7.26.0", - "@babel/eslint-parser": "^7.25.9", + "@babel/eslint-parser": "^7.26.5", "@babel/plugin-syntax-decorators": "^7.25.9", "@babel/plugin-syntax-do-expressions": "^7.25.9", "@babel/plugin-syntax-function-bind": "^7.25.9", From e6b5b41191690ee166d0cca1e9db27092b910f03 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sun, 12 Jan 2025 13:25:31 -0800 Subject: [PATCH 27/40] Update CHANGELOG and bump version --- CHANGELOG.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bec3e261d..60155e7599 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,13 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ## Unreleased +## [7.37.4] - 2025.01.12 + ### Fixed * [`no-unknown-property`]: support `onBeforeToggle`, `popoverTarget`, `popoverTargetAction` attributes ([#3865][] @acusti) * [types] fix types of flat configs ([#3874][] @ljharb) +[7.37.4]: https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.37.3...v7.37.4 [#3874]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3874 [#3865]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3865 diff --git a/package.json b/package.json index 45c0830f8c..e8b927ef18 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-react", - "version": "7.37.3", + "version": "7.37.4", "author": "Yannick Croissant ", "description": "React specific linting rules for ESLint", "main": "index.js", From 7eb6ca9144333c828f24abdc98154a45aec46d54 Mon Sep 17 00:00:00 2001 From: Hamir Mahal Date: Fri, 21 Mar 2025 13:49:02 -0700 Subject: [PATCH 28/40] [Docs] `button-has-type`: clean up phrasing --- CHANGELOG.md | 5 +++++ docs/rules/button-has-type.md | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60155e7599..8a3f010d1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ## Unreleased +### Changed +* [Docs] [`button-has-type`]: clean up phrasing ([#3909][] @hamirmahal) + +[#3909]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3909 + ## [7.37.4] - 2025.01.12 ### Fixed diff --git a/docs/rules/button-has-type.md b/docs/rules/button-has-type.md index 8bd8b6a85b..cf2d5914c8 100644 --- a/docs/rules/button-has-type.md +++ b/docs/rules/button-has-type.md @@ -2,8 +2,8 @@ -The default value of `type` attribute for `button` HTML element is `"submit"` which is often not the desired behavior and may lead to unexpected page reloads. -This rules enforces an explicit `type` attribute for all the `button` elements and checks that its value is valid per spec (i.e., is one of `"button"`, `"submit"`, and `"reset"`). +The default value of the `type` attribute for HTML `button` elements is `"submit"`. This is often not the desired behavior and may lead to unexpected page reloads. +This rules enforces an explicit `type` attribute for all `button` elements and checks that its value is valid per the spec (i.e., is one of `"button"`, `"submit"`, and `"reset"`). ## Rule Details From 98a31f8e76a4d8aa52caeeb55940f35682b18b2f Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 25 Mar 2025 10:41:04 -0700 Subject: [PATCH 29/40] [Dev Deps] update `@babel/core`, `@babel/eslint-parser` --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e8b927ef18..465b49f7d4 100644 --- a/package.json +++ b/package.json @@ -56,8 +56,8 @@ "string.prototype.repeat": "^1.0.0" }, "devDependencies": { - "@babel/core": "^7.26.0", - "@babel/eslint-parser": "^7.26.5", + "@babel/core": "^7.26.10", + "@babel/eslint-parser": "^7.27.0", "@babel/plugin-syntax-decorators": "^7.25.9", "@babel/plugin-syntax-do-expressions": "^7.25.9", "@babel/plugin-syntax-function-bind": "^7.25.9", From addad4687b710c022f868ea17f6cabfaaddd8b44 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 25 Mar 2025 10:41:27 -0700 Subject: [PATCH 30/40] [Deps] update `object.entries` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 465b49f7d4..9f10f323b3 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.8", + "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", From 3fd9b9223e3f4fc6b34eb6f3ab734a7e2c73743d Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 25 Mar 2025 10:45:11 -0700 Subject: [PATCH 31/40] [Fix] `no-unknown-property`: allow shadow root attrs on `