@samitouri / QOS-React / commits / 24e260d35b

Enable rules-of-hooks for DevTools (#34645)

Sebastian "Sebbie" Silbermann committed Sep 29, 2025 at 15:31 UTC 24e260d35bb3a280aded6e79bc55080550569e28
10 files changed +22
.eslintrc.js
+8
@@ -517,6 +517,14 @@ module.exports = {
517 __IS_INTERNAL_VERSION__: 'readonly',
518 },
519 },
520 + {
521 + files: ['packages/react-devtools-*/**/*.js'],
522 + excludedFiles: '**/__tests__/**/*.js',
523 + plugins: ['eslint-plugin-react-hooks-published'],
524 + rules: {
525 + 'react-hooks-published/rules-of-hooks': ERROR,
526 + },
527 + },
528 {
529 files: ['packages/eslint-plugin-react-hooks/src/**/*'],
530 extends: ['plugin:@typescript-eslint/recommended'],
package.json
+1
@@ -71,6 +71,7 @@
71 "eslint-plugin-no-for-of-loops": "^1.0.0",
72 "eslint-plugin-no-function-declare-after-return": "^1.0.0",
73 "eslint-plugin-react": "^6.7.1",
74 + "eslint-plugin-react-hooks-published": "npm:eslint-plugin-react-hooks@^5.2.0",
75 "eslint-plugin-react-internal": "link:./scripts/eslint-rules",
76 "fbjs-scripts": "^3.0.1",
77 "filesize": "^6.0.1",
packages/react-devtools-shared/src/devtools/cache.js
+2
@@ -42,6 +42,7 @@ export type Resource<Input, Key, Value> = {
42 let readContext;
43 if (typeof React.use === 'function') {
44 readContext = function (Context: ReactContext<null>) {
45 + // eslint-disable-next-line react-hooks-published/rules-of-hooks
46 return React.use(Context);
47 };
48 } else if (
@@ -141,6 +142,7 @@ export function createResource<Input, Key, Value>(
142 const key = hashInput(input);
143 const result: Thenable<Value> = accessResult(resource, fetch, input, key);
144 if (typeof React.use === 'function') {
145 + // eslint-disable-next-line react-hooks-published/rules-of-hooks
146 return React.use(result);
147 }
148
packages/react-devtools-shared/src/devtools/views/ErrorBoundary/cache.js
+1
@@ -23,6 +23,7 @@ const API_TIMEOUT = 3000;
23 function readRecord<T>(record: Thenable<T>): T | null {
24 if (typeof React.use === 'function') {
25 try {
26 + // eslint-disable-next-line react-hooks-published/rules-of-hooks
27 return React.use(record);
28 } catch (x) {
29 if (x === null) {
packages/react-devtools-shared/src/dynamicImportCache.js
+1
@@ -30,6 +30,7 @@ const moduleLoaderFunctionToModuleMap: Map<ModuleLoaderFunction, Module> =
30 function readRecord<T>(record: Thenable<T>): T | null {
31 if (typeof React.use === 'function') {
32 try {
33 + // eslint-disable-next-line react-hooks-published/rules-of-hooks
34 return React.use(record);
35 } catch (x) {
36 if (x === null) {
packages/react-devtools-shared/src/hookNamesCache.js
+1
@@ -30,6 +30,7 @@ const TIMEOUT = 30000;
30 function readRecord<T>(record: Thenable<T>): T | null {
31 if (typeof React.use === 'function') {
32 try {
33 + // eslint-disable-next-line react-hooks-published/rules-of-hooks
34 return React.use(record);
35 } catch (x) {
36 if (record.status === 'rejected') {
packages/react-devtools-shared/src/inspectedElementCache.js
+1
@@ -32,6 +32,7 @@ import type {
32
33 function readRecord<T>(record: Thenable<T>): T {
34 if (typeof React.use === 'function') {
35 + // eslint-disable-next-line react-hooks-published/rules-of-hooks
36 return React.use(record);
37 }
38 if (record.status === 'fulfilled') {
packages/react-devtools-shell/src/app/SuspenseTree/index.js
+1
@@ -314,6 +314,7 @@ function LoadLater() {
314
315 function readRecord(promise: any): any {
316 if (typeof React.use === 'function') {
317 + // eslint-disable-next-line react-hooks-published/rules-of-hooks
318 return React.use(promise);
319 }
320 switch (promise.status) {
packages/react-devtools-timeline/src/timelineCache.js
+1
@@ -29,6 +29,7 @@ const fileNameToProfilerDataMap: Map<
29 function readRecord<T>(record: Thenable<T>): T | Error {
30 if (typeof React.use === 'function') {
31 try {
32 + // eslint-disable-next-line react-hooks-published/rules-of-hooks
33 return React.use(record);
34 } catch (x) {
35 if (record.status === 'rejected') {
yarn.lock
+5
@@ -8207,6 +8207,11 @@ eslint-plugin-no-unsanitized@4.0.2:
8207 resolved "https://registry.yarnpkg.com/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.2.tgz#e872b302cdfb5fe1262db989ba29cfcc334b499b"
8208 integrity sha512-Pry0S9YmHoz8NCEMRQh7N0Yexh2MYCNPIlrV52hTmS7qXnTghWsjXouF08bgsrrZqaW9tt1ZiK3j5NEmPE+EjQ==
8209
8210 +"eslint-plugin-react-hooks-published@npm:eslint-plugin-react-hooks@^5.2.0":
8211 + version "5.2.0"
8212 + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3"
8213 + integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==
8214 +
8215 "eslint-plugin-react-internal@link:./scripts/eslint-rules":
8216 version "0.0.0"
8217 uid ""