1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039 |
- const detectDeprecations = !!process.env.SENTRY_DETECT_DEPRECATIONS;
- const baseRules = {
-
-
- strict: ['error', 'global'],
-
-
- 'no-shadow': ['error'],
-
- 'no-shadow-restricted-names': ['error'],
-
- 'no-undef': ['error'],
-
- 'no-unused-vars': [
- 'error',
- {
- vars: 'all',
- args: 'none',
-
-
-
-
-
- varsIgnorePattern: '^_',
- argsIgnorePattern: '^_',
- },
- ],
-
- 'no-use-before-define': ['error', {functions: false}],
-
-
- 'no-cond-assign': ['error', 'always'],
-
- 'no-console': ['warn'],
-
- 'no-alert': ['error'],
-
- 'no-constant-condition': ['warn'],
-
- 'no-empty': ['error'],
-
- 'no-ex-assign': ['error'],
-
- 'no-extra-boolean-cast': ['error'],
-
- 'no-func-assign': ['error'],
-
- 'no-inner-declarations': ['error'],
-
- 'no-invalid-regexp': ['error'],
-
- 'no-irregular-whitespace': ['error'],
-
- 'no-obj-calls': ['error'],
-
- 'no-sparse-arrays': ['error'],
-
- 'block-scoped-var': ['error'],
-
-
- 'consistent-return': ['error'],
-
- 'default-case': ['error'],
-
- 'dot-notation': [
- 'error',
- {
- allowKeywords: true,
- },
- ],
-
- 'guard-for-in': ['off'],
-
- 'no-caller': ['error'],
-
- 'no-eval': ['error'],
-
- 'no-extend-native': ['error'],
-
- 'no-extra-bind': ['error'],
-
- 'no-fallthrough': ['error'],
-
- 'no-floating-decimal': ['error'],
-
- 'no-implied-eval': ['error'],
-
- 'no-lone-blocks': ['error'],
-
- 'no-loop-func': ['error'],
-
- 'no-multi-str': ['error'],
-
- 'no-native-reassign': ['error'],
-
- 'no-new': ['error'],
-
- 'no-new-func': ['error'],
-
- 'no-new-wrappers': ['error'],
-
- 'no-octal': ['error'],
-
- 'no-octal-escape': ['error'],
-
- 'no-param-reassign': ['off'],
-
- 'no-proto': ['error'],
-
- 'no-return-assign': ['error'],
-
- 'no-script-url': ['error'],
-
- 'no-self-compare': ['error'],
-
- 'no-sequences': ['error'],
-
- 'no-throw-literal': ['error'],
-
- 'no-with': ['error'],
-
- radix: ['error'],
-
- 'computed-property-spacing': ['error', 'never'],
-
- 'array-bracket-spacing': ['error', 'never'],
-
- 'object-curly-spacing': ['error', 'never'],
-
- 'object-shorthand': ['error', 'properties'],
-
- 'space-infix-ops': ['error'],
-
- 'vars-on-top': ['off'],
-
- 'wrap-iife': ['error', 'any'],
-
- 'array-callback-return': ['error'],
-
- yoda: ['error'],
-
- 'no-else-return': ['error', {allowElseIf: false}],
-
- 'require-await': ['error'],
-
- 'multiline-comment-style': ['error', 'separate-lines'],
-
- 'spaced-comment': [
- 'error',
- 'always',
- {
- line: {markers: ['/'], exceptions: ['-', '+']},
- block: {exceptions: ['*'], balanced: true},
- },
- ],
- };
- const reactReactRules = {
-
- 'react/display-name': ['off'],
-
- 'react/no-multi-comp': [
- 'off',
- {
- ignoreStateless: true,
- },
- ],
-
- 'react/jsx-fragments': ['error', 'element'],
-
-
- 'react/jsx-handler-names': [
- 'off',
- {
- eventHandlerPrefix: 'handle',
- eventHandlerPropPrefix: 'on',
- },
- ],
-
- 'react/jsx-key': ['error'],
-
- 'react/jsx-no-undef': ['error'],
-
-
- 'react/jsx-uses-react': ['off'],
-
- 'react/jsx-uses-vars': ['error'],
-
-
- 'react/no-deprecated': ['error'],
-
- 'react/no-is-mounted': ['warn'],
-
-
-
- 'react/no-find-dom-node': ['warn'],
-
-
-
- 'react/no-render-return-value': ['error'],
-
-
-
- 'react/no-children-prop': ['error'],
-
-
-
- 'react/no-danger-with-children': ['error'],
-
-
- 'react/no-direct-mutation-state': ['error'],
-
- 'react/no-did-mount-set-state': ['error'],
-
- 'react/no-did-update-set-state': ['error'],
-
- 'react/no-redundant-should-component-update': ['error'],
-
- 'react/no-typos': ['error'],
-
-
- 'react/no-string-refs': ['warn'],
-
-
- 'react/no-unescaped-entities': ['off'],
-
- 'react/no-unknown-property': ['error', {ignore: ['css']}],
-
-
-
- 'react/no-unused-prop-types': ['off'],
-
- 'react/prop-types': ['off'],
-
-
-
- 'react/require-render-return': ['error'],
-
-
- 'react/react-in-jsx-scope': ['off'],
-
- 'react/self-closing-comp': ['error'],
-
-
-
-
- 'react/sort-comp': ['warn'],
-
-
- 'react/jsx-wrap-multilines': ['off'],
-
-
- 'react/jsx-boolean-value': ['error', 'never'],
-
-
- 'react/function-component-definition': [
- 'error',
- {namedComponents: 'function-declaration'},
- ],
- };
- const reactImportRules = {
-
-
- 'import/no-unresolved': ['off'],
- 'import/named': ['off'],
- 'import/default': ['off'],
- 'import/export': ['off'],
- 'import/no-named-as-default-member': ['off'],
-
-
-
-
- 'import/no-named-as-default': ['off'],
-
-
- 'import/no-deprecated': ['off'],
-
-
-
- 'import/no-mutable-exports': ['off'],
-
-
- 'import/no-commonjs': ['off'],
-
-
- 'import/no-amd': ['error'],
-
-
- 'import/no-duplicates': ['error'],
-
-
- 'import/no-namespace': ['off'],
-
-
-
- 'import/extensions': [
- 'off',
- 'always',
- {
- js: 'never',
- jsx: 'never',
- },
- ],
-
-
- 'import/order': [
- 'error',
- {
- groups: ['builtin', 'external', 'internal', ['parent', 'sibling', 'index']],
- 'newlines-between': 'always',
- },
- ],
-
-
- 'import/newline-after-import': ['error'],
-
-
- 'import/prefer-default-export': ['off'],
-
-
- 'import/no-restricted-paths': ['off'],
-
-
- 'import/max-dependencies': ['off', {max: 10}],
-
-
- 'import/no-absolute-path': ['error'],
-
-
- 'import/no-dynamic-require': ['off'],
-
- 'import/dynamic-import-chunkname': ['off'],
-
-
- 'import/no-internal-modules': [
- 'off',
- {
- allow: [],
- },
- ],
-
-
-
-
-
- 'import/unambiguous': ['off'],
-
-
- 'import/no-webpack-loader-syntax': ['error'],
-
-
-
- 'import/no-unassigned-import': ['off'],
-
-
- 'import/no-named-default': ['error'],
-
-
- 'import/no-anonymous-default-export': [
- 'error',
- {
- allowArray: false,
- allowArrowFunction: false,
- allowAnonymousClass: false,
- allowAnonymousFunction: false,
- allowCallExpression: true,
- allowLiteral: false,
- allowObject: false,
- },
- ],
- };
- const reactJestRules = {
- 'jest/no-large-snapshots': ['warn', {maxSize: 2000}],
- 'jest/no-disabled-tests': 'error',
- };
- const reactRules = {
- ...reactReactRules,
- ...reactImportRules,
- ...reactJestRules,
-
- 'react-hooks/exhaustive-deps': 'error',
-
- 'react-hooks/rules-of-hooks': 'error',
-
-
- 'getsentry/jsx-needs-il8n': ['off'],
- 'testing-library/render-result-naming-convention': 'off',
- 'testing-library/no-unnecessary-act': 'off',
-
- 'jest/expect-expect': 'off',
-
-
- 'jest/no-commented-out-tests': 'off',
-
- 'jest/no-conditional-expect': 'off',
-
- 'jest/no-export': 'off',
- 'typescript-sort-keys/interface': [
- 'error',
- 'asc',
- {caseSensitive: true, natural: false, requiredFirst: true},
- ],
-
-
-
- 'no-restricted-imports': [
- 'error',
- {
- paths: [
- {
- name: 'react',
- importNames: ['default'],
- message: 'Prefer named React imports (React types DO NOT need imported!)',
- },
- ],
- },
- ],
- };
- const appRules = {
-
- '@emotion/jsx-import': 'off',
- '@emotion/no-vanilla': 'error',
- '@emotion/import-from-emotion': 'error',
- '@emotion/styled-import': 'error',
-
-
-
- 'no-undef': 'off',
-
- 'arrow-body-style': 'off',
-
- 'no-shadow': 'off',
- '@typescript-eslint/no-shadow': 'error',
-
-
- 'no-unused-vars': 'off',
- '@typescript-eslint/no-unused-vars': [
- 'error',
- {
- vars: 'all',
- args: 'all',
-
-
- caughtErrors: 'none',
-
-
-
-
-
- varsIgnorePattern: '^_',
- argsIgnorePattern: '^_',
- destructuredArrayIgnorePattern: '^_',
- },
- ],
- 'no-use-before-define': 'off',
-
- '@typescript-eslint/no-use-before-define': ['off'],
-
- 'no-restricted-imports': [
- 'error',
- {
- paths: [
- {
- name: 'enzyme',
- message:
- 'Please import from `sentry-test/enzyme` instead. See: https://github.com/getsentry/frontend-handbook#undefined-theme-properties-in-tests for more information',
- },
- {
- name: '@testing-library/react',
- message:
- 'Please import from `sentry-test/reactTestingLibrary` instead so that we can ensure consistency throughout the codebase',
- },
- {
- name: '@testing-library/react-hooks',
- message:
- 'Please import from `sentry-test/reactTestingLibrary` instead so that we can ensure consistency throughout the codebase',
- },
- {
- name: '@testing-library/user-event',
- message:
- 'Please import from `sentry-test/reactTestingLibrary` instead so that we can ensure consistency throughout the codebase',
- },
- {
- name: '@sentry/browser',
- message:
- 'Please import from `@sentry/react` to ensure consistency throughout the codebase.',
- },
- {
- name: 'marked',
- message:
- "Please import marked from 'app/utils/marked' so that we can ensure sanitation of marked output",
- },
- {
- name: 'lodash',
- message:
- "Please import lodash utilities individually. e.g. `import isEqual from 'lodash/isEqual';`. See https://github.com/getsentry/frontend-handbook#lodash from for information",
- },
- {
- name: 'lodash/get',
- message:
- 'Optional chaining `?.` and nullish coalescing operators `??` are available and preferred over using `lodash/get`. See https://github.com/getsentry/frontend-handbook#new-syntax for more information',
- },
- {
- name: 'react-bootstrap',
- message:
- 'Avoid usage of any react-bootstrap components as it will soon be removed',
- },
- {
- name: 'sentry/utils/theme',
- importNames: ['lightColors', 'darkColors'],
- message:
- "'lightColors' and 'darkColors' exports intended for use in Storybook only. Instead, use theme prop from emotion or the useTheme hook.",
- },
- {
- name: 'react-router',
- importNames: ['withRouter'],
- message:
- "Use 'useLocation', 'useParams', 'useNavigate', 'useRoutes' from sentry/utils instead.",
- },
- {
- name: 'sentry/utils/withSentryRouter',
- importNames: ['withSentryRouter'],
- message:
- "Use 'useLocation', 'useParams', 'useNavigate', 'useRoutes' from sentry/utils instead.",
- },
- ],
- },
- ],
-
- 'sort-imports': 'off',
- 'import/order': 'off',
- 'simple-import-sort/imports': [
- 'error',
- {
- groups: [
-
- ['^\\u0000'],
-
-
- [`^(${require('node:module').builtinModules.join('|')})(/|$)`],
-
- ['^react', '^@?\\w'],
-
- ['^(sentry-test|getsentry-test)(/.*|$)'],
-
- ['^(sentry-locale|sentry-images)(/.*|$)'],
- ['^(getsentry-images)(/.*|$)'],
- ['^(app|sentry)(/.*|$)'],
-
- ['^(admin|getsentry)(/.*|$)'],
-
- ['^.+\\.less$'],
-
- ['^\\.\\.(?!/?$)', '^\\.\\./?$'],
-
- ['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'],
- ],
- },
- ],
- 'sentry/no-digits-in-tn': ['error'],
- 'sentry/no-dynamic-translations': ['error'],
-
- '@typescript-eslint/no-restricted-types': [
- 'error',
- {
- types: {
-
-
-
-
-
- Buffer: {
- message:
- 'Use Uint8Array instead. See: https://sindresorhus.com/blog/goodbye-nodejs-buffer',
- suggest: ['Uint8Array'],
- },
- '[]': "Don't use the empty array type `[]`. It only allows empty arrays. Use `SomeType[]` instead.",
- '[[]]':
- "Don't use `[[]]`. It only allows an array with a single element which is an empty array. Use `SomeType[][]` instead.",
- '[[[]]]': "Don't use `[[[]]]`. Use `SomeType[][][]` instead.",
- },
- },
- ],
-
-
-
-
- '@typescript-eslint/no-wrapper-object-types': 'error',
-
- '@typescript-eslint/naming-convention': [
- 'error',
- {
- selector: 'typeLike',
- format: ['PascalCase'],
- leadingUnderscore: 'allow',
- },
- {
- selector: 'enumMember',
- format: ['UPPER_CASE'],
- },
- ],
-
-
- 'no-lookahead-lookbehind-regexp/no-lookahead-lookbehind-regexp': [
- 'error',
- 'no-lookbehind',
- 'no-negative-lookbehind',
- ],
- };
- const strictRules = {
- 'no-console': ['error'],
-
- 'react/no-is-mounted': ['error'],
-
-
- 'react/no-find-dom-node': ['error'],
-
-
- 'react/no-string-refs': ['error'],
- 'jest/no-large-snapshots': ['error', {maxSize: 2000}],
- 'sentry/no-styled-shortcut': ['error'],
- };
- const extendsList = [
- 'plugin:jest/recommended',
- 'plugin:jest-dom/recommended',
- 'plugin:import/typescript',
- ];
- if (detectDeprecations) {
- extendsList.push('plugin:deprecation/recommended');
- }
- module.exports = {
- root: true,
- extends: extendsList,
- plugins: [
- 'jest-dom',
- 'testing-library',
- 'typescript-sort-keys',
- 'react-hooks',
- '@typescript-eslint',
- '@emotion',
- 'import',
- 'react',
- 'sentry',
- 'simple-import-sort',
- 'no-lookahead-lookbehind-regexp',
- ],
- parser: '@typescript-eslint/parser',
- parserOptions: detectDeprecations
- ? {
- warnOnUnsupportedTypeScriptVersion: false,
- ecmaVersion: 6,
- sourceType: 'module',
- ecmaFeatures: {
- jsx: true,
- modules: true,
- legacyDecorators: true,
- },
- project: './tsconfig.json',
- }
- : {
- warnOnUnsupportedTypeScriptVersion: false,
- ecmaVersion: 6,
- sourceType: 'module',
- ecmaFeatures: {
- jsx: true,
- modules: true,
- legacyDecorators: true,
- },
- },
- env: {
- browser: true,
- es6: true,
- jest: true,
- jquery: true,
- },
- globals: {
- require: false,
- expect: false,
- MockApiClient: true,
- tick: true,
- jest: true,
- },
- settings: {
- react: {
- version: '17.0.2',
- },
- 'import/parsers': {
- '@typescript-eslint/parser': ['.ts', '.tsx'],
- },
- 'import/resolver': {
- typescript: {},
- },
- 'import/extensions': ['.js', '.jsx'],
- },
- rules: {
- ...baseRules,
- ...reactRules,
- ...appRules,
- ...strictRules,
- 'react-hooks/rules-of-hooks': 'error',
- 'react-hooks/exhaustive-deps': [
- 'error',
- {additionalHooks: '(useEffectAfterFirstRender|useMemoWithPrevious)'},
- ],
- 'no-restricted-imports': [
- 'error',
- {
- patterns: [
- {
- group: ['sentry/components/devtoolbar/*'],
- message: 'Do not depend on toolbar internals',
- },
- ],
- paths: [
- {
- name: '@testing-library/react',
- message:
- 'Please import from `sentry-test/reactTestingLibrary` instead so that we can ensure consistency throughout the codebase',
- },
- {
- name: '@testing-library/react-hooks',
- message:
- 'Please import from `sentry-test/reactTestingLibrary` instead so that we can ensure consistency throughout the codebase',
- },
- {
- name: '@testing-library/user-event',
- message:
- 'Please import from `sentry-test/reactTestingLibrary` instead so that we can ensure consistency throughout the codebase',
- },
- {
- name: '@sentry/browser',
- message:
- 'Please import from `@sentry/react` to ensure consistency throughout the codebase.',
- },
- {
- name: 'marked',
- message:
- "Please import marked from 'app/utils/marked' so that we can ensure sanitation of marked output",
- },
- {
- name: 'lodash',
- message:
- "Please import lodash utilities individually. e.g. `import isEqual from 'lodash/isEqual';`. See https://github.com/getsentry/frontend-handbook#lodash from for information",
- },
- {
- name: 'lodash/get',
- message:
- 'Optional chaining `?.` and nullish coalescing operators `??` are available and preferred over using `lodash/get`. See https://github.com/getsentry/frontend-handbook#new-syntax for more information',
- },
- {
- name: 'sentry/utils/theme',
- importNames: ['lightColors', 'darkColors'],
- message:
- "'lightColors' and 'darkColors' exports intended for use in Storybook only. Instead, use theme prop from emotion or the useTheme hook.",
- },
- {
- name: 'react-router',
- importNames: ['withRouter'],
- message:
- "Use 'useLocation', 'useParams', 'useNavigate', 'useRoutes' from sentry/utils instead.",
- },
- {
- name: 'sentry/utils/withSentryRouter',
- importNames: ['withSentryRouter'],
- message:
- "Use 'useLocation', 'useParams', 'useNavigate', 'useRoutes' from sentry/utils instead.",
- },
- {
- name: 'qs',
- message: 'Please use query-string instead of qs',
- },
- {
- name: 'moment',
- message: 'Please import moment-timezone instead of moment',
- },
- ],
- },
- ],
-
- 'space-infix-ops': 'off',
- 'object-shorthand': 'off',
- 'object-curly-spacing': 'off',
- 'import/no-amd': 'off',
- 'no-danger-with-children': 'off',
- 'no-fallthrough': 'off',
- 'no-obj-calls': 'off',
- 'array-bracket-spacing': 'off',
- 'computed-property-spacing': 'off',
- 'react/no-danger-with-children': 'off',
- 'jest/no-disabled-tests': 'off',
- },
-
-
- ignorePatterns: ['*.json'],
- overrides: [
- {
- files: ['static/app/components/devtoolbar/**/*.{ts,tsx}'],
- rules: {
- 'no-restricted-imports': [
- 'error',
- {
- paths: [
- {
- name: 'sentry/utils/queryClient',
- message:
- 'Import from `@tanstack/react-query` and `./hooks/useFetchApiData` or `./hooks/useFetchInfiniteApiData` instead.',
- },
- ],
- },
- ],
- },
- },
- {
- files: ['static/**/*.spec.{ts,js}', 'tests/js/**/*.{ts,js}'],
- extends: ['plugin:testing-library/react', ...extendsList],
- rules: {
- ...baseRules,
- ...reactRules,
- ...appRules,
- ...strictRules,
-
- 'space-infix-ops': 'off',
- 'object-shorthand': 'off',
- 'object-curly-spacing': 'off',
- 'import/no-amd': 'off',
- 'no-danger-with-children': 'off',
- 'no-fallthrough': 'off',
- 'no-obj-calls': 'off',
- 'array-bracket-spacing': 'off',
- 'computed-property-spacing': 'off',
- 'react/no-danger-with-children': 'off',
- 'jest/no-disabled-tests': 'off',
- },
- },
- {
-
-
-
- files: ['**/js-sdk-loader.ts'],
- rules: {
- 'no-console': 'off',
- },
- },
- ],
- };
|