initial commit
Some checks failed
ci / go (push) Has been cancelled
ci / admin-ui (push) Has been cancelled
ci / runtime-sdk (push) Has been cancelled
ci / helm (push) Has been cancelled
ci / openapi (push) Has been cancelled
ci / container (push) Has been cancelled
ci / release-config (push) Has been cancelled
ci / shared styling (push) Has been cancelled
ci / security (push) Has been cancelled
ci / all green (push) Has been cancelled
Some checks failed
ci / go (push) Has been cancelled
ci / admin-ui (push) Has been cancelled
ci / runtime-sdk (push) Has been cancelled
ci / helm (push) Has been cancelled
ci / openapi (push) Has been cancelled
ci / container (push) Has been cancelled
ci / release-config (push) Has been cancelled
ci / shared styling (push) Has been cancelled
ci / security (push) Has been cancelled
ci / all green (push) Has been cancelled
This commit is contained in:
commit
951dd8d26b
175 changed files with 50041 additions and 0 deletions
129
web/eslint.config.js
Normal file
129
web/eslint.config.js
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
import js from '@eslint/js'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import globals from 'globals'
|
||||
import tseslint from 'typescript-eslint'
|
||||
|
||||
/**
|
||||
* ESLint flat configuration.
|
||||
*
|
||||
* Two decisions are worth stating:
|
||||
*
|
||||
* 1. Type-aware linting is on (`projectService`), because the rules that catch
|
||||
* real bugs in a codebase using `unknown` at its boundaries need type
|
||||
* information. This is also why TypeScript is pinned to 6.x: see ADR 0004.
|
||||
*
|
||||
* 2. `--max-warnings 0` in the npm script. A warning that is tolerated is a
|
||||
* warning nobody reads, so the build is the place it stops.
|
||||
*/
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: ['dist', 'coverage', 'node_modules', '*.config.js', '*.config.ts'],
|
||||
},
|
||||
|
||||
js.configs.recommended,
|
||||
...tseslint.configs.recommendedTypeChecked,
|
||||
...tseslint.configs.stylisticTypeChecked,
|
||||
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
globals: { ...globals.browser, ...globals.es2022 },
|
||||
},
|
||||
plugins: {
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
|
||||
|
||||
// --- correctness -----------------------------------------------------
|
||||
'@typescript-eslint/no-floating-promises': 'error',
|
||||
'@typescript-eslint/no-misused-promises': [
|
||||
'error',
|
||||
// A promise-returning handler is the normal React pattern; the void
|
||||
// operator is the fix for the cases that are actually a mistake.
|
||||
{ checksVoidReturn: { arguments: false, attributes: false } },
|
||||
],
|
||||
'@typescript-eslint/await-thenable': 'error',
|
||||
'@typescript-eslint/no-unnecessary-condition': 'off',
|
||||
'@typescript-eslint/restrict-template-expressions': [
|
||||
'error',
|
||||
{ allowNumber: true, allowBoolean: true },
|
||||
],
|
||||
'@typescript-eslint/switch-exhaustiveness-check': 'error',
|
||||
// `||` is used deliberately where an empty string should fall through,
|
||||
// which is exactly what `??` does not do.
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'off',
|
||||
// A type alias reads better than an interface for everything in this
|
||||
// codebase, and the two are interchangeable in practice.
|
||||
'@typescript-eslint/consistent-type-definitions': ['error', 'type'],
|
||||
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
|
||||
'@typescript-eslint/consistent-type-imports': [
|
||||
'error',
|
||||
{ prefer: 'type-imports', fixStyle: 'inline-type-imports' },
|
||||
],
|
||||
|
||||
// --- readability -----------------------------------------------------
|
||||
// Both return-type annotation rules are off by design.
|
||||
//
|
||||
// `tsc` with `strict` already enforces a type at every boundary: a
|
||||
// component with a wrongly-typed prop is a compile error whether or not
|
||||
// its return type is written out. What the ESLint rules add is annotation
|
||||
// churn — one per callback, and `(): JSX.Element =>` on components that
|
||||
// legitimately start returning null and then need the annotation widened.
|
||||
// That is a maintenance cost with no defect class behind it.
|
||||
//
|
||||
// What *is* enforced instead: every component declares a typed props
|
||||
// interface, every exported non-component function carries a JSDoc
|
||||
// `@returns`, and `strict` plus `noUncheckedIndexedAccess` run on every
|
||||
// build. See docs/standards.md.
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
// An empty function is a legitimate no-op: a ResizeObserver stub, an
|
||||
// intentionally ignored error, a deliberate empty effect body.
|
||||
'@typescript-eslint/no-empty-function': ['error', { allow: ['arrowFunctions', 'methods'] }],
|
||||
// A leading or trailing underscore is the convention for an intentionally
|
||||
// unused binding, and no-unused-vars above is configured to honour it. The
|
||||
// two rules have to agree or every intentionally-ignored value is a
|
||||
// naming error.
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: 'variable',
|
||||
format: ['camelCase', 'UPPER_CASE', 'PascalCase'],
|
||||
leadingUnderscore: 'allow',
|
||||
trailingUnderscore: 'allow',
|
||||
},
|
||||
{ selector: 'parameter', format: ['camelCase'], leadingUnderscore: 'allow' },
|
||||
{ selector: 'typeLike', format: ['PascalCase'] },
|
||||
],
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrors: 'none' },
|
||||
],
|
||||
'@typescript-eslint/consistent-type-definitions': ['error', 'type'],
|
||||
'no-console': ['warn', { allow: ['warn', 'error'] }],
|
||||
eqeqeq: ['error', 'always', { null: 'ignore' }],
|
||||
'prefer-const': 'error',
|
||||
'object-shorthand': 'error',
|
||||
},
|
||||
},
|
||||
|
||||
// Tests are allowed to reach into internals and to use `any` in a double.
|
||||
{
|
||||
files: ['**/*.test.ts', '**/*.test.tsx', 'src/test/**'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
'no-console': 'off',
|
||||
},
|
||||
},
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue