Files
pentagi/frontend/eslint.config.mjs
T
Sergey KozyrenkoandClaude Opus 4.8 3ac35ee0d2 feat(forms): enforce the validation convention (noValidate + useForm lint guard)
Two convention hardenings on top of useAppForm:

- noValidate on every react-hook-form <form>: validation runs through zod,
  so native HTML5 constraint validation (type="email"/required) firing
  browser-locale popups on submit is unwanted everywhere — not just the
  email-change form that first hit it.
- no-restricted-syntax lint rule flagging mode/reValidateMode on useForm,
  steering new forms to useAppForm (the single owner of the timing).
  use-app-form.ts is exempted (it's the definition); flow-form keeps its
  live-validation mode behind an inline disable pending its migration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:24:31 +07:00

101 lines
3.3 KiB
JavaScript

// @ts-check
import { FlatCompat } from '@eslint/eslintrc';
import js from '@eslint/js';
import perfectionist from 'eslint-plugin-perfectionist';
const compat = new FlatCompat({
baseDirectory: import.meta.dirname,
recommendedConfig: js.configs.recommended,
});
const eslintConfig = [
...compat.config({
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
'prettier',
],
settings: {
react: {
version: 'detect',
},
},
}),
{
rules: {
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
},
],
curly: ['error', 'all'],
'no-fallthrough': 'off',
'no-restricted-syntax': [
'error',
{
message:
'Do not set mode/reValidateMode on useForm — use useAppForm, which owns the silent-until-submit form timing.',
selector:
'CallExpression[callee.name="useForm"] > ObjectExpression > Property[key.name="mode"], CallExpression[callee.name="useForm"] > ObjectExpression > Property[key.name="reValidateMode"]',
},
],
'padding-line-between-statements': [
'error',
{
blankLine: 'always',
next: 'return',
prev: '*',
},
{
blankLine: 'always',
next: 'block-like',
prev: '*',
},
{
blankLine: 'any',
next: 'block-like',
prev: 'case',
},
{
blankLine: 'always',
next: '*',
prev: 'block-like',
},
{
blankLine: 'always',
next: 'block-like',
prev: 'block-like',
},
{
blankLine: 'any',
next: 'while',
prev: 'do',
},
],
// Off until React Compiler lands: its compatibility lint flags every RHF
// watch() / useReactTable as unactionable noise (see OPEN-ISSUES §3).
'react-hooks/incompatible-library': 'off',
'react/no-unescaped-entities': 'off', // Allow quotes in JSX
'react/prop-types': 'off', // TypeScript provides type checking
},
},
{
// useAppForm is the single owner of the form timing — the one place
// allowed to set mode/reValidateMode on useForm.
files: ['src/hooks/use-app-form.ts'],
rules: { 'no-restricted-syntax': 'off' },
},
perfectionist.configs['recommended-natural'],
{
ignores: ['node_modules/**', 'dist/**', 'build/**', 'public/mockServiceWorker.js', 'src/graphql/types.ts'],
},
];
export default eslintConfig;