diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2024-02-10 23:12:01 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-11 04:12:01 +0000 | 
| commit | 765f1ede668f70e3af7717bf4d5f05dbf009c7f8 (patch) | |
| tree | e73f481c93f8bbaa42f7c8216190fb1cb4621301 | |
| parent | 805cf9cb3ea744a6d7c0a5da27fc9ef4e6f08626 (diff) | |
Eslint rule updates (#665)
* Padding newline rules
* Update rules
* Update rules
* Update rules
* Updates
* Update object quotes
* Merge similar ts and js rules
* Change export spacing rules
* Move typescript-eslint rules
* Spacing
* Actually save and commit changes
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; |