TSLint -> ESLint

This commit is contained in:
Jannis Mattheis 2020-09-11 22:17:50 +02:00
parent 33c0e01dae
commit 0d65ca6d3f
13 changed files with 149 additions and 181 deletions

2
ui/.eslintignore Normal file
View File

@ -0,0 +1,2 @@
src/setupTests.ts
src/registerServiceWorker.ts

87
ui/.eslintrc.yml Normal file
View File

@ -0,0 +1,87 @@
---
extends:
- eslint:recommended
- plugin:@typescript-eslint/eslint-recommended
- plugin:@typescript-eslint/recommended
- plugin:@typescript-eslint/recommended-requiring-type-checking
- plugin:react/recommended
- plugin:import/errors
- plugin:import/typescript
- plugin:jest/recommended
- prettier
env:
browser: true
es6: true
node: true
parser: "@typescript-eslint/parser"
parserOptions:
project: tsconfig.json
sourceType: module
plugins:
- "@typescript-eslint"
- react
- import
- unicorn
settings:
react:
version: detect
rules:
consistent-return: error
default-case: error
default-param-last: error
no-loop-func: off
arrow-body-style: [error, as-needed]
import/no-useless-path-segments: error
import/group-exports: off
import/extensions: [error, never]
import/no-duplicates: error
import/first: error
import/no-unused-modules: error
unicorn/no-abusive-eslint-disable: error
unicorn/no-array-instanceof: error
unicorn/no-unreadable-array-destructuring: error
unicorn/no-zero-fractions: error
react/jsx-key: error
react/jsx-pascal-case: error
react/destructuring-assignment: warn
react/function-component-definition: [error, {namedComponents: arrow-function, unnamedComponents: arrow-function}]
react/no-array-index-key: error
react/no-deprecated: error
react/no-string-refs: error
react/no-this-in-sfc: error
react/no-typos: error
react/no-unknown-property: error
react/prefer-stateless-function: error
react/prop-types: off
jest/expect-expect: off
jest/no-jasmine-globals: off
"@typescript-eslint/require-await": off
"@typescript-eslint/array-type": [error, {default: array-simple}]
"@typescript-eslint/await-thenable": error
"@typescript-eslint/no-unused-vars": error
"@typescript-eslint/no-use-before-define": off
"@typescript-eslint/consistent-type-assertions": [error, {assertionStyle: as}]
"@typescript-eslint/no-extra-non-null-assertion": error
"@typescript-eslint/no-inferrable-types": error
"@typescript-eslint/no-this-alias": error
"@typescript-eslint/no-throw-literal": error
"@typescript-eslint/prefer-nullish-coalescing": error
"@typescript-eslint/prefer-optional-chain": error
"@typescript-eslint/prefer-readonly": error
"@typescript-eslint/unbound-method": error
"@typescript-eslint/no-empty-function": off
"@typescript-eslint/explicit-module-boundary-types": off
"@typescript-eslint/no-floating-promises": off
"@typescript-eslint/no-unsafe-member-access": off
"@typescript-eslint/no-unsafe-return": off
"@typescript-eslint/no-unsafe-assignment": off
"@typescript-eslint/restrict-plus-operands": off
"@typescript-eslint/no-misused-promises": off
"@typescript-eslint/no-explicit-any": error

View File

@ -32,8 +32,7 @@
"build": "react-scripts build", "build": "react-scripts build",
"test": "react-scripts test --env=node", "test": "react-scripts test --env=node",
"eject": "react-scripts eject", "eject": "react-scripts eject",
"lint": "tslint --project .", "lint": "eslint \"src/*.{ts,tsx}\"",
"lintfix": "tslint --fix --project .",
"format": "prettier \"src/**/*.{ts,tsx}\" --write", "format": "prettier \"src/**/*.{ts,tsx}\" --write",
"testformat": "prettier \"src/**/*.{ts,tsx}\" --list-different" "testformat": "prettier \"src/**/*.{ts,tsx}\" --list-different"
}, },
@ -52,14 +51,20 @@
"@types/react-router-dom": "^5.1.5", "@types/react-router-dom": "^5.1.5",
"@types/remove-markdown": "^0.1.1", "@types/remove-markdown": "^0.1.1",
"@types/rimraf": "^3.0.0", "@types/rimraf": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^4.1.0",
"@typescript-eslint/parser": "^4.1.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jest": "^24.0.0",
"eslint-plugin-prefer-arrow": "^1.2.2",
"eslint-plugin-react": "^7.20.6",
"eslint-plugin-unicorn": "^21.0.0",
"get-port": "^5.1.1", "get-port": "^5.1.1",
"prettier": "^2.1.1", "prettier": "^2.1.1",
"puppeteer": "^5.3.0", "puppeteer": "^5.3.0",
"react-scripts": "^3.4.3", "react-scripts": "^3.4.3",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"tree-kill": "^1.2.0", "tree-kill": "^1.2.0",
"tslint": "^6.1.2",
"tslint-sonarts": "^1.7.0",
"typescript": "4.0.2", "typescript": "4.0.2",
"wait-on": "^5.2.0" "wait-on": "^5.2.0"
}, },

View File

@ -37,7 +37,7 @@ export class CurrentUser {
return ''; return '';
}; };
private setToken = (token: string) => { private readonly setToken = (token: string) => {
this.tokenCache = token; this.tokenCache = token;
window.localStorage.setItem(tokenKey, token); window.localStorage.setItem(tokenKey, token);
}; };
@ -53,6 +53,7 @@ export class CurrentUser {
url: config.get('url') + 'client', url: config.get('url') + 'client',
method: 'POST', method: 'POST',
data: {name}, data: {name},
// eslint-disable-next-line @typescript-eslint/naming-convention
headers: {Authorization: 'Basic ' + Base64.encode(username + ':' + password)}, headers: {Authorization: 'Basic ' + Base64.encode(username + ':' + password)},
}) })
.then((resp: AxiosResponse<IClient>) => { .then((resp: AxiosResponse<IClient>) => {
@ -81,36 +82,39 @@ export class CurrentUser {
return Promise.reject(); return Promise.reject();
} }
return axios return (
.create() axios
.get(config.get('url') + 'current/user', {headers: {'X-Gotify-Key': this.token()}}) .create()
.then((passThrough) => { // eslint-disable-next-line @typescript-eslint/naming-convention
this.user = passThrough.data; .get(config.get('url') + 'current/user', {headers: {'X-Gotify-Key': this.token()}})
this.loggedIn = true; .then((passThrough) => {
this.connectionErrorMessage = null; this.user = passThrough.data;
this.reconnectTime = 7500; this.loggedIn = true;
return passThrough; this.connectionErrorMessage = null;
}) this.reconnectTime = 7500;
.catch((error: AxiosError) => { return passThrough;
if (!error || !error.response) { })
this.connectionError('No network connection or server unavailable.'); .catch((error: AxiosError) => {
if (!error || !error.response) {
this.connectionError('No network connection or server unavailable.');
return Promise.reject(error);
}
if (error.response.status >= 500) {
this.connectionError(
`${error.response.statusText} (code: ${error.response.status}).`
);
return Promise.reject(error);
}
this.connectionErrorMessage = null;
if (error.response.status >= 400 && error.response.status < 500) {
this.logout();
}
return Promise.reject(error); return Promise.reject(error);
} })
);
if (error.response.status >= 500) {
this.connectionError(
`${error.response.statusText} (code: ${error.response.status}).`
);
return Promise.reject(error);
}
this.connectionErrorMessage = null;
if (error.response.status >= 400 && error.response.status < 500) {
this.logout();
}
return Promise.reject(error);
});
}; };
public logout = async () => { public logout = async () => {
@ -119,9 +123,7 @@ export class CurrentUser {
.then((resp: AxiosResponse<IClient[]>) => { .then((resp: AxiosResponse<IClient[]>) => {
resp.data resp.data
.filter((client) => client.token === this.tokenCache) .filter((client) => client.token === this.tokenCache)
.forEach((client) => { .forEach((client) => axios.delete(config.get('url') + 'client/' + client.id));
return axios.delete(config.get('url') + 'client/' + client.id);
});
}) })
.catch(() => Promise.resolve()); .catch(() => Promise.resolve());
window.localStorage.removeItem(tokenKey); window.localStorage.removeItem(tokenKey);
@ -143,7 +145,7 @@ export class CurrentUser {
}); });
}; };
private connectionError = (message: string) => { private readonly connectionError = (message: string) => {
this.connectionErrorMessage = message; this.connectionErrorMessage = message;
if (this.reconnectTimeoutId !== null) { if (this.reconnectTimeoutId !== null) {
window.clearTimeout(this.reconnectTimeoutId); window.clearTimeout(this.reconnectTimeoutId);

View File

@ -30,8 +30,8 @@ const defaultProdConfig = {
url: urlWithSlash, url: urlWithSlash,
}; };
// eslint-disable-next-line @typescript-eslint/no-unused-vars
declare global { declare global {
// tslint:disable-next-line
interface Window { interface Window {
config: config.IConfig; config: config.IConfig;
} }

View File

@ -23,15 +23,13 @@ export interface StoreMapping {
export type AllStores = Extract<keyof StoreMapping, string>; export type AllStores = Extract<keyof StoreMapping, string>;
export type Stores<T extends AllStores> = Pick<StoreMapping, T>; export type Stores<T extends AllStores> = Pick<StoreMapping, T>;
export const inject = <I extends AllStores>(...stores: I[]) => { // eslint-disable-next-line @typescript-eslint/ban-types
return <P extends {}>( export const inject = <I extends AllStores>(...stores: I[]) => <P extends {}>(
node: React.ComponentType<P> node: React.ComponentType<P>
): React.ComponentType<Pick<P, Exclude<keyof P, I>>> => { ): React.ComponentType<Pick<P, Exclude<keyof P, I>>> =>
// tslint:disable-next-line:no-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
return mobxInject(...stores)(node) as any; mobxInject(...stores)(node) as any;
};
};
export const InjectProvider: React.SFC<{stores: StoreMapping}> = ({children, stores}) => { export const InjectProvider: React.SFC<{stores: StoreMapping}> = ({children, stores}) => (
return <Provider {...stores}>{children}</Provider>; <Provider {...stores}>{children}</Provider>
}; );

View File

@ -13,7 +13,7 @@ export const contentType = (extras?: IMessageExtras): RenderMode => {
return valid ? type : RenderMode.Plain; return valid ? type : RenderMode.Plain;
}; };
// tslint:disable-next-line:no-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const extract = (extras: IMessageExtras | undefined, key: string, path: string): any => { const extract = (extras: IMessageExtras | undefined, key: string, path: string): any => {
if (!extras) { if (!extras) {
return null; return null;

View File

@ -1,4 +1,3 @@
// tslint:disable
// In production, we register a service worker to serve assets from local cache. // In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives // This lets the app load faster on subsequent visits in production, and gives

View File

@ -94,7 +94,7 @@ describe('Client', () => {
expect(await count(page, $table.rows())).toBe(2); expect(await count(page, $table.rows())).toBe(2);
}); });
// tslint:disable-next-line:no-identical-functions // eslint-disable-next-line
it('deletes own client', async () => { it('deletes own client', async () => {
await page.click($table.cell(1, Col.Delete, '.delete')); await page.click($table.cell(1, Col.Delete, '.delete'));

View File

@ -16,7 +16,7 @@ beforeAll(async () => {
afterAll(async () => await gotify.close()); afterAll(async () => await gotify.close());
// tslint:disable-next-line // eslint-disable-next-line
const axiosAuth = {auth: {username: 'admin', password: 'admin'}}; const axiosAuth = {auth: {username: 'admin', password: 'admin'}};
let windowsServerToken: string; let windowsServerToken: string;
@ -35,7 +35,7 @@ const navigate = async (appName: string) => {
await waitForExists(page, selector.heading(), appName); await waitForExists(page, selector.heading(), appName);
}; };
// tslint:disable-next-line // eslint-disable-next-line
describe('Messages', () => { describe('Messages', () => {
it('does login', async () => await auth.login(page)); it('does login', async () => await auth.login(page));
it('is on messages', async () => { it('is on messages', async () => {

View File

@ -37,7 +37,7 @@ export interface IMessage {
} }
export interface IMessageExtras { export interface IMessageExtras {
[key: string]: any; // tslint:disable-line no-any [key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any
} }
export interface IPagedMessages { export interface IPagedMessages {

View File

@ -1,120 +0,0 @@
{
"extends": "tslint-sonarts",
"rules": {
"array-type": [true, "array-simple"],
"arrow-return-shorthand": true,
"ban": [true,
{"name": "Array", "message": "tsstyle#array-constructor"}
],
"ban-types": [true,
["Object", "Use {} instead."],
["String", "Use 'string' instead."],
["Number", "Use 'number' instead."],
["Boolean", "Use 'boolean' instead."],
["Function", "Use (..) => .. instead."]
],
"class-name": true,
"curly": [true],
"forin": true,
"label-position": true,
"member-access": [true],
"new-parens": true,
"no-angle-bracket-type-assertion": true,
"no-any": true,
"no-arg": true,
"no-conditional-assignment": true,
"no-construct": true,
"no-shadowed-variable": true,
"prefer-object-spread": true,
"no-debugger": true,
"no-default-export": false,
"no-duplicate-variable": true,
"no-inferrable-types": true,
"no-namespace": [true, "allow-declarations"],
"cyclomatic-complexity": [true, 13],
"no-duplicate-imports": true,
"no-reference": true,
"no-string-throw": true,
"no-unused-expression": true,
"no-var-keyword": true,
"object-literal-shorthand": true,
"only-arrow-functions": [true, "allow-declarations", "allow-named-functions"],
"prefer-const": true,
"radix": true,
"semicolon": [true, "always", "ignore-bound-class-methods"],
"switch-default": true,
"triple-equals": [true, "allow-null-check"],
"use-isnan": true,
"variable-name": [
true,
"check-format",
"ban-keywords",
"allow-pascal-case",
"allow-leading-underscore",
"allow-trailing-underscore"
],
"cognitive-complexity": true,
"mccabe-complexity": true,
"no-duplicate-string": false,
"no-nested-incdec": false,
"no-all-duplicated-branches": true,
"consecutive-overloads": true,
"max-union-size": false,
"no-accessor-field-mismatch": true,
"no-array-delete": true,
"no-big-function": true,
"no-case-with-or": true,
"no-collection-size-mischeck": true,
"no-commented-code": true,
"no-dead-store": true,
"no-duplicate-in-composite": true,
"no-duplicated-branches": true,
"no-element-overwrite": true,
"no-empty-destructuring": true,
"no-empty-nested-blocks": true,
"no-extra-semicolon": true,
"no-gratuitous-expressions": true,
"no-hardcoded-credentials": true,
"no-identical-conditions": true,
"no-identical-expressions": true,
"no-identical-functions": true,
"no-ignored-initial-value": true,
"no-ignored-return": true,
"no-in-misuse": true,
"no-inconsistent-return": true,
"no-misleading-array-reverse": true,
"no-misspelled-operator": true,
"no-multiline-string-literals": true,
"no-nested-template-literals": true,
"no-redundant-boolean": true,
"no-redundant-jump": true,
"no-redundant-parentheses": true,
"no-return-type-any": true,
"no-same-line-conditional": true,
"no-self-assignment": true,
"no-small-switch": true,
"no-statements-same-line": true,
"no-unconditional-jump": true,
"no-undefined-argument": true,
"no-unenclosed-multiline-block": true,
"no-unthrown-error": true,
"no-unused-array": true,
"no-use-of-empty-return-value": true,
"no-useless-cast": true,
"no-useless-increment": true,
"no-useless-intersection": true,
"no-variable-usage-before-declaration": true,
"parameters-max-number": true,
"prefer-default-last": true,
"prefer-immediate-return": true,
"prefer-promise-shorthand": true,
"use-primitive-type": true,
"use-type-alias": true
},
"linterOptions": {
"exclude": [
"node_modules/**/*.ts"
]
}
}

View File

@ -4689,11 +4689,6 @@ eslint-plugin-prefer-arrow@^1.2.2:
resolved "https://registry.yarnpkg.com/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.2.tgz#0c6d25a6b94cb3e0110a23d129760af5860edb6e" resolved "https://registry.yarnpkg.com/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.2.tgz#0c6d25a6b94cb3e0110a23d129760af5860edb6e"
integrity sha512-C8YMhL+r8RMeMdYAw/rQtE6xNdMulj+zGWud/qIGnlmomiPRaLDGLMeskZ3alN6uMBojmooRimtdrXebLN4svQ== integrity sha512-C8YMhL+r8RMeMdYAw/rQtE6xNdMulj+zGWud/qIGnlmomiPRaLDGLMeskZ3alN6uMBojmooRimtdrXebLN4svQ==
eslint-plugin-promise@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==
eslint-plugin-react-hooks@^1.6.1: eslint-plugin-react-hooks@^1.6.1:
version "1.7.0" version "1.7.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04"