diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a72b1b2..de1e5776 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), * Update to `@shlinkio/shlink-frontend-kit` 0.7.0 * Update to `@shlinkio/shlink-web-component` 0.13.0 * Update to `@shlinkio/shlink-js-sdk` 2.0.0 +* Add `eslint-plugin-react-compiler` ### Deprecated * *Nothing* diff --git a/eslint.config.js b/eslint.config.js index 17ed168b..4e99bef4 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,4 +1,8 @@ import shlink from '@shlinkio/eslint-config-js-coding-standard'; +import reactCompiler from 'eslint-plugin-react-compiler'; /* eslint-disable-next-line no-restricted-exports */ -export default shlink; +export default [ + ...shlink, + reactCompiler.configs.recommended, +]; diff --git a/package-lock.json b/package-lock.json index dc57ca49..1f44dfcc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,6 +57,7 @@ "eslint": "^9.21.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-react": "^7.37.4", + "eslint-plugin-react-compiler": "^19.0.0-beta-40c6c23-20250301", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-simple-import-sort": "^12.1.1", "history": "^5.3.0", @@ -700,6 +701,24 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", @@ -6050,6 +6069,27 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, + "node_modules/eslint-plugin-react-compiler": { + "version": "19.0.0-beta-40c6c23-20250301", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.0.0-beta-40c6c23-20250301.tgz", + "integrity": "sha512-9K59D9imZCdgdbA5OIa4EL1rCoNAmHNDGYW8sI8gYM0ILAb+foIR+3tpv6y0L/KHz1Mbhyx0KqVBq4lSG/5ykQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "hermes-parser": "^0.25.1", + "zod": "^3.22.4", + "zod-validation-error": "^3.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.0.0 || >= 18.0.0" + }, + "peerDependencies": { + "eslint": ">=7" + } + }, "node_modules/eslint-plugin-react-hooks": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", @@ -6857,6 +6897,23 @@ "node": ">= 0.4" } }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, "node_modules/history": { "version": "5.3.0", "dev": true, @@ -12555,6 +12612,29 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.4.0.tgz", + "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.18.0" + } } }, "dependencies": { @@ -12987,6 +13067,16 @@ "@babel/traverse": "^7.25.9" } }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, "@babel/plugin-proposal-private-property-in-object": { "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", @@ -16413,6 +16503,20 @@ } } }, + "eslint-plugin-react-compiler": { + "version": "19.0.0-beta-40c6c23-20250301", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.0.0-beta-40c6c23-20250301.tgz", + "integrity": "sha512-9K59D9imZCdgdbA5OIa4EL1rCoNAmHNDGYW8sI8gYM0ILAb+foIR+3tpv6y0L/KHz1Mbhyx0KqVBq4lSG/5ykQ==", + "dev": true, + "requires": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "hermes-parser": "^0.25.1", + "zod": "^3.22.4", + "zod-validation-error": "^3.0.3" + } + }, "eslint-plugin-react-hooks": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", @@ -16928,6 +17032,21 @@ "function-bind": "^1.1.2" } }, + "hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true + }, + "hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "requires": { + "hermes-estree": "0.25.1" + } + }, "history": { "version": "5.3.0", "dev": true, @@ -20774,6 +20893,19 @@ "yocto-queue": { "version": "0.1.0", "dev": true + }, + "zod": { + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "dev": true + }, + "zod-validation-error": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.4.0.tgz", + "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", + "dev": true, + "requires": {} } } } diff --git a/package.json b/package.json index c113e380..8079c170 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "eslint": "^9.21.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-react": "^7.37.4", + "eslint-plugin-react-compiler": "^19.0.0-beta-40c6c23-20250301", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-simple-import-sort": "^12.1.1", "history": "^5.3.0", diff --git a/src/container/utils.ts b/src/container/utils.ts index 254fdccc..0da77ccb 100644 --- a/src/container/utils.ts +++ b/src/container/utils.ts @@ -1,12 +1,11 @@ import type { IContainer } from 'bottlejs'; import type { FC } from 'react'; -import { useRef } from 'react'; +import { useMemo } from 'react'; export type FCWithDeps = FC & Partial; export function useDependencies(obj: Deps): Omit, keyof FC> { - const depsRef = useRef(obj as Omit, keyof FC>); - return depsRef.current; + return useMemo(() => obj as Omit, keyof FC>, [obj]); } export function componentFactory, keyof FC>>( diff --git a/src/servers/CreateServer.tsx b/src/servers/CreateServer.tsx index 533ceae2..b8c718fa 100644 --- a/src/servers/CreateServer.tsx +++ b/src/servers/CreateServer.tsx @@ -40,7 +40,9 @@ const CreateServer: FCWithDeps = ({ servers const navigate = useNavigate(); const goBack = useGoBack(); const hasServers = !!Object.keys(servers).length; + // eslint-disable-next-line react-compiler/react-compiler const [serversImported, setServersImported] = useTimeoutToggle(false, SHOW_IMPORT_MSG_TIME); + // eslint-disable-next-line react-compiler/react-compiler const [errorImporting, setErrorImporting] = useTimeoutToggle(false, SHOW_IMPORT_MSG_TIME); const [isConfirmModalOpen, toggleConfirmModal] = useToggle(); const [serverData, setServerData] = useState(); diff --git a/src/servers/ManageServers.tsx b/src/servers/ManageServers.tsx index 0bb58e93..25fad262 100644 --- a/src/servers/ManageServers.tsx +++ b/src/servers/ManageServers.tsx @@ -41,6 +41,7 @@ const ManageServers: FCWithDeps = ({ serv [allServers, searchTerm], ); const hasAutoConnect = allServers.some(({ autoConnect }) => !!autoConnect); + // eslint-disable-next-line react-compiler/react-compiler const [errorImporting, setErrorImporting] = useTimeoutToggle(false, SHOW_IMPORT_MSG_TIME); return (