.eslintrc.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. module.exports = {
  2. extends: [
  3. '@wagtail/eslint-config-wagtail',
  4. 'plugin:@typescript-eslint/recommended',
  5. 'plugin:storybook/recommended',
  6. ],
  7. parser: '@typescript-eslint/parser',
  8. plugins: ['@typescript-eslint'],
  9. env: {
  10. jest: true,
  11. browser: true,
  12. },
  13. rules: {
  14. '@typescript-eslint/explicit-function-return-type': 'off',
  15. '@typescript-eslint/explicit-member-accessibility': 'off',
  16. '@typescript-eslint/explicit-module-boundary-types': 'off',
  17. '@typescript-eslint/no-explicit-any': 'off',
  18. '@typescript-eslint/no-use-before-define': ['error'],
  19. // it is often helpful to pull out logic to class methods that may not use `this`
  20. 'class-methods-use-this': 'off',
  21. 'import/extensions': [
  22. 'error',
  23. 'always',
  24. {
  25. ignorePackages: true,
  26. pattern: {
  27. js: 'never',
  28. jsx: 'never',
  29. ts: 'never',
  30. tsx: 'never',
  31. },
  32. },
  33. ],
  34. // does not align with the majority of legacy and newer code, some use named others use default exports
  35. 'import/prefer-default-export': 'off',
  36. // allow no lines between single line members (e.g. static declarations)
  37. 'lines-between-class-members': [
  38. 'error',
  39. 'always',
  40. { exceptAfterSingleLine: true },
  41. ],
  42. 'max-classes-per-file': 'off',
  43. // note you must disable the base rule as it can report incorrect errors
  44. 'no-use-before-define': 'off',
  45. 'react/jsx-filename-extension': ['error', { extensions: ['.js', '.tsx'] }],
  46. 'no-underscore-dangle': [
  47. 'error',
  48. { allow: ['__REDUX_DEVTOOLS_EXTENSION__'] },
  49. ],
  50. // this rule can be confusing as it forces some non-intuitive code for variable assignment
  51. 'prefer-destructuring': 'off',
  52. },
  53. settings: {
  54. 'import/core-modules': ['jquery'],
  55. 'import/resolver': { node: { extensions: ['.js', '.ts', '.tsx'] } },
  56. },
  57. overrides: [
  58. // Rules that we are ignoring currently due to legacy code in React components only
  59. {
  60. files: ['client/src/components/**'],
  61. rules: {
  62. 'jsx-a11y/click-events-have-key-events': 'off',
  63. 'jsx-a11y/interactive-supports-focus': 'off',
  64. 'jsx-a11y/no-noninteractive-element-interactions': 'off',
  65. 'jsx-a11y/role-supports-aria-props': 'off',
  66. 'no-restricted-syntax': 'off',
  67. 'react-hooks/exhaustive-deps': 'off',
  68. 'react-hooks/rules-of-hooks': 'off',
  69. 'react/button-has-type': 'off',
  70. 'react/destructuring-assignment': 'off',
  71. 'react/forbid-prop-types': 'off',
  72. 'react/function-component-definition': 'off',
  73. 'react/jsx-props-no-spreading': 'off',
  74. 'react/no-danger': 'off',
  75. 'react/no-deprecated': 'off',
  76. 'react/require-default-props': 'off',
  77. },
  78. },
  79. // Rules we want to enforce or change for Stimulus Controllers
  80. {
  81. files: ['*Controller.ts'],
  82. rules: {
  83. '@typescript-eslint/member-ordering': [
  84. 'error',
  85. {
  86. classes: {
  87. memberTypes: ['signature', 'field', 'method'],
  88. },
  89. },
  90. ],
  91. '@typescript-eslint/naming-convention': [
  92. 'error',
  93. {
  94. selector: 'method',
  95. format: ['camelCase'],
  96. custom: {
  97. // Use connect or initialize instead of constructor, avoid generic 'render' or 'update' methods and instead be more specific.
  98. regex: '^(constructor|render|update)$',
  99. match: false,
  100. },
  101. },
  102. {
  103. selector: 'classProperty',
  104. format: ['camelCase'],
  105. custom: {
  106. // Use Stimulus values where possible for internal state, avoid a generic state object as these are not reactive.
  107. regex: '^(state)$',
  108. match: false,
  109. },
  110. },
  111. ],
  112. 'no-restricted-properties': [
  113. 'error',
  114. {
  115. object: 'window',
  116. property: 'Stimulus',
  117. message:
  118. "Please import the base Controller or only access the Stimulus instance via the controller's `this.application` attribute.",
  119. },
  120. ],
  121. },
  122. },
  123. // Rules we don’t want to enforce for test and tooling code.
  124. {
  125. files: [
  126. 'client/extract-translatable-strings.js',
  127. 'client/tests/**',
  128. 'webpack.config.js',
  129. 'tailwind.config.js',
  130. 'storybook/**/*',
  131. '*.test.ts',
  132. '*.test.tsx',
  133. '*.test.js',
  134. '*.stories.js',
  135. '*.stories.tsx',
  136. ],
  137. rules: {
  138. '@typescript-eslint/no-empty-function': 'off',
  139. '@typescript-eslint/no-this-alias': 'off',
  140. '@typescript-eslint/no-unused-vars': 'off',
  141. '@typescript-eslint/no-var-requires': 'off',
  142. 'global-require': 'off',
  143. 'import/first': 'off',
  144. 'import/no-extraneous-dependencies': 'off',
  145. 'jsx-a11y/control-has-associated-label': 'off',
  146. 'no-new': 'off',
  147. 'no-unused-expressions': 'off',
  148. 'react/function-component-definition': 'off',
  149. 'react/jsx-props-no-spreading': 'off',
  150. },
  151. },
  152. // Files that use jquery via a global
  153. {
  154. files: [
  155. 'docs/_static/**',
  156. 'wagtail/contrib/search_promotions/static_src/wagtailsearchpromotions/js/query-chooser-modal.js',
  157. 'wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/includes/searchpromotions_formset.js',
  158. 'wagtail/contrib/search_promotions/templates/wagtailsearchpromotions/queries/chooser_field.js',
  159. 'wagtail/documents/static_src/wagtaildocs/js/add-multiple.js',
  160. 'wagtail/embeds/static_src/wagtailembeds/js/embed-chooser-modal.js',
  161. 'wagtail/images/static_src/wagtailimages/js/add-multiple.js',
  162. 'wagtail/images/static_src/wagtailimages/js/focal-point-chooser.js',
  163. 'wagtail/images/static_src/wagtailimages/js/image-url-generator.js',
  164. 'wagtail/snippets/static_src/wagtailsnippets/js/snippet-multiple-select.js',
  165. 'wagtail/users/static_src/wagtailusers/js/group-form.js',
  166. ],
  167. globals: { $: 'readonly', jQuery: 'readonly' },
  168. },
  169. // Files that use other globals or legacy/vendor code that is unable to be easily linted
  170. {
  171. files: ['wagtail/**/**'],
  172. globals: {
  173. buildExpandingFormset: 'readonly',
  174. escapeHtml: 'readonly',
  175. jsonData: 'readonly',
  176. ModalWorkflow: 'readonly',
  177. DOCUMENT_CHOOSER_MODAL_ONLOAD_HANDLERS: 'writable',
  178. EMBED_CHOOSER_MODAL_ONLOAD_HANDLERS: 'writable',
  179. IMAGE_CHOOSER_MODAL_ONLOAD_HANDLERS: 'writable',
  180. QUERY_CHOOSER_MODAL_ONLOAD_HANDLERS: 'writable',
  181. SNIPPET_CHOOSER_MODAL_ONLOAD_HANDLERS: 'writable',
  182. },
  183. rules: {
  184. '@typescript-eslint/no-unused-vars': 'off',
  185. '@typescript-eslint/no-use-before-define': 'off',
  186. 'camelcase': [
  187. 'error',
  188. {
  189. allow: [
  190. '__unused_webpack_module',
  191. '__webpack_modules__',
  192. '__webpack_require__',
  193. ],
  194. properties: 'never',
  195. },
  196. ],
  197. 'consistent-return': 'off',
  198. 'func-names': 'off',
  199. 'id-length': 'off',
  200. 'indent': 'off',
  201. 'key-spacing': 'off',
  202. 'new-cap': 'off',
  203. 'newline-per-chained-call': 'off',
  204. 'no-param-reassign': 'off',
  205. 'no-underscore-dangle': 'off',
  206. 'object-shorthand': 'off',
  207. 'prefer-arrow-callback': 'off',
  208. 'quote-props': 'off',
  209. 'space-before-function-paren': 'off',
  210. 'vars-on-top': 'off',
  211. },
  212. },
  213. ],
  214. };