@spaced-out/ui-design-system
Version:
Sense UI components library
215 lines (199 loc) • 6.64 kB
JavaScript
// ESLint 9 flat config for @spaced-out/ui-design-system
// TypeScript-first config (Flow removed)
import tseslint from 'typescript-eslint';
import ftFlowPlugin from 'eslint-plugin-ft-flow';
import reactPlugin from 'eslint-plugin-react';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
import importPlugin from 'eslint-plugin-import';
import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort';
import unusedImportsPlugin from 'eslint-plugin-unused-imports';
import jestPlugin from 'eslint-plugin-jest';
import storybookPlugin from 'eslint-plugin-storybook';
import globals from 'globals';
export default [
// Global ignores (replaces .eslintignore)
{
ignores: [
'node_modules/**',
'lib/**',
'dist/**',
'storybook-static/**',
'src/assets/fontawesome/**'
],
},
// TypeScript rules for project source (non type-aware for now) //NOTE:(diwaker) make it type-aware later
// Bring in TS-ESLint recommended (no type checking) scoped to TS files
...tseslint.configs.recommended.map((cfg) => ({
...cfg,
files: ['src/**/*.{ts,tsx}'],
languageOptions: {
...(cfg.languageOptions ?? {}),
parserOptions: {
...(cfg.languageOptions?.parserOptions ?? {}),
ecmaVersion: 'latest',
sourceType: 'module',
ecmaFeatures: { jsx: true },
},
globals: {
...globals.browser,
...globals.node,
Iterator: 'readonly',
},
},
settings: {
react: { version: 'detect' },
},
plugins: {
'@typescript-eslint': tseslint.plugin,
// Keep Flow plugin loaded so legacy inline directives don't error
'ft-flow': ftFlowPlugin,
react: reactPlugin,
'react-hooks': reactHooksPlugin,
import: importPlugin,
'simple-import-sort': simpleImportSortPlugin,
'unused-imports': unusedImportsPlugin,
jest: jestPlugin,
storybook: storybookPlugin,
},
})),
// Local project rule tweaks
{
files: ['src/**/*.{ts,tsx}'],
rules: {
// Core
'arrow-body-style': ['warn', 'as-needed'],
curly: ['warn', 'all'],
'comma-spacing': ['warn', { before: false, after: true }],
'eol-last': 'warn',
eqeqeq: ['error', 'always', { null: 'ignore' }],
indent: 'off',
'max-params': ['warn', { max: 4 }],
'no-alert': 'warn',
'no-console': ['error', { allow: ['warn', 'error'] }],
'no-dupe-args': 'error',
'no-dupe-keys': 'error',
'no-duplicate-case': 'error',
// Allow TS overloads
'no-dupe-class-members': 'off',
'no-empty-function': 'warn',
'no-empty-pattern': 'error',
'no-eval': 'error',
'no-extend-native': 'error',
'no-extra-boolean-cast': 'error',
'no-fallthrough': 'error',
'no-floating-decimal': 'error',
'no-inner-declarations': 'error',
'no-loop-func': 'error',
'no-mixed-requires': 'off',
'no-nested-ternary': 'off',
'no-new-symbol': 'error',
'no-redeclare': 'off', // use TS rule
'no-restricted-globals': ['error', 'event', 'location'],
'no-sparse-arrays': 'error',
'no-tabs': 'warn',
'no-this-before-super': 'error',
'no-trailing-spaces': 'warn',
'no-underscore-dangle': 'off',
'no-unmodified-loop-condition': 'warn',
'no-undef': 'off', // TS handles this
'no-unreachable': 'warn',
'no-useless-constructor': 'off', // use TS rule
'no-var': 'error',
'no-with': 'error',
'object-shorthand': 'error',
'prefer-arrow-callback': 'error',
'prefer-const': 'warn',
'prefer-spread': 'warn',
quotes: ['warn', 'single', { allowTemplateLiterals: true }],
'require-yield': 'error',
'rest-spread-spacing': 'error',
strict: ['warn', 'never'],
// import
'import/newline-after-import': ['warn', { count: 2 }],
'import/no-duplicates': 'error',
// react
'react/jsx-no-undef': 'error',
'react/jsx-pascal-case': 'warn',
'react/jsx-uses-react': 'off',
'react/jsx-uses-vars': 'error',
'react/no-array-index-key': 'warn',
'react/no-deprecated': 'error',
'react/no-direct-mutation-state': 'error',
'react/no-string-refs': 'warn',
'react/prop-types': 'off',
'react/react-in-jsx-scope': 'off',
// hooks //NOTE:(diwaker) temp keep as warn during migration; tighten later
'react-hooks/rules-of-hooks': 'warn',
// sorting
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
// unused
'unused-imports/no-unused-imports': 'error',
'unused-imports/no-unused-vars': [
'warn',
{
vars: 'all',
varsIgnorePattern: '^_',
args: 'after-used',
argsIgnorePattern: '^_',
},
],
// TS-specific replacements (non type-aware)
'@typescript-eslint/no-redeclare': 'error',
'@typescript-eslint/no-useless-constructor': 'error',
'@typescript-eslint/consistent-type-imports': ['warn', { prefer: 'type-imports' }],
//NOTE:(diwaker) temp disable for migration fix this later
'@typescript-eslint/no-explicit-any': ['warn', { ignoreRestArgs: true }],
'@typescript-eslint/no-unused-vars': ['warn', {
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_'
}],
'@typescript-eslint/no-unused-expressions': ['warn', {
allowShortCircuit: false,
allowTaggedTemplates: false,
allowTernary: false
}],
'@typescript-eslint/no-this-alias': 'warn',
'@typescript-eslint/ban-ts-comment': 'warn',
'@typescript-eslint/no-empty-object-type': 'warn',
'@typescript-eslint/no-unnecessary-type-constraint': 'warn',
},
},
// Tests (JS/TS)
{
files: ['**/__tests__/*.{js,jsx,ts,tsx}'],
languageOptions: {
globals: globals.jest,
},
plugins: {
jest: jestPlugin,
},
},
// Storybook specifics
{
files: ['**/*.stories.{jsx,tsx}'],
rules: {
semi: ['warn', 'always'],
},
},
// Project import sort groups (apply to JS and TS)
{
files: ['*.{js,jsx,ts,tsx}', '**/*.{js,jsx,ts,tsx}'],
rules: {
'simple-import-sort/imports': [
'error',
{
groups: [
['^react', '^@?\\w'],
['^(@|components)(/.*|$)'],
['^\\u0000'],
['^\\.\\.(?!/?$)', '^\\.\\./?$'],
['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'],
['^.+\\.?(css)$'],
],
},
],
},
},
];