Created
September 11, 2023 10:45
-
-
Save hrdyjan1/99e4bdea63f7f642e95aed9938b46816 to your computer and use it in GitHub Desktop.
Carvago - Frontend Monorepo - eslint
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module.exports = { | |
| settings: { | |
| react: { | |
| version: '18', | |
| }, | |
| }, | |
| parser: '@typescript-eslint/parser', | |
| extends: [ | |
| 'plugin:prettier/recommended', | |
| // enable typescript support | |
| 'plugin:@typescript-eslint/recommended', | |
| // now disable all of the rules that are in conflict with prettier | |
| 'prettier', | |
| // note that we don't add the prettier rules, they add noise to the IDE | |
| // and the code is all being formatted on commit anyway. | |
| /* | |
| * Disallow regex lookbehinds. Whole app crashes in unsupported browsers | |
| */ | |
| 'plugin:no-lookahead-lookbehind-regexp/recommended', | |
| ], | |
| plugins: [ | |
| '@typescript-eslint', | |
| 'react', | |
| 'unused-imports', | |
| 'eag', | |
| 'unicorn', | |
| '@nx', | |
| 'import', | |
| 'filename-export', | |
| ], | |
| settings: { | |
| 'import/parsers': { | |
| '@typescript-eslint/parser': ['.ts', '.tsx'], | |
| }, | |
| 'import/resolver': { | |
| typescript: { | |
| alwaysTryTypes: true, | |
| project: ['tsconfig.base.json'], | |
| }, | |
| }, | |
| }, | |
| rules: { | |
| 'import/no-duplicates': 'warn', | |
| 'import/no-default-export': 'warn', | |
| 'import/no-cycle': ['error', {ignoreExternal: false, maxDepth: 1}], | |
| // 'filename-export/match-named-export': 'warn', | |
| 'no-nested-ternary': 'warn', | |
| 'no-restricted-imports': [ | |
| 'warn', | |
| { | |
| paths: [ | |
| { | |
| name: '@chakra-ui/react', | |
| message: "Don't use chakra. Use platform instead.", | |
| }, | |
| { | |
| name: '@chakra-ui/utils', | |
| message: "Don't use chakra. Use platform instead.", | |
| }, | |
| { | |
| name: '@chakra-ui/react-utils', | |
| message: "Don't use chakra. Use platform instead.", | |
| }, | |
| { | |
| name: '@chakra-ui/layout', | |
| message: "Don't use chakra. Use platform instead.", | |
| }, | |
| { | |
| name: '@chakra-ui/system', | |
| importNames: ['useTheme'], | |
| message: "Don't use this chakra component", | |
| }, | |
| { | |
| name: '@chakra-ui/styled-system', | |
| importNames: ['CSSObject'], | |
| message: "Don't use chakra for styling. Use Platform components or styled-components.", | |
| }, | |
| { | |
| name: 'platform', | |
| importNames: ['theme'], | |
| message: | |
| "Don't use theme directly. Use 'useTheme' hook from styled-components or theme provided inside styled-components css: ${({theme}) => theme.some.token};", | |
| }, | |
| { | |
| name: 'ts-pattern', | |
| importNames: ['P'], | |
| message: 'Import Pattern instead the P shortcut. Pattern has better readability.', | |
| }, | |
| { | |
| name: 'react-router-dom', | |
| importNames: ['generatePath'], | |
| message: 'generatePath is untyped native function, use composePath from platform', | |
| }, | |
| { | |
| name: 'ramda', | |
| importNames: [ | |
| 'path', | |
| 'pathOr', | |
| 'paths', | |
| 'pathEq', | |
| 'modifyPath', | |
| 'assocPath', | |
| 'dissocPath', | |
| 'pathSatisfies', | |
| ], | |
| message: | |
| "Don't use path function if not absolutely necessary. They are not TS friendly, and TS errors can slip through them without any detection ", | |
| }, | |
| { | |
| name: 'react', | |
| importNames: ['FC'], | |
| message: | |
| "Don't use `const MyButton: React.FC<MyButtonProps>` but `function MyButton(props: MyButtonProps)`", | |
| }, | |
| ], | |
| patterns: [ | |
| { | |
| group: ['lodash', 'lodash/*'], | |
| message: 'Use ramda please.', | |
| }, | |
| { | |
| group: ['@material-ui', '@material-ui/*'], | |
| message: "Don't use Material UI anymore. Use Platform components instead.", | |
| }, | |
| ], | |
| }, | |
| ], | |
| 'no-restricted-syntax': [ | |
| 'error', | |
| { | |
| selector: "TSAsExpression[expression.type='TSAsExpression']", | |
| message: 'Using double assertion is an anti-pattern. It is not safe.', | |
| }, | |
| { | |
| selector: "CallExpression[callee.name='String'][arguments.0.type='ChainExpression']", | |
| message: | |
| 'String(undefined) returns "undefined". Please use undefined ?? \'\' or some other approach.', | |
| }, | |
| { | |
| selector: | |
| "CallExpression[callee.property.name='catch'][arguments.0.name='handleApiError'] MemberExpression[object.callee.type='Identifier']:not([property.name='unwrap'])", | |
| message: | |
| 'In order to catch an RTK Query error, you need to unwrap the promise first. Example: deleteVehicle().unwrap().then().catch()', | |
| }, | |
| { | |
| selector: "MemberExpression[object.name='P'][property.name='_']", | |
| message: 'Use Pattern.any instead. It will improve readability.', | |
| }, | |
| { | |
| selector: | |
| "ImportDeclaration[source.value='react'][specifiers.0.type='ImportDefaultSpecifier']", | |
| message: "Use named import instead. Example: import {useState} from 'react'.", | |
| }, | |
| { | |
| selector: | |
| "ImportDeclaration[source.value='ramda'][specifiers.0.type='ImportDefaultSpecifier']", | |
| message: | |
| "Don't import whole library. Use named import instead. Example: import {map} from 'ramda'.", | |
| }, | |
| { | |
| selector: "JSXOpeningElement[name.name='DataGrid'] JSXAttribute[name.name='key']", | |
| message: 'Do not use key to force refresh. Use the useRefreshDataGrid hook instead.', | |
| }, | |
| { | |
| selector: | |
| "Property[value] CallExpression:has(MemberExpression[object.callee.property.name='number']) Identifier[name='transform']", | |
| message: "Don't use Yup.number().transform(...). Use yupNumber() from shared instead.", | |
| }, | |
| { | |
| selector: | |
| "Property[value] CallExpression:has(MemberExpression[object.callee.name='number']) Identifier[name='transform']", | |
| message: "Don't use number().transform(...). Use yupNumber() from shared instead.", | |
| }, | |
| ], | |
| 'unicorn/no-abusive-eslint-disable': 'error', | |
| 'unicorn/no-unsafe-regex': 'error', | |
| 'unicorn/prefer-array-flat-map': 'warn', | |
| 'unicorn/prefer-array-some': 'warn', | |
| 'unicorn/prefer-includes': 'warn', | |
| 'arrow-body-style': 'warn', | |
| 'dot-notation': 'warn', | |
| 'no-var': 'error', | |
| 'no-debugger': 'error', | |
| 'no-alert': 'error', | |
| 'no-console': 'error', | |
| 'react/no-array-index-key': 'warn', | |
| 'react/jsx-no-leaked-render': 'off', | |
| 'eag/no-index': 'warn', | |
| 'eag/no-date-parsing': 'warn', | |
| 'eag/no-css-property': [ | |
| 'warn', | |
| { | |
| property: 'button', | |
| message: | |
| "Using button selector is considered an anti-pattern. Use Button component from platform and it's API as is.", | |
| }, | |
| { | |
| property: 'svg', | |
| message: | |
| "Using svg selector is considered an anti-pattern. Use Icon component from platform and it's API as is.", | |
| }, | |
| { | |
| property: 'letter-spacing', | |
| message: | |
| 'Using letter-spacing directly is considered an anti-pattern. Use on of text components from platform.', | |
| }, | |
| { | |
| property: 'font-size', | |
| message: | |
| 'Using font-size directly is considered an anti-pattern. Use on of text components from platform.', | |
| }, | |
| { | |
| property: 'font-weight', | |
| message: | |
| 'Using font-weight directly is considered an anti-pattern. Use on of text components from platform.', | |
| }, | |
| { | |
| property: 'font-family', | |
| message: | |
| 'Using font-family directly is considered an anti-pattern. Use on of text components from platform.', | |
| }, | |
| { | |
| property: 'font-size', | |
| message: | |
| 'Using font-size directly is considered an anti-pattern. Use on of text components from platform.', | |
| }, | |
| { | |
| property: 'margin', | |
| message: | |
| 'Using margin is considered an anti-pattern. Use a wrapper element like Box with some padding in it.', | |
| }, | |
| { | |
| property: 'px', | |
| exclude: '1px', | |
| message: | |
| 'Using px units is considered an anti-pattern. Use theme.getSize() utility or Box element.', | |
| }, | |
| { | |
| property: 'rem', | |
| message: | |
| 'Using rem units is considered an anti-pattern. Use theme.getSize() utility or Box element.', | |
| }, | |
| { | |
| property: '#', | |
| message: 'Using hex colors is considered an anti-pattern. Use one of theme tokens.', | |
| }, | |
| { | |
| property: ' > ', | |
| message: | |
| 'Using css selectors is considered an anti-pattern. It breaks component encapsulation.', | |
| }, | |
| { | |
| property: 'line-height', | |
| message: | |
| 'Using line-height directly is considered an anti-pattern. Use on of text components from platform.', | |
| }, | |
| ], | |
| 'object-shorthand': 'warn', | |
| 'prefer-arrow-callback': 'warn', | |
| 'prefer-const': 'warn', | |
| // In principle I like this rule, but I also want to use names such as _Foo | |
| // for those internal classes that get passed on to redux connect. | |
| // After much refactoring I realized that I just prefer _Foo to FooImpl. | |
| // Since this rule is being well followed without an eslint rule, I"m switching | |
| // this one off. | |
| '@typescript-eslint/class-name-casing': 'off', | |
| // too many of the graphql generate types break this rule, and they do so | |
| // in a way that makes enough sense that I don"t want to deal with it | |
| '@typescript-eslint/camelcase': 'off', | |
| 'no-unused-vars': 'off', | |
| 'unused-imports/no-unused-imports': 'error', | |
| 'unused-imports/no-unused-vars': [ | |
| 'warn', | |
| { | |
| vars: 'all', | |
| varsIgnorePattern: '^_', | |
| args: 'after-used', | |
| argsIgnorePattern: '^_', | |
| }, | |
| ], | |
| }, | |
| overrides: [ | |
| { | |
| files: '*.{js,jsx}', | |
| rules: { | |
| // this should just be fixed | |
| '@typescript-eslint/no-unused-vars': 'off', | |
| // opinion: this is reasonable to disable | |
| '@typescript-eslint/no-use-before-define': 'off', | |
| '@typescript-eslint/no-var-requires': 'off', | |
| '@typescript-eslint/explicit-function-return-type': 'off', | |
| '@typescript-eslint/ban-ts-comment': 'off', | |
| '@typescript-eslint/explicit-module-boundary-types': 'off', | |
| }, | |
| }, | |
| { | |
| files: '*.{ts,tsx}', | |
| /** | |
| * https://stackoverflow.com/questions/64933543/parsing-error-cannot-read-file-tsconfig-json-eslint | |
| */ | |
| // parserOptions: { | |
| // tsconfigRootDir: __dirname, | |
| // project: ['./tsconfig.base.json'], | |
| // sourceType: 'module', | |
| // }, | |
| rules: { | |
| /** | |
| * Don't forget to regenerate dep-graph if you change those rules | |
| */ | |
| '@nx/enforce-module-boundaries': [ | |
| 'error', | |
| { | |
| allowCircularSelfDependency: false, | |
| enforceBuildableLibDependency: true, | |
| allow: [], | |
| depConstraints: [ | |
| { | |
| sourceTag: 'scope:caraudit', | |
| notDependOnLibsWithTags: [ | |
| 'scope:price-report', | |
| 'scope:omnetic-admin-service', | |
| 'scope:omnetic-dms', | |
| ], | |
| }, | |
| { | |
| sourceTag: 'scope:omnetic-dms', | |
| notDependOnLibsWithTags: [ | |
| 'scope:price-report', | |
| 'scope:omnetic-admin-service', | |
| 'scope:caraudit', | |
| ], | |
| }, | |
| { | |
| sourceTag: 'scope:price-report', | |
| notDependOnLibsWithTags: [ | |
| 'scope:omnetic-dms', | |
| 'scope:omnetic-admin-service', | |
| 'scope:caraudit', | |
| ], | |
| }, | |
| { | |
| sourceTag: 'scope:digital-certificate', | |
| notDependOnLibsWithTags: [ | |
| 'scope:price-report', | |
| 'scope:omnetic-dms', | |
| 'scope:omnetic-admin-service', | |
| ], | |
| }, | |
| { | |
| sourceTag: 'scope:omnetic-admin-service', | |
| notDependOnLibsWithTags: [ | |
| 'scope:omnetic-dms', | |
| 'scope:price-report', | |
| 'scope:digital-certificate', | |
| 'scope:caraudit', | |
| ], | |
| }, | |
| { | |
| sourceTag: 'scope:features', | |
| onlyDependOnLibsWithTags: ['shared'], | |
| }, | |
| { | |
| sourceTag: 'type:app', | |
| onlyDependOnLibsWithTags: ['type:feature', 'type:ui', 'type:util'], | |
| }, | |
| { | |
| sourceTag: 'type:ui', | |
| onlyDependOnLibsWithTags: ['scope:shared'], | |
| }, | |
| { | |
| sourceTag: 'type:feature', | |
| notDependOnLibsWithTags: ['type:app', 'feature:shared'], | |
| }, | |
| { | |
| sourceTag: 'shared-feature', | |
| notDependOnLibsWithTags: ['type:app', 'feature:shared'], | |
| }, | |
| { | |
| sourceTag: 'type:e2e', | |
| onlyDependOnLibsWithTags: ['*'], | |
| }, | |
| { | |
| sourceTag: 'e2e-utils', | |
| onlyDependOnLibsWithTags: ['type:feature', 'type:util'], | |
| }, | |
| { | |
| sourceTag: 'shared', | |
| notDependOnLibsWithTags: ['*'], | |
| }, | |
| ], | |
| }, | |
| ], | |
| // 'eag/number-boolean-explicit-conversion': 'error', | |
| 'require-await': 'error', | |
| 'react/boolean-prop-naming': 'error', | |
| 'react/jsx-key': 'error', | |
| 'react/jsx-no-useless-fragment': 'off', | |
| 'jsx-quotes': ['error', 'prefer-double'], | |
| 'react/jsx-curly-brace-presence': [ | |
| 'error', | |
| {props: 'never', children: 'never', propElementValues: 'always'}, | |
| ], | |
| // disabled because it conflicts with jsx-a11y/alt-text | |
| 'jsx-a11y/img-redundant-alt': 'off', | |
| // changed to match the default tsconfig | |
| '@typescript-eslint/explicit-member-accessibility': 'off', | |
| '@typescript-eslint/explicit-function-return-type': 'off', | |
| '@typescript-eslint/no-non-null-assertion': 'off', | |
| '@typescript-eslint/no-empty-function': 'off', | |
| '@typescript-eslint/no-var-requires': 'off', | |
| '@typescript-eslint/prefer-interface': 'off', | |
| '@typescript-eslint/explicit-module-boundary-types': 'off', | |
| '@typescript-eslint/no-namespace': 'warn', | |
| '@typescript-eslint/no-empty-interface': [ | |
| 'error', | |
| { | |
| allowSingleExtends: true, | |
| }, | |
| ], | |
| '@typescript-eslint/no-angle-bracket-type-assertion': 'off', | |
| '@typescript-eslint/ban-ts-comment': 'off', | |
| '@typescript-eslint/no-unused-vars': 'off', | |
| 'react/forbid-dom-props': [ | |
| 'warn', | |
| { | |
| forbid: [ | |
| 'className', | |
| 'style', | |
| { | |
| propName: 'data-testId', | |
| message: "Don't use data-testId prop (capital I). Use data-testid instead.", | |
| }, | |
| ], | |
| }, | |
| ], | |
| 'react/forbid-component-props': [ | |
| 'warn', | |
| { | |
| forbid: [ | |
| 'css', | |
| 'style', | |
| 'className', | |
| { | |
| propName: '__css', | |
| message: | |
| "Don't style components with chakra. Use platform components or styled-compoennts.", | |
| }, | |
| { | |
| propName: 'data-testId', | |
| message: "Don't use data-testId prop (capital I). Use data-testid instead.", | |
| }, | |
| ], | |
| }, | |
| ], | |
| }, | |
| }, | |
| { | |
| files: ['**/src/components/{Text,Heading,Display,Avatar}/**.tsx'], | |
| rules: { | |
| 'eag/no-css-property': 0, | |
| }, | |
| }, | |
| { | |
| files: ['**/models/**/*.ts'], | |
| rules: { | |
| 'unicorn/no-abusive-eslint-disable': 0, | |
| }, | |
| }, | |
| { | |
| files: ['**/*.stories.ts', '**/*.stories.tsx'], | |
| rules: { | |
| 'import/no-default-export': 0, | |
| }, | |
| }, | |
| { | |
| files: ['**/src/index.ts', '**/src/index.tsx', '**/src/__modules/*/index.*'], | |
| rules: { | |
| 'eag/no-index': 0, | |
| }, | |
| }, | |
| ], | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment