uui-build/linting/eslintrc.base.js (218 lines of code) (raw):

/** * This config was created using next approach: * 1) Use eslint-config-react-app as a basis * 2) Pick additional "non-stylistic" rules from "airbnb" * 3) Pick almost all "stylistic" rules from "airbnb" * 4) Add few UUI-specific "non-stylistic" rules * 5) Add few UUI-specific "stylistic" rules. * * Notes: * - Stylistic rules are those related to spacing, conventions, and generally anything that does not highlight an error or a better way to do something. * - eslint made all "stylistic" rules as frozen. * (see details here: https://eslint.org/blog/2020/05/changes-to-rules-policies/#what-are-the-changes) * - eslint suggests to use another tool (e.g. Prettier) for all "stylistic" stuff. * (see their readme https://github.com/eslint/eslint/blob/main/README.md) * * Reason why we don't use Prettier at the moment: * - No possibility to add JSX attr spaces as described here: https://github.com/prettier/prettier/issues/95 */ const pickFromAirbnb = require('./eslintConfigAirBnb/all'); const { turnOffEslintRulesToBeFixed, shouldTurnOffRulesToBeFixed } = require('./utils/rulesToBeFixed'); const { isCI, isLintStaged, isLintScript } = require('../utils/envUtils'); const { getIgnoredPatterns } = require('./../../.eslintignore'); const { unifiedSeverity } = require('./utils/rulesSeverityUtils'); process.env.NODE_ENV = 'production'; // this line is required by "babel-preset-react-app". module.exports = { env: { browser: true, es6: true, node: true, }, ignorePatterns: getIgnoredPatterns({ isCI: isCI(), isLintStaged: isLintStaged(), isLintScript: isLintScript() }), // We need to remove such directives only if full set of rules is checked. reportUnusedDisableDirectives: !shouldTurnOffRulesToBeFixed, extends: require.resolve('./eslintConfigReactApp/all.js'), rules: { ...uuiJsRules(), ...turnOffEslintRulesToBeFixed(), }, overrides: [ { files: ['**/*.ts?(x)'], rules: { ...uuiJsRules(), ...uuiTsRules(), ...uuiReactRules(), ...turnOffEslintRulesToBeFixed(), /** * Temporarily turn off react-hooks/exhaustive-deps everywhere except for "app". * In the future, we want to enable it globally. But it would require code changes in ~140 places where this rule is intentionally violated. * The code change will be: * 1) put dependencies which we expect never change to the "useRef()", * so that it's explicitly clear why this or that variable is not added to the array of dependencies. * 2) in such case, the react-hooks/exhaustive-deps would not ask to include such variables into the list of dependencies. * * as soon as this is done, this rule can be enabled globally */ 'react-hooks/exhaustive-deps': 'off', }, }, { files: ['**/__tests__/**/*', '**/*.{test}.ts?(x)'], extends: require.resolve('./eslintConfigReactApp/allJest.js'), env: { 'jest/globals': true }, rules: { 'import/no-extraneous-dependencies': 'off', 'no-restricted-imports': ['error', { paths: [ { name: 'react-test-renderer', message: 'Please use: import { renderer } from \'@epam/uui-test-utils\';' }, { name: '@testing-library/react', message: 'Please use: import { ... } from \'@epam/uui-test-utils\';' }, { name: '@testing-library/user-event', message: 'Please use: import { userEvent } from \'@epam/uui-test-utils\';' }, ], patterns: [ { group: ['*.test'], message: 'It\'s not allowed to import "*.test.*" files to any other files.' }, ], }], /** * Don't want to force usage of userEvent because it slows down the performance of tests (with user-event it's ~3 times slower). * https://github.com/testing-library/user-event/issues/650 */ 'testing-library/prefer-user-event': 'off', 'testing-library/render-result-naming-convention': 'off', 'testing-library/no-node-access': unifiedSeverity, 'testing-library/no-manual-cleanup': unifiedSeverity, 'testing-library/prefer-explicit-assert': unifiedSeverity, ...turnOffEslintRulesToBeFixed(), }, }, { files: ['./server/**/*.js', './uui-build/**/*.js'], env: { es6: true, node: true, commonjs: true, }, parserOptions: { ecmaVersion: 2020 }, rules: { ...uuiJsRules(), 'import/no-unresolved': [ unifiedSeverity, { commonjs: true, caseSensitive: true, }, ], 'import/extensions': [ unifiedSeverity, 'never', { ignorePackages: true }, ], ...turnOffEslintRulesToBeFixed(), }, }, ], settings: { 'import/parsers': { '@typescript-eslint/parser': [ '.ts', '.tsx', '.d.ts', ], }, 'import/resolver': { node: { extensions: [ '.js', '.ts', '.tsx', '.d.ts', '.css', '.scss', '.svg', ], }, alias: { map: [['@epam/uui-test-utils', './test-utils/index.ts']] }, }, 'import/extensions': [ '.js', '.ts', '.tsx', '.d.ts', ], 'import/external-module-folders': ['node_modules', 'node_modules/@types'], }, }; function uuiTsRules() { return { // non-stylistic - start ...pickFromAirbnb.typescript.nonStylistic, 'no-unused-expressions': 'off', '@typescript-eslint/no-unused-expressions': uuiJsRules()['no-unused-expressions'], 'no-shadow': 'off', '@typescript-eslint/no-shadow': uuiJsRules()['no-shadow'], // non-stylistic - end // stylistic - start ...pickFromAirbnb.typescript.stylistic, indent: 'off', '@typescript-eslint/indent': uuiJsRules()['indent'], 'comma-dangle': 'off', '@typescript-eslint/comma-dangle': [ unifiedSeverity, { arrays: 'always-multiline', objects: 'always-multiline', imports: 'always-multiline', exports: 'always-multiline', functions: 'always-multiline', generics: 'ignore', // ts-specific }, ], '@typescript-eslint/lines-between-class-members': uuiJsRules()['lines-between-class-members'], // stylistic - end }; } function uuiJsRules() { return { // non-stylistic - start ...pickFromAirbnb.base.nonStylistic, 'default-case': 'off', 'no-use-before-define': 'off', 'guard-for-in': 'off', // we disallow for-in statement by another rule, so this rule not needed. 'no-restricted-syntax': [ unifiedSeverity, { selector: 'ForInStatement', message: 'for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.', }, ], /** * 'import/no-cycle' rule is extremely slow! (this single rule takes 70%+ of total time) * What we can do in case of performance issues: * - keep it turned off and enable only occasionally if necessary. * - change maxDepth to lower value and increase it if you need to see all circular deps. */ 'import/no-cycle': [unifiedSeverity, { maxDepth: 4 }], 'import/no-extraneous-dependencies': ['error', {}], 'no-restricted-imports': ['error', { patterns: [ { group: ['@epam/*/build/*', '@epam/*/build'], message: 'Import from "build" folder of UUI modules is not allowed.' }, { group: ['dayjs', 'dayjs/plugin/*'], message: 'Direct import from "dayjs" module is not allowed. Please use a reusable wrapper instead (dayJsHelper.ts)' }, ], }], 'import/no-unresolved': [ unifiedSeverity, { ignore: [ '^@epam/uui-[\\w]+/styles.css$', '@epam/promo/styles.css', '@epam/loveship/styles.css', ], }, ], 'no-console': [unifiedSeverity, { allow: ['error', 'warn'] }], 'no-param-reassign': [unifiedSeverity, { props: false }], radix: [unifiedSeverity, 'as-needed'], 'no-cond-assign': [unifiedSeverity, 'except-parens'], 'no-unused-expressions': [unifiedSeverity, { allowShortCircuit: true }], eqeqeq: [unifiedSeverity, 'smart'], 'prefer-const': [ unifiedSeverity, { destructuring: 'any', ignoreReadBeforeAssign: true, }, ], 'no-shadow': [unifiedSeverity, { allow: ['props'] }], // non-stylistic- end // stylistic - start ...pickFromAirbnb.base.stylistic, 'no-trailing-spaces': 'off', 'max-len': [ unifiedSeverity, { code: 170, ignoreUrls: true, ignoreComments: true, ignoreTemplateLiterals: true, ignoreRegExpLiterals: true, ignoreStrings: true, }, ], 'array-element-newline': [unifiedSeverity, 'consistent'], 'array-bracket-newline': [unifiedSeverity, 'consistent'], indent: [ unifiedSeverity, 4, { SwitchCase: 1 }, ], 'comma-dangle': [ unifiedSeverity, { arrays: 'always-multiline', objects: 'always-multiline', imports: 'always-multiline', exports: 'always-multiline', functions: 'always-multiline', }, ], 'lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }], // stylistic - end }; } function uuiReactRules() { return { // non-stylistic - start ...pickFromAirbnb.react.nonStylistic, 'react/no-unescaped-entities': [unifiedSeverity, { forbid: ['>', '}'] }], 'react/jsx-no-useless-fragment': unifiedSeverity, 'react/function-component-definition': [ unifiedSeverity, { namedComponents: ['function-declaration', 'function-expression'], unnamedComponents: 'function-expression', }, ], // non-stylistic - end // stylistic - start ...pickFromAirbnb.react.stylistic, 'react/jsx-wrap-multilines': [ unifiedSeverity, { condition: 'parens-new-line', logical: 'parens-new-line', arrow: 'parens-new-line', return: 'parens-new-line', assignment: 'parens-new-line', declaration: 'parens-new-line', }, ], 'react/jsx-curly-spacing': [ unifiedSeverity, 'always', { allowMultiline: true }, ], 'react/jsx-indent': [unifiedSeverity, 4], 'react/jsx-indent-props': [unifiedSeverity, 4], // stylistic - end }; }