From 48f1d012ad5045319d4e492dfbefa39da92817b2 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Mon, 15 Jan 2024 06:12:33 -0500 Subject: Add toError utility function (#523) * Add asError utility function * Rename to toError --- dev/dictionary-validate.js | 7 +++--- dev/to-error.js | 18 +++++++++++++++ ext/js/comm/mecab.js | 3 ++- ext/js/core/to-error.js | 26 ++++++++++++++++++++++ ext/js/dictionary/dictionary-importer.js | 3 ++- ext/js/display/display-anki.js | 17 +++++++------- ext/js/display/display.js | 5 +++-- ext/js/display/option-toggle-hotkey-handler.js | 3 ++- ext/js/dom/text-source-range.js | 3 ++- ext/js/pages/settings/anki-controller.js | 7 +++--- ext/js/pages/settings/anki-templates-controller.js | 3 ++- ext/js/pages/settings/backup-controller.js | 3 ++- .../pages/settings/dictionary-import-controller.js | 5 +++-- ext/js/pages/settings/mecab-controller.js | 3 ++- .../settings/permissions-origin-controller.js | 3 ++- .../settings/recommended-permissions-controller.js | 3 ++- 16 files changed, 85 insertions(+), 27 deletions(-) create mode 100644 dev/to-error.js create mode 100644 ext/js/core/to-error.js diff --git a/dev/dictionary-validate.js b/dev/dictionary-validate.js index 51edcc50..3727310e 100644 --- a/dev/dictionary-validate.js +++ b/dev/dictionary-validate.js @@ -23,6 +23,7 @@ import {performance} from 'perf_hooks'; import {fileURLToPath} from 'url'; import {parseJson} from './json.js'; import {createJsonSchema} from './schema-validate.js'; +import {toError} from './to-error.js'; const dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -47,7 +48,7 @@ async function validateDictionaryBanks(mode, zip, fileNameFormat, schema) { try { jsonSchema = createJsonSchema(mode, schema); } catch (e) { - const e2 = e instanceof Error ? e : new Error(`${e}`); + const e2 = toError(e); e2.message += `\n(in file ${fileNameFormat})}`; throw e2; } @@ -62,7 +63,7 @@ async function validateDictionaryBanks(mode, zip, fileNameFormat, schema) { try { jsonSchema.validate(data); } catch (e) { - const e2 = e instanceof Error ? e : new Error(`${e}`); + const e2 = toError(e); e2.message += `\n(in file ${fileName})}`; throw e2; } @@ -92,7 +93,7 @@ export async function validateDictionary(mode, archive, schemas) { const jsonSchema = createJsonSchema(mode, schemas.index); jsonSchema.validate(index); } catch (e) { - const e2 = e instanceof Error ? e : new Error(`${e}`); + const e2 = toError(e); e2.message += `\n(in file ${indexFileName})}`; throw e2; } diff --git a/dev/to-error.js b/dev/to-error.js new file mode 100644 index 00000000..1cc84f50 --- /dev/null +++ b/dev/to-error.js @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2023 Yomitan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +export {toError} from '../ext/js/core/to-error.js'; diff --git a/ext/js/comm/mecab.js b/ext/js/comm/mecab.js index 6d0f3f40..f3ad7b51 100644 --- a/ext/js/comm/mecab.js +++ b/ext/js/comm/mecab.js @@ -17,6 +17,7 @@ */ import {EventListenerCollection} from '../core.js'; +import {toError} from '../core/to-error.js'; /** * This class is used to connect Yomitan to a native component that is @@ -235,7 +236,7 @@ export class Mecab { try { await this._setupPortPromise; } catch (e) { - throw new Error(e instanceof Error ? e.message : `${e}`); + throw toError(e); } } diff --git a/ext/js/core/to-error.js b/ext/js/core/to-error.js new file mode 100644 index 00000000..4866c3da --- /dev/null +++ b/ext/js/core/to-error.js @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 Yomitan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * Utility function to convert an unknown value to an error. + * This is useful for try-catch situations where the catch parameter has the `unknown` type. + * @param {unknown} value + * @returns {Error} + */ +export function toError(value) { + return value instanceof Error ? value : new Error(`${value}`); +} diff --git a/ext/js/dictionary/dictionary-importer.js b/ext/js/dictionary/dictionary-importer.js index 2c0c7e9c..bfd7a8b2 100644 --- a/ext/js/dictionary/dictionary-importer.js +++ b/ext/js/dictionary/dictionary-importer.js @@ -27,6 +27,7 @@ import { import {stringReverse} from '../core.js'; import {ExtensionError} from '../core/extension-error.js'; import {parseJson} from '../core/json.js'; +import {toError} from '../core/to-error.js'; import {MediaUtil} from '../media/media-util.js'; const ajvSchemas = /** @type {import('dictionary-importer').CompiledSchemaValidators} */ (/** @type {unknown} */ (ajvSchemas0)); @@ -206,7 +207,7 @@ export class DictionaryImporter { try { await dictionaryDatabase.bulkAdd(objectStoreName, entries, i, count); } catch (e) { - errors.push(e instanceof Error ? e : new Error(`${e}`)); + errors.push(toError(e)); } this._progressData.index += count; diff --git a/ext/js/display/display-anki.js b/ext/js/display/display-anki.js index 759998c4..77ba7ffb 100644 --- a/ext/js/display/display-anki.js +++ b/ext/js/display/display-anki.js @@ -17,6 +17,7 @@ */ import {EventListenerCollection, deferPromise} from '../core.js'; +import {toError} from '../core/to-error.js'; import {AnkiNoteBuilder} from '../data/anki-note-builder.js'; import {AnkiUtil} from '../data/anki-util.js'; import {PopupMenu} from '../dom/popup-menu.js'; @@ -159,7 +160,7 @@ export class DisplayAnki { try { ({note: note, errors, requirements} = await this._createNote(dictionaryEntry, mode, [])); } catch (e) { - errors = [e instanceof Error ? e : new Error(`${e}`)]; + errors = [toError(e)]; } /** @type {import('display-anki').AnkiNoteLogData} */ const entry = {mode, note}; @@ -174,7 +175,7 @@ export class DisplayAnki { return { ankiNoteData, - ankiNoteDataException: ankiNoteDataException instanceof Error ? ankiNoteDataException : new Error(`${ankiNoteDataException}`), + ankiNoteDataException: toError(ankiNoteDataException), ankiNotes }; } @@ -490,7 +491,7 @@ export class DisplayAnki { addNoteOkay = true; } catch (e) { allErrors.length = 0; - allErrors.push(e instanceof Error ? e : new Error(`${e}`)); + allErrors.push(toError(e)); } if (addNoteOkay) { @@ -501,7 +502,7 @@ export class DisplayAnki { try { await yomitan.api.suspendAnkiCardsForNote(noteId); } catch (e) { - allErrors.push(e instanceof Error ? e : new Error(`${e}`)); + allErrors.push(toError(e)); } } button.disabled = true; @@ -509,7 +510,7 @@ export class DisplayAnki { } } } catch (e) { - allErrors.push(e instanceof Error ? e : new Error(`${e}`)); + allErrors.push(toError(e)); } finally { progressIndicatorVisible.clearOverride(overrideToken); } @@ -647,7 +648,7 @@ export class DisplayAnki { } } catch (e) { infos = this._getAnkiNoteInfoForceValue(notes, false); - ankiError = e instanceof Error ? e : new Error(`${e}`); + ankiError = toError(e); } /** @type {import('display-anki').DictionaryEntryDetails[]} */ @@ -855,11 +856,11 @@ export class DisplayAnki { await yomitan.api.noteView(noteIds[0], this._noteGuiMode, false); } catch (e) { const displayErrors = ( - e instanceof Error && e.message === 'Mode not supported' ? + toError(e).message === 'Mode not supported' ? [this._display.displayGenerator.instantiateTemplateFragment('footer-notification-anki-view-note-error')] : void 0 ); - this._showErrorNotification([e instanceof Error ? e : new Error(`${e}`)], displayErrors); + this._showErrorNotification([toError(e)], displayErrors); return; } } diff --git a/ext/js/display/display.js b/ext/js/display/display.js index ff77d203..7e7dd426 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -21,6 +21,7 @@ import {FrameEndpoint} from '../comm/frame-endpoint.js'; import {DynamicProperty, EventDispatcher, EventListenerCollection, clone, deepEqual, log, promiseTimeout} from '../core.js'; import {extendApiMap, invokeApiMapHandler} from '../core/api-map.js'; import {ExtensionError} from '../core/extension-error.js'; +import {toError} from '../core/to-error.js'; import {PopupMenu} from '../dom/popup-menu.js'; import {querySelectorNotNull} from '../dom/query-selector.js'; import {ScrollElement} from '../dom/scroll-element.js'; @@ -787,7 +788,7 @@ export class Display extends EventDispatcher { break; } } catch (e) { - this.onError(e instanceof Error ? e : new Error(`${e}`)); + this.onError(toError(e)); } } @@ -922,7 +923,7 @@ export class Display extends EventDispatcher { }; this.setContent(details); } catch (error) { - this.onError(error instanceof Error ? error : new Error(`${error}`)); + this.onError(toError(error)); } } diff --git a/ext/js/display/option-toggle-hotkey-handler.js b/ext/js/display/option-toggle-hotkey-handler.js index 73c92d59..ba4c8578 100644 --- a/ext/js/display/option-toggle-hotkey-handler.js +++ b/ext/js/display/option-toggle-hotkey-handler.js @@ -18,6 +18,7 @@ import {generateId} from '../core.js'; import {ExtensionError} from '../core/extension-error.js'; +import {toError} from '../core/to-error.js'; import {yomitan} from '../yomitan.js'; export class OptionToggleHotkeyHandler { @@ -132,7 +133,7 @@ export class OptionToggleHotkeyHandler { * @returns {DocumentFragment} */ _createErrorMessage(path, error) { - const message = error instanceof Error ? error.message : `${error}`; + const message = toError(error).message; const fragment = document.createDocumentFragment(); const n1 = document.createElement('em'); n1.textContent = path; diff --git a/ext/js/dom/text-source-range.js b/ext/js/dom/text-source-range.js index fd09fdda..7f4db4f2 100644 --- a/ext/js/dom/text-source-range.js +++ b/ext/js/dom/text-source-range.js @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import {toError} from '../core/to-error.js'; import {DocumentUtil} from './document-util.js'; import {DOMTextScanner} from './dom-text-scanner.js'; @@ -228,7 +229,7 @@ export class TextSourceRange { try { return this._range.compareBoundaryPoints(Range.START_TO_START, other.range) === 0; } catch (e) { - if (e instanceof Error && e.name === 'WrongDocumentError') { + if (toError(e).name === 'WrongDocumentError') { // This can happen with shadow DOMs if the ranges are in different documents. return false; } diff --git a/ext/js/pages/settings/anki-controller.js b/ext/js/pages/settings/anki-controller.js index d64034a5..c8daa85b 100644 --- a/ext/js/pages/settings/anki-controller.js +++ b/ext/js/pages/settings/anki-controller.js @@ -19,6 +19,7 @@ import {AnkiConnect} from '../../comm/anki-connect.js'; import {EventListenerCollection, log} from '../../core.js'; import {ExtensionError} from '../../core/extension-error.js'; +import {toError} from '../../core/to-error.js'; import {AnkiUtil} from '../../data/anki-util.js'; import {querySelectorNotNull} from '../../dom/query-selector.js'; import {SelectorObserver} from '../../dom/selector-observer.js'; @@ -409,7 +410,7 @@ export class AnkiController { this._sortStringArray(result); return [result, null]; } catch (e) { - return [[], e instanceof Error ? e : new Error(`${e}`)]; + return [[], toError(e)]; } } @@ -422,7 +423,7 @@ export class AnkiController { this._sortStringArray(result); return [result, null]; } catch (e) { - return [[], e instanceof Error ? e : new Error(`${e}`)]; + return [[], toError(e)]; } } @@ -487,7 +488,7 @@ export class AnkiController { try { await this._testAnkiNoteViewer(mode); } catch (e) { - this._setAnkiNoteViewerStatus(true, e instanceof Error ? e : new Error(`${e}`)); + this._setAnkiNoteViewerStatus(true, toError(e)); return; } this._setAnkiNoteViewerStatus(true, null); diff --git a/ext/js/pages/settings/anki-templates-controller.js b/ext/js/pages/settings/anki-templates-controller.js index 56e992b0..0c82cecc 100644 --- a/ext/js/pages/settings/anki-templates-controller.js +++ b/ext/js/pages/settings/anki-templates-controller.js @@ -17,6 +17,7 @@ */ import {ExtensionError} from '../../core/extension-error.js'; +import {toError} from '../../core/to-error.js'; import {AnkiNoteBuilder} from '../../data/anki-note-builder.js'; import {querySelectorNotNull} from '../../dom/query-selector.js'; import {JapaneseUtil} from '../../language/sandbox/japanese-util.js'; @@ -266,7 +267,7 @@ export class AnkiTemplatesController { allErrors.push(...errors); } } catch (e) { - allErrors.push(e instanceof Error ? e : new Error(`${e}`)); + allErrors.push(toError(e)); } /** diff --git a/ext/js/pages/settings/backup-controller.js b/ext/js/pages/settings/backup-controller.js index 2ae52925..457acc18 100644 --- a/ext/js/pages/settings/backup-controller.js +++ b/ext/js/pages/settings/backup-controller.js @@ -19,6 +19,7 @@ import {Dexie} from '../../../lib/dexie.js'; import {isObject, log} from '../../core.js'; import {parseJson} from '../../core/json.js'; +import {toError} from '../../core/to-error.js'; import {OptionsUtil} from '../../data/options-util.js'; import {ArrayBufferUtil} from '../../data/sandbox/array-buffer-util.js'; import {querySelectorNotNull} from '../../dom/query-selector.js'; @@ -498,7 +499,7 @@ export class BackupController { try { await this._importSettingsFile(file); } catch (error) { - this._showSettingsImportError(error instanceof Error ? error : new Error(`${error}`)); + this._showSettingsImportError(toError(error)); } } diff --git a/ext/js/pages/settings/dictionary-import-controller.js b/ext/js/pages/settings/dictionary-import-controller.js index eadfcb91..0c2fa7a5 100644 --- a/ext/js/pages/settings/dictionary-import-controller.js +++ b/ext/js/pages/settings/dictionary-import-controller.js @@ -18,6 +18,7 @@ import {log} from '../../core.js'; import {ExtensionError} from '../../core/extension-error.js'; +import {toError} from '../../core/to-error.js'; import {DictionaryWorker} from '../../dictionary/dictionary-worker.js'; import {querySelectorNotNull} from '../../dom/query-selector.js'; import {yomitan} from '../../yomitan.js'; @@ -126,7 +127,7 @@ export class DictionaryImportController { this._showErrors(errors); } } catch (error) { - this._showErrors([error instanceof Error ? error : new Error(`${error}`)]); + this._showErrors([toError(error)]); } finally { prevention.end(); this._setModifying(false); @@ -200,7 +201,7 @@ export class DictionaryImportController { await this._importDictionary(files[i], importDetails, onProgress); } } catch (err) { - this._showErrors([err instanceof Error ? err : new Error(`${err}`)]); + this._showErrors([toError(err)]); } finally { prevention.end(); for (const progress of progressContainers) { progress.hidden = true; } diff --git a/ext/js/pages/settings/mecab-controller.js b/ext/js/pages/settings/mecab-controller.js index 9c55c9a0..f57bc3c9 100644 --- a/ext/js/pages/settings/mecab-controller.js +++ b/ext/js/pages/settings/mecab-controller.js @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import {toError} from '../../core/to-error.js'; import {querySelectorNotNull} from '../../dom/query-selector.js'; import {yomitan} from '../../yomitan.js'; @@ -57,7 +58,7 @@ export class MecabController { await yomitan.api.testMecab(); this._setStatus('Connection was successful', false); } catch (e) { - this._setStatus(e instanceof Error ? e.message : `${e}`, true); + this._setStatus(toError(e).message, true); } finally { this._testActive = false; /** @type {HTMLButtonElement} */ (this._testButton).disabled = false; diff --git a/ext/js/pages/settings/permissions-origin-controller.js b/ext/js/pages/settings/permissions-origin-controller.js index 3a9db602..73f06a56 100644 --- a/ext/js/pages/settings/permissions-origin-controller.js +++ b/ext/js/pages/settings/permissions-origin-controller.js @@ -17,6 +17,7 @@ */ import {EventListenerCollection} from '../../core.js'; +import {toError} from '../../core/to-error.js'; import {querySelectorNotNull} from '../../dom/query-selector.js'; export class PermissionsOriginController { @@ -155,7 +156,7 @@ export class PermissionsOriginController { } catch (e) { const errorContainer = /** @type {HTMLElement} */ (this._errorContainer); errorContainer.hidden = false; - errorContainer.textContent = e instanceof Error ? e.message : `${e}`; + errorContainer.textContent = toError(e).message; } if (!added) { return false; } await this._updatePermissions(); diff --git a/ext/js/pages/settings/recommended-permissions-controller.js b/ext/js/pages/settings/recommended-permissions-controller.js index a870de50..0500759e 100644 --- a/ext/js/pages/settings/recommended-permissions-controller.js +++ b/ext/js/pages/settings/recommended-permissions-controller.js @@ -17,6 +17,7 @@ */ import {EventListenerCollection} from '../../core.js'; +import {toError} from '../../core/to-error.js'; export class RecommendedPermissionsController { /** @@ -92,7 +93,7 @@ export class RecommendedPermissionsController { } catch (e) { if (this._errorContainer !== null) { this._errorContainer.hidden = false; - this._errorContainer.textContent = e instanceof Error ? e.message : `${e}`; + this._errorContainer.textContent = toError(e).message; } } if (!added) { return false; } -- cgit v1.2.3