import js from '@eslint/js'; import tseslint from 'typescript-eslint'; import reactHooks from 'eslint-plugin-react-hooks'; import globals from 'globals'; // Flat config (ESLint 9). Browser code (src/) gets react-hooks + browser globals; // everything else (server, shared, e2e, configs, scripts) gets node globals. export default tseslint.config( { ignores: ['**/dist/**', '**/node_modules/**', 'server/dist/**'], }, js.configs.recommended, ...tseslint.configs.recommended, { files: ['src/**/*.{ts,tsx}'], plugins: { 'react-hooks': reactHooks }, languageOptions: { globals: { ...globals.browser, ...globals.es2022 } }, rules: { ...reactHooks.configs.recommended.rules, // We intentionally pass handler objects to hooks that read them via a ref. 'react-hooks/exhaustive-deps': 'off', }, }, { files: [ 'server/**/*.ts', 'shared/**/*.ts', 'e2e/**/*.ts', 'vite.config.ts', 'vitest.config.ts', 'playwright.config.ts', 'scripts/**/*.mjs', 'scripts/**/*.ts', ], languageOptions: { globals: { ...globals.node, ...globals.es2022 } }, rules: { // Node 22 has fetch/AbortSignal/structuredClone as globals. 'no-undef': 'off', }, }, );