From 4da4827bcbcdd1ef163f635d9b29416ff272b0bb Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Mon, 27 Nov 2023 12:48:14 -0500 Subject: Add JSDoc type annotations to project (rebased) --- ext/js/data/anki-note-builder.js | 143 ++++++++++++++++++++++++++++++++++----- 1 file changed, 125 insertions(+), 18 deletions(-) (limited to 'ext/js/data/anki-note-builder.js') diff --git a/ext/js/data/anki-note-builder.js b/ext/js/data/anki-note-builder.js index 398036c0..f8296ee0 100644 --- a/ext/js/data/anki-note-builder.js +++ b/ext/js/data/anki-note-builder.js @@ -16,20 +16,32 @@ * along with this program. If not, see . */ -import {deferPromise, deserializeError} from '../core.js'; +import {deferPromise} from '../core.js'; import {TemplateRendererProxy} from '../templates/template-renderer-proxy.js'; import {yomitan} from '../yomitan.js'; import {AnkiUtil} from './anki-util.js'; export class AnkiNoteBuilder { + /** + * @param {{japaneseUtil: JapaneseUtil}} details + */ constructor({japaneseUtil}) { + /** @type {JapaneseUtil} */ this._japaneseUtil = japaneseUtil; + /** @type {RegExp} */ this._markerPattern = AnkiUtil.cloneFieldMarkerPattern(true); + /** @type {TemplateRendererProxy} */ this._templateRenderer = new TemplateRendererProxy(); + /** @type {import('anki-note-builder').BatchedRequestGroup[]} */ this._batchedRequests = []; + /** @type {boolean} */ this._batchedRequestsQueued = false; } + /** + * @param {import('anki-note-builder').CreateNoteDetails} details + * @returns {Promise} + */ async createNote({ dictionaryEntry, mode, @@ -56,16 +68,15 @@ export class AnkiNoteBuilder { duplicateScopeCheckChildren = true; } + /** @type {Error[]} */ const allErrors = []; let media; if (requirements.length > 0 && mediaOptions !== null) { let errors; ({media, errors} = await this._injectMedia(dictionaryEntry, requirements, mediaOptions)); for (const error of errors) { - allErrors.push(deserializeError(error)); + allErrors.push(ExtensionError.deserialize(error)); } - } else { - media = {}; } const commonData = this._createData(dictionaryEntry, mode, context, resultOutputMode, glossaryLayoutMode, compactTags, media); @@ -77,6 +88,7 @@ export class AnkiNoteBuilder { const formattedFieldValues = await Promise.all(formattedFieldValuePromises); const uniqueRequirements = new Map(); + /** @type {import('anki').NoteFields} */ const noteFields = {}; for (let i = 0, ii = fields.length; i < ii; ++i) { const fieldName = fields[i][0]; @@ -90,6 +102,7 @@ export class AnkiNoteBuilder { } } + /** @type {import('anki').Note} */ const note = { fields: noteFields, tags, @@ -108,6 +121,10 @@ export class AnkiNoteBuilder { return {note, errors: allErrors, requirements: [...uniqueRequirements.values()]}; } + /** + * @param {import('anki-note-builder').GetRenderingDataDetails} details + * @returns {Promise} + */ async getRenderingData({ dictionaryEntry, mode, @@ -115,12 +132,16 @@ export class AnkiNoteBuilder { resultOutputMode='split', glossaryLayoutMode='default', compactTags=false, - marker=null + marker }) { - const commonData = this._createData(dictionaryEntry, mode, context, resultOutputMode, glossaryLayoutMode, compactTags, {}); + const commonData = this._createData(dictionaryEntry, mode, context, resultOutputMode, glossaryLayoutMode, compactTags, void 0); return await this._templateRenderer.getModifiedData({marker, commonData}, 'ankiNote'); } + /** + * @param {import('dictionary').DictionaryEntry} dictionaryEntry + * @returns {import('api').InjectAnkiNoteMediaDefinitionDetails} + */ getDictionaryEntryDetailsForNote(dictionaryEntry) { const {type} = dictionaryEntry; if (type === 'kanji') { @@ -150,6 +171,16 @@ export class AnkiNoteBuilder { // Private + /** + * @param {import('dictionary').DictionaryEntry} dictionaryEntry + * @param {import('anki-templates-internal').CreateMode} mode + * @param {import('anki-templates-internal').Context} context + * @param {import('settings').ResultOutputMode} resultOutputMode + * @param {import('settings').GlossaryLayoutMode} glossaryLayoutMode + * @param {boolean} compactTags + * @param {import('anki-templates').Media|undefined} media + * @returns {import('anki-note-builder').CommonData} + */ _createData(dictionaryEntry, mode, context, resultOutputMode, glossaryLayoutMode, compactTags, media) { return { dictionaryEntry, @@ -162,16 +193,25 @@ export class AnkiNoteBuilder { }; } + /** + * @param {string} field + * @param {import('anki-note-builder').CommonData} commonData + * @param {string} template + * @returns {Promise<{value: string, errors: ExtensionError[], requirements: import('anki-note-builder').Requirement[]}>} + */ async _formatField(field, commonData, template) { + /** @type {ExtensionError[]} */ const errors = []; + /** @type {import('anki-note-builder').Requirement[]} */ const requirements = []; - const value = await this._stringReplaceAsync(field, this._markerPattern, async (g0, marker) => { + const value = await this._stringReplaceAsync(field, this._markerPattern, async (match) => { + const marker = match[1]; try { const {result, requirements: fieldRequirements} = await this._renderTemplateBatched(template, commonData, marker); requirements.push(...fieldRequirements); return result; } catch (e) { - const error = new Error(`Template render error for {${marker}}`); + const error = new ExtensionError(`Template render error for {${marker}}`); error.data = {error: e}; errors.push(error); return `{${marker}-render-error}`; @@ -180,12 +220,19 @@ export class AnkiNoteBuilder { return {value, errors, requirements}; } + /** + * @param {string} str + * @param {RegExp} regex + * @param {(match: RegExpExecArray, index: number, str: string) => (string|Promise)} replacer + * @returns {Promise} + */ async _stringReplaceAsync(str, regex, replacer) { let match; let index = 0; + /** @type {(Promise|string)[]} */ const parts = []; while ((match = regex.exec(str)) !== null) { - parts.push(str.substring(index, match.index), replacer(...match, match.index, str)); + parts.push(str.substring(index, match.index), replacer(match, match.index, str)); index = regex.lastIndex; } if (parts.length === 0) { @@ -195,6 +242,10 @@ export class AnkiNoteBuilder { return (await Promise.all(parts)).join(''); } + /** + * @param {string} template + * @returns {import('anki-note-builder').BatchedRequestGroup} + */ _getBatchedTemplateGroup(template) { for (const item of this._batchedRequests) { if (item.template === template) { @@ -207,7 +258,14 @@ export class AnkiNoteBuilder { return result; } + /** + * @param {string} template + * @param {import('anki-note-builder').CommonData} commonData + * @param {string} marker + * @returns {Promise} + */ _renderTemplateBatched(template, commonData, marker) { + /** @type {import('core').DeferredPromiseDetails} */ const {promise, resolve, reject} = deferPromise(); const {commonDataRequestsMap} = this._getBatchedTemplateGroup(template); let requests = commonDataRequestsMap.get(commonData); @@ -220,6 +278,9 @@ export class AnkiNoteBuilder { return promise; } + /** + * @returns {void} + */ _runBatchedRequestsDelayed() { if (this._batchedRequestsQueued) { return; } this._batchedRequestsQueued = true; @@ -229,20 +290,30 @@ export class AnkiNoteBuilder { }); } + /** + * @returns {void} + */ _runBatchedRequests() { if (this._batchedRequests.length === 0) { return; } const allRequests = []; + /** @type {import('template-renderer').RenderMultiItem[]} */ const items = []; for (const {template, commonDataRequestsMap} of this._batchedRequests) { + /** @type {import('template-renderer').RenderMultiTemplateItem[]} */ const templateItems = []; for (const [commonData, requests] of commonDataRequestsMap.entries()) { + /** @type {import('template-renderer').PartialOrCompositeRenderData[]} */ const datas = []; for (const {marker} of requests) { - datas.push(marker); + datas.push({marker}); } allRequests.push(...requests); - templateItems.push({type: 'ankiNote', commonData, datas}); + templateItems.push({ + type: /** @type {import('anki-templates').RenderMode} */ ('ankiNote'), + commonData, + datas + }); } items.push({template, templateItems}); } @@ -252,6 +323,10 @@ export class AnkiNoteBuilder { this._resolveBatchedRequests(items, allRequests); } + /** + * @param {import('template-renderer').RenderMultiItem[]} items + * @param {import('anki-note-builder').BatchedRequestData[]} requests + */ async _resolveBatchedRequests(items, requests) { let responses; try { @@ -269,7 +344,7 @@ export class AnkiNoteBuilder { const response = responses[i]; const {error} = response; if (typeof error !== 'undefined') { - throw deserializeError(error); + throw ExtensionError.deserialize(error); } else { request.resolve(response.result); } @@ -279,6 +354,12 @@ export class AnkiNoteBuilder { } } + /** + * @param {import('dictionary').DictionaryEntry} dictionaryEntry + * @param {import('anki-note-builder').Requirement[]} requirements + * @param {import('anki-note-builder').MediaOptions} mediaOptions + * @returns {Promise<{media: import('anki-templates').Media, errors: import('core').SerializedError[]}>} + */ async _injectMedia(dictionaryEntry, requirements, mediaOptions) { const timestamp = Date.now(); @@ -288,7 +369,9 @@ export class AnkiNoteBuilder { let injectClipboardImage = false; let injectClipboardText = false; let injectSelectionText = false; + /** @type {import('anki-note-builder').TextFuriganaDetails[]} */ const textFuriganaDetails = []; + /** @type {import('api').InjectAnkiNoteMediaDictionaryMediaDetails[]} */ const dictionaryMediaDetails = []; for (const requirement of requirements) { const {type} = requirement; @@ -315,8 +398,11 @@ export class AnkiNoteBuilder { // Generate request data const dictionaryEntryDetails = this.getDictionaryEntryDetailsForNote(dictionaryEntry); + /** @type {?import('api').InjectAnkiNoteMediaAudioDetails} */ let audioDetails = null; + /** @type {?import('api').InjectAnkiNoteMediaScreenshotDetails} */ let screenshotDetails = null; + /** @type {import('api').InjectAnkiNoteMediaClipboardDetails} */ const clipboardDetails = {image: injectClipboardImage, text: injectClipboardText}; if (injectAudio && dictionaryEntryDetails.type !== 'kanji') { const audioOptions = mediaOptions.audio; @@ -357,6 +443,7 @@ export class AnkiNoteBuilder { const textFurigana = textFuriganaPromise !== null ? await textFuriganaPromise : []; // Format results + /** @type {import('anki-templates').DictionaryMedia} */ const dictionaryMedia = {}; for (const {dictionary, path, fileName} of dictionaryMediaArray) { if (fileName === null) { continue; } @@ -368,21 +455,31 @@ export class AnkiNoteBuilder { dictionaryMedia2[path] = {value: fileName}; } const media = { - audio: (typeof audioFileName === 'string' ? {value: audioFileName} : null), - screenshot: (typeof screenshotFileName === 'string' ? {value: screenshotFileName} : null), - clipboardImage: (typeof clipboardImageFileName === 'string' ? {value: clipboardImageFileName} : null), - clipboardText: (typeof clipboardText === 'string' ? {value: clipboardText} : null), - selectionText: (typeof selectionText === 'string' ? {value: selectionText} : null), + audio: (typeof audioFileName === 'string' ? {value: audioFileName} : void 0), + screenshot: (typeof screenshotFileName === 'string' ? {value: screenshotFileName} : void 0), + clipboardImage: (typeof clipboardImageFileName === 'string' ? {value: clipboardImageFileName} : void 0), + clipboardText: (typeof clipboardText === 'string' ? {value: clipboardText} : void 0), + selectionText: (typeof selectionText === 'string' ? {value: selectionText} : void 0), textFurigana, dictionaryMedia }; return {media, errors}; } + /** + * @returns {string} + */ _getSelectionText() { - return document.getSelection().toString(); + const selection = document.getSelection(); + return selection !== null ? selection.toString() : ''; } + /** + * @param {import('anki-note-builder').TextFuriganaDetails[]} entries + * @param {import('settings').OptionsContext} optionsContext + * @param {number} scanLength + * @returns {Promise} + */ async _getTextFurigana(entries, optionsContext, scanLength) { const results = []; for (const {text, readingMode} of entries) { @@ -401,6 +498,11 @@ export class AnkiNoteBuilder { return results; } + /** + * @param {import('api').ParseTextLine[]} data + * @param {?import('anki-templates').TextFuriganaReadingMode} readingMode + * @returns {string} + */ _createFuriganaHtml(data, readingMode) { let result = ''; for (const term of data) { @@ -418,6 +520,11 @@ export class AnkiNoteBuilder { return result; } + /** + * @param {string} reading + * @param {?import('anki-templates').TextFuriganaReadingMode} readingMode + * @returns {string} + */ _convertReading(reading, readingMode) { switch (readingMode) { case 'hiragana': -- cgit v1.2.3 From 6a3dae04de68ab633da15bbc8ec6b350e38e6d2f Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Mon, 27 Nov 2023 13:54:43 -0500 Subject: Add extension error imports --- ext/js/app/popup.js | 1 + ext/js/comm/anki-connect.js | 1 + ext/js/data/anki-note-builder.js | 1 + ext/js/display/display-generator.js | 1 + ext/js/display/option-toggle-hotkey-handler.js | 1 + ext/js/language/dictionary-worker-handler.js | 1 + ext/js/language/dictionary-worker-media-loader.js | 1 + ext/js/language/dictionary-worker.js | 1 + ext/js/media/audio-downloader.js | 1 + ext/js/pages/settings/anki-controller.js | 1 + ext/js/pages/settings/anki-templates-controller.js | 1 + ext/js/pages/settings/dictionary-import-controller.js | 1 + ext/js/pages/settings/generic-setting-controller.js | 1 + ext/js/templates/sandbox/template-renderer-frame-api.js | 2 ++ ext/js/templates/sandbox/template-renderer.js | 1 + ext/js/templates/template-renderer-proxy.js | 1 + 16 files changed, 17 insertions(+) (limited to 'ext/js/data/anki-note-builder.js') diff --git a/ext/js/app/popup.js b/ext/js/app/popup.js index 31b18f01..4f201fc3 100644 --- a/ext/js/app/popup.js +++ b/ext/js/app/popup.js @@ -18,6 +18,7 @@ import {FrameClient} from '../comm/frame-client.js'; import {DynamicProperty, EventDispatcher, EventListenerCollection, deepEqual} from '../core.js'; +import {ExtensionError} from '../core/extension-error.js'; import {DocumentUtil} from '../dom/document-util.js'; import {dynamicLoader} from '../script/dynamic-loader.js'; import {yomitan} from '../yomitan.js'; diff --git a/ext/js/comm/anki-connect.js b/ext/js/comm/anki-connect.js index b876703f..7ff8d0e1 100644 --- a/ext/js/comm/anki-connect.js +++ b/ext/js/comm/anki-connect.js @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import {ExtensionError} from '../core/extension-error.js'; import {AnkiUtil} from '../data/anki-util.js'; /** diff --git a/ext/js/data/anki-note-builder.js b/ext/js/data/anki-note-builder.js index f8296ee0..28809e1f 100644 --- a/ext/js/data/anki-note-builder.js +++ b/ext/js/data/anki-note-builder.js @@ -17,6 +17,7 @@ */ import {deferPromise} from '../core.js'; +import {ExtensionError} from '../core/extension-error.js'; import {TemplateRendererProxy} from '../templates/template-renderer-proxy.js'; import {yomitan} from '../yomitan.js'; import {AnkiUtil} from './anki-util.js'; diff --git a/ext/js/display/display-generator.js b/ext/js/display/display-generator.js index 9fc700f3..e8be79d9 100644 --- a/ext/js/display/display-generator.js +++ b/ext/js/display/display-generator.js @@ -17,6 +17,7 @@ */ import {isObject} from '../core.js'; +import {ExtensionError} from '../core/extension-error.js'; import {HtmlTemplateCollection} from '../dom/html-template-collection.js'; import {DictionaryDataUtil} from '../language/sandbox/dictionary-data-util.js'; import {yomitan} from '../yomitan.js'; diff --git a/ext/js/display/option-toggle-hotkey-handler.js b/ext/js/display/option-toggle-hotkey-handler.js index e73fcf04..9677e86b 100644 --- a/ext/js/display/option-toggle-hotkey-handler.js +++ b/ext/js/display/option-toggle-hotkey-handler.js @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import {ExtensionError} from '../core/extension-error.js'; import {yomitan} from '../yomitan.js'; export class OptionToggleHotkeyHandler { diff --git a/ext/js/language/dictionary-worker-handler.js b/ext/js/language/dictionary-worker-handler.js index 3a85cb71..9a724386 100644 --- a/ext/js/language/dictionary-worker-handler.js +++ b/ext/js/language/dictionary-worker-handler.js @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import {ExtensionError} from '../core/extension-error.js'; import {DictionaryDatabase} from './dictionary-database.js'; import {DictionaryImporter} from './dictionary-importer.js'; import {DictionaryWorkerMediaLoader} from './dictionary-worker-media-loader.js'; diff --git a/ext/js/language/dictionary-worker-media-loader.js b/ext/js/language/dictionary-worker-media-loader.js index 2701389e..e19a13d3 100644 --- a/ext/js/language/dictionary-worker-media-loader.js +++ b/ext/js/language/dictionary-worker-media-loader.js @@ -17,6 +17,7 @@ */ import {generateId} from '../core.js'; +import {ExtensionError} from '../core/extension-error.js'; /** * Class used for loading and validating media from a worker thread diff --git a/ext/js/language/dictionary-worker.js b/ext/js/language/dictionary-worker.js index b9d0236c..3e78a6ff 100644 --- a/ext/js/language/dictionary-worker.js +++ b/ext/js/language/dictionary-worker.js @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import {ExtensionError} from '../core/extension-error.js'; import {DictionaryImporterMediaLoader} from './dictionary-importer-media-loader.js'; export class DictionaryWorker { diff --git a/ext/js/media/audio-downloader.js b/ext/js/media/audio-downloader.js index 8bd04b2b..7b236790 100644 --- a/ext/js/media/audio-downloader.js +++ b/ext/js/media/audio-downloader.js @@ -17,6 +17,7 @@ */ import {RequestBuilder} from '../background/request-builder.js'; +import {ExtensionError} from '../core/extension-error.js'; import {JsonSchema} from '../data/json-schema.js'; import {ArrayBufferUtil} from '../data/sandbox/array-buffer-util.js'; import {NativeSimpleDOMParser} from '../dom/native-simple-dom-parser.js'; diff --git a/ext/js/pages/settings/anki-controller.js b/ext/js/pages/settings/anki-controller.js index 0ccd018d..722459df 100644 --- a/ext/js/pages/settings/anki-controller.js +++ b/ext/js/pages/settings/anki-controller.js @@ -18,6 +18,7 @@ import {AnkiConnect} from '../../comm/anki-connect.js'; import {EventListenerCollection, log} from '../../core.js'; +import {ExtensionError} from '../../core/extension-error.js'; import {AnkiUtil} from '../../data/anki-util.js'; import {SelectorObserver} from '../../dom/selector-observer.js'; import {ObjectPropertyAccessor} from '../../general/object-property-accessor.js'; diff --git a/ext/js/pages/settings/anki-templates-controller.js b/ext/js/pages/settings/anki-templates-controller.js index d2814880..a0ff96b2 100644 --- a/ext/js/pages/settings/anki-templates-controller.js +++ b/ext/js/pages/settings/anki-templates-controller.js @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import {ExtensionError} from '../../core/extension-error.js'; import {AnkiNoteBuilder} from '../../data/anki-note-builder.js'; import {JapaneseUtil} from '../../language/sandbox/japanese-util.js'; import {yomitan} from '../../yomitan.js'; diff --git a/ext/js/pages/settings/dictionary-import-controller.js b/ext/js/pages/settings/dictionary-import-controller.js index 106ecbca..af8c2fcd 100644 --- a/ext/js/pages/settings/dictionary-import-controller.js +++ b/ext/js/pages/settings/dictionary-import-controller.js @@ -17,6 +17,7 @@ */ import {log} from '../../core.js'; +import {ExtensionError} from '../../core/extension-error.js'; import {DictionaryWorker} from '../../language/dictionary-worker.js'; import {yomitan} from '../../yomitan.js'; import {DictionaryController} from './dictionary-controller.js'; diff --git a/ext/js/pages/settings/generic-setting-controller.js b/ext/js/pages/settings/generic-setting-controller.js index 3c6104a9..47c0d6fe 100644 --- a/ext/js/pages/settings/generic-setting-controller.js +++ b/ext/js/pages/settings/generic-setting-controller.js @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import {ExtensionError} from '../../core/extension-error.js'; import {DocumentUtil} from '../../dom/document-util.js'; import {DOMDataBinder} from '../../dom/dom-data-binder.js'; diff --git a/ext/js/templates/sandbox/template-renderer-frame-api.js b/ext/js/templates/sandbox/template-renderer-frame-api.js index 31ba4500..91400ab8 100644 --- a/ext/js/templates/sandbox/template-renderer-frame-api.js +++ b/ext/js/templates/sandbox/template-renderer-frame-api.js @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +import {ExtensionError} from '../../core/extension-error.js'; + export class TemplateRendererFrameApi { /** * @param {TemplateRenderer} templateRenderer diff --git a/ext/js/templates/sandbox/template-renderer.js b/ext/js/templates/sandbox/template-renderer.js index c7613533..716e3ccc 100644 --- a/ext/js/templates/sandbox/template-renderer.js +++ b/ext/js/templates/sandbox/template-renderer.js @@ -17,6 +17,7 @@ */ import {Handlebars} from '../../../lib/handlebars.js'; +import {ExtensionError} from '../../core/extension-error.js'; export class TemplateRenderer { constructor() { diff --git a/ext/js/templates/template-renderer-proxy.js b/ext/js/templates/template-renderer-proxy.js index e67b715a..642eea8b 100644 --- a/ext/js/templates/template-renderer-proxy.js +++ b/ext/js/templates/template-renderer-proxy.js @@ -17,6 +17,7 @@ */ import {generateId} from '../core.js'; +import {ExtensionError} from '../core/extension-error.js'; export class TemplateRendererProxy { constructor() { -- cgit v1.2.3 From ac562ca36417f2d9fdb860d1f8a879fdccde438d Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Mon, 27 Nov 2023 15:16:07 -0500 Subject: Update types --- .vscode/settings.json | 2 +- ext/js/data/anki-note-builder.js | 4 ++-- ext/js/data/options-util.js | 7 +++++++ ext/js/data/sandbox/anki-note-data-creator.js | 4 ++-- ext/js/display/display-anki.js | 14 +++++++------- ext/js/display/display-audio.js | 4 ++-- ext/js/display/display-content-manager.js | 4 ++-- ext/js/display/display-generator.js | 6 +++--- ext/js/display/display-profile-selection.js | 4 ++-- ext/js/display/display-resizer.js | 4 ++-- ext/js/display/display.js | 18 +++++++++--------- ext/js/display/option-toggle-hotkey-handler.js | 7 ++++--- ext/js/display/query-parser.js | 2 +- ext/js/display/sandbox/pronunciation-generator.js | 4 ++-- ext/js/display/sandbox/structured-content-generator.js | 8 ++++---- ext/js/display/search-display-controller.js | 14 +++++++------- 16 files changed, 57 insertions(+), 49 deletions(-) (limited to 'ext/js/data/anki-note-builder.js') diff --git a/.vscode/settings.json b/.vscode/settings.json index 81cd7b9c..734f6360 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,7 +2,7 @@ "markdown.extension.toc.levels": "1..3", "editor.codeActionsOnSave": { "source.addMissingImports": false, - "source.organizeImports": true, + "source.organizeImports": false, "source.fixAll.eslint": false }, "eslint.format.enable": true, diff --git a/ext/js/data/anki-note-builder.js b/ext/js/data/anki-note-builder.js index 28809e1f..4920db39 100644 --- a/ext/js/data/anki-note-builder.js +++ b/ext/js/data/anki-note-builder.js @@ -24,10 +24,10 @@ import {AnkiUtil} from './anki-util.js'; export class AnkiNoteBuilder { /** - * @param {{japaneseUtil: JapaneseUtil}} details + * @param {{japaneseUtil: import('../language/sandbox/japanese-util.js').JapaneseUtil}} details */ constructor({japaneseUtil}) { - /** @type {JapaneseUtil} */ + /** @type {import('../language/sandbox/japanese-util.js').JapaneseUtil} */ this._japaneseUtil = japaneseUtil; /** @type {RegExp} */ this._markerPattern = AnkiUtil.cloneFieldMarkerPattern(true); diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js index e8723f1f..70c1622f 100644 --- a/ext/js/data/options-util.js +++ b/ext/js/data/options-util.js @@ -1144,6 +1144,9 @@ export class OptionsUtil { return options; } + /** + * @type {import('options-util').ModernUpdateFunctionAsync} + */ async _updateVersion21(options) { await this._applyAnkiFieldTemplatesPatch(options, '/data/templates/anki-field-templates-upgrade-v21.handlebars'); @@ -1163,6 +1166,10 @@ export class OptionsUtil { return options; } + /** + * @param {string} url + * @returns {Promise} + */ _createTab(url) { return new Promise((resolve, reject) => { chrome.tabs.create({url}, (tab) => { diff --git a/ext/js/data/sandbox/anki-note-data-creator.js b/ext/js/data/sandbox/anki-note-data-creator.js index 821d4024..dce71938 100644 --- a/ext/js/data/sandbox/anki-note-data-creator.js +++ b/ext/js/data/sandbox/anki-note-data-creator.js @@ -25,10 +25,10 @@ import {DictionaryDataUtil} from '../../language/sandbox/dictionary-data-util.js export class AnkiNoteDataCreator { /** * Creates a new instance. - * @param {JapaneseUtil} japaneseUtil An instance of `JapaneseUtil`. + * @param {import('../../language/sandbox/japanese-util.js').JapaneseUtil} japaneseUtil An instance of `JapaneseUtil`. */ constructor(japaneseUtil) { - /** @type {JapaneseUtil} */ + /** @type {import('../../language/sandbox/japanese-util.js').JapaneseUtil} */ this._japaneseUtil = japaneseUtil; } diff --git a/ext/js/display/display-anki.js b/ext/js/display/display-anki.js index c0173697..d0da568c 100644 --- a/ext/js/display/display-anki.js +++ b/ext/js/display/display-anki.js @@ -24,14 +24,14 @@ import {yomitan} from '../yomitan.js'; export class DisplayAnki { /** - * @param {Display} display - * @param {DisplayAudio} displayAudio - * @param {JapaneseUtil} japaneseUtil + * @param {import('./display.js').Display} display + * @param {import('./display-audio.js').DisplayAudio} displayAudio + * @param {import('../language/sandbox/japanese-util.js').JapaneseUtil} japaneseUtil */ constructor(display, displayAudio, japaneseUtil) { - /** @type {Display} */ + /** @type {import('./display.js').Display} */ this._display = display; - /** @type {DisplayAudio} */ + /** @type {import('./display-audio.js').DisplayAudio} */ this._displayAudio = displayAudio; /** @type {?string} */ this._ankiFieldTemplates = null; @@ -39,11 +39,11 @@ export class DisplayAnki { this._ankiFieldTemplatesDefault = null; /** @type {AnkiNoteBuilder} */ this._ankiNoteBuilder = new AnkiNoteBuilder({japaneseUtil}); - /** @type {?DisplayNotification} */ + /** @type {?import('./display-notification.js').DisplayNotification} */ this._errorNotification = null; /** @type {?EventListenerCollection} */ this._errorNotificationEventListeners = null; - /** @type {?DisplayNotification} */ + /** @type {?import('./display-notification.js').DisplayNotification} */ this._tagsNotification = null; /** @type {?Promise} */ this._updateAdderButtonsPromise = null; diff --git a/ext/js/display/display-audio.js b/ext/js/display/display-audio.js index 8d917e81..3fbfc3c8 100644 --- a/ext/js/display/display-audio.js +++ b/ext/js/display/display-audio.js @@ -23,10 +23,10 @@ import {yomitan} from '../yomitan.js'; export class DisplayAudio { /** - * @param {Display} display + * @param {import('./display.js').Display} display */ constructor(display) { - /** @type {Display} */ + /** @type {import('./display.js').Display} */ this._display = display; /** @type {?import('display-audio').GenericAudio} */ this._audioPlaying = null; diff --git a/ext/js/display/display-content-manager.js b/ext/js/display/display-content-manager.js index fa8ad0fa..c78ef7e8 100644 --- a/ext/js/display/display-content-manager.js +++ b/ext/js/display/display-content-manager.js @@ -26,10 +26,10 @@ import {yomitan} from '../yomitan.js'; export class DisplayContentManager { /** * Creates a new instance of the class. - * @param {Display} display The display instance that owns this object. + * @param {import('./display.js').Display} display The display instance that owns this object. */ constructor(display) { - /** @type {Display} */ + /** @type {import('./display.js').Display} */ this._display = display; /** @type {import('core').TokenObject} */ this._token = {}; diff --git a/ext/js/display/display-generator.js b/ext/js/display/display-generator.js index e8be79d9..eb464001 100644 --- a/ext/js/display/display-generator.js +++ b/ext/js/display/display-generator.js @@ -29,11 +29,11 @@ export class DisplayGenerator { * @param {import('display').DisplayGeneratorConstructorDetails} details */ constructor({japaneseUtil, contentManager, hotkeyHelpController=null}) { - /** @type {JapaneseUtil} */ + /** @type {import('../language/sandbox/japanese-util.js').JapaneseUtil} */ this._japaneseUtil = japaneseUtil; - /** @type {DisplayContentManager} */ + /** @type {import('./display-content-manager.js').DisplayContentManager} */ this._contentManager = contentManager; - /** @type {?HotkeyHelpController} */ + /** @type {?import('../input/hotkey-help-controller.js').HotkeyHelpController} */ this._hotkeyHelpController = hotkeyHelpController; /** @type {HtmlTemplateCollection} */ this._templates = new HtmlTemplateCollection(); diff --git a/ext/js/display/display-profile-selection.js b/ext/js/display/display-profile-selection.js index 619d07aa..c5cb7d06 100644 --- a/ext/js/display/display-profile-selection.js +++ b/ext/js/display/display-profile-selection.js @@ -22,10 +22,10 @@ import {yomitan} from '../yomitan.js'; export class DisplayProfileSelection { /** - * @param {Display} display + * @param {import('./display.js').Display} display */ constructor(display) { - /** @type {Display} */ + /** @type {import('./display.js').Display} */ this._display = display; /** @type {HTMLElement} */ this._profielList = /** @type {HTMLElement} */ (document.querySelector('#profile-list')); diff --git a/ext/js/display/display-resizer.js b/ext/js/display/display-resizer.js index 6280286d..8ce7e91a 100644 --- a/ext/js/display/display-resizer.js +++ b/ext/js/display/display-resizer.js @@ -20,10 +20,10 @@ import {EventListenerCollection} from '../core.js'; export class DisplayResizer { /** - * @param {Display} display + * @param {import('./display.js').Display} display */ constructor(display) { - /** @type {Display} */ + /** @type {import('./display.js').Display} */ this._display = display; /** @type {?import('core').TokenObject} */ this._token = null; diff --git a/ext/js/display/display.js b/ext/js/display/display.js index f9c36a67..f14291d1 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -43,9 +43,9 @@ export class Display extends EventDispatcher { * @param {number|undefined} tabId * @param {number|undefined} frameId * @param {import('display').DisplayPageType} pageType - * @param {JapaneseUtil} japaneseUtil - * @param {DocumentFocusController} documentFocusController - * @param {HotkeyHandler} hotkeyHandler + * @param {import('../language/sandbox/japanese-util.js').JapaneseUtil} japaneseUtil + * @param {import('../dom/document-focus-controller.js').DocumentFocusController} documentFocusController + * @param {import('../input/hotkey-handler.js').HotkeyHandler} hotkeyHandler */ constructor(tabId, frameId, pageType, japaneseUtil, documentFocusController, hotkeyHandler) { super(); @@ -55,11 +55,11 @@ export class Display extends EventDispatcher { this._frameId = frameId; /** @type {import('display').DisplayPageType} */ this._pageType = pageType; - /** @type {JapaneseUtil} */ + /** @type {import('../language/sandbox/japanese-util.js').JapaneseUtil} */ this._japaneseUtil = japaneseUtil; - /** @type {DocumentFocusController} */ + /** @type {import('../dom/document-focus-controller.js').DocumentFocusController} */ this._documentFocusController = documentFocusController; - /** @type {HotkeyHandler} */ + /** @type {import('../input/hotkey-handler.js').HotkeyHandler} */ this._hotkeyHandler = hotkeyHandler; /** @type {HTMLElement} */ this._container = /** @type {HTMLElement} */ (document.querySelector('#dictionary-entries')); @@ -168,7 +168,7 @@ export class Display extends EventDispatcher { this._copyTextarea = null; /** @type {?TextScanner} */ this._contentTextScanner = null; - /** @type {?DisplayNotification} */ + /** @type {?import('./display-notification.js').DisplayNotification} */ this._tagNotification = null; /** @type {HTMLElement} */ this._footerNotificationContainer = /** @type {HTMLElement} */ (document.querySelector('#content-footer')); @@ -235,7 +235,7 @@ export class Display extends EventDispatcher { this._updateQueryParser(); } - /** @type {JapaneseUtil} */ + /** @type {import('../language/sandbox/japanese-util.js').JapaneseUtil} */ get japaneseUtil() { return this._japaneseUtil; } @@ -245,7 +245,7 @@ export class Display extends EventDispatcher { return this._depth; } - /** @type {HotkeyHandler} */ + /** @type {import('../input/hotkey-handler.js').HotkeyHandler} */ get hotkeyHandler() { return this._hotkeyHandler; } diff --git a/ext/js/display/option-toggle-hotkey-handler.js b/ext/js/display/option-toggle-hotkey-handler.js index 9677e86b..531e208d 100644 --- a/ext/js/display/option-toggle-hotkey-handler.js +++ b/ext/js/display/option-toggle-hotkey-handler.js @@ -16,17 +16,18 @@ * along with this program. If not, see . */ +import {generateId} from '../core.js'; import {ExtensionError} from '../core/extension-error.js'; import {yomitan} from '../yomitan.js'; export class OptionToggleHotkeyHandler { /** - * @param {Display} display + * @param {import('./display.js').Display} display */ constructor(display) { - /** @type {Display} */ + /** @type {import('./display.js').Display} */ this._display = display; - /** @type {?DisplayNotification} */ + /** @type {?import('./display-notification.js').DisplayNotification} */ this._notification = null; /** @type {?number} */ this._notificationHideTimer = null; diff --git a/ext/js/display/query-parser.js b/ext/js/display/query-parser.js index fd173bde..03b54fd5 100644 --- a/ext/js/display/query-parser.js +++ b/ext/js/display/query-parser.js @@ -31,7 +31,7 @@ export class QueryParser extends EventDispatcher { super(); /** @type {import('display').GetSearchContextCallback} */ this._getSearchContext = getSearchContext; - /** @type {JapaneseUtil} */ + /** @type {import('../language/sandbox/japanese-util.js').JapaneseUtil} */ this._japaneseUtil = japaneseUtil; /** @type {string} */ this._text = ''; diff --git a/ext/js/display/sandbox/pronunciation-generator.js b/ext/js/display/sandbox/pronunciation-generator.js index eeedc574..d113485f 100644 --- a/ext/js/display/sandbox/pronunciation-generator.js +++ b/ext/js/display/sandbox/pronunciation-generator.js @@ -18,10 +18,10 @@ export class PronunciationGenerator { /** - * @param {JapaneseUtil} japaneseUtil + * @param {import('../../language/sandbox/japanese-util.js').JapaneseUtil} japaneseUtil */ constructor(japaneseUtil) { - /** @type {JapaneseUtil} */ + /** @type {import('../../language/sandbox/japanese-util.js').JapaneseUtil} */ this._japaneseUtil = japaneseUtil; } diff --git a/ext/js/display/sandbox/structured-content-generator.js b/ext/js/display/sandbox/structured-content-generator.js index af49b643..5a91b01c 100644 --- a/ext/js/display/sandbox/structured-content-generator.js +++ b/ext/js/display/sandbox/structured-content-generator.js @@ -18,14 +18,14 @@ export class StructuredContentGenerator { /** - * @param {DisplayContentManager|AnkiTemplateRendererContentManager} contentManager - * @param {JapaneseUtil} japaneseUtil + * @param {import('../../display/display-content-manager.js').DisplayContentManager|import('../../templates/sandbox/anki-template-renderer-content-manager.js').AnkiTemplateRendererContentManager} contentManager + * @param {import('../../language/sandbox/japanese-util.js').JapaneseUtil} japaneseUtil * @param {Document} document */ constructor(contentManager, japaneseUtil, document) { - /** @type {DisplayContentManager|AnkiTemplateRendererContentManager} */ + /** @type {import('../../display/display-content-manager.js').DisplayContentManager|import('../../templates/sandbox/anki-template-renderer-content-manager.js').AnkiTemplateRendererContentManager} */ this._contentManager = contentManager; - /** @type {JapaneseUtil} */ + /** @type {import('../../language/sandbox/japanese-util.js').JapaneseUtil} */ this._japaneseUtil = japaneseUtil; /** @type {Document} */ this._document = document; diff --git a/ext/js/display/search-display-controller.js b/ext/js/display/search-display-controller.js index 76e7bebe..a9bf2217 100644 --- a/ext/js/display/search-display-controller.js +++ b/ext/js/display/search-display-controller.js @@ -25,21 +25,21 @@ export class SearchDisplayController { /** * @param {number|undefined} tabId * @param {number|undefined} frameId - * @param {Display} display - * @param {DisplayAudio} displayAudio - * @param {JapaneseUtil} japaneseUtil - * @param {SearchPersistentStateController} searchPersistentStateController + * @param {import('./display.js').Display} display + * @param {import('./display-audio.js').DisplayAudio} displayAudio + * @param {import('../language/sandbox/japanese-util.js').JapaneseUtil} japaneseUtil + * @param {import('./search-persistent-state-controller.js').SearchPersistentStateController} searchPersistentStateController */ constructor(tabId, frameId, display, displayAudio, japaneseUtil, searchPersistentStateController) { /** @type {number|undefined} */ this._tabId = tabId; /** @type {number|undefined} */ this._frameId = frameId; - /** @type {Display} */ + /** @type {import('./display.js').Display} */ this._display = display; - /** @type {DisplayAudio} */ + /** @type {import('./display-audio.js').DisplayAudio} */ this._displayAudio = displayAudio; - /** @type {SearchPersistentStateController} */ + /** @type {import('./search-persistent-state-controller.js').SearchPersistentStateController} */ this._searchPersistentStateController = searchPersistentStateController; /** @type {HTMLButtonElement} */ this._searchButton = /** @type {HTMLButtonElement} */ (document.querySelector('#search-button')); -- cgit v1.2.3