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