.eslintrc.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. module.exports = {
  2. root: true,
  3. extends: [
  4. 'eslint:recommended',
  5. 'plugin:react/recommended',
  6. 'plugin:jsx-a11y/recommended',
  7. ],
  8. env: {
  9. browser: true,
  10. node: true,
  11. es6: true,
  12. jest: true,
  13. },
  14. globals: {
  15. ATTACHMENT_HOST: false,
  16. },
  17. parser: '@babel/eslint-parser',
  18. plugins: [
  19. 'react',
  20. 'jsx-a11y',
  21. 'import',
  22. 'promise',
  23. ],
  24. parserOptions: {
  25. sourceType: 'module',
  26. ecmaFeatures: {
  27. experimentalObjectRestSpread: true,
  28. jsx: true,
  29. },
  30. ecmaVersion: 2021,
  31. },
  32. settings: {
  33. react: {
  34. version: 'detect',
  35. },
  36. 'import/extensions': [
  37. '.js',
  38. ],
  39. 'import/ignore': [
  40. 'node_modules',
  41. '\\.(css|scss|json)$',
  42. ],
  43. 'import/resolver': {
  44. node: {
  45. paths: ['app/javascript'],
  46. },
  47. },
  48. },
  49. rules: {
  50. 'brace-style': 'warn',
  51. 'comma-dangle': ['error', 'always-multiline'],
  52. 'comma-spacing': [
  53. 'warn',
  54. {
  55. before: false,
  56. after: true,
  57. },
  58. ],
  59. 'comma-style': ['warn', 'last'],
  60. 'consistent-return': 'error',
  61. 'dot-notation': 'error',
  62. eqeqeq: 'error',
  63. indent: ['warn', 2],
  64. 'jsx-quotes': ['error', 'prefer-single'],
  65. 'no-case-declarations': 'off',
  66. 'no-catch-shadow': 'error',
  67. 'no-console': [
  68. 'warn',
  69. {
  70. allow: [
  71. 'error',
  72. 'warn',
  73. ],
  74. },
  75. ],
  76. 'no-empty': 'off',
  77. 'no-restricted-properties': [
  78. 'error',
  79. { property: 'substring', message: 'Use .slice instead of .substring.' },
  80. { property: 'substr', message: 'Use .slice instead of .substr.' },
  81. ],
  82. 'no-self-assign': 'off',
  83. 'no-trailing-spaces': 'warn',
  84. 'no-unused-expressions': 'error',
  85. 'no-unused-vars': [
  86. 'error',
  87. {
  88. vars: 'all',
  89. args: 'after-used',
  90. ignoreRestSiblings: true,
  91. },
  92. ],
  93. 'no-useless-escape': 'off',
  94. 'object-curly-spacing': ['error', 'always'],
  95. 'padded-blocks': [
  96. 'error',
  97. {
  98. classes: 'always',
  99. },
  100. ],
  101. quotes: ['error', 'single'],
  102. semi: 'error',
  103. 'valid-typeof': 'error',
  104. 'react/jsx-boolean-value': 'error',
  105. 'react/jsx-closing-bracket-location': ['error', 'line-aligned'],
  106. 'react/jsx-curly-spacing': 'error',
  107. 'react/display-name': 'off',
  108. 'react/jsx-equals-spacing': 'error',
  109. 'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'],
  110. 'react/jsx-indent': ['error', 2],
  111. 'react/jsx-no-bind': 'error',
  112. 'react/jsx-no-target-blank': 'off',
  113. 'react/jsx-tag-spacing': 'error',
  114. 'react/jsx-wrap-multilines': 'error',
  115. 'react/no-deprecated': 'off',
  116. 'react/no-unknown-property': 'off',
  117. 'react/self-closing-comp': 'error',
  118. // recommended values found in https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/src/index.js
  119. 'jsx-a11y/accessible-emoji': 'warn',
  120. 'jsx-a11y/click-events-have-key-events': 'off',
  121. 'jsx-a11y/label-has-associated-control': 'off',
  122. 'jsx-a11y/media-has-caption': 'off',
  123. 'jsx-a11y/no-autofocus': 'off',
  124. // recommended rule is:
  125. // 'jsx-a11y/no-interactive-element-to-noninteractive-role': [
  126. // 'error',
  127. // {
  128. // tr: ['none', 'presentation'],
  129. // canvas: ['img'],
  130. // },
  131. // ],
  132. 'jsx-a11y/no-interactive-element-to-noninteractive-role': 'off',
  133. // recommended rule is:
  134. // 'jsx-a11y/no-noninteractive-element-interactions': [
  135. // 'error',
  136. // {
  137. // body: ['onError', 'onLoad'],
  138. // iframe: ['onError', 'onLoad'],
  139. // img: ['onError', 'onLoad'],
  140. // },
  141. // ],
  142. 'jsx-a11y/no-noninteractive-element-interactions': [
  143. 'warn',
  144. {
  145. handlers: [
  146. 'onClick',
  147. ],
  148. },
  149. ],
  150. // recommended rule is:
  151. // 'jsx-a11y/no-noninteractive-tabindex': [
  152. // 'error',
  153. // {
  154. // tags: [],
  155. // roles: ['tabpanel'],
  156. // allowExpressionValues: true,
  157. // },
  158. // ],
  159. 'jsx-a11y/no-noninteractive-tabindex': 'off',
  160. 'jsx-a11y/no-onchange': 'warn',
  161. // recommended is full 'error'
  162. 'jsx-a11y/no-static-element-interactions': [
  163. 'warn',
  164. {
  165. handlers: [
  166. 'onClick',
  167. ],
  168. },
  169. ],
  170. 'import/extensions': [
  171. 'error',
  172. 'always',
  173. {
  174. js: 'never',
  175. },
  176. ],
  177. 'import/newline-after-import': 'error',
  178. 'import/no-extraneous-dependencies': [
  179. 'error',
  180. {
  181. devDependencies: [
  182. 'config/webpack/**',
  183. 'app/javascript/mastodon/test_setup.js',
  184. 'app/javascript/**/__tests__/**',
  185. ],
  186. },
  187. ],
  188. 'import/no-unresolved': 'error',
  189. 'import/no-webpack-loader-syntax': 'error',
  190. 'promise/catch-or-return': [
  191. 'error',
  192. {
  193. allowFinally: true,
  194. },
  195. ],
  196. },
  197. };