Browse Source

Upgrade ESLint configuration, with needed refactorings

- Change ESLint configuration syntax for ease of editing
- Autofix basic issues picked up by ESLint
- Make sure JS linting runs on TypeScript files
Thibaud Colas 3 years ago
parent
commit
81ec3244d3
51 changed files with 149 additions and 95 deletions
  1. 78 18
      .eslintrc.js
  2. 3 3
      client/src/api/admin.ts
  3. 1 1
      client/src/components/Button/Button.tsx
  4. 3 1
      client/src/components/CommentApp/components/Comment/index.tsx
  5. 1 1
      client/src/components/CommentApp/components/CommentHeader/index.tsx
  6. 1 1
      client/src/components/CommentApp/components/CommentReply/index.tsx
  7. 5 5
      client/src/components/CommentApp/main.tsx
  8. 1 1
      client/src/components/Draftail/sources/ModalWorkflowSource.js
  9. 1 1
      client/src/components/Explorer/Explorer.tsx
  10. 2 2
      client/src/components/Explorer/ExplorerHeader.tsx
  11. 1 1
      client/src/components/Explorer/ExplorerItem.tsx
  12. 1 1
      client/src/components/Explorer/ExplorerPanel.tsx
  13. 1 1
      client/src/components/Explorer/ExplorerToggle.tsx
  14. 1 1
      client/src/components/Explorer/PageCount.tsx
  15. 2 2
      client/src/components/Explorer/reducers/nodes.ts
  16. 1 1
      client/src/components/Icon/Icon.tsx
  17. 1 1
      client/src/components/PageExplorer/PageCount.tsx
  18. 1 1
      client/src/components/PageExplorer/PageExplorer.tsx
  19. 2 2
      client/src/components/PageExplorer/PageExplorerHeader.tsx
  20. 1 1
      client/src/components/PageExplorer/PageExplorerItem.tsx
  21. 1 1
      client/src/components/PageExplorer/PageExplorerPanel.tsx
  22. 2 2
      client/src/components/PageExplorer/reducers/nodes.ts
  23. 1 1
      client/src/components/Sidebar/SidebarPanel.tsx
  24. 1 1
      client/src/components/Sidebar/menu/LinkMenuItem.tsx
  25. 1 1
      client/src/components/Sidebar/menu/PageExplorerMenuItem.tsx
  26. 1 1
      client/src/components/Sidebar/menu/SubMenuItem.tsx
  27. 1 1
      client/src/components/Sidebar/modules/Search.tsx
  28. 1 1
      client/src/components/Sidebar/modules/WagtailBranding.tsx
  29. 2 2
      client/src/components/StreamField/blocks/StreamBlock.js
  30. 4 4
      client/src/components/StreamField/blocks/StructBlock.js
  31. 1 1
      client/src/custom.d.ts
  32. 2 2
      client/src/entrypoints/admin/comments.js
  33. 1 1
      client/src/entrypoints/admin/core.js
  34. 1 1
      client/src/entrypoints/admin/hallo-plugins/hallo-wagtaillink.js
  35. 0 4
      client/src/entrypoints/admin/modal-workflow.test.js
  36. 1 1
      client/src/entrypoints/admin/page-chooser.js
  37. 3 3
      client/src/entrypoints/admin/page-editor.js
  38. 1 1
      client/src/entrypoints/admin/privacy-switch.js
  39. 1 1
      client/src/entrypoints/admin/task-chooser.js
  40. 1 1
      client/src/entrypoints/admin/telepath/widgets.js
  41. 2 2
      client/src/entrypoints/admin/workflow-action.js
  42. 1 1
      client/src/entrypoints/admin/workflow-status.js
  43. 1 1
      client/src/entrypoints/contrib/table_block/table.js
  44. 2 2
      client/src/entrypoints/contrib/table_block/table.test.js
  45. 1 1
      client/src/entrypoints/documents/document-chooser.js
  46. 1 1
      client/src/entrypoints/images/image-chooser.js
  47. 1 1
      client/src/entrypoints/snippets/snippet-chooser.js
  48. 1 1
      client/src/utils/cleanForSlug.js
  49. 0 5
      client/tests/integration/.eslintrc.js
  50. 3 2
      package.json
  51. 1 1
      wagtail/contrib/modeladmin/static_src/wagtailmodeladmin/js/prepopulate.js

+ 78 - 18
.eslintrc → .eslintrc.js

@@ -1,23 +1,66 @@
-{
+// Rules which have been enforced in configuration upgrades and flag issues in existing code.
+// We need to consider whether to disable those rules permanently, or fix the issues.
+const legacyCode = {
+  "class-methods-use-this": "off",
+  "constructor-super": "off",
+  "default-param-last": "off",
+  "import/extensions": "off",
+  "import/first": "off",
+  "import/newline-after-import": "off",
+  "import/no-extraneous-dependencies": "off",
+  "import/no-unresolved": "off",
+  "import/no-useless-path-segments": "off",
+  "import/order": "off",
+  "import/prefer-default-export": "off",
+  "jsx-a11y/alt-text": "off",
+  "jsx-a11y/anchor-is-valid": "off",
+  "jsx-a11y/click-events-have-key-events": "off",
+  "jsx-a11y/interactive-supports-focus": "off",
+  "jsx-a11y/no-noninteractive-element-interactions": "off",
+  "jsx-a11y/role-supports-aria-props": "off",
+  "lines-between-class-members": "off",
+  "max-classes-per-file": "off",
+  "no-await-in-loop": "off",
+  "no-continue": "off",
+  "no-else-return": "off",
+  "no-extra-boolean-cast": "off",
+  "no-import-assign": "off",
+  "no-lonely-if": "off",
+  "no-plusplus": "off",
+  "no-prototype-builtins": "off",
+  "no-restricted-syntax": "off",
+  "no-this-before-super": "off",
+  "operator-assignment": "off",
+  "prefer-destructuring": "off",
+  "prefer-object-spread": "off",
+  "prefer-promise-reject-errors": "off",
+  "react-hooks/exhaustive-deps": "off",
+  "react-hooks/rules-of-hooks": "off",
+  "react/button-has-type": "off",
+  "react/destructuring-assignment": "off",
+  "react/forbid-prop-types": "off",
+  "react/function-component-definition": "off",
+  "react/jsx-curly-brace-presence": "off",
+  "react/jsx-filename-extension": "off",
+  "react/jsx-no-useless-fragment": "off",
+  "react/jsx-props-no-spreading": "off",
+  "react/no-danger": "off",
+  "react/no-deprecated": "off",
+  "react/require-default-props": "off",
+}
+
+module.exports = {
+  "extends": [
+    "@wagtail/eslint-config-wagtail",
+    "plugin:@typescript-eslint/recommended"
+  ],
   "parser": "@typescript-eslint/parser",
   "plugins": [
     "@typescript-eslint"
   ],
-  "extends": [
-    "wagtail",
-    "plugin:@typescript-eslint/recommended"
-  ],
-
   "env": {
-    "jest": true
-  },
-
-  "settings": {
-    "import/resolver": {
-      "webpack": {
-        "config": "client/webpack.config.js"
-      }
-    }
+    "jest": true,
+    "browser": true,
   },
   "rules": {
     "no-underscore-dangle": ["error", { "allow": ["__REDUX_DEVTOOLS_EXTENSION__"] }],
@@ -28,9 +71,26 @@
     "@typescript-eslint/explicit-module-boundary-types": "off",
     "@typescript-eslint/explicit-member-accessibility": "off",
     "@typescript-eslint/explicit-function-return-type": "off",
-    "@typescript-eslint/no-explicit-any": "off"
+    "@typescript-eslint/no-explicit-any": "off",
+    'react/jsx-filename-extension': [
+      "error",
+      { extensions: ['.js', '.tsx'] },
+    ],
+    'import/extensions': [
+      "error",
+      'always',
+      {
+        ignorePackages: true,
+        pattern: {
+          js: 'never',
+          jsx: 'never',
+          ts: 'never',
+          tsx: 'never',
+        },
+      },
+    ],
+    ...legacyCode,
   },
-
   "overrides": [
     {
       // Rules we don’t want to enforce for test and tooling code.
@@ -45,6 +105,7 @@
       "globals": { "$": "readonly" }
     },
     {
+      "files": ["wagtail/**/**"],
       "globals": {
         "$": "readonly",
         "addMessage": "readonly",
@@ -61,7 +122,6 @@
         "QUERY_CHOOSER_MODAL_ONLOAD_HANDLERS": "writable",
         "SNIPPET_CHOOSER_MODAL_ONLOAD_HANDLERS": "writable"
       },
-      "files": ["wagtail/**/**"],
       "rules": {
         "@typescript-eslint/no-unused-vars": "off",
         "@typescript-eslint/no-use-before-define": "off",

+ 3 - 3
client/src/api/admin.ts

@@ -8,7 +8,7 @@ export interface WagtailPageAPI {
     status: {
       status: string;
       live: boolean;
-      /* eslint-disable-next-line camelcase */
+       
       has_unpublished_changes: boolean;
     }
     children: any;
@@ -18,13 +18,13 @@ export interface WagtailPageAPI {
     locale?: string;
     translations?: any;
   };
-  /* eslint-disable-next-line camelcase */
+   
   admin_display_title?: string;
 }
 
 interface WagtailPageListAPI {
   meta: {
-    /* eslint-disable-next-line camelcase */
+     
     total_count: number;
   };
   items: WagtailPageAPI[];

+ 1 - 1
client/src/components/Button/Button.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import * as React from 'react';
 

+ 3 - 1
client/src/components/CommentApp/components/Comment/index.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+
 
 import React from 'react';
 import ReactDOM from 'react-dom';
@@ -639,6 +639,7 @@ export default class CommentComponent extends React.Component<CommentProps> {
   }
 
   componentDidMount() {
+    // eslint-disable-next-line react/no-find-dom-node
     const element = ReactDOM.findDOMNode(this);
 
     if (element instanceof HTMLElement) {
@@ -658,6 +659,7 @@ export default class CommentComponent extends React.Component<CommentProps> {
   }
 
   componentDidUpdate() {
+    // eslint-disable-next-line react/no-find-dom-node
     const element = ReactDOM.findDOMNode(this);
 
     // Keep height up to date so that other comments will be moved out of the way

+ 1 - 1
client/src/components/CommentApp/components/CommentHeader/index.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import dateFormat from 'dateformat';
 import React, { FunctionComponent, useState, useEffect, useRef } from 'react';

+ 1 - 1
client/src/components/CommentApp/components/CommentReply/index.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import React from 'react';
 

+ 5 - 5
client/src/components/CommentApp/main.tsx

@@ -72,7 +72,7 @@ export const defaultStrings = {
   SAVE_PAGE_TO_SAVE_REPLY: 'Save the page to save this reply',
 };
 
-/* eslint-disable camelcase */
+ 
 // This is done as this is serialized pretty directly from the Django model
 export interface InitialCommentReply {
   pk: number;
@@ -97,7 +97,7 @@ export interface InitialComment {
 }
 /* eslint-enable */
 
-// eslint-disable-next-line camelcase
+ 
 const getAuthor = (authors: Map<string, {name: string, avatar_url: string}>, id: any): Author => {
   const authorData = getOrDefault(authors, String(id), { name: '', avatar_url: '' });
 
@@ -165,7 +165,7 @@ export class CommentApp {
     });
     this.layout = new LayoutController();
   }
-  // eslint-disable-next-line camelcase
+   
   setUser(userId: any, authors: Map<string, {name: string, avatar_url: string}>) {
     this.store.dispatch(
       updateGlobalSettings({
@@ -237,7 +237,7 @@ export class CommentApp {
     outputElement: HTMLElement,
     userId: any,
     initialComments: InitialComment[],
-    // eslint-disable-next-line camelcase
+     
     authors: Map<string, {name: string, avatar_url: string}>,
     translationStrings: TranslatableStrings | null
   ) {
@@ -338,7 +338,7 @@ export class CommentApp {
       }
 
       // If this is the initial focused comment. Focus and pin it
-      // eslint-disable-next-line no-warning-comments
+       
       // TODO: Scroll to this comment
       if (initialFocusedCommentId && comment.pk === initialFocusedCommentId) {
         this.store.dispatch(setFocusedComment(commentId, { updatePinnedComment: true, forceFocus: true }));

+ 1 - 1
client/src/components/Draftail/sources/ModalWorkflowSource.js

@@ -46,7 +46,7 @@ class ModalWorkflowSource extends Component {
 
     $(document.body).on('hidden.bs.modal', this.onClose);
 
-    // eslint-disable-next-line new-cap
+     
     this.workflow = global.ModalWorkflow({
       url,
       urlParams,

+ 1 - 1
client/src/components/Explorer/Explorer.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import React from 'react';
 import { connect } from 'react-redux';

+ 2 - 2
client/src/components/Explorer/ExplorerHeader.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import React from 'react';
 import { ADMIN_URLS, STRINGS } from '../../config/wagtailConfig';
@@ -30,7 +30,7 @@ const SelectLocale: React.FunctionComponent<SelectLocaleProps> = ({ locale, tran
   return (
     <div className="c-explorer__header__select">
       <select value={locale} onChange={onChange} disabled={options.length < 2}>{options}</select>
-      <span></span>
+      <span />
     </div>
   );
 };

+ 1 - 1
client/src/components/Explorer/ExplorerItem.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import React from 'react';
 

+ 1 - 1
client/src/components/Explorer/ExplorerPanel.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import React from 'react';
 import FocusTrap from 'focus-trap-react';

+ 1 - 1
client/src/components/Explorer/ExplorerToggle.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import React from 'react';
 import { connect } from 'react-redux';

+ 1 - 1
client/src/components/Explorer/PageCount.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import React from 'react';
 

+ 2 - 2
client/src/components/Explorer/reducers/nodes.ts

@@ -66,7 +66,7 @@ interface GetChildrenSuccess {
   payload: {
     id: number;
     meta: {
-      /* eslint-disable-next-line camelcase */
+       
       total_count: number;
     };
     items: WagtailPageAPI[];
@@ -87,7 +87,7 @@ interface GetTranslationsSuccess {
   payload: {
     id: number;
     meta: {
-      /* eslint-disable-next-line camelcase */
+       
       total_count: number;
     };
     items: WagtailPageAPI[];

+ 1 - 1
client/src/components/Icon/Icon.tsx

@@ -12,7 +12,7 @@ export interface IconProps {
 const Icon: React.FunctionComponent<IconProps> = ({ name, className, title }) => (
   <>
     <svg className={`icon icon-${name} ${className || ''}`} aria-hidden="true">
-      <use href={`#icon-${name}`}></use>
+      <use href={`#icon-${name}`} />
     </svg>
     {title &&
       <span className="visuallyhidden">

+ 1 - 1
client/src/components/PageExplorer/PageCount.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import React from 'react';
 

+ 1 - 1
client/src/components/PageExplorer/PageExplorer.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import React from 'react';
 import { connect } from 'react-redux';

+ 2 - 2
client/src/components/PageExplorer/PageExplorerHeader.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import React from 'react';
 import { ADMIN_URLS, STRINGS } from '../../config/wagtailConfig';
@@ -30,7 +30,7 @@ const SelectLocale: React.FunctionComponent<SelectLocaleProps> = ({ locale, tran
   return (
     <div className="c-page-explorer__header__select">
       <select value={locale} onChange={onChange} disabled={options.length < 2}>{options}</select>
-      <span></span>
+      <span />
     </div>
   );
 };

+ 1 - 1
client/src/components/PageExplorer/PageExplorerItem.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import React from 'react';
 

+ 1 - 1
client/src/components/PageExplorer/PageExplorerPanel.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+
 
 import React from 'react';
 

+ 2 - 2
client/src/components/PageExplorer/reducers/nodes.ts

@@ -66,7 +66,7 @@ interface GetChildrenSuccess {
   payload: {
     id: number;
     meta: {
-      /* eslint-disable-next-line camelcase */
+       
       total_count: number;
     };
     items: WagtailPageAPI[];
@@ -87,7 +87,7 @@ interface GetTranslationsSuccess {
   payload: {
     id: number;
     meta: {
-      /* eslint-disable-next-line camelcase */
+       
       total_count: number;
     };
     items: WagtailPageAPI[];

+ 1 - 1
client/src/components/Sidebar/SidebarPanel.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import * as React from 'react';
 

+ 1 - 1
client/src/components/Sidebar/menu/LinkMenuItem.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import * as React from 'react';
 

+ 1 - 1
client/src/components/Sidebar/menu/PageExplorerMenuItem.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import * as React from 'react';
 

+ 1 - 1
client/src/components/Sidebar/menu/SubMenuItem.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import * as React from 'react';
 

+ 1 - 1
client/src/components/Sidebar/modules/Search.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import * as React from 'react';
 

+ 1 - 1
client/src/components/Sidebar/modules/WagtailBranding.tsx

@@ -1,4 +1,4 @@
-/* eslint-disable react/prop-types */
+ 
 
 import * as React from 'react';
 import { ModuleDefinition, Strings } from '../Sidebar';

+ 2 - 2
client/src/components/StreamField/blocks/StreamBlock.js

@@ -237,7 +237,7 @@ export class StreamBlock extends BaseSequenceBlock {
     // If we can add blocks, check if there are any block types that have count limits
     this.disabledBlockTypes = new Set();
     if (this.canAddBlock) {
-      // eslint-disable-next-line no-restricted-syntax
+       
       for (const blockType in this.blockDef.meta.blockCounts) {
         if (this.blockDef.meta.blockCounts.hasOwnProperty(blockType)) {
           const counts = this.blockDef.meta.blockCounts[blockType];
@@ -332,7 +332,7 @@ export class StreamBlock extends BaseSequenceBlock {
     }
 
     // Block errors
-    // eslint-disable-next-line no-restricted-syntax
+     
     for (const blockIndex in error.blockErrors) {
       if (error.blockErrors.hasOwnProperty(blockIndex)) {
         this.children[blockIndex].setError(error.blockErrors[blockIndex]);

+ 4 - 4
client/src/components/StreamField/blocks/StructBlock.js

@@ -75,7 +75,7 @@ export class StructBlock {
   }
 
   setState(state) {
-    // eslint-disable-next-line guard-for-in, no-restricted-syntax
+    // eslint-disable-next-line guard-for-in
     for (const name in state) {
       this.childBlocks[name].setState(state[name]);
     }
@@ -87,7 +87,7 @@ export class StructBlock {
     }
     const error = errorList[0];
 
-    // eslint-disable-next-line no-restricted-syntax
+     
     for (const blockName in error.blockErrors) {
       if (error.blockErrors.hasOwnProperty(blockName)) {
         this.childBlocks[blockName].setError(error.blockErrors[blockName]);
@@ -97,7 +97,7 @@ export class StructBlock {
 
   getState() {
     const state = {};
-    // eslint-disable-next-line guard-for-in, no-restricted-syntax
+    // eslint-disable-next-line guard-for-in
     for (const name in this.childBlocks) {
       state[name] = this.childBlocks[name].getState();
     }
@@ -106,7 +106,7 @@ export class StructBlock {
 
   getValue() {
     const value = {};
-    // eslint-disable-next-line guard-for-in, no-restricted-syntax
+    // eslint-disable-next-line guard-for-in
     for (const name in this.childBlocks) {
       value[name] = this.childBlocks[name].getValue();
     }

+ 1 - 1
client/src/custom.d.ts

@@ -23,7 +23,7 @@ declare global {
         I18N_ENABLED: boolean;
         LOCALES: {
             code: string;
-            /* eslint-disable-next-line camelcase */
+             
             display_name: string;
         }[];
         STRINGS: any;

+ 2 - 2
client/src/entrypoints/admin/comments.js

@@ -112,7 +112,7 @@ window.comments = (() => {
     onUnfocus() {
       this.node.classList.add('button-secondary');
       this.node.ariaLabel = STRINGS.FOCUS_COMMENT;
-      // eslint-disable-next-line no-warning-comments
+       
       // TODO: ensure comment is focused accessibly when this is clicked,
       // and that screenreader users can return to the annotation point when desired
     }
@@ -214,7 +214,7 @@ window.comments = (() => {
           }
         }
       });
-      // eslint-disable-next-line no-warning-comments
+       
       return unsubscribeWidget; // TODO: listen for widget deletion and use this
     }
     updateVisibility(newShown) {

+ 1 - 1
client/src/entrypoints/admin/core.js

@@ -571,7 +571,7 @@ const DropDownController = {
 function DropDown(el, registry) {
   if (!el || !registry) {
     if ('error' in console) {
-      // eslint-disable-next-line max-len, no-console
+      // eslint-disable-next-line no-console
       console.error('A dropdown was created without an element or the DropDownController.\nMake sure to pass both to your component.');
       return;
     }

+ 1 - 1
client/src/entrypoints/admin/hallo-plugins/hallo-wagtaillink.js

@@ -73,7 +73,7 @@ $.widget('IKS.hallowagtaillink', {
         urlParams.link_text = lastSelection.toString();
       }
 
-      // eslint-disable-next-line no-undef, new-cap
+      // eslint-disable-next-line no-undef
       return ModalWorkflow({
         url: url,
         urlParams: urlParams,

+ 0 - 4
client/src/entrypoints/admin/modal-workflow.test.js

@@ -24,7 +24,6 @@ describe('modal-workflow', () => {
     let modalWorkflow;
 
     const openModal = () => {
-      // eslint-disable-next-line new-cap
       modalWorkflow = window.ModalWorkflow({ url: 'path/to/endpoint' });
     };
 
@@ -53,7 +52,6 @@ describe('modal-workflow', () => {
     let modalWorkflow;
 
     const openModal = () => {
-      // eslint-disable-next-line new-cap
       modalWorkflow = window.ModalWorkflow({ url: 'path/to/endpoint' });
     };
 
@@ -81,7 +79,6 @@ describe('modal-workflow', () => {
     let modalWorkflow;
 
     const openModal = () => {
-      // eslint-disable-next-line new-cap
       modalWorkflow = window.ModalWorkflow({ url: 'path/to/endpoint' });
     };
 
@@ -109,7 +106,6 @@ describe('modal-workflow', () => {
     let modalWorkflow;
 
     const openModal = () => {
-      // eslint-disable-next-line new-cap
       modalWorkflow = window.ModalWorkflow({
         url: 'path/to/endpoint',
         urlParams,

+ 1 - 1
client/src/entrypoints/admin/page-chooser.js

@@ -72,7 +72,7 @@ function createPageChooser(id, openAtParentId, options) {
       if (options.user_perms) {
         urlParams.user_perms = options.user_perms;
       }
-      // eslint-disable-next-line no-undef, new-cap
+      // eslint-disable-next-line no-undef
       ModalWorkflow({
         url: url,
         urlParams: urlParams,

+ 3 - 3
client/src/entrypoints/admin/page-editor.js

@@ -233,7 +233,7 @@ function initErrorDetection() {
   });
 
   // now identify them on each tab
-  // eslint-disable-next-line no-restricted-syntax, guard-for-in
+  // eslint-disable-next-line guard-for-in
   for (const index in errorSections) {
     $('[data-tab-nav] a[href="#' + index + '"]').addClass('errors').attr('data-count', errorSections[index]);
   }
@@ -296,7 +296,7 @@ $(() => {
       // and deleted (DOMSubtreeModified event), and we need to delay
       // setPreviewData when typing to avoid useless extra AJAX requests
       // (so we postpone setPreviewData when keyup occurs).
-      // eslint-disable-next-line no-warning-comments
+       
       // TODO: Replace DOMSubtreeModified with a MutationObserver.
       $form.on('change keyup DOMSubtreeModified', () => {
         clearTimeout(autoUpdatePreviewDataTimeout);
@@ -321,7 +321,7 @@ $(() => {
       } else {
         window.focus();
         previewWindow.close();
-        // eslint-disable-next-line no-warning-comments
+         
         // TODO: Stop sending the form, as it removes file data.
         $form.trigger('submit');
       }

+ 1 - 1
client/src/entrypoints/admin/privacy-switch.js

@@ -4,7 +4,7 @@ $(() => {
   /* Interface to set permissions from the explorer / editor */
   // eslint-disable-next-line func-names
   $('button.action-set-privacy').on('click', function () {
-    // eslint-disable-next-line no-undef, new-cap
+    // eslint-disable-next-line no-undef
     ModalWorkflow({
       url: this.getAttribute('data-url'),
       onload: {

+ 1 - 1
client/src/entrypoints/admin/task-chooser.js

@@ -7,7 +7,7 @@ function createTaskChooser(id) {
   const editAction = chooserElement.find('.action-edit');
 
   $('.action-choose', chooserElement).on('click', () => {
-    // eslint-disable-next-line no-undef, new-cap
+    // eslint-disable-next-line no-undef
     ModalWorkflow({
       url: chooserElement.data('chooserUrl'),
       // eslint-disable-next-line no-undef

+ 1 - 1
client/src/entrypoints/admin/telepath/widgets.js

@@ -1,4 +1,4 @@
-/* eslint-disable indent */
+ 
 
 /* global $ */
 

+ 2 - 2
client/src/entrypoints/admin/workflow-action.js

@@ -20,7 +20,7 @@ function ActivateWorkflowActionsForDashboard(csrfToken) {
       e.stopPropagation();
 
       if ('launchModal' in buttonElement.dataset) {
-        // eslint-disable-next-line no-undef, new-cap
+        // eslint-disable-next-line no-undef
         ModalWorkflow({
           url: buttonElement.dataset.workflowActionUrl,
           onload: {
@@ -68,7 +68,7 @@ function ActivateWorkflowActionsForEditView(formSelector) {
         e.stopPropagation();
 
         // open the modal at the given URL
-        // eslint-disable-next-line no-undef, new-cap
+        // eslint-disable-next-line no-undef
         ModalWorkflow({
           url: buttonElement.dataset.workflowActionModalUrl,
           onload: {

+ 1 - 1
client/src/entrypoints/admin/workflow-status.js

@@ -4,7 +4,7 @@ $(() => {
   /* Interface to view the workflow status from the explorer / editor */
   // eslint-disable-next-line func-names
   $('button.action-workflow-status').on('click', function () {
-    // eslint-disable-next-line no-undef, new-cap
+    // eslint-disable-next-line no-undef
     ModalWorkflow({
       url: this.getAttribute('data-url'),
     });

+ 1 - 1
client/src/entrypoints/contrib/table_block/table.js

@@ -209,7 +209,7 @@ class TableInput {
             <input type="text" id="${id}-handsontable-col-caption" name="handsontable-col-caption" />
           </div>
           <p class="help">
-            ${this.strings['A heading that identifies the overall topic of the table, and is useful for screen reader users'] /* eslint-disable-line max-len */}
+            ${this.strings['A heading that identifies the overall topic of the table, and is useful for screen reader users']  }
           </p>
         </div>
       </div>

+ 2 - 2
client/src/entrypoints/contrib/table_block/table.test.js

@@ -37,7 +37,7 @@ const TEST_STRINGS = {
   'Column header': 'Column header',
   'Display the first column as a header.': 'Display the first column as a header.',
   'Table caption': 'Table caption',
-  // eslint-disable-next-line max-len
+   
   'A heading that identifies the overall topic of the table, and is useful for screen reader users': 'A heading that identifies the overall topic of the table, and is useful for screen reader users',
   'Table': 'Table'
 };
@@ -127,7 +127,7 @@ describe('telepath: wagtail.widgets.TableInput', () => {
       'Column header': 'En-tête de colonne',
       'Display the first column as a header.': 'Affichez la première colonne sous forme d\'en-tête.',
       'Table caption': 'Légende du tableau',
-      // eslint-disable-next-line max-len
+       
       'A heading that identifies the overall topic of the table, and is useful for screen reader users': 'Un en-tête qui identifie le sujet général du tableau et qui est utile pour les utilisateurs de lecteurs d\'écran',
       'Table': 'Tableau'
     };

+ 1 - 1
client/src/entrypoints/documents/document-chooser.js

@@ -54,7 +54,7 @@ function createDocumentChooser(id) {
       $('.action-choose', chooserElement).focus();
     },
     openChooserModal: () => {
-      // eslint-disable-next-line no-undef, new-cap
+      // eslint-disable-next-line no-undef
       ModalWorkflow({
         url: chooserBaseUrl,
         // eslint-disable-next-line no-undef

+ 1 - 1
client/src/entrypoints/images/image-chooser.js

@@ -66,7 +66,7 @@ function createImageChooser(id) {
     },
 
     openChooserModal: () => {
-      // eslint-disable-next-line no-undef, new-cap
+      // eslint-disable-next-line no-undef
       ModalWorkflow({
         url: chooserBaseUrl,
         // eslint-disable-next-line no-undef

+ 1 - 1
client/src/entrypoints/snippets/snippet-chooser.js

@@ -64,7 +64,7 @@ function createSnippetChooser(id) {
         urlQuery = '?locale=' + wagtailConfig.ACTIVE_CONTENT_LOCALE;
       }
 
-      // eslint-disable-next-line no-undef, new-cap
+      // eslint-disable-next-line no-undef
       ModalWorkflow({
         url: chooserBaseUrl + urlQuery,
         // eslint-disable-next-line no-undef

+ 1 - 1
client/src/utils/cleanForSlug.js

@@ -2,7 +2,7 @@ export function cleanForSlug(val, useURLify) {
   if (useURLify) {
     // URLify performs extra processing on the string (e.g. removing stopwords) and is more suitable
     // for creating a slug from the title, rather than sanitising a slug entered manually
-    // eslint-disable-next-line no-undef, new-cap
+    // eslint-disable-next-line no-undef
     const cleaned = URLify(val, 255, window.unicodeSlugsEnabled);
 
     // if the result is blank (e.g. because the title consisted entirely of stopwords),

+ 0 - 5
client/tests/integration/.eslintrc.js

@@ -18,9 +18,4 @@ module.exports = {
     page: 'readonly',
     TEST_ORIGIN: 'readonly'
   },
-  settings: {
-    'import/resolver': {
-      webpack: null,
-    }
-  },
 };

+ 3 - 2
package.json

@@ -95,6 +95,7 @@
   },
   "dependencies": {
     "core-js": "^2.5.3",
+    "dateformat": "^2.2.0",
     "draft-js": "^0.10.5",
     "draftail": "^1.4.1",
     "draftjs-filters": "^2.5.0",
@@ -126,8 +127,8 @@
     "gulp:prod:build": "gulp build",
     "webpack:dev:watch": "webpack --config ./client/webpack.config.js --mode development --progress --watch",
     "webpack:prod:build": "webpack --config ./client/webpack.config.js --mode production",
-    "fix:js": "eslint --fix ./",
-    "lint:js": "eslint --report-unused-disable-directives ./",
+    "fix:js": "eslint --ext .js,.ts,.tsx --fix ./",
+    "lint:js": "eslint --ext .js,.ts,.tsx --report-unused-disable-directives ./",
     "lint:css": "stylelint **/*.scss",
     "lint": "npm run lint:js && npm run lint:css",
     "test": "npm run test:unit",

+ 1 - 1
wagtail/contrib/modeladmin/static_src/wagtailmodeladmin/js/prepopulate.js

@@ -1,4 +1,4 @@
-/* global URLify*/
+/* global URLify */
 (function($) {
     $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) {
         /*