Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update eslint unsafe rule #887

Merged
merged 10 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@
"@typescript-eslint/no-misused-promises": "off",
"@typescript-eslint/no-redundant-type-constituents": "error",
"@typescript-eslint/no-unsafe-argument": "error",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-assignment": "error",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-enum-comparison": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
Expand Down
1 change: 1 addition & 0 deletions dev/dictionary-validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ async function validateDictionaryBanks(mode, entries, schemasDetails) {
export async function validateDictionary(mode, archiveData, schemas) {
const entries = await getDictionaryArchiveEntries(archiveData);
const indexFileName = getIndexFileName();
/** @type {import('dictionary-data').Index} */
const index = await getDictionaryArchiveJson(entries, indexFileName);
const version = index.format || index.version;

Expand Down
2 changes: 1 addition & 1 deletion ext/js/accessibility/google-docs-xray.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

/** Entry point. */
function main() {
/** @type {Window} */
/** @type {unknown} */
// @ts-expect-error - Firefox Xray vision
const window2 = window.wrappedJSObject;
if (!(typeof window2 === 'object' && window2 !== null)) { return; }
Expand Down
29 changes: 19 additions & 10 deletions ext/js/background/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -1831,16 +1831,7 @@ export class Backend {
}

try {
const tabWindow = await new Promise((resolve, reject) => {
chrome.windows.get(tab.windowId, {}, (value) => {
const e = chrome.runtime.lastError;
if (e) {
reject(new Error(e.message));
} else {
resolve(value);
}
});
});
const tabWindow = await this._getWindow(tab.windowId);
if (!tabWindow.focused) {
await /** @type {Promise<void>} */ (new Promise((resolve, reject) => {
chrome.windows.update(tab.windowId, {focused: true}, () => {
Expand All @@ -1858,6 +1849,23 @@ export class Backend {
}
}

/**
* @param {number} windowId
* @returns {Promise<chrome.windows.Window>}
*/
_getWindow(windowId) {
return new Promise((resolve, reject) => {
chrome.windows.get(windowId, {}, (value) => {
const e = chrome.runtime.lastError;
if (e) {
reject(new Error(e.message));
} else {
resolve(value);
}
});
});
}

/**
* @param {number} tabId
* @param {number} frameId
Expand Down Expand Up @@ -2208,6 +2216,7 @@ export class Backend {
async _injectAnkiNoteDictionaryMedia(ankiConnect, timestamp, dictionaryMediaDetails) {
const targets = [];
const detailsList = [];
/** @type {Map<string, {dictionary: string, path: string, media: ?import('dictionary-database').MediaDataStringContent}>} */
const detailsMap = new Map();
for (const {dictionary, path} of dictionaryMediaDetails) {
const target = {dictionary, path};
Expand Down
1 change: 1 addition & 0 deletions ext/js/background/offscreen-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export class OffscreenProxy {
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
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const matchedClients = await clients.matchAll();
// @ts-expect-error - Types not set up for service workers yet
return await matchedClients.some((client) => client.url === offscreenUrl);
Expand Down
28 changes: 18 additions & 10 deletions ext/js/background/script-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,7 @@ export function injectStylesheet(type, content, tabId, frameId, allFrames) {
* @returns {Promise<boolean>} `true` if a script is registered, `false` otherwise.
*/
export async function isContentScriptRegistered(id) {
const scripts = await new Promise((resolve, reject) => {
chrome.scripting.getRegisteredContentScripts({ids: [id]}, (result) => {
const e = chrome.runtime.lastError;
if (e) {
reject(new Error(e.message));
} else {
resolve(result);
}
});
});
const scripts = await getRegisteredContentScripts([id]);
for (const script of scripts) {
if (script.id === id) {
return true;
Expand Down Expand Up @@ -155,3 +146,20 @@ function createContentScriptRegistrationOptions(details, id) {
}
return options;
}

/**
* @param {string[]} ids
* @returns {Promise<chrome.scripting.RegisteredContentScript[]>}
*/
function getRegisteredContentScripts(ids) {
return new Promise((resolve, reject) => {
chrome.scripting.getRegisteredContentScripts({ids}, (result) => {
const e = chrome.runtime.lastError;
if (e) {
reject(new Error(e.message));
} else {
resolve(result);
}
});
});
}
7 changes: 4 additions & 3 deletions ext/js/comm/anki-connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import {ExtensionError} from '../core/extension-error.js';
import {parseJson} from '../core/json.js';
import {isObjectNotArray} from '../core/object-utilities.js';
import {getRootDeckName} from '../data/anki-util.js';

/**
Expand Down Expand Up @@ -606,15 +607,15 @@ export class AnkiConnect {
if (typeof modelName !== 'string') {
throw this._createError(`Unexpected result type at index ${i}, field modelName: expected string, received ${this._getTypeName(modelName)}`, result);
}
if (typeof fields !== 'object' || fields === null) {
throw this._createError(`Unexpected result type at index ${i}, field fields: expected string, received ${this._getTypeName(fields)}`, result);
if (!isObjectNotArray(fields)) {
throw this._createError(`Unexpected result type at index ${i}, field fields: expected object, received ${this._getTypeName(fields)}`, result);
}
const tags2 = /** @type {string[]} */ (this._normalizeArray(tags, -1, 'string', ', field tags'));
const cards2 = /** @type {number[]} */ (this._normalizeArray(cards, -1, 'number', ', field cards'));
/** @type {{[key: string]: import('anki').NoteFieldInfo}} */
const fields2 = {};
for (const [key, fieldInfo] of Object.entries(fields)) {
if (typeof fieldInfo !== 'object' || fieldInfo === null) { continue; }
if (!isObjectNotArray(fieldInfo)) { continue; }
const {value, order} = fieldInfo;
if (typeof value !== 'string' || typeof order !== 'number') { continue; }
fields2[key] = {value, order};
Expand Down
1 change: 1 addition & 0 deletions ext/js/comm/frame-ancestry-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ export class FrameAncestryHandler {
}

/** @type {?ShadowRoot|undefined} */
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const shadowRoot = (
element.shadowRoot ||
// @ts-expect-error - openOrClosedShadowRoot is available to Firefox 63+ for WebExtensions
Expand Down
1 change: 1 addition & 0 deletions ext/js/comm/frame-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export class FrameClient {
*/
_connectInternal(frame, targetOrigin, hostFrameId, setupFrame, timeout) {
return new Promise((resolve, reject) => {
/** @type {Map<string, string>} */
const tokenMap = new Map();
/** @type {?import('core').Timeout} */
let timer = null;
Expand Down
1 change: 1 addition & 0 deletions ext/js/data/anki-note-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export class AnkiNoteBuilder {
}

const formattedFieldValues = await Promise.all(formattedFieldValuePromises);
/** @type {Map<string, import('anki-note-builder').Requirement>} */
const uniqueRequirements = new Map();
/** @type {import('anki').NoteFields} */
const noteFields = {};
Expand Down
10 changes: 5 additions & 5 deletions ext/js/data/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,10 @@ export class Database {
request.onsuccess = (e) => {
const cursor = /** @type {IDBRequest<?IDBCursorWithValue>} */ (e.target).result;
if (cursor) {
/** @type {TResult} */
/** @type {unknown} */
const value = cursor.value;
if (noPredicate || predicate(value, predicateArg)) {
resolve(value, data);
if (noPredicate || predicate(/** @type {TResult} */ (value), predicateArg)) {
resolve(/** @type {TResult} */ (value), data);
} else {
cursor.continue();
}
Expand Down Expand Up @@ -424,9 +424,9 @@ export class Database {
request.onsuccess = (e) => {
const cursor = /** @type {IDBRequest<?IDBCursorWithValue>} */ (e.target).result;
if (cursor) {
/** @type {TResult} */
/** @type {unknown} */
const value = cursor.value;
results.push(value);
results.push(/** @type {TResult} */ (value));
cursor.continue();
} else {
onSuccess(results, data);
Expand Down
2 changes: 1 addition & 1 deletion ext/js/data/json-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -1263,7 +1263,7 @@ class JsonSchemaProxyHandler {
/**
* @param {import('ext/json-schema').ValueObjectOrArray} target
* @param {string|number|symbol} property
* @param {import('core').SafeAny} value
* @param {unknown} value
* @returns {boolean}
* @throws {Error}
*/
Expand Down
2 changes: 2 additions & 0 deletions ext/js/data/options-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {JsonSchema} from './json-schema.js';
// of the options object to a newer format. SafeAny is used for much of this, since every single
// legacy format does not contain type definitions.
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */

export class OptionsUtil {
constructor() {
Expand Down Expand Up @@ -1295,4 +1296,5 @@ export class OptionsUtil {
}
}

/* eslint-enable @typescript-eslint/no-unsafe-assignment */
/* eslint-enable @typescript-eslint/no-unsafe-argument */
1 change: 1 addition & 0 deletions ext/js/dictionary/dictionary-data-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export function groupTermTags(dictionaryEntry) {
const {headwords} = dictionaryEntry;
const headwordCount = headwords.length;
const uniqueCheck = (headwordCount > 1);
/** @type {Map<string, number>} */
const resultsIndexMap = new Map();
const results = [];
for (let i = 0; i < headwordCount; ++i) {
Expand Down
4 changes: 3 additions & 1 deletion ext/js/display/display-history.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class DisplayHistory extends EventDispatcher {
/** @type {Map<string, import('display-history').Entry>} */
this._historyMap = new Map();

/** @type {unknown} */
const historyState = history.state;
const {id, state} = (
isObjectNotArray(historyState) ?
Expand Down Expand Up @@ -188,6 +189,7 @@ export class DisplayHistory extends EventDispatcher {

/** */
_updateStateFromHistory() {
/** @type {unknown} */
let state = history.state;
let id = null;
if (isObjectNotArray(state)) {
Expand All @@ -208,7 +210,7 @@ export class DisplayHistory extends EventDispatcher {

// Fallback
this._current.id = (typeof id === 'string' ? id : this._generateId());
this._current.state = state;
this._current.state = /** @type {import('display-history').EntryState} */ (state);
this._current.content = null;
this._clear();
}
Expand Down
6 changes: 4 additions & 2 deletions ext/js/input/hotkey-help-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ export class HotkeyHelpController {
const hotkey = (global ? this._globalActionHotkeys : this._localActionHotkeys).get(action);
for (let i = 0, ii = attributes.length; i < ii; ++i) {
const attribute = attributes[i];
/** @type {unknown} */
let value;
if (typeof hotkey !== 'undefined') {
value = /** @type {unknown} */ (multipleValues ? values[i] : values);
value = multipleValues ? values[i] : values;
if (typeof value === 'string') {
value = value.replace(replacementPattern, hotkey);
}
Expand Down Expand Up @@ -158,7 +159,8 @@ export class HotkeyHelpController {
if (typeof hotkey !== 'string') { return null; }
const data = /** @type {unknown} */ (parseJson(hotkey));
if (!Array.isArray(data)) { return null; }
const [action, attributes, values] = /** @type {unknown[]} */ (data);
const dataArray = /** @type {unknown[]} */ (data);
const [action, attributes, values] = dataArray;
if (typeof action !== 'string') { return null; }
/** @type {string[]} */
const attributesArray = [];
Expand Down
19 changes: 12 additions & 7 deletions ext/js/language/translator.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ export class Translator {
return false;
}

/** @type {Map<string, number>} */
const frequencyCounter = new Map();

for (const element of array1) {
Expand Down Expand Up @@ -400,6 +401,7 @@ export class Translator {
* @returns {Map<string, import('translation-internal').DatabaseDeinflection[]>}
*/
_groupDeinflectionsByTerm(deinflections) {
/** @type {Map<string, import('translation-internal').DatabaseDeinflection[]>} */
const result = new Map();
for (const deinflection of deinflections) {
const {deinflectedText} = deinflection;
Expand Down Expand Up @@ -455,7 +457,7 @@ export class Translator {
/** @type {import('translation-internal').DatabaseDeinflection[]} */
const deinflections = [];
const used = new Set();
/** @type {Map<string, import('core').SafeAny>} */
/** @type {import('translation-internal').TextCache} */
const sourceCache = new Map(); // For reusing text processors' outputs

for (
Expand Down Expand Up @@ -498,14 +500,15 @@ export class Translator {

/**
* @param {import('language').TextProcessorWithId<unknown>[]} textProcessors
* @param {Map<string, unknown>} processorVariant
* @param {import('translation-internal').TextProcessorVariant} processorVariant
* @param {string} text
* @param {Map<string, import('core').SafeAny>} textCache
* @param {import('translation-internal').TextCache} textCache
* @returns {string}
*/
_applyTextProcessors(textProcessors, processorVariant, text, textCache) {
for (const {id, textProcessor: {process}} of textProcessors) {
const setting = processorVariant.get(id);

let level1 = textCache.get(text);
if (!level1) {
level1 = new Map();
Expand All @@ -522,7 +525,7 @@ export class Translator {
text = process(text, setting);
level2.set(setting, text);
} else {
text = level2.get(setting);
text = level2.get(setting) || '';
}
}

Expand Down Expand Up @@ -681,6 +684,7 @@ export class Translator {
/** @type {import('dictionary-database').TermExactRequest[]} */
const termList = [];
const targetList = [];
/** @type {Map<string, {groups: import('translator').DictionaryEntryGroup[]}>} */
const targetMap = new Map();

for (const group of groupedDictionaryEntries) {
Expand Down Expand Up @@ -1362,10 +1366,10 @@ export class Translator {

/**
* @param {Map<string, unknown[]>} arrayVariants
* @returns {Map<string, unknown>[]}
* @returns {import('translation-internal').TextProcessorVariant[]}
*/
_getArrayVariants(arrayVariants) {
/** @type {Map<string, unknown>[]} */
/** @type {import('translation-internal').TextProcessorVariant[]} */
const results = [];
const variantKeys = [...arrayVariants.keys()];
const entryVariantLengths = [];
Expand All @@ -1376,7 +1380,7 @@ export class Translator {
const totalVariants = entryVariantLengths.reduce((acc, length) => acc * length, 1);

for (let variantIndex = 0; variantIndex < totalVariants; ++variantIndex) {
/** @type {Map<string, unknown>} */
/** @type {import('translation-internal').TextProcessorVariant}} */
const variant = new Map();
let remainingIndex = variantIndex;

Expand Down Expand Up @@ -2076,6 +2080,7 @@ export class Translator {
* @param {boolean} ascending
*/
_updateSortFrequencies(dictionaryEntries, dictionary, ascending) {
/** @type {Map<number, number>} */
const frequencyMap = new Map();
for (const dictionaryEntry of dictionaryEntries) {
const {definitions, frequencies} = dictionaryEntry;
Expand Down
10 changes: 7 additions & 3 deletions ext/js/pages/settings/backup-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -574,12 +574,16 @@ export class BackupController {
* @returns {Promise<Blob>}
*/
async _exportDatabase(databaseName) {
const db = await new Dexie(databaseName).open();
const DexieConstructor = /** @type {import('dexie').DexieConstructor} */ (/** @type {unknown} */ (Dexie));
const db = new DexieConstructor(databaseName);
await db.open();
/** @type {unknown} */
// @ts-expect-error - The export function is declared as an extension which has no type information.
const blob = await db.export({
progressCallback: this._databaseExportProgressCallback.bind(this)
});
await db.close();
return blob;
db.close();
return /** @type {Blob} */ (blob);
}

/** */
Expand Down
1 change: 1 addition & 0 deletions ext/js/pages/settings/dictionary-import-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ export class DictionaryImportController {
* @param {Error[]} errors
*/
_showErrors(errors) {
/** @type {Map<string, number>} */
const uniqueErrors = new Map();
for (const error of errors) {
log.error(error);
Expand Down
Loading