diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2023-11-27 17:43:53 -0500 |
---|---|---|
committer | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2023-11-27 17:43:53 -0500 |
commit | 29317da4ea237557e1805a834913dad73c51ed8a (patch) | |
tree | e19ff6014774b42a95c22dbc7874b51d7bc3bf66 | |
parent | a96be7d413c8f1714f0d1b44b3987f2eb87b22d8 (diff) |
Update offscreen
-rw-r--r-- | ext/js/background/offscreen-proxy.js | 137 | ||||
-rw-r--r-- | ext/js/background/offscreen.js | 121 | ||||
-rw-r--r-- | ext/js/language/translator.js | 4 | ||||
-rw-r--r-- | types/ext/dictionary-database.d.ts | 2 | ||||
-rw-r--r-- | types/ext/offscreen.d.ts | 115 | ||||
-rw-r--r-- | types/ext/translator.d.ts | 12 |
6 files changed, 298 insertions, 93 deletions
diff --git a/ext/js/background/offscreen-proxy.js b/ext/js/background/offscreen-proxy.js index 0fb2f269..757d78d5 100644 --- a/ext/js/background/offscreen-proxy.js +++ b/ext/js/background/offscreen-proxy.js @@ -18,13 +18,17 @@ import {isObject} from '../core.js'; import {ArrayBufferUtil} from '../data/sandbox/array-buffer-util.js'; +import {ExtensionError} from '../core/extension-error.js'; export class OffscreenProxy { constructor() { + /** @type {?Promise<void>} */ this._creatingOffscreen = null; } - // https://developer.chrome.com/docs/extensions/reference/offscreen/ + /** + * @see https://developer.chrome.com/docs/extensions/reference/offscreen/ + */ async prepare() { if (await this._hasOffscreenDocument()) { return; @@ -36,20 +40,30 @@ export class OffscreenProxy { this._creatingOffscreen = chrome.offscreen.createDocument({ url: 'offscreen.html', - reasons: ['CLIPBOARD'], + reasons: [ + /** @type {chrome.offscreen.Reason} */ ('CLIPBOARD') + ], justification: 'Access to the clipboard' }); await this._creatingOffscreen; this._creatingOffscreen = null; } + /** + * @returns {Promise<boolean>} + */ async _hasOffscreenDocument() { const offscreenUrl = chrome.runtime.getURL('offscreen.html'); - if (!chrome.runtime.getContexts) { // chrome version <116 + // @ts-ignore - API not defined yet + if (!chrome.runtime.getContexts) { // chrome version below 116 + // Clients: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/clients + // @ts-ignore - Types not set up for service workers yet const matchedClients = await clients.matchAll(); + // @ts-ignore - Types not set up for service workers yet return await matchedClients.some((client) => client.url === offscreenUrl); } + // @ts-ignore - API not defined yet const contexts = await chrome.runtime.getContexts({ contextTypes: ['OFFSCREEN_DOCUMENT'], documentUrls: [offscreenUrl] @@ -57,103 +71,152 @@ export class OffscreenProxy { return !!contexts.length; } - sendMessagePromise(...args) { + /** + * @template {import('offscreen').MessageType} TMessageType + * @param {import('offscreen').Message<TMessageType>} message + * @returns {Promise<import('offscreen').MessageReturn<TMessageType>>} + */ + sendMessagePromise(message) { return new Promise((resolve, reject) => { - const callback = (response) => { + chrome.runtime.sendMessage(message, (response) => { try { resolve(this._getMessageResponseResult(response)); } catch (error) { reject(error); } - }; - - chrome.runtime.sendMessage(...args, callback); + }); }); } + /** + * @template [TReturn=unknown] + * @param {import('core').Response<TReturn>} response + * @returns {TReturn} + * @throws {Error} + */ _getMessageResponseResult(response) { - let error = chrome.runtime.lastError; + const error = chrome.runtime.lastError; if (error) { throw new Error(error.message); } if (!isObject(response)) { throw new Error('Offscreen document did not respond'); } - error = response.error; - if (error) { - throw deserializeError(error); + const error2 = response.error; + if (error2) { + throw ExtensionError.deserialize(error2); } return response.result; } } export class DictionaryDatabaseProxy { + /** + * @param {OffscreenProxy} offscreen + */ constructor(offscreen) { + /** @type {OffscreenProxy} */ this._offscreen = offscreen; } - prepare() { - return this._offscreen.sendMessagePromise({action: 'databasePrepareOffscreen'}); + /** + * @returns {Promise<void>} + */ + async prepare() { + await this._offscreen.sendMessagePromise({action: 'databasePrepareOffscreen'}); } - getDictionaryInfo() { + /** + * @returns {Promise<import('dictionary-importer').Summary[]>} + */ + async getDictionaryInfo() { return this._offscreen.sendMessagePromise({action: 'getDictionaryInfoOffscreen'}); } - purge() { - return this._offscreen.sendMessagePromise({action: 'databasePurgeOffscreen'}); + /** + * @returns {Promise<boolean>} + */ + async purge() { + return await this._offscreen.sendMessagePromise({action: 'databasePurgeOffscreen'}); } + /** + * @param {import('dictionary-database').MediaRequest[]} targets + * @returns {Promise<import('dictionary-database').Media[]>} + */ async getMedia(targets) { - const serializedMedia = await this._offscreen.sendMessagePromise({action: 'databaseGetMediaOffscreen', params: {targets}}); + const serializedMedia = /** @type {import('dictionary-database').Media<string>[]} */ (await this._offscreen.sendMessagePromise({action: 'databaseGetMediaOffscreen', params: {targets}})); const media = serializedMedia.map((m) => ({...m, content: ArrayBufferUtil.base64ToArrayBuffer(m.content)})); return media; } } export class TranslatorProxy { + /** + * @param {OffscreenProxy} offscreen + */ constructor(offscreen) { + /** @type {OffscreenProxy} */ this._offscreen = offscreen; } - prepare(deinflectionReasons) { - return this._offscreen.sendMessagePromise({action: 'translatorPrepareOffscreen', params: {deinflectionReasons}}); + /** + * @param {import('deinflector').ReasonsRaw} deinflectionReasons + */ + async prepare(deinflectionReasons) { + await this._offscreen.sendMessagePromise({action: 'translatorPrepareOffscreen', params: {deinflectionReasons}}); } - async findKanji(text, findKanjiOptions) { - const enabledDictionaryMapList = [...findKanjiOptions.enabledDictionaryMap]; - const modifiedKanjiOptions = { - ...findKanjiOptions, + /** + * @param {string} text + * @param {import('translation').FindKanjiOptions} options + * @returns {Promise<import('dictionary').KanjiDictionaryEntry[]>} + */ + async findKanji(text, options) { + const enabledDictionaryMapList = [...options.enabledDictionaryMap]; + /** @type {import('offscreen').FindKanjiOptionsOffscreen} */ + const modifiedOptions = { + ...options, enabledDictionaryMap: enabledDictionaryMapList }; - return this._offscreen.sendMessagePromise({action: 'findKanjiOffscreen', params: {text, findKanjiOptions: modifiedKanjiOptions}}); + return this._offscreen.sendMessagePromise({action: 'findKanjiOffscreen', params: {text, options: modifiedOptions}}); } - async findTerms(mode, text, findTermsOptions) { - const {enabledDictionaryMap, excludeDictionaryDefinitions, textReplacements} = findTermsOptions; + /** + * @param {import('translator').FindTermsMode} mode + * @param {string} text + * @param {import('translation').FindTermsOptions} options + * @returns {Promise<import('translator').FindTermsResult>} + */ + async findTerms(mode, text, options) { + const {enabledDictionaryMap, excludeDictionaryDefinitions, textReplacements} = options; const enabledDictionaryMapList = [...enabledDictionaryMap]; const excludeDictionaryDefinitionsList = excludeDictionaryDefinitions ? [...excludeDictionaryDefinitions] : null; const textReplacementsSerialized = textReplacements.map((group) => { - if (!group) { - return group; - } - return group.map((opt) => ({...opt, pattern: opt.pattern.toString()})); + return group !== null ? group.map((opt) => ({...opt, pattern: opt.pattern.toString()})) : null; }); - const modifiedFindTermsOptions = { - ...findTermsOptions, + /** @type {import('offscreen').FindTermsOptionsOffscreen} */ + const modifiedOptions = { + ...options, enabledDictionaryMap: enabledDictionaryMapList, excludeDictionaryDefinitions: excludeDictionaryDefinitionsList, textReplacements: textReplacementsSerialized }; - return this._offscreen.sendMessagePromise({action: 'findTermsOffscreen', params: {mode, text, findTermsOptions: modifiedFindTermsOptions}}); + return this._offscreen.sendMessagePromise({action: 'findTermsOffscreen', params: {mode, text, options: modifiedOptions}}); } + /** + * @param {import('translator').TermReadingList} termReadingList + * @param {string[]} dictionaries + * @returns {Promise<import('translator').TermFrequencySimple[]>} + */ async getTermFrequencies(termReadingList, dictionaries) { return this._offscreen.sendMessagePromise({action: 'getTermFrequenciesOffscreen', params: {termReadingList, dictionaries}}); } - clearDatabaseCaches() { - return this._offscreen.sendMessagePromise({action: 'clearDatabaseCachesOffscreen'}); + /** */ + async clearDatabaseCaches() { + await this._offscreen.sendMessagePromise({action: 'clearDatabaseCachesOffscreen'}); } } @@ -173,7 +236,7 @@ export class ClipboardReaderProxy { set browser(value) { if (this._browser === value) { return; } this._browser = value; - this._offscreen.sendMessagePromise({action: 'clipboardSetBrowserOffsecreen', params: {value}}); + this._offscreen.sendMessagePromise({action: 'clipboardSetBrowserOffscreen', params: {value}}); } /** diff --git a/ext/js/background/offscreen.js b/ext/js/background/offscreen.js index 6302aa84..1b68887b 100644 --- a/ext/js/background/offscreen.js +++ b/ext/js/background/offscreen.js @@ -23,7 +23,6 @@ import {ArrayBufferUtil} from '../data/sandbox/array-buffer-util.js'; import {DictionaryDatabase} from '../language/dictionary-database.js'; import {JapaneseUtil} from '../language/sandbox/japanese-util.js'; import {Translator} from '../language/translator.js'; -import {yomitan} from '../yomitan.js'; /** * This class controls the core logic of the extension, including API calls @@ -34,12 +33,16 @@ export class Offscreen { * Creates a new instance. */ constructor() { + /** @type {JapaneseUtil} */ this._japaneseUtil = new JapaneseUtil(wanakana); + /** @type {DictionaryDatabase} */ this._dictionaryDatabase = new DictionaryDatabase(); + /** @type {Translator} */ this._translator = new Translator({ japaneseUtil: this._japaneseUtil, database: this._dictionaryDatabase }); + /** @type {ClipboardReader} */ this._clipboardReader = new ClipboardReader({ // eslint-disable-next-line no-undef document: (typeof document === 'object' && document !== null ? document : null), @@ -47,42 +50,45 @@ export class Offscreen { richContentPasteTargetSelector: '#clipboard-rich-content-paste-target' }); + /** @type {import('offscreen').MessageHandlerMap} */ this._messageHandlers = new Map([ - ['clipboardGetTextOffscreen', {async: true, contentScript: true, handler: this._getTextHandler.bind(this)}], - ['clipboardGetImageOffscreen', {async: true, contentScript: true, handler: this._getImageHandler.bind(this)}], - ['clipboardSetBrowserOffsecreen', {async: false, contentScript: true, handler: this._setClipboardBrowser.bind(this)}], - ['databasePrepareOffscreen', {async: true, contentScript: true, handler: this._prepareDatabaseHandler.bind(this)}], - ['getDictionaryInfoOffscreen', {async: true, contentScript: true, handler: this._getDictionaryInfoHandler.bind(this)}], - ['databasePurgeOffscreen', {async: true, contentScript: true, handler: this._purgeDatabaseHandler.bind(this)}], - ['databaseGetMediaOffscreen', {async: true, contentScript: true, handler: this._getMediaHandler.bind(this)}], - ['translatorPrepareOffscreen', {async: false, contentScript: true, handler: this._prepareTranslatorHandler.bind(this)}], - ['findKanjiOffscreen', {async: true, contentScript: true, handler: this._findKanjiHandler.bind(this)}], - ['findTermsOffscreen', {async: true, contentScript: true, handler: this._findTermsHandler.bind(this)}], - ['getTermFrequenciesOffscreen', {async: true, contentScript: true, handler: this._getTermFrequenciesHandler.bind(this)}], - ['clearDatabaseCachesOffscreen', {async: false, contentScript: true, handler: this._clearDatabaseCachesHandler.bind(this)}] + ['clipboardGetTextOffscreen', {async: true, handler: this._getTextHandler.bind(this)}], + ['clipboardGetImageOffscreen', {async: true, handler: this._getImageHandler.bind(this)}], + ['clipboardSetBrowserOffscreen', {async: false, handler: this._setClipboardBrowser.bind(this)}], + ['databasePrepareOffscreen', {async: true, handler: this._prepareDatabaseHandler.bind(this)}], + ['getDictionaryInfoOffscreen', {async: true, handler: this._getDictionaryInfoHandler.bind(this)}], + ['databasePurgeOffscreen', {async: true, handler: this._purgeDatabaseHandler.bind(this)}], + ['databaseGetMediaOffscreen', {async: true, handler: this._getMediaHandler.bind(this)}], + ['translatorPrepareOffscreen', {async: false, handler: this._prepareTranslatorHandler.bind(this)}], + ['findKanjiOffscreen', {async: true, handler: this._findKanjiHandler.bind(this)}], + ['findTermsOffscreen', {async: true, handler: this._findTermsHandler.bind(this)}], + ['getTermFrequenciesOffscreen', {async: true, handler: this._getTermFrequenciesHandler.bind(this)}], + ['clearDatabaseCachesOffscreen', {async: false, handler: this._clearDatabaseCachesHandler.bind(this)}] ]); const onMessage = this._onMessage.bind(this); chrome.runtime.onMessage.addListener(onMessage); + /** @type {?Promise<void>} */ this._prepareDatabasePromise = null; } - _getTextHandler({useRichText}) { - return this._clipboardReader.getText(useRichText); + /** @type {import('offscreen').MessageHandler<'clipboardGetTextOffscreen', true>} */ + async _getTextHandler({useRichText}) { + return await this._clipboardReader.getText(useRichText); } - _getImageHandler() { - return this._clipboardReader.getImage(); + /** @type {import('offscreen').MessageHandler<'clipboardGetImageOffscreen', true>} */ + async _getImageHandler() { + return await this._clipboardReader.getImage(); } - /** - * @param {{value: import('environment').Browser}} details - */ + /** @type {import('offscreen').MessageHandler<'clipboardSetBrowserOffscreen', false>} */ _setClipboardBrowser({value}) { this._clipboardReader.browser = value; } + /** @type {import('offscreen').MessageHandler<'databasePrepareOffscreen', true>} */ _prepareDatabaseHandler() { if (this._prepareDatabasePromise !== null) { return this._prepareDatabasePromise; @@ -91,70 +97,79 @@ export class Offscreen { return this._prepareDatabasePromise; } - _getDictionaryInfoHandler() { - return this._dictionaryDatabase.getDictionaryInfo(); + /** @type {import('offscreen').MessageHandler<'getDictionaryInfoOffscreen', true>} */ + async _getDictionaryInfoHandler() { + return await this._dictionaryDatabase.getDictionaryInfo(); } - _purgeDatabaseHandler() { - return this._dictionaryDatabase.purge(); + /** @type {import('offscreen').MessageHandler<'databasePurgeOffscreen', true>} */ + async _purgeDatabaseHandler() { + return await this._dictionaryDatabase.purge(); } + /** @type {import('offscreen').MessageHandler<'databaseGetMediaOffscreen', true>} */ async _getMediaHandler({targets}) { const media = await this._dictionaryDatabase.getMedia(targets); const serializedMedia = media.map((m) => ({...m, content: ArrayBufferUtil.arrayBufferToBase64(m.content)})); return serializedMedia; } + /** @type {import('offscreen').MessageHandler<'translatorPrepareOffscreen', false>} */ _prepareTranslatorHandler({deinflectionReasons}) { - return this._translator.prepare(deinflectionReasons); + this._translator.prepare(deinflectionReasons); } - _findKanjiHandler({text, findKanjiOptions}) { - findKanjiOptions.enabledDictionaryMap = new Map(findKanjiOptions.enabledDictionaryMap); - return this._translator.findKanji(text, findKanjiOptions); + /** @type {import('offscreen').MessageHandler<'findKanjiOffscreen', true>} */ + async _findKanjiHandler({text, options}) { + /** @type {import('translation').FindKanjiOptions} */ + const modifiedOptions = { + ...options, + enabledDictionaryMap: new Map(options.enabledDictionaryMap) + }; + return await this._translator.findKanji(text, modifiedOptions); } - _findTermsHandler({mode, text, findTermsOptions}) { - findTermsOptions.enabledDictionaryMap = new Map(findTermsOptions.enabledDictionaryMap); - if (findTermsOptions.excludeDictionaryDefinitions) { - findTermsOptions.excludeDictionaryDefinitions = new Set(findTermsOptions.excludeDictionaryDefinitions); - } - findTermsOptions.textReplacements = findTermsOptions.textReplacements.map((group) => { - if (!group) { - return group; - } + /** @type {import('offscreen').MessageHandler<'findTermsOffscreen', true>} */ + _findTermsHandler({mode, text, options}) { + const enabledDictionaryMap = new Map(options.enabledDictionaryMap); + const excludeDictionaryDefinitions = ( + options.excludeDictionaryDefinitions !== null ? + new Set(options.excludeDictionaryDefinitions) : + null + ); + const textReplacements = options.textReplacements.map((group) => { + if (group === null) { return null; } return group.map((opt) => { - const [, pattern, flags] = opt.pattern.match(/\/(.*?)\/([a-z]*)?$/i); // https://stackoverflow.com/a/33642463 + // https://stackoverflow.com/a/33642463 + const match = opt.pattern.match(/\/(.*?)\/([a-z]*)?$/i); + const [, pattern, flags] = match !== null ? match : ['', '', '']; return {...opt, pattern: new RegExp(pattern, flags ?? '')}; }); }); - return this._translator.findTerms(mode, text, findTermsOptions); + /** @type {import('translation').FindTermsOptions} */ + const modifiedOptions = { + ...options, + enabledDictionaryMap, + excludeDictionaryDefinitions, + textReplacements + }; + return this._translator.findTerms(mode, text, modifiedOptions); } + /** @type {import('offscreen').MessageHandler<'getTermFrequenciesOffscreen', true>} */ _getTermFrequenciesHandler({termReadingList, dictionaries}) { return this._translator.getTermFrequencies(termReadingList, dictionaries); } + /** @type {import('offscreen').MessageHandler<'clearDatabaseCachesOffscreen', false>} */ _clearDatabaseCachesHandler() { - return this._translator.clearDatabaseCaches(); + this._translator.clearDatabaseCaches(); } + /** @type {import('extension').ChromeRuntimeOnMessageCallback} */ _onMessage({action, params}, sender, callback) { const messageHandler = this._messageHandlers.get(action); if (typeof messageHandler === 'undefined') { return false; } - this._validatePrivilegedMessageSender(sender); - return invokeMessageHandler(messageHandler, params, callback, sender); } - - _validatePrivilegedMessageSender(sender) { - let {url} = sender; - if (typeof url === 'string' && yomitan.isExtensionUrl(url)) { return; } - const {tab} = url; - if (typeof tab === 'object' && tab !== null) { - ({url} = tab); - if (typeof url === 'string' && yomitan.isExtensionUrl(url)) { return; } - } - throw new Error('Invalid message sender'); - } } diff --git a/ext/js/language/translator.js b/ext/js/language/translator.js index c21b16b1..aa1b71dd 100644 --- a/ext/js/language/translator.js +++ b/ext/js/language/translator.js @@ -157,7 +157,7 @@ export class Translator { /** * Gets a list of frequency information for a given list of term-reading pairs * and a list of dictionaries. - * @param {{term: string, reading: string|null}[]} termReadingList An array of `{term, reading}` pairs. If reading is null, + * @param {import('translator').TermReadingList} termReadingList An array of `{term, reading}` pairs. If reading is null, * the reading won't be compared. * @param {string[]} dictionaries An array of dictionary names. * @returns {Promise<import('translator').TermFrequencySimple[]>} An array of term frequencies. @@ -203,7 +203,7 @@ export class Translator { * @param {Map<string, import('translation').FindTermDictionary>} enabledDictionaryMap * @param {import('translation').FindTermsOptions} options * @param {TranslatorTagAggregator} tagAggregator - * @returns {Promise<{dictionaryEntries: import('dictionary').TermDictionaryEntry[], originalTextLength: number}>} + * @returns {Promise<import('translator').FindTermsResult>} */ async _findTermsInternal(text, enabledDictionaryMap, options, tagAggregator) { if (options.removeNonJapaneseCharacters) { diff --git a/types/ext/dictionary-database.d.ts b/types/ext/dictionary-database.d.ts index 2e0f854b..06a246e8 100644 --- a/types/ext/dictionary-database.d.ts +++ b/types/ext/dictionary-database.d.ts @@ -35,7 +35,7 @@ export interface MediaDataBase<TContentType = unknown> { export interface MediaDataArrayBufferContent extends MediaDataBase<ArrayBuffer> {} export interface MediaDataStringContent extends MediaDataBase<string> {} -export type Media = {index: number} & MediaDataBase<ArrayBuffer>; +export type Media<T extends (ArrayBuffer | string) = ArrayBuffer> = {index: number} & MediaDataBase<T>; export type DatabaseTermEntry = { expression: string; diff --git a/types/ext/offscreen.d.ts b/types/ext/offscreen.d.ts new file mode 100644 index 00000000..7dd64d1e --- /dev/null +++ b/types/ext/offscreen.d.ts @@ -0,0 +1,115 @@ +/* + * 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 <https://www.gnu.org/licenses/>. + */ + +import type * as Core from './core'; +import type * as Deinflector from './deinflector'; +import type * as Dictionary from './dictionary'; +import type * as DictionaryDatabase from './dictionary-database'; +import type * as DictionaryImporter from './dictionary-importer'; +import type * as Environment from './environment'; +import type * as Translation from './translation'; +import type * as Translator from './translator'; + +export type MessageAny2 = Message<keyof MessageDetailsMap>; + +export type Message<T extends MessageType> = ( + MessageDetailsMap[T] extends undefined ? + {action: T} : + {action: T, params: MessageDetailsMap[T]} +); + +export type MessageReturn<T extends MessageType> = MessageReturnMap[T]; + +type MessageDetailsMap = { + databasePrepareOffscreen: undefined; + getDictionaryInfoOffscreen: undefined; + databasePurgeOffscreen: undefined; + databaseGetMediaOffscreen: { + targets: DictionaryDatabase.MediaRequest[]; + }; + translatorPrepareOffscreen: { + deinflectionReasons: Deinflector.ReasonsRaw; + }; + findKanjiOffscreen: { + text: string; + options: FindKanjiOptionsOffscreen; + }; + findTermsOffscreen: { + mode: Translator.FindTermsMode; + text: string; + options: FindTermsOptionsOffscreen; + }; + getTermFrequenciesOffscreen: { + termReadingList: Translator.TermReadingList; + dictionaries: string[]; + }; + clearDatabaseCachesOffscreen: undefined; + clipboardSetBrowserOffscreen: { + value: Environment.Browser | null; + }; + clipboardGetTextOffscreen: { + useRichText: boolean; + }; + clipboardGetImageOffscreen: undefined; +}; + +type MessageReturnMap = { + databasePrepareOffscreen: void; + getDictionaryInfoOffscreen: DictionaryImporter.Summary[]; + databasePurgeOffscreen: boolean; + databaseGetMediaOffscreen: DictionaryDatabase.Media<string>[]; + translatorPrepareOffscreen: void; + findKanjiOffscreen: Dictionary.KanjiDictionaryEntry[]; + findTermsOffscreen: Translator.FindTermsResult; + getTermFrequenciesOffscreen: Translator.TermFrequencySimple[]; + clearDatabaseCachesOffscreen: void; + clipboardSetBrowserOffscreen: void; + clipboardGetTextOffscreen: string; + clipboardGetImageOffscreen: string | null; +}; + +export type MessageType = keyof MessageDetailsMap; + +export type FindKanjiOptionsOffscreen = Omit<Translation.FindKanjiOptions, 'enabledDictionaryMap'> & { + enabledDictionaryMap: [ + key: string, + options: Translation.FindKanjiDictionary, + ][]; +}; + + +export type FindTermsOptionsOffscreen = Omit<Translation.FindTermsOptions, 'enabledDictionaryMap' | 'excludeDictionaryDefinitions' | 'textReplacements'> & { + enabledDictionaryMap: [ + key: string, + options: Translation.FindTermDictionary, + ][]; + excludeDictionaryDefinitions: string[] | null; + textReplacements: (FindTermsTextReplacementOffscreen[] | null)[]; +}; + +export type FindTermsTextReplacementOffscreen = Omit<Translation.FindTermsTextReplacement, 'pattern'> & { + pattern: string; +}; + +export type MessageHandler< + TMessage extends MessageType, + TIsAsync extends boolean, +> = ( + details: MessageDetailsMap[TMessage], +) => (TIsAsync extends true ? Promise<MessageReturn<TMessage>> : MessageReturn<TMessage>); + +export type MessageHandlerMap = Map<MessageType, Core.MessageHandlerDetails>; diff --git a/types/ext/translator.d.ts b/types/ext/translator.d.ts index f17b3bf6..e7d45295 100644 --- a/types/ext/translator.d.ts +++ b/types/ext/translator.d.ts @@ -81,3 +81,15 @@ export type SequenceQuery = { }; export type FindTermsMode = 'simple' | 'group' | 'merge' | 'split'; + +export type TermReadingItem = { + term: string; + reading: string | null; +}; + +export type TermReadingList = TermReadingItem[]; + +export type FindTermsResult = { + dictionaryEntries: Dictionary.TermDictionaryEntry[]; + originalTextLength: number; +}; |