50 lines
1.3 KiB
JavaScript
50 lines
1.3 KiB
JavaScript
import i18next from 'eslint-plugin-i18next'
|
|
import react from 'eslint-plugin-react'
|
|
import jsxA11y from 'eslint-plugin-jsx-a11y'
|
|
|
|
/**
|
|
* Enforces the CONVENTIONS.md rules:
|
|
* - i18n keying (no-literal-string)
|
|
* - strict jsx-a11y
|
|
* - react hooks / components
|
|
*
|
|
* Custom rules that ship in Stage 3 (noted in CONVENTIONS.md):
|
|
* - no-array-methods-in-widgets
|
|
* - no-date-libraries-in-widgets
|
|
*/
|
|
export default [
|
|
{
|
|
files: ['src/**/*.{ts,tsx}'],
|
|
ignores: [
|
|
'src/routeTree.gen.ts',
|
|
'**/*.gen.ts',
|
|
'**/*.gen.d.ts',
|
|
'dist/**',
|
|
'node_modules/**',
|
|
],
|
|
plugins: { i18next, react, 'jsx-a11y': jsxA11y },
|
|
languageOptions: {
|
|
ecmaVersion: 'latest',
|
|
sourceType: 'module',
|
|
parserOptions: {
|
|
ecmaFeatures: { jsx: true },
|
|
},
|
|
},
|
|
rules: {
|
|
// i18n keying — every visible string must go through t()
|
|
'i18next/no-literal-string': [
|
|
'error',
|
|
{
|
|
markupOnly: true,
|
|
onlyAttribute: ['label', 'placeholder', 'title', 'aria-label'],
|
|
ignoreCallee: ['t', 'i18n.t', 'useTranslation'],
|
|
ignoreComponent: ['Code', 'Kbd'],
|
|
},
|
|
],
|
|
|
|
// A11y — Radix defaults stay; no escape hatch to <div onClick>
|
|
...jsxA11y.configs.strict.rules,
|
|
},
|
|
},
|
|
]
|