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
pull/7917/head
Thibaud Colas 2021-12-23 03:18:04 +00:00 zatwierdzone przez LB (Ben Johnston)
rodzic 23bc6b2670
commit 81ec3244d3
51 zmienionych plików z 149 dodań i 95 usunięć

Wyświetl plik

@ -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 dont 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",

Wyświetl plik

@ -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[];

Wyświetl plik

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

Wyświetl plik

@ -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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -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 }));

Wyświetl plik

@ -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,

Wyświetl plik

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

Wyświetl plik

@ -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>
);
};

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -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[];

Wyświetl plik

@ -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">

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -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>
);
};

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -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[];

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -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]);

Wyświetl plik

@ -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();
}

Wyświetl plik

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

Wyświetl plik

@ -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) {

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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,

Wyświetl plik

@ -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,

Wyświetl plik

@ -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,

Wyświetl plik

@ -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');
}

Wyświetl plik

@ -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: {

Wyświetl plik

@ -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

Wyświetl plik

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

Wyświetl plik

@ -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: {

Wyświetl plik

@ -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'),
});

Wyświetl plik

@ -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>

Wyświetl plik

@ -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'
};

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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),

Wyświetl plik

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

Wyświetl plik

@ -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",

Wyświetl plik

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