fix(core-eslint): activate React rules-of-hooks for all TSX surfaces
next.js and react-internal.js are plain re-exports of base, so no rules-of-hooks checking was active anywhere despite three React apps and core-ui. Wire eslint-plugin-react-hooks in base.js scoped to **/*.tsx (non-React packages untouched). Fixes the one violation it surfaced: web-tanstack's root route called Route.useLoaderData inside an anonymous component callback — extracted to a named RootComponent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,17 @@
|
|||||||
import { Outlet, createRootRoute } from "@tanstack/react-router";
|
import { Outlet, createRootRoute } from "@tanstack/react-router";
|
||||||
import { getNonce } from "@repo/core-shared/security/tanstack";
|
import { getNonce } from "@repo/core-shared/security/tanstack";
|
||||||
|
|
||||||
|
function RootComponent() {
|
||||||
|
const { nonce } = Route.useLoaderData();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* nonce exposed to client so instrumentation-client.ts can read it */}
|
||||||
|
<meta name="csp-nonce" content={nonce} />
|
||||||
|
<Outlet />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export const Route = createRootRoute({
|
export const Route = createRootRoute({
|
||||||
loader: async () => {
|
loader: async () => {
|
||||||
try {
|
try {
|
||||||
@@ -12,14 +23,5 @@ export const Route = createRootRoute({
|
|||||||
return { nonce: "" };
|
return { nonce: "" };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
component: () => {
|
component: RootComponent,
|
||||||
const { nonce } = Route.useLoaderData();
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{/* nonce exposed to client so instrumentation-client.ts can read it */}
|
|
||||||
<meta name="csp-nonce" content={nonce} />
|
|
||||||
<Outlet />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import eslintConfigPrettier from "eslint-config-prettier";
|
|||||||
import tseslint from "typescript-eslint";
|
import tseslint from "typescript-eslint";
|
||||||
import turboPlugin from "eslint-plugin-turbo";
|
import turboPlugin from "eslint-plugin-turbo";
|
||||||
import boundaries from "eslint-plugin-boundaries";
|
import boundaries from "eslint-plugin-boundaries";
|
||||||
|
import reactHooks from "eslint-plugin-react-hooks";
|
||||||
import globals from "globals";
|
import globals from "globals";
|
||||||
import conformancePlugin from "./plugin.js";
|
import conformancePlugin from "./plugin.js";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
@@ -195,6 +196,13 @@ export default [
|
|||||||
"no-restricted-imports": "off",
|
"no-restricted-imports": "off",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// React rules-of-hooks for every TSX surface (apps, core-ui, feature
|
||||||
|
// ui/**). Scoped to .tsx so non-React packages are untouched.
|
||||||
|
{
|
||||||
|
files: ["**/*.tsx"],
|
||||||
|
plugins: { "react-hooks": reactHooks },
|
||||||
|
rules: reactHooks.configs.recommended.rules,
|
||||||
|
},
|
||||||
// E1 — Event handlers must not be re-exported. Wire them only inside the
|
// E1 — Event handlers must not be re-exported. Wire them only inside the
|
||||||
// consumer feature's bind-production / bind-dev-seed (spec § 2.2 Rule E1).
|
// consumer feature's bind-production / bind-dev-seed (spec § 2.2 Rule E1).
|
||||||
// J — Direct `payload.jobs.*` access is forbidden outside the integration
|
// J — Direct `payload.jobs.*` access is forbidden outside the integration
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
"eslint": "^9.20.0",
|
"eslint": "^9.20.0",
|
||||||
"eslint-config-prettier": "^10.1.0",
|
"eslint-config-prettier": "^10.1.0",
|
||||||
"eslint-plugin-boundaries": "^4.2.2",
|
"eslint-plugin-boundaries": "^4.2.2",
|
||||||
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-turbo": "^2.4.0",
|
"eslint-plugin-turbo": "^2.4.0",
|
||||||
"typescript-eslint": "^8.25.0",
|
"typescript-eslint": "^8.25.0",
|
||||||
"vitest": "^3.1.0"
|
"vitest": "^3.1.0"
|
||||||
|
|||||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@@ -733,6 +733,9 @@ importers:
|
|||||||
eslint-plugin-boundaries:
|
eslint-plugin-boundaries:
|
||||||
specifier: ^4.2.2
|
specifier: ^4.2.2
|
||||||
version: 4.2.2(@typescript-eslint/parser@8.58.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))
|
version: 4.2.2(@typescript-eslint/parser@8.58.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))
|
||||||
|
eslint-plugin-react-hooks:
|
||||||
|
specifier: ^5.2.0
|
||||||
|
version: 5.2.0(eslint@9.39.4(jiti@2.7.0))
|
||||||
eslint-plugin-turbo:
|
eslint-plugin-turbo:
|
||||||
specifier: ^2.4.0
|
specifier: ^2.4.0
|
||||||
version: 2.9.4(eslint@9.39.4(jiti@2.7.0))(turbo@2.9.4)
|
version: 2.9.4(eslint@9.39.4(jiti@2.7.0))(turbo@2.9.4)
|
||||||
@@ -10680,6 +10683,15 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ">=6.0.0"
|
eslint: ">=6.0.0"
|
||||||
|
|
||||||
|
eslint-plugin-react-hooks@5.2.0:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==,
|
||||||
|
}
|
||||||
|
engines: { node: ">=10" }
|
||||||
|
peerDependencies:
|
||||||
|
eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
|
||||||
|
|
||||||
eslint-plugin-turbo@2.9.4:
|
eslint-plugin-turbo@2.9.4:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@@ -24134,6 +24146,10 @@ snapshots:
|
|||||||
- eslint-import-resolver-webpack
|
- eslint-import-resolver-webpack
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
eslint-plugin-react-hooks@5.2.0(eslint@9.39.4(jiti@2.7.0)):
|
||||||
|
dependencies:
|
||||||
|
eslint: 9.39.4(jiti@2.7.0)
|
||||||
|
|
||||||
eslint-plugin-turbo@2.9.4(eslint@9.39.4(jiti@2.7.0))(turbo@2.9.4):
|
eslint-plugin-turbo@2.9.4(eslint@9.39.4(jiti@2.7.0))(turbo@2.9.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
dotenv: 16.0.3
|
dotenv: 16.0.3
|
||||||
|
|||||||
Reference in New Issue
Block a user