.eslintrc.js 8.2 KB

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