diff options
39 files changed, 267 insertions, 117 deletions
diff --git a/.eslintrc.json b/.eslintrc.json index 5b6ebd05..32bbdaec 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,8 +3,7 @@ "extends": [ "eslint:recommended", "plugin:jsonc/recommended-with-json", - "plugin:eslint-comments/recommended", - "plugin:@typescript-eslint/recommended" + "plugin:eslint-comments/recommended" ], "parser": "@typescript-eslint/parser", "parserOptions": { @@ -76,34 +75,84 @@ "prefer-const": ["error", {"destructuring": "all"}], "require-atomic-updates": "off", + "@stylistic/array-bracket-newline": ["error", "consistent"], "@stylistic/array-bracket-spacing": ["error", "never"], + "@stylistic/array-element-newline": ["error", "consistent"], "@stylistic/arrow-parens": ["error", "always"], "@stylistic/arrow-spacing": ["error", {"before": true, "after": true}], "@stylistic/block-spacing": ["error", "always"], "@stylistic/brace-style": ["error", "1tbs", {"allowSingleLine": true}], "@stylistic/comma-dangle": ["error", "never"], "@stylistic/comma-spacing": ["error", {"before": false, "after": true}], + "@stylistic/comma-style": ["error", "last"], "@stylistic/computed-property-spacing": ["error", "never"], + "@stylistic/dot-location": ["error", "property"], "@stylistic/eol-last": ["error", "always"], "@stylistic/func-call-spacing": ["error", "never"], + "@stylistic/function-call-argument-newline": ["error", "consistent"], + "@stylistic/function-call-spacing": ["error", "never"], "@stylistic/function-paren-newline": ["error", "multiline-arguments"], "@stylistic/generator-star-spacing": ["error", "before"], + "@stylistic/implicit-arrow-linebreak": ["error", "beside"], "@stylistic/indent": ["error", 4, {"SwitchCase": 1, "MemberExpression": 1, "flatTernaryExpressions": true, "ignoredNodes": ["ConditionalExpression"]}], + "@stylistic/indent-binary-ops": ["error", 0], "@stylistic/key-spacing": ["error", {"beforeColon": false, "afterColon": true, "mode": "strict"}], "@stylistic/keyword-spacing": ["error", {"before": true, "after": true}], + "@stylistic/linebreak-style": ["error", "unix"], + "@stylistic/lines-around-comment": "off", + "@stylistic/lines-between-class-members": ["error", "always", {"exceptAfterSingleLine": true}], + "@stylistic/max-len": "off", + "@stylistic/max-statements-per-line": ["error", {"max": 2}], + "@stylistic/member-delimiter-style": [ + "error", + { + "multiline": {"delimiter": "semi", "requireLast": true}, + "singleline": {"delimiter": "comma", "requireLast": false}, + "multilineDetection": "brackets" + } + ], + "@stylistic/multiline-ternary": ["error", "always-multiline"], "@stylistic/new-parens": "error", + "@stylistic/newline-per-chained-call": ["error", {"ignoreChainWithDepth": 3}], + "@stylistic/no-confusing-arrow": "error", + "@stylistic/no-extra-parens": "off", + "@stylistic/no-extra-semi": "error", + "@stylistic/no-floating-decimal": "error", + "@stylistic/no-mixed-operators": ["error", {"allowSamePrecedence": true, "groups": [["&&", "||"]]}], + "@stylistic/no-mixed-spaces-and-tabs": "error", "@stylistic/no-multi-spaces": "error", - "@stylistic/no-multiple-empty-lines": ["error", {"max": 2}], + "@stylistic/no-multiple-empty-lines": ["error", {"max": 2, "maxEOF": 0, "maxBOF": 0}], + "@stylistic/no-tabs": "error", "@stylistic/no-trailing-spaces": "error", "@stylistic/no-whitespace-before-property": "error", + "@stylistic/nonblock-statement-body-position": ["error", "beside"], "@stylistic/object-curly-newline": "error", "@stylistic/object-curly-spacing": ["error", "never"], + "@stylistic/object-property-newline": ["error", {"allowAllPropertiesOnSameLine": true}], + "@stylistic/one-var-declaration-per-line": ["error", "initializations"], + "@stylistic/operator-linebreak": ["error", "after"], "@stylistic/padded-blocks": ["error", "never"], - "@stylistic/quote-props": ["error", "consistent"], + "@stylistic/padding-line-between-statements": [ + "error", + {"blankLine": "always", "prev": "*", "next": "import"}, + {"blankLine": "always", "prev": "import", "next": "*"}, + {"blankLine": "always", "prev": "*", "next": "export"}, + {"blankLine": "always", "prev": "import", "next": "let"}, + {"blankLine": "always", "prev": "import", "next": "const"}, + {"blankLine": "always", "prev": "export", "next": "let"}, + {"blankLine": "always", "prev": "export", "next": "const"}, + {"blankLine": "always", "prev": "export", "next": "export"}, + {"blankLine": "always", "prev": "export", "next": "type"}, + {"blankLine": "always", "prev": "type", "next": "export"}, + {"blankLine": "always", "prev": "type", "next": "type"}, + {"blankLine": "never", "prev": "import", "next": "import"} + ], + "@stylistic/quote-props": ["error", "consistent-as-needed", {"numbers": true}], "@stylistic/quotes": ["error", "single", "avoid-escape"], "@stylistic/rest-spread-spacing": ["error", "never"], "@stylistic/semi": "error", "@stylistic/semi-spacing": ["error", {"before": false, "after": true}], + "@stylistic/semi-style": ["error", "last"], "@stylistic/space-before-blocks": ["error", "always"], "@stylistic/space-before-function-paren": ["error", {"anonymous": "never", "named": "never", "asyncArrow": "always"}], "@stylistic/space-in-parens": ["error", "never"], @@ -113,7 +162,21 @@ "@stylistic/switch-colon-spacing": ["error", {"after": true, "before": false}], "@stylistic/template-curly-spacing": ["error", "never"], "@stylistic/template-tag-spacing": ["error", "never"], + "@stylistic/type-annotation-spacing": [ + "error", + { + "before": false, + "after": true, + "overrides": { + "arrow": {"before": true, "after": true} + } + } + ], + "@stylistic/type-generic-spacing": "error", + "@stylistic/type-named-tuple-spacing": "error", "@stylistic/wrap-iife": ["error", "inside"], + "@stylistic/wrap-regex": "off", + "@stylistic/yield-star-spacing": ["error", {"before": true, "after": false}], "no-unsanitized/method": "error", "no-unsanitized/property": "error", @@ -184,29 +247,44 @@ "eslint-comments/no-unused-disable": "error", - "unused-imports/no-unused-imports": "error", - - "@typescript-eslint/ban-ts-comment": ["error", {"ts-expect-error": {"descriptionFormat": "^ - .+$"}}], - "@typescript-eslint/ban-types": ["error", {"types": {"object": true}, "extendDefaults": true}], - "@typescript-eslint/consistent-type-exports": "off", - "@typescript-eslint/no-explicit-any": "error", - "@typescript-eslint/no-shadow": ["error", {"builtinGlobals": false}], - "@typescript-eslint/no-this-alias": "error", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-var-requires": "off" + "unused-imports/no-unused-imports": "error" }, "overrides": [ { "files": [ + "*.js", "*.ts" ], + "extends": [ + "plugin:@typescript-eslint/recommended-type-checked" + ], "rules": { - "no-undef": "off", - - "@typescript-eslint/no-unused-vars": ["error", {"vars": "local", "args": "after-used", "argsIgnorePattern": "^_", "caughtErrors": "none"}], + "@typescript-eslint/no-floating-promises": "off", + "@typescript-eslint/no-misused-promises": "off", + "@typescript-eslint/no-redundant-type-constituents": "off", + "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-enum-comparison": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/require-await": "off", + "@typescript-eslint/restrict-template-expressions": "off", + "@typescript-eslint/ban-ts-comment": ["error", {"ts-expect-error": {"descriptionFormat": "^ - .+$"}}], + "@typescript-eslint/ban-types": ["error", {"types": {"object": true}, "extendDefaults": true}], + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-shadow": ["error", {"builtinGlobals": false}], + "@typescript-eslint/no-this-alias": "error", + "@typescript-eslint/no-unused-vars": ["error", {"vars": "local", "args": "after-used", "argsIgnorePattern": "^_", "caughtErrors": "none"}] + } + }, + { + "files": [ + "*.ts" + ], + "rules": { "@stylistic/block-spacing": "off", - "@stylistic/brace-style": ["error", "1tbs", {"allowSingleLine": true}], "@stylistic/comma-dangle": [ "error", { @@ -220,32 +298,9 @@ "tuples": "always-multiline" } ], - "@stylistic/comma-spacing": ["error", {"before": false, "after": true}], - "@stylistic/function-call-spacing": ["error", "never"], - "@stylistic/indent": ["error", 4], - "@stylistic/key-spacing": ["error", {"beforeColon": false, "afterColon": true, "mode": "strict"}], - "@stylistic/keyword-spacing": ["error", {"before": true, "after": true}], - "@stylistic/lines-around-comment": "off", - "@stylistic/lines-between-class-members": ["error", "always"], - "@stylistic/member-delimiter-style": [ - "error", - { - "multiline": {"delimiter": "semi", "requireLast": true}, - "singleline": {"delimiter": "comma", "requireLast": false}, - "multilineDetection": "brackets" - } - ], - "@stylistic/no-multiple-empty-lines": ["error", {"max": 1, "maxEOF": 0}], - "@stylistic/no-extra-parens": ["error", "all"], - "@stylistic/no-extra-semi": "error", - "@stylistic/object-curly-spacing": ["error", "never"], - "@stylistic/padding-line-between-statements": "off", - "@stylistic/quotes": ["error", "single", "avoid-escape"], - "@stylistic/semi": "error", - "@stylistic/space-before-blocks": ["error", "always"], - "@stylistic/space-before-function-paren": ["error", {"anonymous": "never", "named": "never", "asyncArrow": "always"}], - "@stylistic/space-infix-ops": "error", - "@stylistic/type-annotation-spacing": "error" + "@stylistic/indent-binary-ops": "off", + "@stylistic/no-multiple-empty-lines": ["error", {"max": 1, "maxEOF": 0, "maxBOF": 0}], + "@stylistic/no-extra-parens": ["error", "all"] } }, { diff --git a/dev/bin/build.js b/dev/bin/build.js index 190964d5..bc0a8cb8 100644 --- a/dev/bin/build.js +++ b/dev/bin/build.js @@ -23,10 +23,10 @@ import JSZip from 'jszip'; import {fileURLToPath} from 'node:url'; import path from 'path'; import readline from 'readline'; +import {parseArgs} from 'util'; import {buildLibs} from '../build-libs.js'; import {ManifestUtil} from '../manifest-util.js'; import {getAllFiles, testMain} from '../util.js'; -import {parseArgs} from 'util'; const dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -267,7 +267,8 @@ export async function main(argv) { await buildLibs(); const variantNames = /** @type {string[]} */ (( argv.length === 0 || args.all ? - manifestUtil.getVariants().filter(({buildable}) => buildable !== false).map(({name}) => name) : [] + manifestUtil.getVariants().filter(({buildable}) => buildable !== false).map(({name}) => name) : + [] )); await build(buildDir, extDir, manifestUtil, variantNames, manifestPath, dryRun, dryRunBuildZip, yomitanVersion); } finally { diff --git a/dev/generate-css-json.js b/dev/generate-css-json.js index b196e411..26bdfa64 100644 --- a/dev/generate-css-json.js +++ b/dev/generate-css-json.js @@ -151,7 +151,10 @@ export function generateRules(cssFilePath, overridesCssFilePath) { const styles = []; if (typeof declarations !== 'undefined') { for (const declaration of declarations) { - if (declaration.type !== 'declaration') { console.log(declaration); continue; } + if (declaration.type !== 'declaration') { + console.log(declaration); + continue; + } const {property, value} = /** @type {css.Declaration} */ (declaration); if (typeof property !== 'string' || typeof value !== 'string') { continue; } styles.push([property, value]); diff --git a/dev/lib/dexie.js b/dev/lib/dexie.js index 834260e0..ffbd2923 100644 --- a/dev/lib/dexie.js +++ b/dev/lib/dexie.js @@ -14,6 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ + import Dexie from 'dexie'; import 'dexie-export-import'; diff --git a/dev/lib/parse5.js b/dev/lib/parse5.js index 03249db4..ce92730d 100644 --- a/dev/lib/parse5.js +++ b/dev/lib/parse5.js @@ -14,4 +14,5 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ + export * from 'parse5'; diff --git a/dev/lib/ucs2length.js b/dev/lib/ucs2length.js index ce9027de..7ca3c545 100644 --- a/dev/lib/ucs2length.js +++ b/dev/lib/ucs2length.js @@ -14,7 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ + import ucs2length from 'ajv/dist/runtime/ucs2length.js'; + const ucs2length2 = ucs2length.default; -export {ucs2length2 as ucs2length}; +export {ucs2length2 as ucs2length}; diff --git a/dev/lib/wanakana.js b/dev/lib/wanakana.js index b2679cec..24cf63ab 100644 --- a/dev/lib/wanakana.js +++ b/dev/lib/wanakana.js @@ -14,4 +14,5 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ + export * from 'wanakana'; diff --git a/dev/lib/z-worker.js b/dev/lib/z-worker.js index 142ed8fc..4e5fe318 100644 --- a/dev/lib/z-worker.js +++ b/dev/lib/z-worker.js @@ -14,4 +14,5 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ + import '../../node_modules/@zip.js/zip.js/lib/z-worker.js'; diff --git a/dev/lib/zip.js b/dev/lib/zip.js index 007b4285..62d0784c 100644 --- a/dev/lib/zip.js +++ b/dev/lib/zip.js @@ -14,4 +14,5 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ + export * from '@zip.js/zip.js/lib/zip.js'; diff --git a/dev/manifest-util.js b/dev/manifest-util.js index 6ab81790..741f8b31 100644 --- a/dev/manifest-util.js +++ b/dev/manifest-util.js @@ -342,4 +342,3 @@ export class ManifestUtil { return modifiedManifest; } } - diff --git a/ext/data/language/japanese-transforms.json b/ext/data/language/japanese-transforms.json index b3a00a73..b1f39cbc 100644 --- a/ext/data/language/japanese-transforms.json +++ b/ext/data/language/japanese-transforms.json @@ -1010,4 +1010,3 @@ } ] } - diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js index 909faf29..8b5e8383 100644 --- a/ext/js/background/backend.js +++ b/ext/js/background/backend.js @@ -2480,7 +2480,7 @@ export class Backend { chrome.storage.session.get(['openedWelcomePage']).then((result) => { if (!result.openedWelcomePage) { this._openWelcomeGuidePage(); - chrome.storage.session.set({'openedWelcomePage': true}); + chrome.storage.session.set({openedWelcomePage: true}); } }); } diff --git a/ext/js/comm/cross-frame-api.js b/ext/js/comm/cross-frame-api.js index 8fbee20c..4b4e9419 100644 --- a/ext/js/comm/cross-frame-api.js +++ b/ext/js/comm/cross-frame-api.js @@ -410,6 +410,7 @@ export class CrossFrameAPI { } return await this._createCommPort(otherTabId, otherFrameId); } + /** * @param {number} otherTabId * @param {number} otherFrameId diff --git a/ext/js/core/logger.js b/ext/js/core/logger.js index 165e1ae2..6cf1cc1f 100644 --- a/ext/js/core/logger.js +++ b/ext/js/core/logger.js @@ -59,6 +59,7 @@ export class Logger extends EventDispatcher { } else { errorString = ( typeof error === 'object' && error !== null ? + // eslint-disable-next-line @typescript-eslint/no-base-to-string error.toString() : `${error}` ); diff --git a/ext/js/data/json-schema.js b/ext/js/data/json-schema.js index 9b7ea011..3342e387 100644 --- a/ext/js/data/json-schema.js +++ b/ext/js/data/json-schema.js @@ -805,7 +805,7 @@ export class JsonSchema { const {type: schemaType, const: schemaConst, enum: schemaEnum} = schema; const type = this._getValueType(value); if (!this._isValueTypeAny(value, type, schemaType)) { - throw this._createError(`Value type ${type} does not match schema type ${schemaType}`); + throw this._createError(`Value type ${type} does not match schema type ${Array.isArray(schemaType) ? schemaType.join(',') : schemaType}`); } if (typeof schemaConst !== 'undefined' && !this._valuesAreEqual(value, schemaConst)) { diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js index d93927a7..2ecd5527 100644 --- a/ext/js/data/options-util.js +++ b/ext/js/data/options-util.js @@ -46,7 +46,8 @@ export class OptionsUtil { // Invalid options let options = /** @type {{[key: string]: unknown}} */ ( typeof optionsInput === 'object' && optionsInput !== null && !Array.isArray(optionsInput) ? - optionsInput : {} + optionsInput : + {} ); // Check for legacy options @@ -495,6 +496,7 @@ export class OptionsUtil { * @returns {import('options-util').UpdateFunction[]} */ _getVersionUpdates(targetVersion) { + /* eslint-disable @typescript-eslint/unbound-method */ const result = [ this._updateVersion1, this._updateVersion2, @@ -521,6 +523,7 @@ export class OptionsUtil { this._updateVersion23, this._updateVersion24 ]; + /* eslint-enable @typescript-eslint/unbound-method */ if (typeof targetVersion === 'number' && targetVersion < result.length) { result.splice(targetVersion); } @@ -1090,9 +1093,9 @@ export class OptionsUtil { } if (customTemplates && isObject(chrome.storage)) { - chrome.storage.session.set({'needsCustomTemplatesWarning': true}); + chrome.storage.session.set({needsCustomTemplatesWarning: true}); await this._createTab(chrome.runtime.getURL('/welcome.html')); - chrome.storage.session.set({'openedWelcomePage': true}); + chrome.storage.session.set({openedWelcomePage: true}); } } diff --git a/ext/js/dictionary/dictionary-database.js b/ext/js/dictionary/dictionary-database.js index 1c52b7ab..6c7de339 100644 --- a/ext/js/dictionary/dictionary-database.js +++ b/ext/js/dictionary/dictionary-database.js @@ -37,7 +37,10 @@ export class DictionaryDatabase { /** @type {import('dictionary-database').CreateQuery<string>} */ this._createBoundQuery1 = (item) => IDBKeyRange.bound(item, `${item}\uffff`, false, false); /** @type {import('dictionary-database').CreateQuery<string>} */ - this._createBoundQuery2 = (item) => { item = stringReverse(item); return IDBKeyRange.bound(item, `${item}\uffff`, false, false); }; + this._createBoundQuery2 = (item) => { + item = stringReverse(item); + return IDBKeyRange.bound(item, `${item}\uffff`, false, false); + }; /** @type {import('dictionary-database').CreateResult<import('dictionary-database').TermExactRequest, import('dictionary-database').DatabaseTermEntryWithId, import('dictionary-database').TermEntry>} */ this._createTermBind1 = this._createTermExact.bind(this); /** @type {import('dictionary-database').CreateResult<import('dictionary-database').DictionaryAndQueryRequest, import('dictionary-database').DatabaseTermEntryWithId, import('dictionary-database').TermEntry>} */ diff --git a/ext/js/display/display-audio.js b/ext/js/display/display-audio.js index deaa0976..7d75d6b0 100644 --- a/ext/js/display/display-audio.js +++ b/ext/js/display/display-audio.js @@ -514,8 +514,10 @@ export class DisplayAudio { !canToggleOff || primaryCardAudio === null || primaryCardAudio.index !== index || - primaryCardAudio.subIndex !== subIndex - ) ? {index: index, subIndex} : null; + primaryCardAudio.subIndex !== subIndex ? + {index: index, subIndex} : + null + ); cacheEntry.primaryCardAudio = primaryCardAudio; if (menu !== null) { diff --git a/ext/js/display/display.js b/ext/js/display/display.js index f05feac8..a5dad2d1 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -806,8 +806,10 @@ export class Display extends EventDispatcher { const historyMode = ( eventType === 'click' || !(typeof historyState === 'object' && historyState !== null) || - historyState.cause !== 'queryParser' - ) ? 'new' : 'overwrite'; + historyState.cause !== 'queryParser' ? + 'new' : + 'overwrite' + ); /** @type {import('display').ContentDetails} */ const details = { focus: false, diff --git a/ext/js/pages/action-popup-main.js b/ext/js/pages/action-popup-main.js index e5738878..b5728215 100644 --- a/ext/js/pages/action-popup-main.js +++ b/ext/js/pages/action-popup-main.js @@ -50,7 +50,8 @@ class DisplayController { typeof manifest.options_ui === 'object' && manifest.options_ui !== null && typeof manifest.options_ui.page === 'string' ? - manifest.options_ui.page : '' + manifest.options_ui.page : + '' ); this._setupButtonEvents('.action-open-settings', 'openSettingsPage', chrome.runtime.getURL(optionsPageUrl)); this._setupButtonEvents('.action-open-permissions', null, chrome.runtime.getURL('/permissions.html')); diff --git a/ext/js/pages/settings/backup-controller.js b/ext/js/pages/settings/backup-controller.js index 79733c4d..59bcaed9 100644 --- a/ext/js/pages/settings/backup-controller.js +++ b/ext/js/pages/settings/backup-controller.js @@ -579,7 +579,9 @@ export class BackupController { */ async _exportDatabase(databaseName) { const db = await new Dexie(databaseName).open(); - const blob = await db.export({progressCallback: this._databaseExportProgressCallback}); + const blob = await db.export({ + progressCallback: this._databaseExportProgressCallback.bind(this) + }); await db.close(); return blob; } @@ -639,12 +641,14 @@ export class BackupController { } /** - * @param {string} databaseName + * @param {string} _databaseName * @param {File} file */ - async _importDatabase(databaseName, file) { + async _importDatabase(_databaseName, file) { await this._settingsController.application.api.purgeDatabase(); - await Dexie.import(file, {progressCallback: this._databaseImportProgressCallback}); + await Dexie.import(file, { + progressCallback: this._databaseImportProgressCallback.bind(this) + }); this._settingsController.application.api.triggerDatabaseUpdated('dictionary', 'import'); this._settingsController.application.triggerStorageChanged(); } diff --git a/ext/js/pages/settings/profile-controller.js b/ext/js/pages/settings/profile-controller.js index c5ccbe7d..5a7b5ed4 100644 --- a/ext/js/pages/settings/profile-controller.js +++ b/ext/js/pages/settings/profile-controller.js @@ -549,7 +549,8 @@ export class ProfileController { Number.isFinite(intValue) && intValue >= 0 && intValue < this.profileCount ? - intValue : null + intValue : + null ); } diff --git a/ext/js/pages/welcome-main.js b/ext/js/pages/welcome-main.js index 82afaacb..9990b4e7 100644 --- a/ext/js/pages/welcome-main.js +++ b/ext/js/pages/welcome-main.js @@ -63,7 +63,7 @@ await Application.main(async (application) => { setupEnvironmentInfo(application.api); - chrome.storage.session.get({'needsCustomTemplatesWarning': false}).then((result) => { + chrome.storage.session.get({needsCustomTemplatesWarning: false}).then((result) => { if (result.needsCustomTemplatesWarning) { document.documentElement.dataset.warnCustomTemplates = 'true'; chrome.storage.session.remove(['needsCustomTemplatesWarning']); diff --git a/ext/js/templates/sandbox/anki-template-renderer.js b/ext/js/templates/sandbox/anki-template-renderer.js index 135200da..2320a0b1 100644 --- a/ext/js/templates/sandbox/anki-template-renderer.js +++ b/ext/js/templates/sandbox/anki-template-renderer.js @@ -279,7 +279,10 @@ export class AnkiTemplateRenderer { const regex = new RegExp(pattern, typeof flags === 'string' ? flags : ''); /** @type {string[]} */ const parts = []; - value.replace(regex, (g0) => { parts.push(g0); return g0; }); + value.replace(regex, (g0) => { + parts.push(g0); + return g0; + }); value = parts.join(''); } catch (e) { return `${e}`; @@ -531,6 +534,7 @@ export class AnkiTemplateRenderer { _concat(args) { let result = ''; for (let i = 0, ii = args.length; i < ii; ++i) { + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands result += args[i]; } return result; diff --git a/ext/js/templates/template-renderer-proxy.js b/ext/js/templates/template-renderer-proxy.js index e4814ec4..c1f5a5bf 100644 --- a/ext/js/templates/template-renderer-proxy.js +++ b/ext/js/templates/template-renderer-proxy.js @@ -16,8 +16,8 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import {generateId} from '../core/utilities.js'; import {ExtensionError} from '../core/extension-error.js'; +import {generateId} from '../core/utilities.js'; export class TemplateRendererProxy { constructor() { @@ -220,10 +220,14 @@ export class TemplateRendererProxy { } }; - let timer = (typeof timeout === 'number' ? setTimeout(() => { - cleanup(); - reject(new Error('Timeout')); - }, timeout) : null); + let timer = ( + typeof timeout === 'number' ? + setTimeout(() => { + cleanup(); + reject(new Error('Timeout')); + }, timeout) : + null + ); this._invocations.add(invocation); diff --git a/playwright.config.js b/playwright.config.js index a13eb710..4cd94b6b 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -14,9 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ + // @ts-check import {defineConfig, devices} from '@playwright/test'; - /** * Read environment variables from file. * https://github.com/motdotla/dotenv @@ -116,4 +116,3 @@ export default defineConfig({ // port: 3000, // }, }); - diff --git a/test/core.test.js b/test/core.test.js index 0ddcc2d1..7e19d04d 100644 --- a/test/core.test.js +++ b/test/core.test.js @@ -269,8 +269,16 @@ function testDeepEqual() { /** @type {import('test/core').DeepEqualTestData} */ const recursiveTestsData = [ { - value1: (() => { const x = {}; x.x = x; return x; })(), - value2: (() => { const x = {}; x.x = x; return x; })(), + value1: (() => { + const x = {}; + x.x = x; + return x; + })(), + value2: (() => { + const x = {}; + x.x = x; + return x; + })(), expected: false } ]; diff --git a/test/fixtures/dom-test.js b/test/fixtures/dom-test.js index a0a17127..578b1324 100644 --- a/test/fixtures/dom-test.js +++ b/test/fixtures/dom-test.js @@ -43,10 +43,13 @@ function prepareWindow(window) { export async function setupDomTest(htmlFilePath) { const html = typeof htmlFilePath === 'string' ? fs.readFileSync(htmlFilePath, {encoding: 'utf8'}) : '<!DOCTYPE html>'; const env = builtinEnvironments.jsdom; - const {teardown} = await env.setup(global, {jsdom: {html}}); + const environment = await env.setup(global, {jsdom: {html}}); const window = /** @type {import('jsdom').DOMWindow} */ (/** @type {unknown} */ (global.window)); prepareWindow(window); - return {window, teardown}; + return { + window, + teardown: (global) => environment.teardown(global) + }; } /** @@ -59,13 +62,13 @@ export function createDomTest(htmlFilePath) { // eslint-disable-next-line no-empty-pattern window: async ({}, use) => { const env = builtinEnvironments.jsdom; - const {teardown} = await env.setup(global, {jsdom: {html}}); + const environment = await env.setup(global, {jsdom: {html}}); const window = /** @type {import('jsdom').DOMWindow} */ (/** @type {unknown} */ (global.window)); prepareWindow(window); try { await use(window); } finally { - teardown(global); + environment.teardown(global); } } }); diff --git a/test/hotkey-util.test.js b/test/hotkey-util.test.js index bf1124a5..01a2b536 100644 --- a/test/hotkey-util.test.js +++ b/test/hotkey-util.test.js @@ -160,7 +160,7 @@ function testSortModifiers() { const hotkeyUtil = new HotkeyUtil(); for (const {modifiers, expected} of data) { - test(`[${modifiers}] -> [${expected}]`, () => { + test(`[${modifiers.join(',')}] -> [${expected.join(',')}]`, () => { const modifiers2 = hotkeyUtil.sortModifiers(modifiers); expect(modifiers2).toStrictEqual(modifiers); expect(modifiers2).toStrictEqual(expected); diff --git a/test/json-schema.test.js b/test/json-schema.test.js index ab2c0c65..af4b7acd 100644 --- a/test/json-schema.test.js +++ b/test/json-schema.test.js @@ -520,7 +520,7 @@ function testValidate2() { /* eslint-enable @stylistic/no-multi-spaces */ describe.each(data)('Schema %#', ({schema, inputs}) => { - test.each(inputs)(`schemaValidate(${schema}, $value) -> $expected`, ({expected, value}) => { + test.each(inputs)(`schemaValidate(${JSON.stringify(schema)}, $value) -> $expected`, ({expected, value}) => { const actual = schemaValidate(schema, value); expect(actual).toStrictEqual(expected); }); @@ -878,7 +878,7 @@ function testGetValidValueOrDefault1() { ]; describe.each(data)('Schema %#', ({schema, inputs}) => { - test.each(inputs)(`getValidValueOrDefault(${schema}, %o) -> %o`, (value, expected) => { + test.each(inputs)(`getValidValueOrDefault(${JSON.stringify(schema)}, %o) -> %o`, (value, expected) => { const actual = getValidValueOrDefault(schema, value); expect(actual).toStrictEqual(expected); }); @@ -985,11 +985,15 @@ function testProxy1() { {error: true, value: ['default'], action: (value) => { value[0] = null; }}, {error: false, value: ['default'], action: (value) => { delete value[0]; }}, {error: false, value: ['default'], action: (value) => { value[1] = 'string'; }}, - {error: false, value: ['default'], action: (value) => { - value[1] = 'string'; - if (value.length !== 2) { throw new Error(`Invalid length; expected=2; actual=${value.length}`); } - if (typeof value.push !== 'function') { throw new Error(`Invalid push; expected=function; actual=${typeof value.push}`); } - }} + { + error: false, + value: ['default'], + action: (value) => { + value[1] = 'string'; + if (value.length !== 2) { throw new Error(`Invalid length; expected=2; actual=${value.length}`); } + if (typeof value.push !== 'function') { throw new Error(`Invalid push; expected=function; actual=${typeof value.push}`); } + } + } ] }, diff --git a/test/playwright/playwright-util.js b/test/playwright/playwright-util.js index bf171251..b364c80b 100644 --- a/test/playwright/playwright-util.js +++ b/test/playwright/playwright-util.js @@ -20,6 +20,7 @@ import path from 'path'; import {fileURLToPath} from 'url'; const dirname = path.dirname(fileURLToPath(import.meta.url)); + export const root = path.join(dirname, '..', '..'); export const test = base.extend({ @@ -47,6 +48,7 @@ export const test = base.extend({ await use(extensionId); } }); + export const expect = test.expect; export const mockModelFieldNames = [ @@ -58,10 +60,10 @@ export const mockModelFieldNames = [ /** @type {{[key: string]: string|undefined}} */ export const mockModelFieldsToAnkiValues = { - 'Word': '{expression}', - 'Reading': '{furigana-plain}', - 'Sentence': '{clipboard-text}', - 'Audio': '{audio}' + Word: '{expression}', + Reading: '{furigana-plain}', + Sentence: '{clipboard-text}', + Audio: '{audio}' }; /** @@ -87,23 +89,30 @@ export const writeToClipboardFromPage = async (page, text) => { }; export const expectedAddNoteBody = { - 'action': 'addNote', - 'params': - { - 'note': { - 'fields': { - 'Word': '読む', 'Reading': '読[よ]む', 'Audio': '[sound:mock_audio.mp3]', 'Sentence': '読むの例文' + version: 2, + action: 'addNote', + params: { + note: { + fields: { + Word: '読む', + Reading: '読[よ]む', + Audio: '[sound:mock_audio.mp3]', + Sentence: '読むの例文' }, - 'tags': ['yomitan'], - 'deckName': 'Mock Deck', - 'modelName': 'Mock Model', - 'options': { - 'allowDuplicate': false, 'duplicateScope': 'collection', 'duplicateScopeOptions': { - 'deckName': null, 'checkChildren': false, 'checkAllModels': false + tags: ['yomitan'], + deckName: 'Mock Deck', + modelName: 'Mock Model', + options: { + allowDuplicate: false, + duplicateScope: 'collection', + duplicateScopeOptions: { + deckName: null, + checkChildren: false, + checkAllModels: false } } } - }, 'version': 2 + } }; const baseAnkiResp = { @@ -113,11 +122,11 @@ const baseAnkiResp = { /** @type {{[key: string]: import('core').SerializableObject}} */ const ankiRouteResponses = { - 'version': Object.assign({body: JSON.stringify(6)}, baseAnkiResp), - 'deckNames': Object.assign({body: JSON.stringify(['Mock Deck'])}, baseAnkiResp), - 'modelNames': Object.assign({body: JSON.stringify(['Mock Model'])}, baseAnkiResp), - 'modelFieldNames': Object.assign({body: JSON.stringify(mockModelFieldNames)}, baseAnkiResp), - 'canAddNotes': Object.assign({body: JSON.stringify([true, true])}, baseAnkiResp), - 'storeMediaFile': Object.assign({body: JSON.stringify('mock_audio.mp3')}, baseAnkiResp), - 'addNote': Object.assign({body: JSON.stringify(102312488912)}, baseAnkiResp) + version: Object.assign({body: JSON.stringify(6)}, baseAnkiResp), + deckNames: Object.assign({body: JSON.stringify(['Mock Deck'])}, baseAnkiResp), + modelNames: Object.assign({body: JSON.stringify(['Mock Model'])}, baseAnkiResp), + modelFieldNames: Object.assign({body: JSON.stringify(mockModelFieldNames)}, baseAnkiResp), + canAddNotes: Object.assign({body: JSON.stringify([true, true])}, baseAnkiResp), + storeMediaFile: Object.assign({body: JSON.stringify('mock_audio.mp3')}, baseAnkiResp), + addNote: Object.assign({body: JSON.stringify(102312488912)}, baseAnkiResp) }; diff --git a/types/ext/backend.d.ts b/types/ext/backend.d.ts index ce973630..a832e434 100644 --- a/types/ext/backend.d.ts +++ b/types/ext/backend.d.ts @@ -18,6 +18,7 @@ import type * as Api from './api'; export type DatabaseUpdateType = 'dictionary'; + export type DatabaseUpdateCause = 'purge' | 'delete' | 'import'; export type MecabParseResults = [ diff --git a/types/ext/dictionary-data.d.ts b/types/ext/dictionary-data.d.ts index 434f5a27..0128f83f 100644 --- a/types/ext/dictionary-data.d.ts +++ b/types/ext/dictionary-data.d.ts @@ -102,9 +102,13 @@ export type TermGlossaryContent = ( ); export type TermGlossaryString = string; + export type TermGlossaryText = {type: 'text', text: string}; + export type TermGlossaryImage = {type: 'image'} & TermImage; + export type TermGlossaryStructuredContent = {type: 'structured-content', content: StructuredContent.Content}; + export type TermGlossaryDeinflection = [ uninflected: string, inflectionRuleChain: string[], diff --git a/types/ext/dictionary-database.d.ts b/types/ext/dictionary-database.d.ts index 1ae4603f..84c6da62 100644 --- a/types/ext/dictionary-database.d.ts +++ b/types/ext/dictionary-database.d.ts @@ -36,7 +36,9 @@ export type MediaDataArrayBufferContent = MediaDataBase<ArrayBuffer>; export type MediaDataStringContent = MediaDataBase<string>; -export type Media<T extends (ArrayBuffer | string) = ArrayBuffer> = {index: number} & MediaDataBase<T>; +type MediaType = ArrayBuffer | string; + +export type Media<T extends MediaType = ArrayBuffer> = {index: number} & MediaDataBase<T>; export type DatabaseTermEntry = { expression: string; @@ -198,7 +200,6 @@ export type ObjectStoreName = ( 'media' ); -/* eslint-disable @stylistic/indent */ export type ObjectStoreData<T extends ObjectStoreName> = ( T extends 'dictionaries' ? DictionaryImporter.Summary : T extends 'terms' ? DatabaseTermEntry : @@ -209,7 +210,6 @@ export type ObjectStoreData<T extends ObjectStoreName> = ( T extends 'media' ? MediaDataArrayBufferContent : never ); -/* eslint-enable @stylistic/indent */ export type DeleteDictionaryProgressData = { count: number; diff --git a/types/ext/input.d.ts b/types/ext/input.d.ts index ab05f015..e71a0110 100644 --- a/types/ext/input.d.ts +++ b/types/ext/input.d.ts @@ -16,6 +16,9 @@ */ export type ModifierKey = 'alt' | 'ctrl' | 'meta' | 'shift'; + export type ModifierMouseButton = 'mouse0' | 'mouse1' | 'mouse2' | 'mouse3' | 'mouse4' | 'mouse5'; + export type Modifier = ModifierKey | ModifierMouseButton; + export type ModifierType = 'key' | 'mouse'; diff --git a/types/ext/profile-conditions-util.d.ts b/types/ext/profile-conditions-util.d.ts index 441c9b97..288a3f78 100644 --- a/types/ext/profile-conditions-util.d.ts +++ b/types/ext/profile-conditions-util.d.ts @@ -33,6 +33,6 @@ export type NormalizedOptionsContext1 = Settings.OptionsContext1 & { export type NormalizedOptionsContext2 = Settings.OptionsContext2; -export type NormalizedOptionsContext3 = Settings.OptionsContext2; +export type NormalizedOptionsContext3 = Settings.OptionsContext3; export type NormalizedOptionsContext = NormalizedOptionsContext1 | NormalizedOptionsContext2 | NormalizedOptionsContext3; diff --git a/types/ext/settings-modifications.d.ts b/types/ext/settings-modifications.d.ts index b052ba30..becfea5c 100644 --- a/types/ext/settings-modifications.d.ts +++ b/types/ext/settings-modifications.d.ts @@ -68,10 +68,15 @@ export type Modification = ( ); export type ScopedRead = Read & OptionsScope; + export type ScopedModificationSet = ModificationSet & OptionsScope; + export type ScopedModificationDelete = ModificationDelete & OptionsScope; + export type ScopedModificationSwap = ModificationSwap & OptionsScope; + export type ScopedModificationSplice = ModificationSplice & OptionsScope; + export type ScopedModificationPush = ModificationPush & OptionsScope; export type ScopedModification = ( @@ -83,14 +88,19 @@ export type ScopedModification = ( ); export type ModificationSetResult = unknown; + export type ModificationDeleteResult = true; + export type ModificationSwapResult = true; + export type ModificationSpliceResult = unknown[]; + export type ModificationPushResult = number; export type ModificationResult = ( ModificationSetResult | ModificationDeleteResult | + // eslint-disable-next-line @typescript-eslint/no-duplicate-type-constituents ModificationSwapResult | ModificationSpliceResult | ModificationPushResult diff --git a/types/ext/settings.d.ts b/types/ext/settings.d.ts index 96440823..a900dbe6 100644 --- a/types/ext/settings.d.ts +++ b/types/ext/settings.d.ts @@ -349,25 +349,39 @@ export type PreventMiddleMouseOptions = { }; export type ResultOutputMode = 'group' | 'merge' | 'split'; + export type PopupDisplayMode = 'default' | 'full-width'; + export type PopupHorizontalTextPosition = 'below' | 'above'; + export type PopupVerticalTextPosition = 'default' | 'before' | 'after' | 'left' | 'right'; + export type GlossaryLayoutMode = 'default' | 'compact'; + export type PopupTheme = 'light' | 'dark' | 'browser'; + export type PopupOuterTheme = 'light' | 'dark' | 'browser' | 'site'; + export type PopupCurrentIndicatorMode = 'none' | 'asterisk' | 'triangle' | 'bar-left' | 'bar-right' | 'dot-left' | 'dot-right'; + export type PopupActionBarVisibility = 'auto' | 'always'; + export type PopupActionBarLocation = 'left' | 'right' | 'top' | 'bottom'; + export type FrequencyDisplayMode = 'tags' | 'tags-grouped' | 'split-tags' | 'split-tags-grouped' | 'inline-list' | 'list'; + export type TermDisplayMode = 'ruby' | 'ruby-and-reading' | 'term-and-reading'; + export type SortFrequencyDictionaryOrder = 'ascending' | 'descending'; export type PopupWindowType = 'normal' | 'popup'; + export type PopupWindowState = 'normal' | 'maximized' | 'fullscreen'; export type AudioSourceType = 'jpod101' | 'jpod101-alternate' | 'jisho' | 'text-to-speech' | 'text-to-speech-reading' | 'custom' | 'custom-json'; export type TranslationConvertType = 'false' | 'true' | 'variant'; + export type TranslationCollapseEmphaticSequences = 'false' | 'true' | 'full'; export type DictionaryDefinitionsCollapsible = 'not-collapsible' | 'expanded' | 'collapsed' | 'force-collapsed' | 'force-expanded'; @@ -375,11 +389,15 @@ export type DictionaryDefinitionsCollapsible = 'not-collapsible' | 'expanded' | export type ParsingReadingMode = 'hiragana' | 'katakana' | 'romaji' | 'dictionary-reading' | 'none'; export type AnkiScreenshotFormat = 'png' | 'jpeg'; + export type AnkiDuplicateScope = 'collection' | 'deck' | 'deck-root'; + export type AnkiDisplayTags = 'never' | 'always' | 'non-standard'; + export type AnkiNoteGuiMode = 'browse' | 'edit'; export type SentenceTerminationCharacterMode = 'custom' | 'custom-no-newlines' | 'newlines' | 'none'; export type InputsHotkeyModifier = 'alt' | 'ctrl' | 'shift' | 'meta'; + export type InputsHotkeyScope = 'popup' | 'search' | 'web'; diff --git a/types/other/rollup-parse-ast.d.ts b/types/other/rollup-parse-ast.d.ts index d798f09e..efc42411 100644 --- a/types/other/rollup-parse-ast.d.ts +++ b/types/other/rollup-parse-ast.d.ts @@ -22,4 +22,5 @@ import type {ParseAst, ParseAstAsync} from 'rollup'; export const parseAst: ParseAst; + export const parseAstAsync: ParseAstAsync; |