diff options
-rw-r--r-- | .eslintrc.json | 36 | ||||
-rw-r--r-- | dev/generate-css-json.js | 1 | ||||
-rw-r--r-- | dev/util.js | 8 | ||||
-rw-r--r-- | ext/js/background/backend.js | 6 | ||||
-rw-r--r-- | ext/js/background/offscreen-proxy.js | 2 | ||||
-rw-r--r-- | ext/js/background/profile-conditions-util.js | 2 | ||||
-rw-r--r-- | ext/js/data/permissions-util.js | 72 | ||||
-rw-r--r-- | ext/js/dictionary/dictionary-data-util.js | 2 | ||||
-rw-r--r-- | ext/js/dom/dom-text-scanner.js | 6 | ||||
-rw-r--r-- | ext/js/language/ja/japanese.js | 6 | ||||
-rw-r--r-- | ext/js/language/translator.js | 2 | ||||
-rw-r--r-- | ext/js/pages/permissions-main.js | 4 | ||||
-rw-r--r-- | test/fixtures/dom-test.js | 1 | ||||
-rw-r--r-- | test/language-transformer.test.js | 3 | ||||
-rw-r--r-- | test/options-util.test.js | 14 | ||||
-rw-r--r-- | test/playwright/integration.spec.js | 4 | ||||
-rw-r--r-- | test/playwright/playwright-util.js | 2 | ||||
-rw-r--r-- | test/playwright/visual.spec.js | 12 | ||||
-rw-r--r-- | test/profile-conditions-util.test.js | 4 | ||||
-rw-r--r-- | test/utilities/translator.js | 1 | ||||
-rw-r--r-- | types/ext/application.d.ts | 3 |
21 files changed, 116 insertions, 75 deletions
diff --git a/.eslintrc.json b/.eslintrc.json index 30d495d2..361e5f24 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -42,18 +42,42 @@ "/dev/lib/handlebars/" ], "rules": { + "accessor-pairs": "error", + "capitalized-comments": [ + "error", + "always", + { + "ignorePattern": "case|[a-z]+[A-Z0-9]|[a-z]+\\.\\w", + "ignoreInlineComments": true, + "ignoreConsecutiveComments": true + } + ], "curly": ["error", "all"], + "default-case-last": "error", "dot-notation": "error", "eqeqeq": "error", "func-names": ["error", "always"], "guard-for-in": "error", + "grouped-accessor-pairs": "error", + "new-cap": "error", + "no-alert": "error", "no-case-declarations": "error", + "no-caller": "error", "no-const-assign": "error", - "no-constant-condition": "off", + "no-constant-condition": ["error", {"checkLoops": false}], + "no-constructor-return": "error", + "no-duplicate-imports": "error", + "no-eval": "error", + "no-extend-native": "error", "no-global-assign": "error", "no-implicit-globals": "error", + "no-implied-eval": "error", "no-new": "error", + "no-new-native-nonconstructor": "error", + "no-octal": "off", + "no-octal-escape": "off", "no-param-reassign": "off", + "no-promise-executor-return": "error", "no-prototype-builtins": "error", "no-restricted-syntax": [ "error", @@ -66,7 +90,11 @@ "selector": "MemberExpression[property.name=json]" } ], - "no-shadow": ["off", {"builtinGlobals": false}], + "no-self-compare": "error", + "no-sequences": "error", + "no-shadow": ["error", {"builtinGlobals": false}], + "no-shadow-restricted-names": "error", + "no-template-curly-in-string": "error", "no-undef": "error", "no-undefined": "error", "no-underscore-dangle": ["error", {"allowAfterThis": true, "allowAfterSuper": false, "allowAfterThisConstructor": false}], @@ -75,8 +103,12 @@ "no-unused-vars": ["error", {"vars": "local", "args": "after-used", "argsIgnorePattern": "^_", "caughtErrors": "none"}], "no-unused-expressions": "error", "no-var": "error", + "no-with": "error", "prefer-const": ["error", {"destructuring": "all"}], + "radix": "error", "require-atomic-updates": "off", + "sort-imports": "off", + "yoda": ["error", "never"], "@stylistic/array-bracket-newline": ["error", "consistent"], "@stylistic/array-bracket-spacing": ["error", "never"], diff --git a/dev/generate-css-json.js b/dev/generate-css-json.js index a837c9e2..adb75495 100644 --- a/dev/generate-css-json.js +++ b/dev/generate-css-json.js @@ -91,6 +91,7 @@ function removeProperty(styles, property, removedProperties) { * @returns {string} */ export function formatRulesJson(rules) { + // This is similar to the following code, but formatted a but more succinctly: // return JSON.stringify(rules, null, 4); const indent1 = ' '; const indent2 = indent1.repeat(2); diff --git a/dev/util.js b/dev/util.js index eee16964..817b0d84 100644 --- a/dev/util.js +++ b/dev/util.js @@ -57,7 +57,7 @@ export function getAllFiles(baseDirectory, predicate = null) { export function createDictionaryArchive(dictionaryDirectory, dictionaryName) { const fileNames = fs.readdirSync(dictionaryDirectory); - // const zipFileWriter = new BlobWriter(); + // Const zipFileWriter = new BlobWriter(); // const zipWriter = new ZipWriter(zipFileWriter); const archive = new JSZip(); @@ -70,7 +70,7 @@ export function createDictionaryArchive(dictionaryDirectory, dictionaryName) { } archive.file(fileName, JSON.stringify(json, null, 0)); - // await zipWriter.add(fileName, new TextReader(JSON.stringify(json, null, 0))); + // Await zipWriter.add(fileName, new TextReader(JSON.stringify(json, null, 0))); } else { const content = fs.readFileSync(path.join(dictionaryDirectory, fileName), {encoding: null}); archive.file(fileName, content); @@ -83,14 +83,14 @@ export function createDictionaryArchive(dictionaryDirectory, dictionaryName) { // console.log('??'); } } - // await zipWriter.close(); + // Await zipWriter.close(); // Retrieves the Blob object containing the zip content into `zipFileBlob`. It // is also returned by zipWriter.close() for more convenience. // const zipFileBlob = await zipFileWriter.getData(); return archive; - // return zipFileBlob; + // Return zipFileBlob; } /** diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js index 8ab56232..e246f0bb 100644 --- a/ext/js/background/backend.js +++ b/ext/js/background/backend.js @@ -437,7 +437,7 @@ export class Backend { /** @type {import('api').ApiHandler<'requestBackendReadySignal'>} */ _onApiRequestBackendReadySignal(_params, sender) { - // tab ID isn't set in background (e.g. browser_action) + // Tab ID isn't set in background (e.g. browser_action) /** @type {import('application').ApiMessage<'applicationBackendReady'>} */ const data = {action: 'applicationBackendReady'}; if (typeof sender.tab === 'undefined') { @@ -1547,7 +1547,7 @@ export class Backend { return ( isObject(chrome.action) && typeof chrome.action.getTitle === 'function' ? - new Promise((resolve) => chrome.action.getTitle({}, resolve)) : + new Promise((resolve) => { chrome.action.getTitle({}, resolve); }) : Promise.resolve('') ); } @@ -2601,7 +2601,7 @@ export class Backend { const match = /^\d+/.exec(version); if (match === null) { return; } - const versionNumber = Number.parseInt(match[0]); + const versionNumber = Number.parseInt(match[0], 10); if (!(Number.isFinite(versionNumber) && versionNumber >= 77)) { return; } await navigator.storage.persist(); diff --git a/ext/js/background/offscreen-proxy.js b/ext/js/background/offscreen-proxy.js index 085048c1..5a79f41a 100644 --- a/ext/js/background/offscreen-proxy.js +++ b/ext/js/background/offscreen-proxy.js @@ -85,7 +85,7 @@ export class OffscreenProxy { */ async _hasOffscreenDocument() { const offscreenUrl = chrome.runtime.getURL('offscreen.html'); - if (!chrome.runtime.getContexts) { // chrome version below 116 + if (!chrome.runtime.getContexts) { // Chrome version below 116 // Clients: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/clients // @ts-expect-error - Types not set up for service workers yet const matchedClients = await clients.matchAll(); diff --git a/ext/js/background/profile-conditions-util.js b/ext/js/background/profile-conditions-util.js index e2d58725..4e4e38d7 100644 --- a/ext/js/background/profile-conditions-util.js +++ b/ext/js/background/profile-conditions-util.js @@ -229,7 +229,7 @@ function createSchemaPopupLevelGreaterThanOrEqual(value) { }; } -// url schema creation functions +// URL schema creation functions /** * @param {string} value diff --git a/ext/js/data/permissions-util.js b/ext/js/data/permissions-util.js index 097fe34d..1ccc630f 100644 --- a/ext/js/data/permissions-util.js +++ b/ext/js/data/permissions-util.js @@ -40,14 +40,16 @@ function ankiFieldMarkerMayUseClipboard(marker) { * @returns {Promise<boolean>} */ export function hasPermissions(permissions) { - return new Promise((resolve, reject) => chrome.permissions.contains(permissions, (result) => { - const e = chrome.runtime.lastError; - if (e) { - reject(new Error(e.message)); - } else { - resolve(result); - } - })); + return new Promise((resolve, reject) => { + chrome.permissions.contains(permissions, (result) => { + const e = chrome.runtime.lastError; + if (e) { + reject(new Error(e.message)); + } else { + resolve(result); + } + }); + }); } /** @@ -58,22 +60,26 @@ export function hasPermissions(permissions) { export function setPermissionsGranted(permissions, shouldHave) { return ( shouldHave ? - new Promise((resolve, reject) => chrome.permissions.request(permissions, (result) => { - const e = chrome.runtime.lastError; - if (e) { - reject(new Error(e.message)); - } else { - resolve(result); - } - })) : - new Promise((resolve, reject) => chrome.permissions.remove(permissions, (result) => { - const e = chrome.runtime.lastError; - if (e) { - reject(new Error(e.message)); - } else { - resolve(!result); - } - })) + new Promise((resolve, reject) => { + chrome.permissions.request(permissions, (result) => { + const e = chrome.runtime.lastError; + if (e) { + reject(new Error(e.message)); + } else { + resolve(result); + } + }); + }) : + new Promise((resolve, reject) => { + chrome.permissions.remove(permissions, (result) => { + const e = chrome.runtime.lastError; + if (e) { + reject(new Error(e.message)); + } else { + resolve(!result); + } + }); + }) ); } @@ -81,14 +87,16 @@ export function setPermissionsGranted(permissions, shouldHave) { * @returns {Promise<chrome.permissions.Permissions>} */ export function getAllPermissions() { - return new Promise((resolve, reject) => chrome.permissions.getAll((result) => { - const e = chrome.runtime.lastError; - if (e) { - reject(new Error(e.message)); - } else { - resolve(result); - } - })); + return new Promise((resolve, reject) => { + chrome.permissions.getAll((result) => { + const e = chrome.runtime.lastError; + if (e) { + reject(new Error(e.message)); + } else { + resolve(result); + } + }); + }); } /** diff --git a/ext/js/dictionary/dictionary-data-util.js b/ext/js/dictionary/dictionary-data-util.js index a2a106cc..a90668f4 100644 --- a/ext/js/dictionary/dictionary-data-util.js +++ b/ext/js/dictionary/dictionary-data-util.js @@ -286,7 +286,7 @@ export function isNonNounVerbOrAdjective(wordClasses) { case 'vs': isVerbOrAdjective = true; isSuruVerb = true; - // falls through + // Falls through case 'n': isNoun = true; break; diff --git a/ext/js/dom/dom-text-scanner.js b/ext/js/dom/dom-text-scanner.js index 5b3ea564..e263d9f3 100644 --- a/ext/js/dom/dom-text-scanner.js +++ b/ext/js/dom/dom-text-scanner.js @@ -551,10 +551,10 @@ export class DOMTextScanner { case 'block': case 'flex': case 'grid': - case 'list': // list-item - case 'table': // table, table-* + case 'list': // Also includes: list-item + case 'table': // Also includes: table, table-* return true; - case 'ruby': // ruby-* + case 'ruby': // Also includes: ruby-* return (pos >= 0); default: return false; diff --git a/ext/js/language/ja/japanese.js b/ext/js/language/ja/japanese.js index 818daa0b..2c9a1f7f 100644 --- a/ext/js/language/ja/japanese.js +++ b/ext/js/language/ja/japanese.js @@ -557,17 +557,17 @@ export function convertHalfWidthKanaToFullWidth(text, sourceMap = null) { let index = 0; switch (text.charCodeAt(i + 1)) { - case 0xff9e: // dakuten + case 0xff9e: // Dakuten index = 1; break; - case 0xff9f: // handakuten + case 0xff9f: // Handakuten index = 2; break; } let c2 = mapping[index]; if (index > 0) { - if (c2 === '-') { // invalid + if (c2 === '-') { // Invalid index = 0; c2 = mapping[0]; } else { diff --git a/ext/js/language/translator.js b/ext/js/language/translator.js index 2ba1ce0d..b2342e8d 100644 --- a/ext/js/language/translator.js +++ b/ext/js/language/translator.js @@ -1609,7 +1609,7 @@ export class Translator { sequence: rawSequence, rules } = databaseEntry; - // cast is safe because getDeinflections filters out deinflection definitions + // Cast is safe because getDeinflections filters out deinflection definitions const contentDefinitions = /** @type {import('dictionary-data').TermGlossaryContent[]} */ (definitions); const reading = (rawReading.length > 0 ? rawReading : term); const {index: dictionaryIndex, priority: dictionaryPriority} = this._getDictionaryOrder(dictionary, enabledDictionaryMap); diff --git a/ext/js/pages/permissions-main.js b/ext/js/pages/permissions-main.js index 17169c12..3be97b78 100644 --- a/ext/js/pages/permissions-main.js +++ b/ext/js/pages/permissions-main.js @@ -43,14 +43,14 @@ async function setupEnvironmentInfo(api) { * @returns {Promise<boolean>} */ async function isAllowedIncognitoAccess() { - return await new Promise((resolve) => chrome.extension.isAllowedIncognitoAccess(resolve)); + return await new Promise((resolve) => { chrome.extension.isAllowedIncognitoAccess(resolve); }); } /** * @returns {Promise<boolean>} */ async function isAllowedFileSchemeAccess() { - return await new Promise((resolve) => chrome.extension.isAllowedFileSchemeAccess(resolve)); + return await new Promise((resolve) => { chrome.extension.isAllowedFileSchemeAccess(resolve); }); } /** diff --git a/test/fixtures/dom-test.js b/test/fixtures/dom-test.js index 578b1324..961e0a77 100644 --- a/test/fixtures/dom-test.js +++ b/test/fixtures/dom-test.js @@ -28,6 +28,7 @@ function prepareWindow(window) { // Define innerText setter as an alias for textContent setter Object.defineProperty(window.HTMLDivElement.prototype, 'innerText', { + get() { return this.textContent; }, set(value) { this.textContent = value; } }); diff --git a/test/language-transformer.test.js b/test/language-transformer.test.js index 0c8ef08d..7c0da48b 100644 --- a/test/language-transformer.test.js +++ b/test/language-transformer.test.js @@ -923,7 +923,7 @@ describe('LanguageTransformer', () => { {term: 'あかい', source: 'あけえ', rule: 'adj-i', reasons: ['-e']}, {term: 'こわい', source: 'こええ', rule: 'adj-i', reasons: ['-e']}, {term: 'つよい', source: 'つええ', rule: 'adj-i', reasons: ['-e']}, - // small -e + // Small -e {term: 'すごい', source: 'すげぇ', rule: 'adj-i', reasons: ['-e']}, {term: 'やばい', source: 'やべぇ', rule: 'adj-i', reasons: ['-e']}, {term: 'うるさい', source: 'うるせぇ', rule: 'adj-i', reasons: ['-e']}, @@ -1152,7 +1152,6 @@ describe('LanguageTransformer', () => { languageTransformer.addDescriptor(descriptor); describe('deinflections', () => { - // for (const {valid, tests} of data) { describe.each(data)('$category', ({valid, tests}) => { for (const {source, term, rule, reasons} of tests) { const {has} = hasTermReasons(languageTransformer, source, term, rule, reasons); diff --git a/test/options-util.test.js b/test/options-util.test.js index a178aecb..3a1b1efb 100644 --- a/test/options-util.test.js +++ b/test/options-util.test.js @@ -702,7 +702,7 @@ describe('OptionsUtil', () => { const match = fileNameRegex.exec(fileName); if (match !== null) { updates.push({ - version: Number.parseInt(match[1]), + version: Number.parseInt(match[1], 10), changes: loadDataFile(path.join(templatesDirPath, match[0])) }); } @@ -846,7 +846,7 @@ describe('OptionsUtil', () => { {{~> (lookup . "marker") ~}} `.trimStart() }, - // glossary and glossary-brief update + // Glossary and glossary-brief update { oldVersion: 7, newVersion: 12, @@ -1238,7 +1238,7 @@ describe('OptionsUtil', () => { <<<UPDATE-ADDITIONS>>> {{~> (lookup . "marker") ~}}`.trimStart() }, - // block helper update: furigana and furiganaPlain + // Block helper update: furigana and furiganaPlain { oldVersion: 20, newVersion: 21, @@ -1326,7 +1326,7 @@ describe('OptionsUtil', () => { {{~> (lookup . "marker") ~}}`.trimStart() }, - // block helper update: formatGlossary + // Block helper update: formatGlossary { oldVersion: 20, newVersion: 21, @@ -1400,7 +1400,7 @@ describe('OptionsUtil', () => { {{~> (lookup . "marker") ~}}`.trimStart() }, - // block helper update: set and get + // Block helper update: set and get { oldVersion: 20, newVersion: 21, @@ -1502,7 +1502,7 @@ describe('OptionsUtil', () => { {{~> (lookup . "marker") ~}}`.trimStart() }, - // block helper update: hasMedia and getMedia + // Block helper update: hasMedia and getMedia { oldVersion: 20, newVersion: 21, @@ -1584,7 +1584,7 @@ describe('OptionsUtil', () => { {{~> (lookup . "marker") ~}}`.trimStart() }, - // block helper update: pronunciation + // Block helper update: pronunciation { oldVersion: 20, newVersion: 21, diff --git a/test/playwright/integration.spec.js b/test/playwright/integration.spec.js index 170714a1..06af3fd2 100644 --- a/test/playwright/integration.spec.js +++ b/test/playwright/integration.spec.js @@ -31,13 +31,13 @@ import { test.beforeEach(async ({context}) => { // Wait for the on-install welcome.html tab to load, which becomes the foreground tab const welcome = await context.waitForEvent('page'); - await welcome.close(); // close the welcome tab so our main tab becomes the foreground tab -- otherwise, the screenshot can hang + await welcome.close(); // Close the welcome tab so our main tab becomes the foreground tab -- otherwise, the screenshot can hang }); test('search clipboard', async ({page, extensionId}) => { await page.goto(`chrome-extension://${extensionId}/search.html`); await page.locator('#search-option-clipboard-monitor-container > label').click(); - await page.waitForTimeout(200); // race + await page.waitForTimeout(200); // Race await writeToClipboardFromPage(page, 'あ'); await expect(page.locator('#search-textbox')).toHaveValue('あ'); diff --git a/test/playwright/playwright-util.js b/test/playwright/playwright-util.js index b364c80b..b9a4831a 100644 --- a/test/playwright/playwright-util.js +++ b/test/playwright/playwright-util.js @@ -28,7 +28,7 @@ export const test = base.extend({ context: async ({}, use) => { const pathToExtension = path.join(root, 'ext'); const context = await chromium.launchPersistentContext('', { - // headless: false, + // Disabled: headless: false, args: [ '--headless=new', `--disable-extensions-except=${pathToExtension}`, diff --git a/test/playwright/visual.spec.js b/test/playwright/visual.spec.js index fc8bb8df..157cedc7 100644 --- a/test/playwright/visual.spec.js +++ b/test/playwright/visual.spec.js @@ -22,7 +22,7 @@ import {expect, root, test} from './playwright-util.js'; test.beforeEach(async ({context}) => { // Wait for the on-install welcome.html tab to load, which becomes the foreground tab const welcome = await context.waitForEvent('page'); - welcome.close(); // close the welcome tab so our main tab becomes the foreground tab -- otherwise, the screenshot can hang + welcome.close(); // Close the welcome tab so our main tab becomes the foreground tab -- otherwise, the screenshot can hang }); test('visual', async ({page, extensionId}) => { @@ -63,9 +63,9 @@ test('visual', async ({page, extensionId}) => { if (typeof popup_frame === 'undefined') { frame_attached = page.waitForEvent('frameattached'); } - await page.mouse.move(box.x + offset.x, box.y + offset.y, {steps: 10}); // hover over the test + await page.mouse.move(box.x + offset.x, box.y + offset.y, {steps: 10}); // Hover over the test if (typeof popup_frame === 'undefined') { - popup_frame = await frame_attached; // wait for popup to be attached + popup_frame = await frame_attached; // Wait for popup to be attached } try { // Some tests don't have a popup, so don't fail if it's not there @@ -75,11 +75,11 @@ test('visual', async ({page, extensionId}) => { console.log(test_name + ' has no popup'); } - await page.bringToFront(); // bring the page to the foreground so the screenshot doesn't hang; for some reason the frames result in page being in the background + await page.bringToFront(); // Bring the page to the foreground so the screenshot doesn't hang; for some reason the frames result in page being in the background await expect.soft(page).toHaveScreenshot(test_name + '.png'); - await page.mouse.click(0, 0); // click away so popup disappears - await (await /** @type {import('@playwright/test').Frame} */ (popup_frame).frameElement()).waitForElementState('hidden'); // wait for popup to disappear + await page.mouse.click(0, 0); // Click away so popup disappears + await (await /** @type {import('@playwright/test').Frame} */ (popup_frame).frameElement()).waitForElementState('hidden'); // Wait for popup to disappear }; // Test document 1 diff --git a/test/profile-conditions-util.test.js b/test/profile-conditions-util.test.js index 6de5ad1d..590e5873 100644 --- a/test/profile-conditions-util.test.js +++ b/test/profile-conditions-util.test.js @@ -250,7 +250,7 @@ describe('Profile conditions utilities', () => { ] }, - // url tests + // Url tests { conditionGroups: [ { @@ -606,7 +606,7 @@ describe('Profile conditions utilities', () => { ] }, - // flags tests + // Flags tests { conditionGroups: [ { diff --git a/test/utilities/translator.js b/test/utilities/translator.js index b77bfb39..f452e688 100644 --- a/test/utilities/translator.js +++ b/test/utilities/translator.js @@ -16,6 +16,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +// eslint-disable-next-line no-template-curly-in-string const placeholder = '${title}'; /** diff --git a/types/ext/application.d.ts b/types/ext/application.d.ts index 903c8e45..930220f0 100644 --- a/types/ext/application.d.ts +++ b/types/ext/application.d.ts @@ -15,11 +15,10 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import type {TokenString} from './core'; +import type {TokenString, EventNames, EventArgument as BaseEventArgument} from './core'; import type {SearchMode} from './display'; import type {FrameEndpointReadyDetails, FrameEndpointConnectedDetails} from './frame-client'; import type {DatabaseUpdateType, DatabaseUpdateCause} from './backend'; -import type {EventNames, EventArgument as BaseEventArgument} from './core'; import type { ApiMap as BaseApiMap, ApiHandler as BaseApiHandler, |