From bdaa77ff0d7c23f1594575ac22fb9693f1802b24 Mon Sep 17 00:00:00 2001 From: Cashew <52880648+Scrub1492@users.noreply.github.com> Date: Mon, 25 Dec 2023 17:13:34 +0900 Subject: Narrow down enum types (#431) * narrow down enum types * add enum types * change from default to case * add enum types * remove comments * remove comments * fix * Move getErrorLevelValue to Logger * Add enum type for LogErrorLevelValue * add eslint switch-exhaustiveness-check rule * Revert "add eslint switch-exhaustiveness-check" This reverts commit 49f9caabf0af900bc5ba2b80f5baff72c27e02cd. * move from labelled loop to helper functions * move helper functions downward --- ext/js/background/backend.js | 19 +- ext/js/core.js | 15 ++ ext/js/dom/dom-text-scanner.js | 227 ++++++++++++--------- ext/js/language/text-scanner.js | 12 +- .../pages/settings/dictionary-import-controller.js | 9 +- types/ext/dictionary-importer.d.ts | 25 ++- types/ext/dom-text-scanner.d.ts | 39 ++++ types/ext/log.d.ts | 11 + types/ext/text-scanner.d.ts | 13 ++ 9 files changed, 250 insertions(+), 120 deletions(-) create mode 100644 types/ext/dom-text-scanner.d.ts diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js index df4b9777..a4cf6949 100644 --- a/ext/js/background/backend.js +++ b/ext/js/background/backend.js @@ -342,8 +342,9 @@ export class Backend { * @param {{level: import('log').LogLevel}} params */ _onLog({level}) { - const levelValue = this._getErrorLevelValue(level); - if (levelValue <= this._getErrorLevelValue(this._logErrorLevel)) { return; } + const levelValue = log.getLogErrorLevelValue(level); + const currentLogErrorLevel = this._logErrorLevel !== null ? log.getLogErrorLevelValue(this._logErrorLevel) : 0; + if (levelValue <= currentLogErrorLevel) { return; } this._logErrorLevel = level; this._updateBadge(); @@ -1451,20 +1452,6 @@ export class Backend { return results; } - /** - * @param {?import('log').LogLevel} errorLevel - * @returns {number} - */ - _getErrorLevelValue(errorLevel) { - switch (errorLevel) { - case 'info': return 0; - case 'debug': return 0; - case 'warn': return 1; - case 'error': return 2; - default: return 0; - } - } - /** * @param {import('settings-modifications').OptionsScope} target * @returns {import('settings').Options|import('settings').ProfileOptions} diff --git a/ext/js/core.js b/ext/js/core.js index 9995ee5b..63c2f527 100644 --- a/ext/js/core.js +++ b/ext/js/core.js @@ -734,6 +734,21 @@ export class Logger extends EventDispatcher { error(error, context = null) { this.log(error, 'error', context); } + + /** + * @param {import('log').LogLevel} errorLevel + * @returns {import('log').LogErrorLevelValue} + */ + getLogErrorLevelValue(errorLevel) { + switch (errorLevel) { + case 'log': + case 'info': + case 'debug': + return 0; + case 'warn': return 1; + case 'error': return 2; + } + } } /** diff --git a/ext/js/dom/dom-text-scanner.js b/ext/js/dom/dom-text-scanner.js index df097688..6d979515 100644 --- a/ext/js/dom/dom-text-scanner.js +++ b/ext/js/dom/dom-text-scanner.js @@ -170,6 +170,7 @@ export class DOMTextScanner { const nodeValueLength = nodeValue.length; const {preserveNewlines, preserveWhitespace} = this._getWhitespaceSettings(textNode); + let done = false; let lineHasWhitespace = this._lineHasWhitespace; let lineHasContent = this._lineHasContent; let content = this._content; @@ -181,51 +182,11 @@ export class DOMTextScanner { const char = StringUtil.readCodePointsForward(nodeValue, offset, 1); offset += char.length; const charAttributes = DOMTextScanner.getCharacterAttributes(char, preserveNewlines, preserveWhitespace); + /** @type {import('dom-text-scanner').SeekTextNoteDetails} */ + const seekTextNoteDetails = {done, lineHasWhitespace, lineHasContent, content, offset, remainder, newlines}; - if (charAttributes === 0) { - // Character should be ignored - continue; - } else if (charAttributes === 1) { - // Character is collapsible whitespace - lineHasWhitespace = true; - } else { - // Character should be added to the content - if (newlines > 0) { - if (content.length > 0) { - const useNewlineCount = Math.min(remainder, newlines); - content += '\n'.repeat(useNewlineCount); - remainder -= useNewlineCount; - newlines -= useNewlineCount; - } else { - newlines = 0; - } - lineHasContent = false; - lineHasWhitespace = false; - if (remainder <= 0) { - offset -= char.length; // Revert character offset - break; - } - } - - lineHasContent = (charAttributes === 2); // 3 = character is a newline - - if (lineHasWhitespace) { - if (lineHasContent) { - content += ' '; - lineHasWhitespace = false; - if (--remainder <= 0) { - offset -= char.length; // Revert character offset - break; - } - } else { - lineHasWhitespace = false; - } - } - - content += char; - - if (--remainder <= 0) { break; } - } + ({done, lineHasWhitespace, lineHasContent, content, offset, remainder, newlines} = this._checkCharacterForward(char, charAttributes, seekTextNoteDetails)); + if (done) { break; } } this._lineHasWhitespace = lineHasWhitespace; @@ -256,6 +217,7 @@ export class DOMTextScanner { const nodeValueLength = nodeValue.length; const {preserveNewlines, preserveWhitespace} = this._getWhitespaceSettings(textNode); + let done = false; let lineHasWhitespace = this._lineHasWhitespace; let lineHasContent = this._lineHasContent; let content = this._content; @@ -268,50 +230,11 @@ export class DOMTextScanner { offset -= char.length; const charAttributes = DOMTextScanner.getCharacterAttributes(char, preserveNewlines, preserveWhitespace); - if (charAttributes === 0) { - // Character should be ignored - continue; - } else if (charAttributes === 1) { - // Character is collapsible whitespace - lineHasWhitespace = true; - } else { - // Character should be added to the content - if (newlines > 0) { - if (content.length > 0) { - const useNewlineCount = Math.min(remainder, newlines); - content = '\n'.repeat(useNewlineCount) + content; - remainder -= useNewlineCount; - newlines -= useNewlineCount; - } else { - newlines = 0; - } - lineHasContent = false; - lineHasWhitespace = false; - if (remainder <= 0) { - offset += char.length; // Revert character offset - break; - } - } - - lineHasContent = (charAttributes === 2); // 3 = character is a newline + /** @type {import('dom-text-scanner').SeekTextNoteDetails} */ + const seekTextNoteDetails = {done, lineHasWhitespace, lineHasContent, content, offset, remainder, newlines}; - if (lineHasWhitespace) { - if (lineHasContent) { - content = ' ' + content; - lineHasWhitespace = false; - if (--remainder <= 0) { - offset += char.length; // Revert character offset - break; - } - } else { - lineHasWhitespace = false; - } - } - - content = char + content; - - if (--remainder <= 0) { break; } - } + ({done, lineHasWhitespace, lineHasContent, content, offset, remainder, newlines} = this._checkCharacterBackward(char, charAttributes, seekTextNoteDetails)); + if (done) { break; } } this._lineHasWhitespace = lineHasWhitespace; @@ -350,6 +273,130 @@ export class DOMTextScanner { return {preserveNewlines: false, preserveWhitespace: false}; } + /** + * @param {string} char + * @param {import('dom-text-scanner').CharacterAttributesEnum} charAttributes + * @param {import('dom-text-scanner').SeekTextNoteDetails} seekTextNoteDetails + * @returns {import('dom-text-scanner').SeekTextNoteDetails} + */ + _checkCharacterForward(char, charAttributes, seekTextNoteDetails) { + let {done, lineHasWhitespace, lineHasContent, content, offset, remainder, newlines} = seekTextNoteDetails; + + switch (charAttributes) { + case 0: + break; + case 1: + lineHasWhitespace = true; + break; + case 2: + case 3: + if (newlines > 0) { + if (content.length > 0) { + const useNewlineCount = Math.min(remainder, newlines); + content += '\n'.repeat(useNewlineCount); + remainder -= useNewlineCount; + newlines -= useNewlineCount; + } else { + newlines = 0; + } + lineHasContent = false; + lineHasWhitespace = false; + if (remainder <= 0) { + offset -= char.length; // Revert character offset + done = true; + break; + } + } + + lineHasContent = (charAttributes === 2); // 3 = character is a newline + + if (lineHasWhitespace) { + if (lineHasContent) { + content += ' '; + lineHasWhitespace = false; + if (--remainder <= 0) { + offset -= char.length; // Revert character offset + done = true; + break; + } + } else { + lineHasWhitespace = false; + } + } + + content += char; + + if (--remainder <= 0) { + done = true; + break; + } + } + + return {done, lineHasWhitespace, lineHasContent, content, offset, remainder, newlines}; + } + + /** + * @param {string} char + * @param {import('dom-text-scanner').CharacterAttributesEnum} charAttributes + * @param {import('dom-text-scanner').SeekTextNoteDetails} seekTextNoteDetails + * @returns {import('dom-text-scanner').SeekTextNoteDetails} + */ + _checkCharacterBackward(char, charAttributes, seekTextNoteDetails) { + let {done, lineHasWhitespace, lineHasContent, content, offset, remainder, newlines} = seekTextNoteDetails; + + switch (charAttributes) { + case 0: + break; + case 1: + lineHasWhitespace = true; + break; + case 2: + case 3: + if (newlines > 0) { + if (content.length > 0) { + const useNewlineCount = Math.min(remainder, newlines); + content = '\n'.repeat(useNewlineCount) + content; + remainder -= useNewlineCount; + newlines -= useNewlineCount; + } else { + newlines = 0; + } + lineHasContent = false; + lineHasWhitespace = false; + if (remainder <= 0) { + offset += char.length; // Revert character offset + done = true; + break; + } + } + + lineHasContent = (charAttributes === 2); // 3 = character is a newline + + if (lineHasWhitespace) { + if (lineHasContent) { + content = ' ' + content; + lineHasWhitespace = false; + if (--remainder <= 0) { + offset += char.length; // Revert character offset + done = true; + break; + } + } else { + lineHasWhitespace = false; + } + } + + content = char + content; + + if (--remainder <= 0) { + done = true; + break; + } + } + + return {done, lineHasWhitespace, lineHasContent, content, offset, remainder, newlines}; + } + // Static helpers /** @@ -468,11 +515,7 @@ export class DOMTextScanner { * @param {string} character A string containing a single character. * @param {boolean} preserveNewlines Whether or not newlines should be preserved. * @param {boolean} preserveWhitespace Whether or not whitespace should be preserved. - * @returns {number} An integer representing the attributes of the character. - * 0: Character should be ignored. - * 1: Character is collapsible whitespace. - * 2: Character should be added to the content. - * 3: Character should be added to the content and is a newline. + * @returns {import('dom-text-scanner').CharacterAttributesEnum} An enum representing the attributes of the character. */ static getCharacterAttributes(character, preserveNewlines, preserveWhitespace) { switch (character.charCodeAt(0)) { diff --git a/ext/js/language/text-scanner.js b/ext/js/language/text-scanner.js index 800e3697..164e150e 100644 --- a/ext/js/language/text-scanner.js +++ b/ext/js/language/text-scanner.js @@ -137,8 +137,8 @@ export class TextScanner extends EventDispatcher { this._preventNextClick = false; /** @type {boolean} */ this._preventScroll = false; - /** @type {0|1|2|3} */ - this._penPointerState = 0; // 0 = not active; 1 = hovering; 2 = touching; 3 = hovering after touching + /** @type {import('text-scanner').PenPointerState} */ + this._penPointerState = 0; /** @type {Map} */ this._pointerIdTypeMap = new Map(); @@ -1382,13 +1382,13 @@ export class TextScanner extends EventDispatcher { return input.scanOnPenRelease; } switch (this._penPointerState) { - case 1: // hovering + case 1: return input.scanOnPenHover; - case 2: // touching + case 2: return input.scanOnPenMove; - case 3: // hovering after touching + case 3: return input.scanOnPenReleaseHover; - default: // not active + case 0: return false; } } diff --git a/ext/js/pages/settings/dictionary-import-controller.js b/ext/js/pages/settings/dictionary-import-controller.js index c478b265..79a62d32 100644 --- a/ext/js/pages/settings/dictionary-import-controller.js +++ b/ext/js/pages/settings/dictionary-import-controller.js @@ -161,6 +161,7 @@ export class DictionaryImportController { }; let statusPrefix = ''; + /** @type {import('dictionary-importer.js').ImportStep} */ let stepIndex = -2; /** @type {import('dictionary-worker').ImportProgressCallback} */ const onProgress = (data) => { @@ -178,8 +179,8 @@ export class DictionaryImportController { for (const label of statusLabels) { label.textContent = statusString; } switch (stepIndex2) { - case -2: // Initialize - case 5: // Data import + case -2: + case 5: this._triggerStorageChanged(); break; } @@ -210,11 +211,12 @@ export class DictionaryImportController { } /** - * @param {number} stepIndex + * @param {import('dictionary-importer').ImportStep} stepIndex * @returns {string} */ _getImportLabel(stepIndex) { switch (stepIndex) { + case -2: return ''; case -1: case 0: return 'Loading dictionary'; case 1: return 'Loading schemas'; @@ -222,7 +224,6 @@ export class DictionaryImportController { case 3: return 'Formatting data'; case 4: return 'Importing media'; case 5: return 'Importing data'; - default: return ''; } } diff --git a/types/ext/dictionary-importer.d.ts b/types/ext/dictionary-importer.d.ts index cccfdc42..cda1bd19 100644 --- a/types/ext/dictionary-importer.d.ts +++ b/types/ext/dictionary-importer.d.ts @@ -23,9 +23,30 @@ import type * as StructuredContent from './structured-content'; export type OnProgressCallback = (data: ProgressData) => void; +/** + * An enum representing the import step. + * + * `-2` `-1` Dictionary import is uninitialized. + * + * `0` Load dictionary archive and validate index step. + * + * `1` Load schemas and get archive files step. + * + * `2` Load and validate dictionary data step. + * + * `3` Format dictionary data and extended data support step. + * + * `4` Resolve async requirements and import media step. + * + * `5` Add dictionary descriptor and import data step. + */ +export type ImportStep = -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5; + +export type ImportStepCount = 6; + export type ProgressData = { - stepIndex: number; - stepCount: number; + stepIndex: ImportStep; + stepCount: ImportStepCount; index: number; count: number; }; diff --git a/types/ext/dom-text-scanner.d.ts b/types/ext/dom-text-scanner.d.ts new file mode 100644 index 00000000..e3ae4b53 --- /dev/null +++ b/types/ext/dom-text-scanner.d.ts @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 Yomitan 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 . + */ + +/** + * An enum representing the attributes of the character. + * + * `0` Character should be ignored. + * + * `1` Character is collapsible whitespace. + * + * `2` Character should be added to the content. + * + * `3` Character should be added to the content and is a newline. + */ +export type CharacterAttributesEnum = 0 | 1 | 2 | 3; + +export type SeekTextNoteDetails = { + done: boolean; + lineHasWhitespace: boolean; + lineHasContent: boolean; + content: string; + offset: number; + remainder: number; + newlines: number; +}; diff --git a/types/ext/log.d.ts b/types/ext/log.d.ts index ac2f606b..904bf848 100644 --- a/types/ext/log.d.ts +++ b/types/ext/log.d.ts @@ -22,3 +22,14 @@ export type LoggerEventType = 'log'; export type LogContext = { url: string; }; + +/** + * An enum representing the log error level. + * + * `0` _log_, _info_, _debug_ level. + * + * `1` _warn_ level. + * + * `2` _error_ level. + */ +export type LogErrorLevelValue = 0 | 1 | 2; diff --git a/types/ext/text-scanner.d.ts b/types/ext/text-scanner.d.ts index 5b806dab..d56d623a 100644 --- a/types/ext/text-scanner.d.ts +++ b/types/ext/text-scanner.d.ts @@ -185,6 +185,19 @@ export type PointerEventType = ( 'script' ); +/** + * An enum representing the pen pointer state. + * + * `0` Not active. + * + * `1` Hovering. + * + * `2` Touching. + * + * `3` Hovering after touching. + */ +export type PenPointerState = 0 | 1 | 2 | 3; + export type SentenceTerminatorMap = Map; export type SentenceForwardQuoteMap = Map; -- cgit v1.2.3