UNPKG

@tpzdsp/eslint-config-dsp

Version:

re-usable config for ESLint, Prettier and semantic-release

211 lines (206 loc) 5.99 kB
import eslintConfigPrettier from 'eslint-config-prettier/flat'; import importPlugin from 'eslint-plugin-import'; import jestDom from 'eslint-plugin-jest-dom'; import jsxA11y from 'eslint-plugin-jsx-a11y'; import prettier from 'eslint-plugin-prettier'; import react from 'eslint-plugin-react'; import reactHooks from 'eslint-plugin-react-hooks'; import js from '@eslint/js'; import tsEslint from '@typescript-eslint/eslint-plugin'; import tsEslintParser from '@typescript-eslint/parser'; import vitest from '@vitest/eslint-plugin'; import 'eslint-import-resolver-alias'; import 'eslint-import-resolver-typescript'; export const NO_RESTRICTED_STYNAX_CONFIG = [ { selector: 'FunctionExpression', message: 'Use ES6 arrow functions instead.', }, { selector: 'FunctionDeclaration', message: 'Use arrow functions instead of function declarations.', }, { selector: 'ForStatement', message: 'Use functional iterators like .map(), .forEach(), or for...of instead of a manual for-loop.', }, { selector: 'ForInStatement', message: 'Avoid for...in loops as they iterate over inherited properties. Use Object.keys() or Object.entries() instead.', }, { selector: "ImportDeclaration[source.value='react'] > ImportDefaultSpecifier[local.name='React']", message: 'Default import of React is no longer necessary, and should not be used.', }, ]; export default [ { name: 'eslint:recommended', rules: { ...js.configs.recommended.rules, curly: 'error', camelcase: 'off', 'no-var': 'error', 'no-restricted-syntax': ['error', ...NO_RESTRICTED_STYNAX_CONFIG], 'no-restricted-imports': [ 'error', { patterns: ['../../*'], // only allow `./` and `../` }, ], }, }, { name: 'typescript', files: ['**/*.ts', '**/*.tsx'], languageOptions: { parser: tsEslintParser, parserOptions: { project: true, }, }, plugins: { '@typescript-eslint': tsEslint, }, rules: { ...tsEslint.configs.recommended.rules, ...tsEslint.configs['stylistic-type-checked'].rules, '@typescript-eslint/no-unused-vars': 'error', '@typescript-eslint/consistent-type-definitions': ['error', 'type'], '@typescript-eslint/naming-convention': [ 'error', { selector: 'default', format: ['camelCase'], }, { selector: 'import', format: ['camelCase', 'PascalCase'], }, { selector: 'function', format: ['camelCase', 'PascalCase'], }, { selector: 'typeLike', format: ['PascalCase'] }, { selector: 'typeProperty', format: null }, // allow any case { selector: 'enumMember', format: ['PascalCase'] }, { selector: 'variable', format: ['camelCase', 'PascalCase', 'UPPER_CASE'], }, { selector: 'objectLiteralProperty', format: null, // allow any case }, { selector: 'objectLiteralMethod', format: ['camelCase', 'PascalCase'], }, ], }, }, { name: 'react-and-a11y', files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'], plugins: { react, 'jsx-a11y': jsxA11y, import: importPlugin, prettier, ...reactHooks.configs['recommended-latest'].plugins, }, rules: { ...react.configs.recommended.rules, ...jsxA11y.configs.strict.rules, ...reactHooks.configs['recommended-latest'].rules, 'import/order': [ 'error', { groups: [ 'builtin', // Split external into unscoped and scoped manually 'external', 'internal', // Absolute imports from the same project ['parent', 'sibling', 'index'], // Relative imports 'object', // TypeScript Type imports ], 'newlines-between': 'always', alphabetize: { order: 'asc', caseInsensitive: true }, pathGroups: [ { // Match scoped packages and move them after unscoped pattern: '@*/**', group: 'external', position: 'after', }, { pattern: 'react', group: 'builtin', position: 'before', }, { pattern: '@/**', // Project root alias group: 'internal', position: 'before', }, ], pathGroupsExcludedImportTypes: ['react', 'builtin', 'internal'], }, ], 'prettier/prettier': [ 'error', { endOfLine: 'auto', }, ], 'react/react-in-jsx-scope': 'off', 'react/jsx-pascal-case': ['error', { allowNamespace: true, allowAllCaps: true }], }, settings: { react: { version: 'detect', }, 'import/resolver': { typescript: {}, alias: { map: [['@', './src']], // Must have this configured in the TS config too extensions: ['.js', '.jsx', '.ts', '.tsx'], }, }, }, }, { name: 'testing', files: [ '**/*.test.js', '**/*.test.jsx', '**/*.test.ts', '**/*.test.tsx', '**/__tests__/**/*.js', '**/__tests__/**/*.jsx', '**/__tests__/**/*.ts', '**/__tests__/**/*.tsx', ], plugins: { vitest, 'jest-dom': jestDom, }, rules: { ...vitest.configs.recommended.rules, 'vitest/padding-around-describe-blocks': 'error', 'vitest/padding-around-test-blocks': 'error', 'jest-dom/prefer-checked': 'warn', 'jest-dom/prefer-enabled-disabled': 'warn', 'jest-dom/prefer-required': 'warn', }, }, { name: 'ignores', files: ['**/*.ts', '**/*.tsx'], ignores: ['node_modules/', 'dist/', 'build/'], }, eslintConfigPrettier, ];