.eslintrc.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. /* eslint-env node */
  2. const detectDeprecations = !!process.env.SENTRY_DETECT_DEPRECATIONS;
  3. const baseRules = {
  4. /**
  5. * Strict mode
  6. */
  7. // https://eslint.org/docs/rules/strict
  8. strict: ['error', 'global'],
  9. /**
  10. * Variables
  11. */
  12. // https://eslint.org/docs/rules/no-shadow-restricted-names
  13. 'no-shadow-restricted-names': ['error'],
  14. /**
  15. * Possible errors
  16. */
  17. // https://eslint.org/docs/rules/no-cond-assign
  18. 'no-cond-assign': ['error', 'always'],
  19. // https://eslint.org/docs/rules/no-alert
  20. 'no-alert': ['error'],
  21. // https://eslint.org/docs/rules/no-constant-condition
  22. 'no-constant-condition': ['warn'],
  23. // https://eslint.org/docs/rules/no-empty
  24. 'no-empty': ['error'],
  25. // https://eslint.org/docs/rules/no-ex-assign
  26. 'no-ex-assign': ['error'],
  27. // https://eslint.org/docs/rules/no-extra-boolean-cast
  28. 'no-extra-boolean-cast': ['error'],
  29. // https://eslint.org/docs/rules/no-func-assign
  30. 'no-func-assign': ['error'],
  31. // https://eslint.org/docs/rules/no-inner-declarations
  32. 'no-inner-declarations': ['error'],
  33. // https://eslint.org/docs/rules/no-invalid-regexp
  34. 'no-invalid-regexp': ['error'],
  35. // https://eslint.org/docs/rules/no-irregular-whitespace
  36. 'no-irregular-whitespace': ['error'],
  37. // https://eslint.org/docs/rules/no-obj-calls
  38. 'no-obj-calls': ['error'],
  39. // https://eslint.org/docs/rules/no-sparse-arrays
  40. 'no-sparse-arrays': ['error'],
  41. // https://eslint.org/docs/rules/block-scoped-var
  42. 'block-scoped-var': ['error'],
  43. /**
  44. * Best practices
  45. */
  46. // https://eslint.org/docs/rules/consistent-return
  47. 'consistent-return': ['error'],
  48. // https://eslint.org/docs/rules/default-case
  49. 'default-case': ['error'],
  50. // https://eslint.org/docs/rules/dot-notation
  51. 'dot-notation': [
  52. 'error',
  53. {
  54. allowKeywords: true,
  55. },
  56. ],
  57. // https://eslint.org/docs/rules/guard-for-in [REVISIT ME]
  58. 'guard-for-in': ['off'],
  59. // https://eslint.org/docs/rules/no-caller
  60. 'no-caller': ['error'],
  61. // https://eslint.org/docs/rules/no-eval
  62. 'no-eval': ['error'],
  63. // https://eslint.org/docs/rules/no-extend-native
  64. 'no-extend-native': ['error'],
  65. // https://eslint.org/docs/rules/no-extra-bind
  66. 'no-extra-bind': ['error'],
  67. // https://eslint.org/docs/rules/no-fallthrough
  68. 'no-fallthrough': ['error'],
  69. // https://eslint.org/docs/rules/no-floating-decimal
  70. 'no-floating-decimal': ['error'],
  71. // https://eslint.org/docs/rules/no-implied-eval
  72. 'no-implied-eval': ['error'],
  73. // https://eslint.org/docs/rules/no-lone-blocks
  74. 'no-lone-blocks': ['error'],
  75. // https://eslint.org/docs/rules/no-loop-func
  76. 'no-loop-func': ['error'],
  77. // https://eslint.org/docs/rules/no-multi-str
  78. 'no-multi-str': ['error'],
  79. // https://eslint.org/docs/rules/no-native-reassign
  80. 'no-native-reassign': ['error'],
  81. // https://eslint.org/docs/rules/no-new
  82. 'no-new': ['error'],
  83. // https://eslint.org/docs/rules/no-new-func
  84. 'no-new-func': ['error'],
  85. // https://eslint.org/docs/rules/no-new-wrappers
  86. 'no-new-wrappers': ['error'],
  87. // https://eslint.org/docs/rules/no-octal
  88. 'no-octal': ['error'],
  89. // https://eslint.org/docs/rules/no-octal-escape
  90. 'no-octal-escape': ['error'],
  91. // https://eslint.org/docs/rules/no-param-reassign [REVISIT ME]
  92. 'no-param-reassign': ['off'],
  93. // https://eslint.org/docs/rules/no-proto
  94. 'no-proto': ['error'],
  95. // https://eslint.org/docs/rules/no-return-assign
  96. 'no-return-assign': ['error'],
  97. // https://eslint.org/docs/rules/no-script-url
  98. 'no-script-url': ['error'],
  99. // https://eslint.org/docs/rules/no-self-compare
  100. 'no-self-compare': ['error'],
  101. // https://eslint.org/docs/rules/no-sequences
  102. 'no-sequences': ['error'],
  103. // https://eslint.org/docs/rules/no-throw-literal
  104. 'no-throw-literal': ['error'],
  105. // https://eslint.org/docs/rules/no-with
  106. 'no-with': ['error'],
  107. // https://eslint.org/docs/rules/radix
  108. radix: ['error'],
  109. // https://eslint.org/docs/rules/space-in-brackets.html
  110. 'computed-property-spacing': ['error', 'never'],
  111. // https://eslint.org/docs/rules/space-in-brackets.html
  112. 'array-bracket-spacing': ['error', 'never'],
  113. // https://eslint.org/docs/rules/space-in-brackets.html
  114. 'object-curly-spacing': ['error', 'never'],
  115. // https://eslint.org/docs/rules/object-shorthand
  116. 'object-shorthand': ['error', 'properties'],
  117. // https://eslint.org/docs/rules/space-infix-ops.html
  118. 'space-infix-ops': ['error'],
  119. // https://eslint.org/docs/rules/vars-on-top
  120. 'vars-on-top': ['off'],
  121. // https://eslint.org/docs/rules/wrap-iife
  122. 'wrap-iife': ['error', 'any'],
  123. // https://eslint.org/docs/rules/array-callback-return
  124. 'array-callback-return': ['error'],
  125. // https://eslint.org/docs/rules/yoda
  126. yoda: ['error'],
  127. // https://eslint.org/docs/rules/no-else-return
  128. 'no-else-return': ['error', {allowElseIf: false}],
  129. // https://eslint.org/docs/rules/require-await
  130. 'require-await': ['error'],
  131. // https://eslint.org/docs/rules/multiline-comment-style
  132. 'multiline-comment-style': ['error', 'separate-lines'],
  133. // https://eslint.org/docs/rules/spaced-comment
  134. 'spaced-comment': [
  135. 'error',
  136. 'always',
  137. {
  138. line: {markers: ['/'], exceptions: ['-', '+']},
  139. block: {exceptions: ['*'], balanced: true},
  140. },
  141. ],
  142. };
  143. const reactReactRules = {
  144. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md
  145. 'react/display-name': ['off'],
  146. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md
  147. 'react/no-multi-comp': [
  148. 'off',
  149. {
  150. ignoreStateless: true,
  151. },
  152. ],
  153. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-fragments.md
  154. 'react/jsx-fragments': ['error', 'element'],
  155. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-handler-names.md
  156. // Ensures that any component or prop methods used to handle events are correctly prefixed.
  157. 'react/jsx-handler-names': [
  158. 'off',
  159. {
  160. eventHandlerPrefix: 'handle',
  161. eventHandlerPropPrefix: 'on',
  162. },
  163. ],
  164. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-key.md
  165. 'react/jsx-key': ['error'],
  166. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md
  167. 'react/jsx-no-undef': ['error'],
  168. // Disabled as we use the newer JSX transform babel plugin.
  169. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md
  170. 'react/jsx-uses-react': ['off'],
  171. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md
  172. 'react/jsx-uses-vars': ['error'],
  173. /**
  174. * Deprecation related rules
  175. */
  176. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-deprecated.md
  177. 'react/no-deprecated': ['error'],
  178. // Prevent usage of the return value of React.render
  179. // deprecation: https://facebook.github.io/react/docs/react-dom.html#render
  180. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-render-return-value.md
  181. 'react/no-render-return-value': ['error'],
  182. // Children should always be actual children, not passed in as a prop.
  183. // When using JSX, the children should be nested between the opening and closing tags. When not using JSX, the children should be passed as additional arguments to React.createElement.
  184. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-children-prop.md
  185. 'react/no-children-prop': ['error'],
  186. // This rule helps prevent problems caused by using children and the dangerouslySetInnerHTML prop at the same time.
  187. // React will throw a warning if this rule is ignored.
  188. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger-with-children.md
  189. 'react/no-danger-with-children': ['error'],
  190. // Prevent direct mutation of this.state
  191. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-direct-mutation-state.md
  192. 'react/no-direct-mutation-state': ['error'],
  193. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-mount-set-state.md
  194. 'react/no-did-mount-set-state': ['error'],
  195. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md"
  196. 'react/no-did-update-set-state': ['error'],
  197. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-redundant-should-component-update.md
  198. 'react/no-redundant-should-component-update': ['error'],
  199. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-typos.md
  200. 'react/no-typos': ['error'],
  201. // Prevent invalid characters from appearing in markup
  202. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unescaped-entities.md
  203. 'react/no-unescaped-entities': ['off'],
  204. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md
  205. 'react/no-unknown-property': ['error', {ignore: ['css']}],
  206. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unused-prop-types.md
  207. // Disabled since this currently fails to correctly detect a lot of
  208. // typescript prop type usage.
  209. 'react/no-unused-prop-types': ['off'],
  210. // We do not need proptypes since we're using typescript
  211. 'react/prop-types': ['off'],
  212. // When writing the render method in a component it is easy to forget to return the JSX content.
  213. // This rule will warn if the return statement is missing.
  214. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-render-return.md
  215. 'react/require-render-return': ['error'],
  216. // Disabled as we are using the newer JSX transform babel plugin.
  217. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md
  218. 'react/react-in-jsx-scope': ['off'],
  219. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md
  220. 'react/self-closing-comp': ['error'],
  221. // This also causes issues with typescript
  222. // See: https://github.com/yannickcr/eslint-plugin-react/issues/2066
  223. //
  224. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md
  225. 'react/sort-comp': ['warn'],
  226. // Disabled because of prettier
  227. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/wrap-multilines.md
  228. 'react/jsx-wrap-multilines': ['off'],
  229. // Consistent <Component booleanProp /> (never add ={true})
  230. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md
  231. 'react/jsx-boolean-value': ['error', 'never'],
  232. // Consistent function component declaration styles
  233. // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/function-component-definition.md
  234. 'react/function-component-definition': [
  235. 'error',
  236. {namedComponents: 'function-declaration'},
  237. ],
  238. };
  239. const reactImportRules = {
  240. // Not recommended to be enabled with typescript-eslint
  241. // https://typescript-eslint.io/linting/troubleshooting/performance-troubleshooting/#eslint-plugin-import
  242. 'import/no-unresolved': ['off'],
  243. 'import/named': ['off'],
  244. 'import/default': ['off'],
  245. 'import/export': ['off'],
  246. 'import/no-named-as-default-member': ['off'],
  247. // Redflags
  248. // do not allow a default import name to match a named export (airbnb: error)
  249. // Issue with `DefaultIssuePlugin` and `app/plugins/index`
  250. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-named-as-default.md
  251. 'import/no-named-as-default': ['off'],
  252. // disallow use of jsdoc-marked-deprecated imports
  253. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-deprecated.md
  254. 'import/no-deprecated': ['off'],
  255. // Forbid mutable exports (airbnb: error)
  256. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md
  257. // TODO: enable?
  258. 'import/no-mutable-exports': ['off'],
  259. // disallow require()
  260. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-commonjs.md
  261. 'import/no-commonjs': ['off'],
  262. // disallow AMD require/define
  263. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-amd.md
  264. 'import/no-amd': ['error'],
  265. // disallow duplicate imports
  266. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-duplicates.md
  267. 'import/no-duplicates': ['error'],
  268. // disallow namespace imports
  269. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-namespace.md
  270. 'import/no-namespace': ['off'],
  271. // Ensure consistent use of file extension within the import path
  272. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md
  273. // TODO this fucks up getsentry
  274. 'import/extensions': [
  275. 'off',
  276. 'always',
  277. {
  278. js: 'never',
  279. jsx: 'never',
  280. },
  281. ],
  282. // Require a newline after the last import/require in a group
  283. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/newline-after-import.md
  284. 'import/newline-after-import': ['error'],
  285. // Require modules with a single export to use a default export (airbnb: error)
  286. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md
  287. 'import/prefer-default-export': ['off'],
  288. // Restrict which files can be imported in a given folder
  289. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-restricted-paths.md
  290. 'import/no-restricted-paths': ['off'],
  291. // Forbid modules to have too many dependencies
  292. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/max-dependencies.md
  293. 'import/max-dependencies': ['off', {max: 10}],
  294. // Forbid import of modules using absolute paths
  295. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-absolute-path.md
  296. 'import/no-absolute-path': ['error'],
  297. // Forbid require() calls with expressions (airbnb: error)
  298. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-dynamic-require.md
  299. 'import/no-dynamic-require': ['off'],
  300. // Use webpack default chunk names
  301. 'import/dynamic-import-chunkname': ['off'],
  302. // prevent importing the submodules of other modules
  303. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-internal-modules.md
  304. 'import/no-internal-modules': [
  305. 'off',
  306. {
  307. allow: [],
  308. },
  309. ],
  310. // Warn if a module could be mistakenly parsed as a script by a consumer
  311. // leveraging Unambiguous JavaScript Grammar
  312. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/unambiguous.md
  313. // this should not be enabled until this proposal has at least been *presented* to TC39.
  314. // At the moment, it"s not a thing.
  315. 'import/unambiguous': ['off'],
  316. // Forbid Webpack loader syntax in imports
  317. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-webpack-loader-syntax.md
  318. 'import/no-webpack-loader-syntax': ['error'],
  319. // Prevent unassigned imports
  320. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unassigned-import.md
  321. // importing for side effects is perfectly acceptable, if you need side effects.
  322. 'import/no-unassigned-import': ['off'],
  323. // Prevent importing the default as if it were named
  324. // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-named-default.md
  325. 'import/no-named-default': ['error'],
  326. // Reports if a module"s default export is unnamed
  327. // https://github.com/benmosher/eslint-plugin-import/blob/d9b712ac7fd1fddc391f7b234827925c160d956f/docs/rules/no-anonymous-default-export.md
  328. 'import/no-anonymous-default-export': [
  329. 'error',
  330. {
  331. allowArray: false,
  332. allowArrowFunction: false,
  333. allowAnonymousClass: false,
  334. allowAnonymousFunction: false,
  335. allowCallExpression: true,
  336. allowLiteral: false,
  337. allowObject: false,
  338. },
  339. ],
  340. };
  341. const reactJestRules = {
  342. 'jest/no-disabled-tests': 'error',
  343. };
  344. const reactRules = {
  345. ...reactReactRules,
  346. ...reactImportRules,
  347. ...reactJestRules,
  348. /**
  349. * React hooks
  350. */
  351. 'react-hooks/exhaustive-deps': 'error',
  352. // Biome not yet enforcing all parts of this rule https://github.com/biomejs/biome/issues/1984
  353. 'react-hooks/rules-of-hooks': 'error',
  354. /**
  355. * Custom
  356. */
  357. // highlights literals in JSX components w/o translation tags
  358. 'getsentry/jsx-needs-il8n': ['off'],
  359. 'testing-library/render-result-naming-convention': 'off',
  360. 'testing-library/no-unnecessary-act': 'off',
  361. // Disabled as we have many tests which render as simple validations
  362. 'jest/expect-expect': 'off',
  363. // Disabled as we have some comment out tests that cannot be
  364. // uncommented due to typescript errors.
  365. 'jest/no-commented-out-tests': 'off',
  366. // Disabled as we do sometimes have conditional expects
  367. 'jest/no-conditional-expect': 'off',
  368. // Useful for exporting some test utilities
  369. 'jest/no-export': 'off',
  370. 'typescript-sort-keys/interface': [
  371. 'error',
  372. 'asc',
  373. {caseSensitive: true, natural: false, requiredFirst: true},
  374. ],
  375. };
  376. const appRules = {
  377. /**
  378. * emotion rules for v10
  379. *
  380. * This probably aren't as necessary anymore, but let's remove when we move to v11
  381. */
  382. '@emotion/jsx-import': 'off',
  383. '@emotion/no-vanilla': 'error',
  384. '@emotion/import-from-emotion': 'error',
  385. '@emotion/styled-import': 'error',
  386. // no-undef is redundant with typescript as tsc will complain
  387. // A downside is that we won't get eslint errors about it, but your editors should
  388. // support tsc errors so....
  389. // https://eslint.org/docs/rules/no-undef
  390. 'no-undef': 'off',
  391. // Let formatter handle this
  392. 'arrow-body-style': 'off',
  393. /**
  394. * Need to use typescript version of these rules
  395. * https://eslint.org/docs/rules/no-shadow
  396. */
  397. 'no-shadow': 'off',
  398. '@typescript-eslint/no-shadow': 'error',
  399. // This only override the `args` rule (which is "none"). There are too many errors and it's difficult to manually
  400. // fix them all, so we'll have to incrementally update.
  401. // https://eslint.org/docs/rules/no-unused-vars
  402. 'no-unused-vars': 'off',
  403. '@typescript-eslint/no-unused-vars': [
  404. 'error',
  405. {
  406. vars: 'all',
  407. args: 'all',
  408. // TODO(scttcper): We could enable this to enforce catch (error)
  409. // https://eslint.org/docs/latest/rules/no-unused-vars#caughterrors
  410. caughtErrors: 'none',
  411. // Ignore vars that start with an underscore
  412. // e.g. if you want to omit a property using object spread:
  413. //
  414. // const {name: _name, ...props} = this.props;
  415. //
  416. varsIgnorePattern: '^_',
  417. argsIgnorePattern: '^_',
  418. destructuredArrayIgnorePattern: '^_',
  419. },
  420. ],
  421. // https://eslint.org/docs/rules/no-use-before-define
  422. 'no-use-before-define': 'off',
  423. // This seems to have been turned on while previously it had been off
  424. '@typescript-eslint/no-use-before-define': ['off'],
  425. /**
  426. * Restricted imports, e.g. deprecated libraries, etc
  427. *
  428. * See: https://eslint.org/docs/rules/no-restricted-imports
  429. */
  430. 'no-restricted-imports': [
  431. 'error',
  432. {
  433. paths: [
  434. {
  435. name: 'enzyme',
  436. message:
  437. 'Please import from `sentry-test/enzyme` instead. See: https://github.com/getsentry/frontend-handbook#undefined-theme-properties-in-tests for more information',
  438. },
  439. {
  440. name: '@testing-library/react',
  441. message:
  442. 'Please import from `sentry-test/reactTestingLibrary` instead so that we can ensure consistency throughout the codebase',
  443. },
  444. {
  445. name: '@testing-library/react-hooks',
  446. message:
  447. 'Please import from `sentry-test/reactTestingLibrary` instead so that we can ensure consistency throughout the codebase',
  448. },
  449. {
  450. name: '@testing-library/user-event',
  451. message:
  452. 'Please import from `sentry-test/reactTestingLibrary` instead so that we can ensure consistency throughout the codebase',
  453. },
  454. {
  455. name: '@sentry/browser',
  456. message:
  457. 'Please import from `@sentry/react` to ensure consistency throughout the codebase.',
  458. },
  459. {
  460. name: 'marked',
  461. message:
  462. "Please import marked from 'app/utils/marked' so that we can ensure sanitation of marked output",
  463. },
  464. {
  465. name: 'lodash',
  466. message:
  467. "Please import lodash utilities individually. e.g. `import isEqual from 'lodash/isEqual';`. See https://github.com/getsentry/frontend-handbook#lodash from for information",
  468. },
  469. {
  470. name: 'lodash/get',
  471. message:
  472. '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',
  473. },
  474. {
  475. name: 'react-bootstrap',
  476. message:
  477. 'Avoid usage of any react-bootstrap components as it will soon be removed',
  478. },
  479. {
  480. name: 'sentry/utils/theme',
  481. importNames: ['lightColors', 'darkColors'],
  482. message:
  483. "'lightColors' and 'darkColors' exports intended for use in Storybook only. Instead, use theme prop from emotion or the useTheme hook.",
  484. },
  485. {
  486. name: 'react-router',
  487. importNames: ['withRouter'],
  488. message:
  489. "Use 'useLocation', 'useParams', 'useNavigate', 'useRoutes' from sentry/utils instead.",
  490. },
  491. {
  492. name: 'sentry/utils/withSentryRouter',
  493. importNames: ['withSentryRouter'],
  494. message:
  495. "Use 'useLocation', 'useParams', 'useNavigate', 'useRoutes' from sentry/utils instead.",
  496. },
  497. ],
  498. },
  499. ],
  500. /**
  501. * Better import sorting
  502. */
  503. 'sort-imports': 'off',
  504. 'import/order': 'off',
  505. 'simple-import-sort/imports': [
  506. 'error',
  507. {
  508. groups: [
  509. // Side effect imports.
  510. ['^\\u0000'],
  511. // Node.js builtins.
  512. // biome-ignore lint/correctness/noNodejsModules: Need to get the list of things!
  513. [`^(${require('node:module').builtinModules.join('|')})(/|$)`],
  514. // Packages. `react` related packages come first.
  515. ['^react', '^@?\\w'],
  516. // Test should be separate from the app
  517. ['^(sentry-test|getsentry-test)(/.*|$)'],
  518. // Internal packages.
  519. ['^(sentry-locale|sentry-images)(/.*|$)'],
  520. ['^(getsentry-images)(/.*|$)'],
  521. ['^(app|sentry)(/.*|$)'],
  522. // Getsentry packages.
  523. ['^(admin|getsentry)(/.*|$)'],
  524. // Style imports.
  525. ['^.+\\.less$'],
  526. // Parent imports. Put `..` last.
  527. ['^\\.\\.(?!/?$)', '^\\.\\./?$'],
  528. // Other relative imports. Put same-folder imports and `.` last.
  529. ['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'],
  530. ],
  531. },
  532. ],
  533. 'sentry/no-digits-in-tn': ['error'],
  534. 'sentry/no-dynamic-translations': ['error'],
  535. // https://github.com/xojs/eslint-config-xo-typescript/blob/9791a067d6a119a21a4db72c02f1da95e25ffbb6/index.js#L95
  536. '@typescript-eslint/no-restricted-types': [
  537. 'error',
  538. {
  539. types: {
  540. // TODO(scttcper): Turn object on to make our types more strict
  541. // object: {
  542. // message: 'The `object` type is hard to use. Use `Record<string, unknown>` instead. See: https://github.com/typescript-eslint/typescript-eslint/pull/848',
  543. // fixWith: 'Record<string, unknown>'
  544. // },
  545. Buffer: {
  546. message:
  547. 'Use Uint8Array instead. See: https://sindresorhus.com/blog/goodbye-nodejs-buffer',
  548. suggest: ['Uint8Array'],
  549. },
  550. '[]': "Don't use the empty array type `[]`. It only allows empty arrays. Use `SomeType[]` instead.",
  551. '[[]]':
  552. "Don't use `[[]]`. It only allows an array with a single element which is an empty array. Use `SomeType[][]` instead.",
  553. '[[[]]]': "Don't use `[[[]]]`. Use `SomeType[][][]` instead.",
  554. },
  555. },
  556. ],
  557. // TODO(scttcper): Turn no-empty-object-type on to make our types more strict
  558. // '@typescript-eslint/no-empty-object-type': 'error',
  559. // TODO(scttcper): Turn no-function on to make our types more strict
  560. // '@typescript-eslint/no-unsafe-function-type': 'error',
  561. '@typescript-eslint/no-wrapper-object-types': 'error',
  562. // Naming convention enforcements
  563. '@typescript-eslint/naming-convention': [
  564. 'error',
  565. {
  566. selector: 'typeLike',
  567. format: ['PascalCase'],
  568. leadingUnderscore: 'allow',
  569. },
  570. {
  571. selector: 'enumMember',
  572. format: ['UPPER_CASE'],
  573. },
  574. ],
  575. // Don't allow lookbehind expressions in regexp as they crash safari
  576. // We've accidentally used lookbehinds a few times and caused problems.
  577. 'no-lookahead-lookbehind-regexp/no-lookahead-lookbehind-regexp': [
  578. 'error',
  579. 'no-lookbehind',
  580. 'no-negative-lookbehind',
  581. ],
  582. };
  583. const strictRules = {
  584. // https://eslint.org/docs/rules/no-console
  585. 'no-console': ['error'],
  586. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md
  587. 'react/no-is-mounted': ['error'],
  588. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-find-dom-node.md
  589. // Recommended to use callback refs instead
  590. 'react/no-find-dom-node': ['error'],
  591. // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md
  592. // This is now considered legacy, callback refs preferred
  593. 'react/no-string-refs': ['error'],
  594. 'jest/no-large-snapshots': ['error', {maxSize: 2000}],
  595. 'sentry/no-styled-shortcut': ['error'],
  596. };
  597. const extendsList = [
  598. 'plugin:jest/recommended',
  599. 'plugin:jest-dom/recommended',
  600. 'plugin:import/typescript',
  601. ];
  602. if (detectDeprecations) {
  603. extendsList.push('plugin:deprecation/recommended');
  604. }
  605. module.exports = {
  606. root: true,
  607. extends: extendsList,
  608. plugins: [
  609. 'jest-dom',
  610. 'testing-library',
  611. 'typescript-sort-keys',
  612. 'react-hooks',
  613. '@typescript-eslint',
  614. '@emotion',
  615. 'import',
  616. 'react',
  617. 'sentry',
  618. 'simple-import-sort',
  619. 'no-lookahead-lookbehind-regexp',
  620. ],
  621. parser: '@typescript-eslint/parser',
  622. parserOptions: detectDeprecations
  623. ? {
  624. warnOnUnsupportedTypeScriptVersion: false,
  625. ecmaVersion: 6,
  626. sourceType: 'module',
  627. ecmaFeatures: {
  628. jsx: true,
  629. modules: true,
  630. legacyDecorators: true,
  631. },
  632. project: './tsconfig.json',
  633. }
  634. : {
  635. warnOnUnsupportedTypeScriptVersion: false,
  636. ecmaVersion: 6,
  637. sourceType: 'module',
  638. ecmaFeatures: {
  639. jsx: true,
  640. modules: true,
  641. legacyDecorators: true,
  642. },
  643. },
  644. env: {
  645. browser: true,
  646. es6: true,
  647. jest: true,
  648. jquery: true, // hard-loaded into vendor.js
  649. },
  650. globals: {
  651. require: false,
  652. expect: false,
  653. MockApiClient: true,
  654. tick: true,
  655. jest: true,
  656. },
  657. settings: {
  658. react: {
  659. version: '17.0.2', // React version, can not `detect` because of getsentry
  660. },
  661. 'import/parsers': {
  662. '@typescript-eslint/parser': ['.ts', '.tsx'],
  663. },
  664. 'import/resolver': {
  665. typescript: {},
  666. },
  667. 'import/extensions': ['.js', '.jsx'],
  668. },
  669. rules: {
  670. ...baseRules,
  671. ...reactRules,
  672. ...appRules,
  673. ...strictRules,
  674. 'react-hooks/rules-of-hooks': 'error',
  675. 'react-hooks/exhaustive-deps': [
  676. 'error',
  677. {additionalHooks: '(useEffectAfterFirstRender|useMemoWithPrevious)'},
  678. ],
  679. 'no-restricted-imports': [
  680. 'error',
  681. {
  682. patterns: [
  683. {
  684. group: ['sentry/components/devtoolbar/*'],
  685. message: 'Do not depend on toolbar internals',
  686. },
  687. ],
  688. paths: [
  689. {
  690. name: '@testing-library/react',
  691. message:
  692. 'Please import from `sentry-test/reactTestingLibrary` instead so that we can ensure consistency throughout the codebase',
  693. },
  694. {
  695. name: '@testing-library/react-hooks',
  696. message:
  697. 'Please import from `sentry-test/reactTestingLibrary` instead so that we can ensure consistency throughout the codebase',
  698. },
  699. {
  700. name: '@testing-library/user-event',
  701. message:
  702. 'Please import from `sentry-test/reactTestingLibrary` instead so that we can ensure consistency throughout the codebase',
  703. },
  704. {
  705. name: '@sentry/browser',
  706. message:
  707. 'Please import from `@sentry/react` to ensure consistency throughout the codebase.',
  708. },
  709. {
  710. name: 'marked',
  711. message:
  712. "Please import marked from 'app/utils/marked' so that we can ensure sanitation of marked output",
  713. },
  714. {
  715. name: 'lodash',
  716. message:
  717. "Please import lodash utilities individually. e.g. `import isEqual from 'lodash/isEqual';`. See https://github.com/getsentry/frontend-handbook#lodash from for information",
  718. },
  719. {
  720. name: 'lodash/get',
  721. message:
  722. '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',
  723. },
  724. {
  725. name: 'sentry/utils/theme',
  726. importNames: ['lightColors', 'darkColors'],
  727. message:
  728. "'lightColors' and 'darkColors' exports intended for use in Storybook only. Instead, use theme prop from emotion or the useTheme hook.",
  729. },
  730. {
  731. name: 'react-router',
  732. importNames: ['withRouter'],
  733. message:
  734. "Use 'useLocation', 'useParams', 'useNavigate', 'useRoutes' from sentry/utils instead.",
  735. },
  736. {
  737. name: 'sentry/utils/withSentryRouter',
  738. importNames: ['withSentryRouter'],
  739. message:
  740. "Use 'useLocation', 'useParams', 'useNavigate', 'useRoutes' from sentry/utils instead.",
  741. },
  742. {
  743. name: 'qs',
  744. message: 'Please use query-string instead of qs',
  745. },
  746. {
  747. name: 'moment',
  748. message: 'Please import moment-timezone instead of moment',
  749. },
  750. ],
  751. },
  752. ],
  753. // TODO(@anonrig): Remove this from eslint-sentry-config
  754. 'space-infix-ops': 'off',
  755. 'object-shorthand': 'off',
  756. 'object-curly-spacing': 'off',
  757. 'import/no-amd': 'off',
  758. 'no-danger-with-children': 'off',
  759. 'no-fallthrough': 'off',
  760. 'no-obj-calls': 'off',
  761. 'array-bracket-spacing': 'off',
  762. 'computed-property-spacing': 'off',
  763. 'react/no-danger-with-children': 'off',
  764. 'jest/no-disabled-tests': 'off',
  765. },
  766. // JSON file formatting is handled by Biome. ESLint should not be linting
  767. // and formatting these files.
  768. ignorePatterns: ['*.json'],
  769. overrides: [
  770. {
  771. files: ['static/app/components/devtoolbar/**/*.{ts,tsx}'],
  772. rules: {
  773. 'no-restricted-imports': [
  774. 'error',
  775. {
  776. paths: [
  777. {
  778. name: 'sentry/utils/queryClient',
  779. message:
  780. 'Import from `@tanstack/react-query` and `./hooks/useFetchApiData` or `./hooks/useFetchInfiniteApiData` instead.',
  781. },
  782. ],
  783. },
  784. ],
  785. },
  786. },
  787. {
  788. files: ['static/**/*.spec.{ts,js}', 'tests/js/**/*.{ts,js}'],
  789. extends: ['plugin:testing-library/react', ...extendsList],
  790. rules: {
  791. ...baseRules,
  792. ...reactRules,
  793. ...appRules,
  794. ...strictRules,
  795. // TODO(@anonrig): Remove this from eslint-sentry-config
  796. 'space-infix-ops': 'off',
  797. 'object-shorthand': 'off',
  798. 'object-curly-spacing': 'off',
  799. 'import/no-amd': 'off',
  800. 'no-danger-with-children': 'off',
  801. 'no-fallthrough': 'off',
  802. 'no-obj-calls': 'off',
  803. 'array-bracket-spacing': 'off',
  804. 'computed-property-spacing': 'off',
  805. 'react/no-danger-with-children': 'off',
  806. 'jest/no-disabled-tests': 'off',
  807. },
  808. },
  809. {
  810. // We specify rules explicitly for the sdk-loader here so we do not have
  811. // eslint ignore comments included in the source file, which is consumed
  812. // by users.
  813. files: ['**/js-sdk-loader.ts'],
  814. rules: {
  815. 'no-console': 'off',
  816. },
  817. },
  818. ],
  819. };