chore(13-01): install ESLint+Prettier, author flat config, wire lint/format scripts

- Install eslint@9.39.4 @eslint/js@9.39.4 typescript-eslint@8.61.0
  eslint-plugin-react@7.37.5 eslint-plugin-react-hooks@7.1.1
  eslint-config-prettier@10.1.8 prettier@3.8.4 as root devDependencies
- Author eslint.config.js: ignores → base recommendedTypeChecked (projectService:true)
  → pwa-react block (apps/pwa/** only) → disableTypeChecked override (config files +
  apps/api/tests) → prettier-last (eslint-config-prettier/flat)
- Add .prettierrc (singleQuote:true, printWidth:100) and .prettierignore
- Add "type":"module" to root package.json; add format/format:check scripts
- Add lint script (--max-warnings 0) to apps/api and apps/pwa
This commit is contained in:
Lucas Berger
2026-06-11 19:44:57 -04:00
parent 66c54507ad
commit df62d333d0
7 changed files with 1200 additions and 2 deletions
+88
View File
@@ -0,0 +1,88 @@
// eslint.config.js — root flat ESLint config (ESM)
// Covers: apps/api (Node/TS) + apps/pwa (React 19 + TypeScript)
// typescript-eslint v8, projectService: true (auto-discovers all tsconfigs)
// ESLint pinned to 9.39.4 — do NOT upgrade to ESLint 10 until eslint-plugin-react
// resolves the "getFilename is not a function" incompatibility (jsx-eslint#3977).
import js from '@eslint/js'
import tseslint from 'typescript-eslint'
import reactPlugin from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import prettierConfig from 'eslint-config-prettier/flat'
export default tseslint.config(
// ── 1. Global ignores (replaces .eslintignore) ────────────────────────────
{
ignores: [
'**/dist/**', // build output: apps/api/dist, apps/pwa/dist, generated sw.js
'**/node_modules/**',
'apps/api/src/db/migrations/**', // generated Drizzle SQL files
'pnpm-lock.yaml',
],
},
// ── 2. Base: all TS/TSX files in both apps ────────────────────────────────
// Uses recommendedTypeChecked (type-aware) per D-13-01.
// NOT strict/strictTypeChecked — D-13-03 explicitly rejects the extra churn.
{
files: ['apps/**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommendedTypeChecked,
],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
// Allow _-prefixed names as intentionally unused (params + vars)
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
],
},
},
// ── 3. React + Hooks: PWA only (D-13-02) ────────────────────────────────
// Apps/api is Node/TS only — React config does NOT apply there.
{
files: ['apps/pwa/**/*.{ts,tsx}'],
extends: [
reactPlugin.configs.flat.recommended,
reactHooks.configs.flat.recommended,
],
settings: {
react: { version: 'detect' },
},
rules: {
// TypeScript props typing supersedes prop-types in React 19 (RESEARCH Open Question 2)
'react/prop-types': 'off',
},
},
// ── 4. disableTypeChecked override (D-13-10) ─────────────────────────────
// These files are outside all tsconfig projects (tool configs + API test dir).
// projectService: true cannot type-check them → disable type-aware rules only.
// Non-type-aware rules (syntax, no-unused-vars) still apply.
// Source: typescript-eslint.io/troubleshooting/typed-linting/#i-get-errors-telling-me-the-file-must-be-included
{
files: [
'apps/api/drizzle.config.ts',
'apps/api/vitest.config.ts',
'apps/pwa/vite.config.ts',
'apps/pwa/vitest.config.ts',
'apps/pwa/playwright.config.ts',
'apps/api/tests/**/*.ts', // excluded from apps/api/tsconfig.json (Pitfall 2)
'eslint.config.js', // this file itself (not a ts project member)
],
extends: [tseslint.configs.disableTypeChecked],
},
// ── 5. eslint-config-prettier: MUST BE LAST ──────────────────────────────
// Disables all ESLint formatting rules that conflict with Prettier (D-13-07).
// Use the /flat import path for ESM flat config (Pitfall 7).
// Source: github.com/prettier/eslint-config-prettier
prettierConfig,
)