Migrate from TSLint to ESLint

TSLint deprecated and is being replaced by ESLint.

Add Vue CLI plugin (@vue/cli-plugin-eslint) using:
`vue add @vue/cli-plugin-eslint`. It also adds `.eslintrc.js` manually
for Cypress since Vue CLI for ESLint misses it (vuejs/vue-cli#6892).

Also rename `npm run lint:vue` to `npm run lint:eslint` for better
clarification.

This commit disables all rules that the current code is not compliant
with. This allows for enabling them gradually and separating commits
instead of mixing ESLint introduction with other code changes.

AirBnb is chosen as base configuration.

"Standard" is not chosen due to its poor defaults. It makes code cleaner
but harder to maintain:
  - It converts interfaces to types which is harder to read.
  - Removes semicolons that helps to eliminate some ambigious code.

"Airbnb" on the other hand helps for easier future changes and
maintinability:
  - Includes more useful rules.
  - Keeps the semicolons and interfaces.
  - Enforces trailing commas that makes it easier to delete lines later on.
  - Delete branches: standard, prettier.
This commit is contained in:
undergroundwires
2021-12-27 22:42:27 +01:00
parent 455084c17b
commit 61b475fa8d
20 changed files with 7333 additions and 3204 deletions

7
.editorconfig Normal file
View File

@@ -0,0 +1,7 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 100

122
.eslintrc.js Normal file
View File

@@ -0,0 +1,122 @@
module.exports = {
root: true,
env: {
node: true,
},
extends: [
// Vue specific rules, eslint-plugin-vue
// Added by Vue CLI
'plugin:vue/essential',
// Extends eslint-config-airbnb
// Added by Vue CLI
// Here until https://github.com/vuejs/eslint-config-airbnb/issues/23 is done
'@vue/airbnb',
// Extends @typescript-eslint/recommended
// Uses the recommended rules from the @typescript-eslint/eslint-plugin
// Added by Vue CLI
'@vue/typescript/recommended',
],
parserOptions: {
ecmaVersion: 'latest',
},
rules: {
'no-console': 'off', // process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': 'off', // process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'linebreak-style': 'off',
'no-useless-constructor': 'off',
'import/prefer-default-export': 'off',
'class-methods-use-this': 'off',
'no-use-before-define': 'off',
'no-restricted-syntax': 'off',
'global-require': 'off',
'max-len': 'off',
'import/no-unresolved': 'off',
'import/no-webpack-loader-syntax': 'off',
'import/extensions': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'no-plusplus': 'off',
'no-mixed-operators': 'off',
'import/no-extraneous-dependencies': 'off',
'@typescript-eslint/no-empty-function': 'off',
'no-return-assign': 'off',
'no-await-in-loop': 'off',
'no-shadow': 'off',
'vuejs-accessibility/accessible-emoji': 'off',
'no-promise-executor-return': 'off',
'no-new': 'off',
'no-useless-escape': 'off',
'prefer-destructuring': 'off',
'no-param-reassign': 'off',
'no-irregular-whitespace': 'off',
'no-undef': 'off',
'no-underscore-dangle': 'off',
'vuejs-accessibility/form-control-has-label': 'off',
'vuejs-accessibility/click-events-have-key-events': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'camelcase': 'off',
'no-restricted-globals': 'off',
'default-param-last': 'off',
'no-continue': 'off',
'vuejs-accessibility/anchor-has-content': 'off',
'@typescript-eslint/no-extra-semi': 'off',
'no-multi-spaces': 'off',
'indent': 'off',
'comma-dangle': 'off',
'semi': 'off',
'quotes': 'off',
'key-spacing': 'off',
'lines-between-class-members': 'off',
'import/order': 'off',
'space-in-parens': 'off',
'array-bracket-spacing': 'off',
'object-curly-spacing': 'off',
'@typescript-eslint/no-inferrable-types': 'off',
'import/no-duplicates': 'off',
'function-paren-newline': 'off',
'operator-linebreak': 'off',
'no-multiple-empty-lines': 'off',
'object-curly-newline': 'off',
'object-property-newline': 'off',
'arrow-body-style': 'off',
'no-useless-return': 'off',
'prefer-template': 'off',
'func-call-spacing': 'off',
'no-spaced-func': 'off',
'padded-blocks': 'off',
'implicit-arrow-linebreak': 'off',
'function-call-argument-newline': 'off',
'comma-spacing': 'off',
'comma-style': 'off',
'newline-per-chained-call': 'off',
'no-useless-computed-key': 'off',
'no-else-return': 'off',
'quote-props': 'off',
'no-restricted-properties': 'off',
'prefer-exponentiation-operator': 'off',
'semi-spacing': 'off',
'prefer-object-spread': 'off',
'import/newline-after-import': 'off',
'strict': 'off',
'no-trailing-spaces': 'off',
'no-confusing-arrow': 'off',
'eol-last': 'off',
'import/no-useless-path-segments': 'off',
'spaced-comment': 'off',
'@typescript-eslint/no-empty-interface': 'off',
},
overrides: [
{
files: [
'**/__tests__/*.{j,t}s?(x)',
'**/tests/unit/**/*.spec.{j,t}s?(x)',
],
env: {
mocha: true,
},
},
],
};

View File

@@ -8,7 +8,7 @@ jobs:
strategy:
matrix:
lint-command:
- npm run lint:vue
- npm run lint:eslint
- npm run lint:yaml
- npm run lint:md
- npm run lint:md:relative-urls

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 KiB

After

Width:  |  Height:  |  Size: 632 KiB

10336
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,18 +8,18 @@
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"test:integration": "vue-cli-service test:unit \"tests/integration/**/*.spec.ts\"",
"test:e2e": "vue-cli-service test:e2e",
"lint": "npm run lint:vue && npm run lint:yaml && npm run lint:md && npm run lint:md:relative-urls && npm run lint:md:consistency",
"lint": "npm run lint:md && npm run lint:md:consistency && npm run lint:md:relative-urls && npm run lint:eslint && npm run lint:yaml",
"electron:build": "vue-cli-service electron:build",
"electron:serve": "vue-cli-service electron:serve",
"lint:md": "markdownlint **/*.md --ignore node_modules",
"lint:md:consistency": "remark . --frail --use remark-preset-lint-consistent",
"lint:md:relative-urls": "remark . --frail --use remark-validate-links",
"lint:vue": "vue-cli-service lint --no-fix",
"lint:eslint": "vue-cli-service lint --no-fix",
"lint:yaml": "yamllint **/*.yaml --ignore=node_modules/**/*.yaml",
"postinstall": "electron-builder install-app-deps",
"postuninstall": "electron-builder install-app-deps"
"postuninstall": "electron-builder install-app-deps",
"test:integration": "vue-cli-service test:unit \"tests/integration/**/*.spec.ts\""
},
"main": "background.js",
"dependencies": {
@@ -48,17 +48,26 @@
"@types/chai": "^4.2.22",
"@types/file-saver": "^2.0.3",
"@types/mocha": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^5.4.0",
"@typescript-eslint/parser": "^5.4.0",
"@vue/cli-plugin-babel": "^4.5.14",
"@vue/cli-plugin-e2e-cypress": "^4.5.14",
"@vue/cli-plugin-e2e-cypress": "~4.5.14",
"@vue/cli-plugin-eslint": "~5.0.0-rc.1",
"@vue/cli-plugin-typescript": "^4.5.14",
"@vue/cli-plugin-unit-mocha": "^4.5.14",
"@vue/cli-service": "^4.5.14",
"@vue/eslint-config-airbnb": "^6.0.0",
"@vue/eslint-config-typescript": "^9.1.0",
"@vue/test-utils": "1.2.2",
"chai": "^4.3.4",
"electron": "^15.3.0",
"electron-devtools-installer": "^3.2.0",
"electron-log": "^4.4.1",
"electron-updater": "^4.3.9",
"eslint": "^7.32.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-vue": "^8.0.3",
"eslint-plugin-vuejs-accessibility": "^1.1.0",
"js-yaml-loader": "^1.2.2",
"markdownlint-cli": "^0.29.0",
"raw-loader": "^4.0.2",

View File

@@ -91,7 +91,7 @@ app.on('ready', async () => {
try {
await installExtension(VUEJS_DEVTOOLS);
} catch (e) {
console.error('Vue Devtools failed to install:', e.toString()); // tslint:disable-line:no-console
console.error('Vue Devtools failed to install:', e.toString());
}
}
createWindow();

View File

@@ -2,11 +2,9 @@ import Vue, { VNode } from 'vue';
declare global {
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {
}
// tslint:disable no-empty-interface
interface ElementClass extends Vue {
}

12
tests/e2e/.eslintrc.js Normal file
View File

@@ -0,0 +1,12 @@
module.exports = {
plugins: [
'cypress',
],
env: {
mocha: true,
'cypress/globals': true,
},
rules: {
strict: 'off',
},
};

View File

@@ -9,7 +9,7 @@ export async function getUrlStatusesInParallel(
// urls = [ 'https://privacy.sexy' ]; // Here to comment out when testing
const uniqueUrls = Array.from(new Set(urls));
options = { ...DefaultOptions, ...options };
console.log('Options: ', options); // tslint:disable-line: no-console
console.log('Options: ', options);
const results = await request(uniqueUrls, options);
return results;
}

View File

@@ -8,7 +8,7 @@ export async function getUrlStatus(
options = { ...DefaultOptions, ...options };
const fetchOptions = getFetchOptions(url, options);
return retryWithExponentialBackOff(async () => {
console.log('Requesting', url); // tslint:disable-line: no-console
console.log('Requesting', url);
let result: IUrlStatus;
try {
const response = await fetchFollow(url, fetchOptions, options.followOptions);

View File

@@ -97,7 +97,6 @@ describe('ApplicationCode', () => {
};
},
};
// tslint:disable-next-line:no-unused-expression
new ApplicationCode(selection, expectedDefinition, generatorMock);
// act
const act = () => selection.changed.notify([]);
@@ -122,7 +121,6 @@ describe('ApplicationCode', () => {
};
},
};
// tslint:disable-next-line:no-unused-expression
new ApplicationCode(selection, expectedDefinition, generatorMock);
// act
const act = () => selection.changed.notify(scriptsToSelect);

View File

@@ -20,7 +20,7 @@ describe('SelectedScript', () => {
const script = new ScriptStub(expectedId)
.withRevertCode(undefined);
// act
function construct() { new SelectedScript(script, true); } // tslint:disable-line:no-unused-expression
function construct() { new SelectedScript(script, true); }
// assert
expect(construct).to.throw('cannot revert an irreversible script');
});

View File

@@ -1,7 +1,6 @@
import 'mocha';
import { expect } from 'chai';
import { ExpressionPosition } from '@/application/Parser/Script/Compiler/Expressions/Expression/ExpressionPosition';
// tslint:disable-next-line:max-line-length
import { ExpressionEvaluator, Expression } from '@/application/Parser/Script/Compiler/Expressions/Expression/Expression';
import { IReadOnlyFunctionCallArgumentCollection } from '@/application/Parser/Script/Compiler/Function/Call/Argument/IFunctionCallArgumentCollection';
import { FunctionCallArgumentCollectionStub } from '@tests/unit/stubs/FunctionCallArgumentCollectionStub';

View File

@@ -126,7 +126,6 @@ describe('SharedFunctionsParser', () => {
const invalidParameterName = 'invalid function p@r4meter name';
const functionName = 'functionName';
let parameterException: Error;
// tslint:disable-next-line:no-unused-expression
try { new FunctionParameter(invalidParameterName, false); } catch (e) { parameterException = e; }
const expectedError = `"${functionName}": ${parameterException.message}`;
const functionData = FunctionDataStub.createWithCode()

View File

@@ -1,11 +1,9 @@
import 'mocha';
import { expect } from 'chai';
import { INode, NodeType } from '@/presentation/components/Scripts/View/ScriptsTree/SelectableTree/Node/INode';
// tslint:disable-next-line:max-line-length
import { getReverter } from '@/presentation/components/Scripts/View/ScriptsTree/SelectableTree/Node/Reverter/ReverterFactory';
import { ScriptReverter } from '@/presentation/components/Scripts/View/ScriptsTree/SelectableTree/Node/Reverter/ScriptReverter';
import { CategoryReverter } from '@/presentation/components/Scripts/View/ScriptsTree/SelectableTree/Node/Reverter/CategoryReverter';
// tslint:disable-next-line:max-line-length
import { getScriptNodeId, getCategoryNodeId } from '@/presentation/components/Scripts/View/ScriptsTree/ScriptNodeParser';
import { CategoryCollectionStub } from '@tests/unit/stubs/CategoryCollectionStub';
import { CategoryStub } from '@tests/unit/stubs/CategoryStub';

View File

@@ -1,4 +1,3 @@
// tslint:disable-next-line:max-line-length
import { IFunctionCallArgument } from '@/application/Parser/Script/Compiler/Function/Call/Argument/IFunctionCallArgument';
import { IFunctionCallArgumentCollection } from '@/application/Parser/Script/Compiler/Function/Call/Argument/IFunctionCallArgumentCollection';
import { FunctionCallArgumentStub } from './FunctionCallArgumentStub';

View File

@@ -1,4 +1,3 @@
// tslint:disable-next-line:max-line-length
import { IFunctionCallArgument } from '@/application/Parser/Script/Compiler/Function/Call/Argument/IFunctionCallArgument';
export class FunctionCallArgumentStub implements IFunctionCallArgument {

View File

@@ -1,19 +0,0 @@
{
"defaultSeverity": "warning",
"extends": [
"tslint:recommended"
],
"linterOptions": {
"exclude": [
"node_modules/**"
]
},
"rules": {
"indent": [true, "spaces", 2],
"interface-name": false,
"no-consecutive-blank-lines": false,
"object-literal-sort-keys": false,
"ordered-imports": false,
"quotemark": [true, "single"]
}
}