From 48df8ab3b17beb68b280d020d570bc97faabacc6 Mon Sep 17 00:00:00 2001 From: Sidney Keese Date: Thu, 3 Sep 2020 07:59:24 -0700 Subject: [PATCH] ESLint Migration --- .eslintignore | 6 -- .eslintrc.js | 139 +++++++++++++++++--------------- ts/backbone/views/Lightbox.ts | 2 - ts/build/notarize.ts | 4 +- ts/model-types.d.ts | 2 +- ts/scripts/zip-macos-release.ts | 5 +- ts/services/bounce.ts | 6 +- ts/services/calling.ts | 51 +++++++----- ts/services/networkObserver.ts | 4 +- ts/services/updateListener.ts | 2 +- ts/util/lint/exceptions.json | 8 +- tsconfig.json | 6 +- tslint.json | 10 ++- 13 files changed, 133 insertions(+), 112 deletions(-) diff --git a/.eslintignore b/.eslintignore index 22a42f698..6f3028c8e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -33,16 +33,10 @@ webpack.config.ts # Temporarily ignored during TSLint transition # JIRA: DESKTOP-304 ts/*.ts -ts/backbone/** -ts/build/** ts/components/*.ts ts/components/*.tsx ts/components/conversation/** ts/components/stickers/** -ts/notifications/** -ts/protobuf/** -ts/scripts/** -ts/services/** ts/shims/** ts/sql/** ts/state/** diff --git a/.eslintrc.js b/.eslintrc.js index 895847997..75ae1ccfe 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,5 +1,75 @@ // For reference: https://github.com/airbnb/javascript +const rules = { + 'comma-dangle': [ + 'error', + { + arrays: 'always-multiline', + objects: 'always-multiline', + imports: 'always-multiline', + exports: 'always-multiline', + functions: 'never', + }, + ], + + // prevents us from accidentally checking in exclusive tests (`.only`): + 'mocha/no-exclusive-tests': 'error', + + // encourage consistent use of `async` / `await` instead of `then` + 'more/no-then': 'error', + + // it helps readability to put public API at top, + 'no-use-before-define': 'off', + + // useful for unused or internal fields + 'no-underscore-dangle': 'off', + + // useful for unused parameters + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + + // though we have a logger, we still remap console to log to disk + 'no-console': 'error', + + // consistently place operators at end of line except ternaries + 'operator-linebreak': [ + 'error', + 'after', + { overrides: { '?': 'ignore', ':': 'ignore' } }, + ], + + // Temporarily turned off during transition from TSLint + // JIRA: DESKTOP-623 + 'import/order': 'off', + 'no-else-return': 'off', + 'no-async-promise-executor': 'off', + 'prefer-object-spread': 'off', + strict: 'off', + + quotes: [ + 'error', + 'single', + { avoidEscape: true, allowTemplateLiterals: false }, + ], + + // Prettier overrides: + 'arrow-parens': 'off', + 'function-paren-newline': 'off', + 'max-len': [ + 'error', + { + // Prettier generally limits line length to 80 but sometimes goes over. + // The `max-len` plugin doesn’t let us omit `code` so we set it to a + // high value as a buffer to let Prettier control the line length: + code: 999, + // We still want to limit comments as before: + comments: 90, + ignoreUrls: true, + }, + ], + + 'import/prefer-default-export': 'off', +}; + module.exports = { root: true, settings: { @@ -32,78 +102,17 @@ module.exports = { 'plugin:react/recommended', 'airbnb-typescript-prettier', ], + rules, }, { - files: ['**/*.stories.tsx'], + files: ['**/*.stories.tsx', 'ts/build/**'], rules: { + ...rules, 'import/no-extraneous-dependencies': 'off', 'react/jsx-props-no-spreading': 'off', }, }, ], - rules: { - 'comma-dangle': [ - 'error', - { - arrays: 'always-multiline', - objects: 'always-multiline', - imports: 'always-multiline', - exports: 'always-multiline', - functions: 'never', - }, - ], - - // prevents us from accidentally checking in exclusive tests (`.only`): - 'mocha/no-exclusive-tests': 'error', - - // encourage consistent use of `async` / `await` instead of `then` - 'more/no-then': 'error', - - // it helps readability to put public API at top, - 'no-use-before-define': 'off', - - // useful for unused or internal fields - 'no-underscore-dangle': 'off', - - // though we have a logger, we still remap console to log to disk - 'no-console': 'error', - - // consistently place operators at end of line except ternaries - 'operator-linebreak': [ - 'error', - 'after', - { overrides: { '?': 'ignore', ':': 'ignore' } }, - ], - - // Temporarily turned off during transition from TSLint - // JIRA: DESKTOP-623 - 'import/order': 'off', - 'no-else-return': 'off', - 'no-async-promise-executor': 'off', - 'prefer-object-spread': 'off', - strict: 'off', - - quotes: [ - 'error', - 'single', - { avoidEscape: true, allowTemplateLiterals: false }, - ], - - // Prettier overrides: - 'arrow-parens': 'off', - 'function-paren-newline': 'off', - 'max-len': [ - 'error', - { - // Prettier generally limits line length to 80 but sometimes goes over. - // The `max-len` plugin doesn’t let us omit `code` so we set it to a - // high value as a buffer to let Prettier control the line length: - code: 999, - // We still want to limit comments as before: - comments: 90, - ignoreUrls: true, - }, - ], - }, + rules, }; diff --git a/ts/backbone/views/Lightbox.ts b/ts/backbone/views/Lightbox.ts index 04da21003..6a83fea90 100644 --- a/ts/backbone/views/Lightbox.ts +++ b/ts/backbone/views/Lightbox.ts @@ -5,7 +5,6 @@ export const show = (element: HTMLElement): void => { if (!container) { throw new TypeError("'.lightbox-container' is required"); } - // tslint:disable-next-line:no-inner-html container.innerHTML = ''; container.style.display = 'block'; container.appendChild(element); @@ -18,7 +17,6 @@ export const hide = (): void => { if (!container) { return; } - // tslint:disable-next-line:no-inner-html container.innerHTML = ''; container.style.display = 'none'; }; diff --git a/ts/build/notarize.ts b/ts/build/notarize.ts index 02df9d72d..641ea079f 100644 --- a/ts/build/notarize.ts +++ b/ts/build/notarize.ts @@ -3,15 +3,13 @@ import { readdir as readdirCallback } from 'fs'; import pify from 'pify'; -// tslint:disable-next-line no-implicit-dependencies import { notarize } from 'electron-notarize'; -// @ts-ignore import * as packageJson from '../../package.json'; const readdir = pify(readdirCallback); -/* tslint:disable:no-console */ +/* eslint-disable no-console */ go().catch(error => { console.error(error.stack); diff --git a/ts/model-types.d.ts b/ts/model-types.d.ts index 0e926bfb7..15b943d89 100644 --- a/ts/model-types.d.ts +++ b/ts/model-types.d.ts @@ -70,7 +70,7 @@ type ConversationAttributesType = { version: number; }; -declare class ConversationModelType extends Backbone.Model< +export declare class ConversationModelType extends Backbone.Model< ConversationAttributesType > { id: string; diff --git a/ts/scripts/zip-macos-release.ts b/ts/scripts/zip-macos-release.ts index 168779c4c..7c1fb2e88 100644 --- a/ts/scripts/zip-macos-release.ts +++ b/ts/scripts/zip-macos-release.ts @@ -1,11 +1,12 @@ -/* tslint:disable no-console non-literal-fs-path */ +/* eslint-disable no-console */ + import fs from 'fs'; import path from 'path'; import rimraf from 'rimraf'; import { execSync } from 'child_process'; import packageJSON from '../../package.json'; -export function zipMacOSRelease() { +export function zipMacOSRelease(): void { if (process.platform !== 'darwin') { return; } diff --git a/ts/services/bounce.ts b/ts/services/bounce.ts index 4deddf032..0c4415e13 100644 --- a/ts/services/bounce.ts +++ b/ts/services/bounce.ts @@ -2,15 +2,11 @@ import { app, BrowserWindow, ipcMain } from 'electron'; let bounceId = -1; -export function init(win: BrowserWindow) { +export function init(win: BrowserWindow): void { ipcMain.on('bounce-app-icon-start', (_, isCritical = false) => { if (app.dock) { const type = isCritical ? 'critical' : 'informational'; bounceId = app.dock.bounce(type); - - if (bounceId < 0) { - return; - } } else if (win && win.flashFrame) { win.once('focus', () => { win.flashFrame(false); diff --git a/ts/services/calling.ts b/ts/services/calling.ts index 3508983e1..7a5f00f11 100644 --- a/ts/services/calling.ts +++ b/ts/services/calling.ts @@ -1,3 +1,5 @@ +/* eslint-disable class-methods-use-this */ + import { Call, CallEndedReason, @@ -39,9 +41,13 @@ export type CallHistoryDetailsType = { export class CallingClass { readonly videoCapturer: GumVideoCapturer; + readonly videoRenderer: CanvasVideoRenderer; + private uxActions?: UxActionsType; + private lastMediaDeviceSettings?: MediaDeviceSettings; + private deviceReselectionTimer?: NodeJS.Timeout; constructor() { @@ -85,7 +91,7 @@ export class CallingClass { async startOutgoingCall( conversation: ConversationModelType, isVideoCall: boolean - ) { + ): Promise { if (!this.uxActions) { window.log.error('Missing uxActions, new call not allowed.'); return; @@ -130,7 +136,7 @@ export class CallingClass { }); } - async accept(callId: CallId, asVideoCall: boolean) { + async accept(callId: CallId, asVideoCall: boolean): Promise { const haveMediaPermissions = await this.requestPermissions(asVideoCall); if (haveMediaPermissions) { await this.startDeviceReselectionTimer(); @@ -143,19 +149,19 @@ export class CallingClass { } } - decline(callId: CallId) { + decline(callId: CallId): void { RingRTC.decline(callId); } - hangup(callId: CallId) { + hangup(callId: CallId): void { RingRTC.hangup(callId); } - setOutgoingAudio(callId: CallId, enabled: boolean) { + setOutgoingAudio(callId: CallId, enabled: boolean): void { RingRTC.setOutgoingAudio(callId, enabled); } - setOutgoingVideo(callId: CallId, enabled: boolean) { + setOutgoingVideo(callId: CallId, enabled: boolean): void { RingRTC.setOutgoingVideo(callId, enabled); } @@ -177,7 +183,6 @@ export class CallingClass { } } - // tslint:disable-next-line cyclomatic-complexity private mediaDeviceSettingsEqual( a?: MediaDeviceSettings, b?: MediaDeviceSettings @@ -195,7 +200,7 @@ export class CallingClass { ) { return false; } - for (let i = 0; i < a.availableCameras.length; i++) { + for (let i = 0; i < a.availableCameras.length; i += 1) { if ( a.availableCameras[i].deviceId !== b.availableCameras[i].deviceId || a.availableCameras[i].groupId !== b.availableCameras[i].groupId || @@ -204,7 +209,7 @@ export class CallingClass { return false; } } - for (let i = 0; i < a.availableMicrophones.length; i++) { + for (let i = 0; i < a.availableMicrophones.length; i += 1) { if ( a.availableMicrophones[i].name !== b.availableMicrophones[i].name || a.availableMicrophones[i].uniqueId !== @@ -213,7 +218,7 @@ export class CallingClass { return false; } } - for (let i = 0; i < a.availableSpeakers.length; i++) { + for (let i = 0; i < a.availableSpeakers.length; i += 1) { if ( a.availableSpeakers[i].name !== b.availableSpeakers[i].name || a.availableSpeakers[i].uniqueId !== b.availableSpeakers[i].uniqueId @@ -351,7 +356,8 @@ export class CallingClass { const matchingId = available.filter(d => d.deviceId === preferred); const nonInfrared = available.filter(d => !d.label.includes('IR Camera')); - /// By default, pick the first non-IR camera (but allow the user to pick the infrared if they so desire) + // By default, pick the first non-IR camera (but allow the user to pick the + // infrared if they so desire) if (matchingId.length > 0) { return matchingId[0].deviceId; } else if (nonInfrared.length > 0) { @@ -361,19 +367,19 @@ export class CallingClass { } } - setPreferredMicrophone(device: AudioDevice) { + setPreferredMicrophone(device: AudioDevice): void { window.log.info('MediaDevice: setPreferredMicrophone', device); window.storage.put('preferred-audio-input-device', device); RingRTC.setAudioInput(device.index); } - setPreferredSpeaker(device: AudioDevice) { + setPreferredSpeaker(device: AudioDevice): void { window.log.info('MediaDevice: setPreferredSpeaker', device); window.storage.put('preferred-audio-output-device', device); RingRTC.setAudioOutput(device.index); } - async setPreferredCamera(device: string) { + async setPreferredCamera(device: string): Promise { window.log.info('MediaDevice: setPreferredCamera', device); window.storage.put('preferred-video-input-device', device); await this.videoCapturer.setPreferredDevice(device); @@ -382,7 +388,7 @@ export class CallingClass { async handleCallingMessage( envelope: EnvelopeClass, callingMessage: CallingMessageClass - ) { + ): Promise { const enableIncomingCalls = await window.getIncomingCallNotification(); if (callingMessage.offer && !enableIncomingCalls) { // Drop offers silently if incoming call notifications are disabled. @@ -421,7 +427,8 @@ export class CallingClass { await this.videoCapturer.setPreferredDevice(settings.selectedCamera); } - // Assume that the MediaDeviceSettings have been obtained very recently and the index is still valid (no devices have been plugged in in between). + // Assume that the MediaDeviceSettings have been obtained very recently and + // the index is still valid (no devices have been plugged in in between). if (settings.selectedMicrophone) { window.log.info( 'MediaDevice: selecting microphone', @@ -583,6 +590,7 @@ export class CallingClass { let acceptedTime: number | undefined; + // eslint-disable-next-line no-param-reassign call.handleStateChanged = () => { if (call.state === CallState.Accepted) { acceptedTime = Date.now(); @@ -597,6 +605,7 @@ export class CallingClass { }); }; + // eslint-disable-next-line no-param-reassign call.handleRemoteVideoEnabled = () => { uxActions.remoteVideoChange({ remoteVideoEnabled: call.remoteVideoEnabled, @@ -610,8 +619,6 @@ export class CallingClass { line: number, message: string ) { - // info/warn/error are only needed to be logged for now. - // tslint:disable-next-line switch-default switch (level) { case CallLogLevel.Info: window.log.info(`${fileName}:${line} ${message}`); @@ -621,6 +628,9 @@ export class CallingClass { break; case CallLogLevel.Error: window.log.error(`${fileName}:${line} ${message}`); + break; + default: + break; } } @@ -686,8 +696,10 @@ export class CallingClass { private addCallHistoryForEndedCall( conversation: ConversationModelType, call: Call, - acceptedTime: number | undefined + acceptedTimeParam: number | undefined ) { + let acceptedTime = acceptedTimeParam; + const { endedReason, isIncoming } = call; const wasAccepted = Boolean(acceptedTime); const isOutgoing = !isIncoming; @@ -700,7 +712,6 @@ export class CallingClass { (isOutgoing && endedReason === CallEndedReason.RemoteHangupNeedPermission)); if (call.endedReason === CallEndedReason.AcceptedOnAnotherDevice) { - // tslint:disable-next-line no-parameter-reassignment acceptedTime = Date.now(); } diff --git a/ts/services/networkObserver.ts b/ts/services/networkObserver.ts index 56f3ee173..d8b66a514 100644 --- a/ts/services/networkObserver.ts +++ b/ts/services/networkObserver.ts @@ -11,7 +11,9 @@ type NetworkActions = { const REFRESH_INTERVAL = 5000; -export function initializeNetworkObserver(networkActions: NetworkActions) { +export function initializeNetworkObserver( + networkActions: NetworkActions +): void { const { log } = window; log.info(`Initializing network observer every ${REFRESH_INTERVAL}ms`); diff --git a/ts/services/updateListener.ts b/ts/services/updateListener.ts index 7f0402ea5..f30840d51 100644 --- a/ts/services/updateListener.ts +++ b/ts/services/updateListener.ts @@ -13,7 +13,7 @@ type EventsType = { export function initializeUpdateListener( updatesActions: UpdatesActions, events: EventsType -) { +): void { ipcRenderer.on('show-update-dialog', (_, dialogType: Dialogs) => { updatesActions.showUpdateDialog(dialogType); }); diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index 7b9950f54..e33c033dd 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -10251,7 +10251,7 @@ "rule": "DOM-innerHTML", "path": "ts/backbone/views/Lightbox.js", "line": " container.innerHTML = '';", - "lineNumber": 9, + "lineNumber": 8, "reasonCategory": "usageTrusted", "updated": "2018-09-17T20:50:40.689Z", "reasonDetail": "Hard-coded value" @@ -10260,7 +10260,7 @@ "rule": "DOM-innerHTML", "path": "ts/backbone/views/Lightbox.js", "line": " container.innerHTML = '';", - "lineNumber": 19, + "lineNumber": 17, "reasonCategory": "usageTrusted", "updated": "2018-09-17T20:50:40.689Z", "reasonDetail": "Hard-coded value" @@ -10269,7 +10269,7 @@ "rule": "DOM-innerHTML", "path": "ts/backbone/views/Lightbox.ts", "line": " container.innerHTML = '';", - "lineNumber": 9, + "lineNumber": 8, "reasonCategory": "usageTrusted", "updated": "2018-09-17T20:50:40.689Z", "reasonDetail": "Hard-coded value" @@ -10278,7 +10278,7 @@ "rule": "DOM-innerHTML", "path": "ts/backbone/views/Lightbox.ts", "line": " container.innerHTML = '';", - "lineNumber": 22, + "lineNumber": 20, "reasonCategory": "usageTrusted", "updated": "2018-09-17T20:50:40.689Z", "reasonDetail": "Hard-coded value" diff --git a/tsconfig.json b/tsconfig.json index c83a13728..75d1249a1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -53,5 +53,9 @@ // "experimentalDecorators": true, // Enables experimental support for ES7 decorators. // "emitDecoratorMetadata": true, // Enables experimental support for emitting type metadata for decorators. }, - "include": ["ts/**/*", "node_modules/zkgroup/zkgroup/modules/*"] + "include": [ + "ts/**/*", + "node_modules/zkgroup/zkgroup/modules/*", + "package.json" + ] } diff --git a/tslint.json b/tslint.json index 28f882dae..eefe15e09 100644 --- a/tslint.json +++ b/tslint.json @@ -176,6 +176,14 @@ }, "rulesDirectory": ["node_modules/tslint-microsoft-contrib"], "linterOptions": { - "exclude": ["ts/components/emoji/**/*.ts"] + "exclude": [ + "ts/components/emoji/**", + "ts/backbone/**", + "ts/build/**", + "ts/notifications/**", + "ts/protobuf/**", + "ts/scripts/**", + "ts/services/**" + ] } }