diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2024-02-08 06:52:06 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-08 11:52:06 +0000 | 
| commit | d4381831209dfbbbddd6d238c68461c9601573e2 (patch) | |
| tree | 87839d80f838464ff92ebc7fa652029b9329cc96 /ext/js | |
| parent | 725a90dd6570044a3df6631051aaab8b026ca6c2 (diff) | |
Update eslint (#638)
* Add json test
* Update vscode settings to better handle json
* Collapse eslint rules for easier readability
* Reorganize
* Update no-multi-spaces rule for JSON
* Rules updates
* Switch to @stylistic/eslint-plugin
* Update deprecated stylistic rules
* Group stylistic rules
* Simplify rules
* Move eslint env overrides to end of file
* Add test
* Move promiseAnimationFrame to separate file
* Remove unneeded eslint disable
* Remove unneeded
Diffstat (limited to 'ext/js')
| -rw-r--r-- | ext/js/app/frontend.js | 10 | ||||
| -rw-r--r-- | ext/js/app/popup-factory.js | 4 | ||||
| -rw-r--r-- | ext/js/application.js | 4 | ||||
| -rw-r--r-- | ext/js/background/backend.js | 4 | ||||
| -rw-r--r-- | ext/js/background/offscreen.js | 5 | ||||
| -rw-r--r-- | ext/js/core/promise-animation-frame.js | 62 | ||||
| -rw-r--r-- | ext/js/core/utilities.js | 45 | ||||
| -rw-r--r-- | ext/js/data/options-util.js | 6 | ||||
| -rw-r--r-- | ext/js/display/display-anki.js | 4 | ||||
| -rw-r--r-- | ext/js/display/display-audio.js | 4 | ||||
| -rw-r--r-- | ext/js/display/display.js | 4 | ||||
| -rw-r--r-- | ext/js/pages/settings/keyboard-shortcuts-controller.js | 4 | ||||
| -rw-r--r-- | ext/js/pages/settings/popup-preview-frame.js | 4 | ||||
| -rw-r--r-- | ext/js/pages/settings/profile-conditions-ui.js | 4 | ||||
| -rw-r--r-- | ext/js/templates/sandbox/anki-template-renderer.js | 4 | 
15 files changed, 92 insertions, 76 deletions
| diff --git a/ext/js/app/frontend.js b/ext/js/app/frontend.js index 5f412340..27e7700e 100644 --- a/ext/js/app/frontend.js +++ b/ext/js/app/frontend.js @@ -19,7 +19,7 @@  import {createApiMap, invokeApiMapHandler} from '../core/api-map.js';  import {EventListenerCollection} from '../core/event-listener-collection.js';  import {log} from '../core/logger.js'; -import {promiseAnimationFrame} from '../core/utilities.js'; +import {promiseAnimationFrame} from '../core/promise-animation-frame.js';  import {DocumentUtil} from '../dom/document-util.js';  import {TextSourceElement} from '../dom/text-source-element.js';  import {TextSourceGenerator} from '../dom/text-source-generator.js'; @@ -115,7 +115,7 @@ export class Frontend {          /** @type {?import('settings').OptionsContext} */          this._optionsContextOverride = null; -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          /** @type {import('application').ApiMap} */          this._runtimeApiMap = createApiMap([              ['frontendRequestReadyBroadcast',   this._onMessageRequestFrontendReadyBroadcast.bind(this)], @@ -127,7 +127,7 @@ export class Frontend {              ['scanSelectedText', this._onActionScanSelectedText.bind(this)],              ['scanTextAtCaret',  this._onActionScanTextAtCaret.bind(this)]          ]); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */      }      /** @@ -187,7 +187,7 @@ export class Frontend {          this._textScanner.on('searchEmpty', this._onSearchEmpty.bind(this));          this._textScanner.on('searchError', this._onSearchError.bind(this)); -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          this._application.crossFrame.registerHandlers([              ['frontendClosePopup',       this._onApiClosePopup.bind(this)],              ['frontendCopySelection',    this._onApiCopySelection.bind(this)], @@ -195,7 +195,7 @@ export class Frontend {              ['frontendGetPopupInfo',     this._onApiGetPopupInfo.bind(this)],              ['frontendGetPageInfo',      this._onApiGetPageInfo.bind(this)]          ]); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */          this._prepareSiteSpecific();          this._updateContentScale(); diff --git a/ext/js/app/popup-factory.js b/ext/js/app/popup-factory.js index 1b7d21db..c5187291 100644 --- a/ext/js/app/popup-factory.js +++ b/ext/js/app/popup-factory.js @@ -49,7 +49,7 @@ export class PopupFactory {       */      prepare() {          this._frameOffsetForwarder.prepare(); -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          this._application.crossFrame.registerHandlers([              ['popupFactoryGetOrCreatePopup',     this._onApiGetOrCreatePopup.bind(this)],              ['popupFactorySetOptionsContext',    this._onApiSetOptionsContext.bind(this)], @@ -67,7 +67,7 @@ export class PopupFactory {              ['popupFactoryGetFrameSize',         this._onApiGetFrameSize.bind(this)],              ['popupFactorySetFrameSize',         this._onApiSetFrameSize.bind(this)]          ]); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */      }      /** diff --git a/ext/js/application.js b/ext/js/application.js index 13938aa8..227e9d5e 100644 --- a/ext/js/application.js +++ b/ext/js/application.js @@ -93,7 +93,7 @@ export class Application extends EventDispatcher {          /** @type {boolean} */          this._isReady = false; -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          /** @type {import('application').ApiMap} */          this._apiMap = createApiMap([              ['applicationIsReady',         this._onMessageIsReady.bind(this)], @@ -102,7 +102,7 @@ export class Application extends EventDispatcher {              ['applicationDatabaseUpdated', this._onMessageDatabaseUpdated.bind(this)],              ['applicationZoomChanged',     this._onMessageZoomChanged.bind(this)]          ]); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */      }      /** @type {WebExtension} */ diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js index 85acac89..909faf29 100644 --- a/ext/js/background/backend.js +++ b/ext/js/background/backend.js @@ -139,7 +139,7 @@ export class Backend {          /** @type {Map<string, (() => void)[]>} */          this._applicationReadyHandlers = new Map(); -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          /** @type {import('api').ApiMap} */          this._apiMap = createApiMap([              ['applicationReady',             this._onApiApplicationReady.bind(this)], @@ -185,7 +185,7 @@ export class Backend {              ['findAnkiNotes',                this._onApiFindAnkiNotes.bind(this)],              ['openCrossFramePort',           this._onApiOpenCrossFramePort.bind(this)]          ]); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */          /** @type {Map<string, (params?: import('core').SerializableObject) => void>} */          this._commandHandlers = new Map(/** @type {[name: string, handler: (params?: import('core').SerializableObject) => void][]} */ ([ diff --git a/ext/js/background/offscreen.js b/ext/js/background/offscreen.js index b203e326..754db517 100644 --- a/ext/js/background/offscreen.js +++ b/ext/js/background/offscreen.js @@ -39,14 +39,13 @@ export class Offscreen {          });          /** @type {ClipboardReader} */          this._clipboardReader = new ClipboardReader({ -            // eslint-disable-next-line no-undef              document: (typeof document === 'object' && document !== null ? document : null),              pasteTargetSelector: '#clipboard-paste-target',              richContentPasteTargetSelector: '#clipboard-rich-content-paste-target'          }); -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          /** @type {import('offscreen').ApiMap} */          this._apiMap = createApiMap([              ['clipboardGetTextOffscreen',    this._getTextHandler.bind(this)], @@ -62,7 +61,7 @@ export class Offscreen {              ['getTermFrequenciesOffscreen',  this._getTermFrequenciesHandler.bind(this)],              ['clearDatabaseCachesOffscreen', this._clearDatabaseCachesHandler.bind(this)]          ]); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */          /** @type {?Promise<void>} */          this._prepareDatabasePromise = null; diff --git a/ext/js/core/promise-animation-frame.js b/ext/js/core/promise-animation-frame.js new file mode 100644 index 00000000..0bcd6970 --- /dev/null +++ b/ext/js/core/promise-animation-frame.js @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2023-2024  Yomitan Authors + * Copyright (C) 2019-2022  Yomichan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <https://www.gnu.org/licenses/>. + */ + +/** + * Creates a promise that will resolve after the next animation frame, using `requestAnimationFrame`. + * @param {number} [timeout] A maximum duration (in milliseconds) to wait until the promise resolves. If null or omitted, no timeout is used. + * @returns {Promise<{time: number, timeout: boolean}>} A promise that is resolved with `{time, timeout}`, where `time` is the timestamp from `requestAnimationFrame`, + *   and `timeout` is a boolean indicating whether the cause was a timeout or not. + * @throws The promise throws an error if animation is not supported in this context, such as in a service worker. + */ +export function promiseAnimationFrame(timeout) { +    return new Promise((resolve, reject) => { +        if (typeof cancelAnimationFrame !== 'function' || typeof requestAnimationFrame !== 'function') { +            reject(new Error('Animation not supported in this context')); +            return; +        } + +        /** @type {?import('core').Timeout} */ +        let timer = null; +        /** @type {?number} */ +        let frameRequest = null; +        /** +         * @param {number} time +         */ +        const onFrame = (time) => { +            frameRequest = null; +            if (timer !== null) { +                clearTimeout(timer); +                timer = null; +            } +            resolve({time, timeout: false}); +        }; +        const onTimeout = () => { +            timer = null; +            if (frameRequest !== null) { +                cancelAnimationFrame(frameRequest); +                frameRequest = null; +            } +            resolve({time: performance.now(), timeout: true}); +        }; + +        frameRequest = requestAnimationFrame(onFrame); +        if (typeof timeout === 'number') { +            timer = setTimeout(onTimeout, timeout); +        } +    }); +} diff --git a/ext/js/core/utilities.js b/ext/js/core/utilities.js index 784acdaf..1b785e79 100644 --- a/ext/js/core/utilities.js +++ b/ext/js/core/utilities.js @@ -270,48 +270,3 @@ export function deferPromise() {  export function promiseTimeout(delay) {      return delay <= 0 ? Promise.resolve() : new Promise((resolve) => { setTimeout(resolve, delay); });  } - -/** - * Creates a promise that will resolve after the next animation frame, using `requestAnimationFrame`. - * @param {number} [timeout] A maximum duration (in milliseconds) to wait until the promise resolves. If null or omitted, no timeout is used. - * @returns {Promise<{time: number, timeout: boolean}>} A promise that is resolved with `{time, timeout}`, where `time` is the timestamp from `requestAnimationFrame`, - *   and `timeout` is a boolean indicating whether the cause was a timeout or not. - * @throws The promise throws an error if animation is not supported in this context, such as in a service worker. - */ -export function promiseAnimationFrame(timeout) { -    return new Promise((resolve, reject) => { -        if (typeof cancelAnimationFrame !== 'function' || typeof requestAnimationFrame !== 'function') { -            reject(new Error('Animation not supported in this context')); -            return; -        } - -        /** @type {?import('core').Timeout} */ -        let timer = null; -        /** @type {?number} */ -        let frameRequest = null; -        /** -         * @param {number} time -         */ -        const onFrame = (time) => { -            frameRequest = null; -            if (timer !== null) { -                clearTimeout(timer); -                timer = null; -            } -            resolve({time, timeout: false}); -        }; -        const onTimeout = () => { -            timer = null; -            if (frameRequest !== null) { -                cancelAnimationFrame(frameRequest); -                frameRequest = null; -            } -            resolve({time: performance.now(), timeout: true}); -        }; - -        frameRequest = requestAnimationFrame(onFrame); -        if (typeof timeout === 'number') { -            timer = setTimeout(onTimeout, timeout); -        } -    }); -} diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js index 3f3a5ab8..d93927a7 100644 --- a/ext/js/data/options-util.js +++ b/ext/js/data/options-util.js @@ -687,7 +687,7 @@ export class OptionsUtil {          const rawPattern1 = '{{~#if definitionTags~}}<i>({{#each definitionTags}}{{name}}{{#unless @last}}, {{/unless}}{{/each}})</i> {{/if~}}';          const pattern1 = new RegExp(`((\r?\n)?[ \t]*)${escapeRegExp(rawPattern1)}`, 'g');          const replacement1 = ( -        // eslint-disable-next-line indent +        // eslint-disable-next-line @stylistic/indent  `{{~#scope~}}      {{~#set "any" false}}{{/set~}}      {{~#if definitionTags~}}{{#each definitionTags~}} @@ -771,7 +771,7 @@ export class OptionsUtil {              };              delete profile.options.anki.sentenceExt;              profile.options.general.popupActionBarLocation = 'top'; -            /* eslint-disable no-multi-spaces */ +            /* eslint-disable @stylistic/no-multi-spaces */              profile.options.inputs = {                  hotkeys: [                      {action: 'close',             key: 'Escape',    modifiers: [],       scopes: ['popup'], enabled: true}, @@ -792,7 +792,7 @@ export class OptionsUtil {                      {action: 'copyHostSelection', key: 'KeyC',      modifiers: ['ctrl'], scopes: ['popup'], enabled: true}                  ]              }; -            /* eslint-enable no-multi-spaces */ +            /* eslint-enable @stylistic/no-multi-spaces */              profile.options.anki.suspendNewCards = false;              profile.options.popupWindow = {                  width: profile.options.general.popupWidth, diff --git a/ext/js/display/display-anki.js b/ext/js/display/display-anki.js index c19cfa22..665521dd 100644 --- a/ext/js/display/display-anki.js +++ b/ext/js/display/display-anki.js @@ -109,14 +109,14 @@ export class DisplayAnki {      /** */      prepare() {          this._noteContext = this._getNoteContext(); -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          this._display.hotkeyHandler.registerActions([              ['addNoteKanji',      () => { this._tryAddAnkiNoteForSelectedEntry('kanji'); }],              ['addNoteTermKanji',  () => { this._tryAddAnkiNoteForSelectedEntry('term-kanji'); }],              ['addNoteTermKana',   () => { this._tryAddAnkiNoteForSelectedEntry('term-kana'); }],              ['viewNote',          this._viewNoteForSelectedEntry.bind(this)]          ]); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */          this._display.on('optionsUpdated', this._onOptionsUpdated.bind(this));          this._display.on('contentClear', this._onContentClear.bind(this));          this._display.on('contentUpdateStart', this._onContentUpdateStart.bind(this)); diff --git a/ext/js/display/display-audio.js b/ext/js/display/display-audio.js index 4acd6494..deaa0976 100644 --- a/ext/js/display/display-audio.js +++ b/ext/js/display/display-audio.js @@ -82,7 +82,7 @@ export class DisplayAudio {      /** */      prepare() {          this._audioSystem.prepare(); -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          this._display.hotkeyHandler.registerActions([              ['playAudio',           this._onHotkeyActionPlayAudio.bind(this)],              ['playAudioFromSource', this._onHotkeyActionPlayAudioFromSource.bind(this)] @@ -90,7 +90,7 @@ export class DisplayAudio {          this._display.registerDirectMessageHandlers([              ['displayAudioClearAutoPlayTimer', this._onMessageClearAutoPlayTimer.bind(this)]          ]); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */          this._display.on('optionsUpdated', this._onOptionsUpdated.bind(this));          this._display.on('contentClear', this._onContentClear.bind(this));          this._display.on('contentUpdateEntry', this._onContentUpdateEntry.bind(this)); diff --git a/ext/js/display/display.js b/ext/js/display/display.js index 676f1a4f..f05feac8 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -200,7 +200,7 @@ export class Display extends EventDispatcher {          /** @type {ThemeController} */          this._themeController = new ThemeController(document.documentElement); -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          this._hotkeyHandler.registerActions([              ['close',             () => { this._onHotkeyClose(); }],              ['nextEntry',         this._onHotkeyActionMoveRelative.bind(this, 1)], @@ -224,7 +224,7 @@ export class Display extends EventDispatcher {          this.registerWindowMessageHandlers([              ['displayExtensionUnloaded', this._onMessageExtensionUnloaded.bind(this)]          ]); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */      }      /** @type {import('../application.js').Application} */ diff --git a/ext/js/pages/settings/keyboard-shortcuts-controller.js b/ext/js/pages/settings/keyboard-shortcuts-controller.js index 9392f768..24d34d5b 100644 --- a/ext/js/pages/settings/keyboard-shortcuts-controller.js +++ b/ext/js/pages/settings/keyboard-shortcuts-controller.js @@ -45,7 +45,7 @@ export class KeyboardShortcutController {          this._stringComparer = new Intl.Collator('en-US'); // Invariant locale          /** @type {HTMLElement} */          this._scrollContainer = querySelectorNotNull(document, '#keyboard-shortcuts-modal .modal-body'); -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          /** @type {Map<string, import('keyboard-shortcut-controller').ActionDetails>} */          this._actionDetails = new Map([              ['',                                 {scopes: new Set()}], @@ -70,7 +70,7 @@ export class KeyboardShortcutController {              ['scanTextAtCaret',                  {scopes: new Set(['web'])}],              ['toggleOption',                     {scopes: new Set(['popup', 'search']), argument: {template: 'hotkey-argument-setting-path', default: ''}}]          ]); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */      }      /** @type {import('./settings-controller.js').SettingsController} */ diff --git a/ext/js/pages/settings/popup-preview-frame.js b/ext/js/pages/settings/popup-preview-frame.js index e9cfa541..1ad4859b 100644 --- a/ext/js/pages/settings/popup-preview-frame.js +++ b/ext/js/pages/settings/popup-preview-frame.js @@ -59,7 +59,7 @@ export class PopupPreviewFrame {          /** @type {string} */          this._targetOrigin = chrome.runtime.getURL('/').replace(/\/$/, ''); -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          /** @type {Map<string, (params: import('core').SerializableObjectAny) => void>} */          this._windowMessageHandlers = new Map(/** @type {[key: string, handler: (params: import('core').SerializableObjectAny) => void][]} */ ([              ['PopupPreviewFrame.setText',              this._onSetText.bind(this)], @@ -67,7 +67,7 @@ export class PopupPreviewFrame {              ['PopupPreviewFrame.setCustomOuterCss',    this._setCustomOuterCss.bind(this)],              ['PopupPreviewFrame.updateOptionsContext', this._updateOptionsContext.bind(this)]          ])); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */      }      /** */ diff --git a/ext/js/pages/settings/profile-conditions-ui.js b/ext/js/pages/settings/profile-conditions-ui.js index d07751fb..5801af17 100644 --- a/ext/js/pages/settings/profile-conditions-ui.js +++ b/ext/js/pages/settings/profile-conditions-ui.js @@ -51,7 +51,7 @@ export class ProfileConditionsUI extends EventDispatcher {          const normalizeInteger = this._normalizeInteger.bind(this);          const validateFlags = this._validateFlags.bind(this);          const normalizeFlags = this._normalizeFlags.bind(this); -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          /** @type {Map<import('profile-conditions-ui').DescriptorType, import('profile-conditions-ui').Descriptor>} */          this._descriptors = new Map([              [ @@ -107,7 +107,7 @@ export class ProfileConditionsUI extends EventDispatcher {                  }              ]          ]); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */          /** @type {Set<string>} */          this._validFlags = new Set([              'clipboard' diff --git a/ext/js/templates/sandbox/anki-template-renderer.js b/ext/js/templates/sandbox/anki-template-renderer.js index 8ece8e24..135200da 100644 --- a/ext/js/templates/sandbox/anki-template-renderer.js +++ b/ext/js/templates/sandbox/anki-template-renderer.js @@ -68,7 +68,7 @@ export class AnkiTemplateRenderer {       * Prepares the data that is necessary before the template renderer can be safely used.       */      async prepare() { -        /* eslint-disable no-multi-spaces */ +        /* eslint-disable @stylistic/no-multi-spaces */          this._templateRenderer.registerHelpers([              ['dumpObject',       this._dumpObject.bind(this)],              ['furigana',         this._furigana.bind(this)], @@ -98,7 +98,7 @@ export class AnkiTemplateRenderer {              ['hiragana',         this._hiragana.bind(this)],              ['katakana',         this._katakana.bind(this)]          ]); -        /* eslint-enable no-multi-spaces */ +        /* eslint-enable @stylistic/no-multi-spaces */          this._templateRenderer.registerDataType('ankiNote', {              modifier: ({marker, commonData}) => createAnkiNoteData(marker, commonData),              composeData: ({marker}, commonData) => ({marker, commonData}) |