summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/js/background/offscreen.js2
-rw-r--r--ext/js/core/api-map.js58
-rw-r--r--types/ext/api-map.d.ts100
-rw-r--r--types/ext/offscreen.d.ts10
4 files changed, 138 insertions, 32 deletions
diff --git a/ext/js/background/offscreen.js b/ext/js/background/offscreen.js
index 44b0af77..1cab5929 100644
--- a/ext/js/background/offscreen.js
+++ b/ext/js/background/offscreen.js
@@ -138,7 +138,7 @@ export class Offscreen {
}
/** @type {import('offscreen').OffscreenApiHandler<'findTermsOffscreen'>} */
- _findTermsHandler({mode, text, options}) {
+ async _findTermsHandler({mode, text, options}) {
const enabledDictionaryMap = new Map(options.enabledDictionaryMap);
const excludeDictionaryDefinitions = (
options.excludeDictionaryDefinitions !== null ?
diff --git a/ext/js/core/api-map.js b/ext/js/core/api-map.js
index eb4abeea..09be8035 100644
--- a/ext/js/core/api-map.js
+++ b/ext/js/core/api-map.js
@@ -15,10 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+import {ExtensionError} from './extension-error.js';
+
/**
* @template {import('api-map').ApiSurface} [TApiSurface=never]
- * @param {import('api-map').ApiMapInit<TApiSurface>} init
- * @returns {import('api-map').ApiMap<TApiSurface>}
+ * @template {unknown[]} [TExtraParams=[]]
+ * @param {import('api-map').ApiMapInit<TApiSurface, TExtraParams>} init
+ * @returns {import('api-map').ApiMap<TApiSurface, TExtraParams>}
*/
export function createApiMap(init) {
return new Map(init);
@@ -26,8 +29,9 @@ export function createApiMap(init) {
/**
* @template {import('api-map').ApiSurface} [TApiSurface=never]
- * @param {import('api-map').ApiMap<TApiSurface>} map
- * @param {import('api-map').ApiMapInit<TApiSurface>} init
+ * @template {unknown[]} [TExtraParams=[]]
+ * @param {import('api-map').ApiMap<TApiSurface, TExtraParams>} map
+ * @param {import('api-map').ApiMapInit<TApiSurface, TExtraParams>} init
* @throws {Error}
*/
export function extendApiMap(map, init) {
@@ -39,10 +43,52 @@ export function extendApiMap(map, init) {
/**
* @template {import('api-map').ApiSurface} [TApiSurface=never]
- * @param {import('api-map').ApiMap<TApiSurface>} map
+ * @template {unknown[]} [TExtraParams=[]]
+ * @param {import('api-map').ApiMap<TApiSurface, TExtraParams>} map
* @param {string} name
- * @returns {import('api-map').ApiHandlerAny<TApiSurface>|undefined}
+ * @returns {import('api-map').ApiHandlerAny<TApiSurface, TExtraParams>|undefined}
*/
export function getApiMapHandler(map, name) {
return map.get(/** @type {import('api-map').ApiNames<TApiSurface>} */ (name));
}
+
+/**
+ * @template {import('api-map').ApiSurface} [TApiSurface=never]
+ * @template {unknown[]} [TExtraParams=[]]
+ * @param {import('api-map').ApiMap<TApiSurface, TExtraParams>} map
+ * @param {string} name
+ * @param {import('api-map').ApiParamsAny<TApiSurface>} params
+ * @param {TExtraParams} extraParams
+ * @param {(response: import('core').Response<import('api-map').ApiReturnAny<TApiSurface>>) => void} callback
+ * @param {() => void} [handlerNotFoundCallback]
+ * @returns {boolean} `true` if async, `false` otherwise.
+ */
+export function invokeApiMapHandler(map, name, params, extraParams, callback, handlerNotFoundCallback) {
+ const handler = getApiMapHandler(map, name);
+ if (typeof handler === 'undefined') {
+ if (typeof handlerNotFoundCallback === 'function') {
+ try {
+ handlerNotFoundCallback();
+ } catch (error) {
+ // NOP
+ }
+ }
+ return false;
+ }
+ try {
+ const promiseOrResult = handler(/** @type {import('core').SafeAny} */ (params), ...extraParams);
+ if (promiseOrResult instanceof Promise) {
+ /** @type {Promise<unknown>} */ (promiseOrResult).then(
+ (result) => { callback({result}); },
+ (error) => { callback({error: ExtensionError.serialize(error)}); }
+ );
+ return true;
+ } else {
+ callback({result: promiseOrResult});
+ return false;
+ }
+ } catch (error) {
+ callback({error: ExtensionError.serialize(error)});
+ return false;
+ }
+}
diff --git a/types/ext/api-map.d.ts b/types/ext/api-map.d.ts
index eebc886a..4a4eb87c 100644
--- a/types/ext/api-map.d.ts
+++ b/types/ext/api-map.d.ts
@@ -15,41 +15,101 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+/**
+ * This type describes the structure of an API surface.
+ * It is effectively just an object containing a list of items which describe a basic API functionality.
+ */
type ApiSurface = {
- [name: string]: ApiItem;
+ [name: string]: ApiDescriptor;
};
-type ApiItem = {
+/**
+ * This type describes the structure of a single API function.
+ */
+type ApiDescriptor = {
+ /** The parameters for the function. If there are no parameters, `void` should be used. */
params: void | {[name: string]: unknown};
+ /** The return type for the function. */
return: unknown;
};
-export type ApiHandler<TApiItem extends ApiItem> = (params: TApiItem['params']) => TApiItem['return'] | Promise<TApiItem['return']>;
+/**
+ * This type represents a mapping of an entire API surface to its handlers.
+ */
+type ApiHandlerSurface<TSurface extends ApiSurface, TExtraParams extends ApiTExtraParams> = {
+ [name in ApiNames<TSurface>]: ApiHandler<TSurface[name], TExtraParams>;
+};
-type ApiHandlerSurface<TApiSurface extends ApiSurface> = {[name in ApiNames<TApiSurface>]: ApiHandler<TApiSurface[name]>};
+/**
+ * This type represents a single API map initializer.
+ * Type safety is enforced by ensuring that the name and handler signature are valid.
+ */
+type ApiMapInitItem<TSurface extends ApiSurface, TExtraParams extends ApiTExtraParams, TName extends ApiNames<TSurface>> = [
+ name: TName,
+ handler: ApiHandler<TSurface[TName], TExtraParams>,
+];
-export type ApiHandlerAny<TApiSurface extends ApiSurface> = ApiHandlerSurface<TApiSurface>[ApiNames<TApiSurface>];
+/**
+ * This type represents a union of all API map initializers for a given surface.
+ */
+type ApiMapInitItemAny<TSurface extends ApiSurface, TExtraParams extends ApiTExtraParams> = {[key in ApiNames<TSurface>]: ApiMapInitItem<TSurface, TExtraParams, key>}[ApiNames<TSurface>];
-export type ApiNames<TApiSurface extends ApiSurface> = keyof TApiSurface;
+/** Base type for extra params, which is just a generic array. */
+type ApiTExtraParams = unknown[];
-export type ApiParams<TApiSurface extends ApiSurface, TName extends ApiNames<TApiSurface>> = TApiSurface[TName]['params'];
+/** Default type for extra params, which is an empty array. */
+type ApiExtraParamsDefault = [];
-export type ApiReturn<TApiSurface extends ApiSurface, TName extends ApiNames<TApiSurface>> = TApiSurface[TName]['return'];
+/** Type alias for the params member of a descriptor. */
+export type ApiParams<TDescriptor extends ApiDescriptor> = TDescriptor['params'];
-export type ApiMap<TApiSurface extends ApiSurface> = Map<ApiNames<TApiSurface>, ApiHandlerAny<TApiSurface>>;
+/** Type alias for a single param of a descriptor. */
+export type ApiParam<TDescriptor extends ApiDescriptor, TParamName extends ApiParamNames<TDescriptor>> = ApiParams<TDescriptor>[TParamName];
-export type ApiMapInit<TApiSurface extends ApiSurface> = ApiMapInitItemAny<TApiSurface>[];
+/** Type alias for the union of parameter names in a descriptor. */
+export type ApiParamNames<TDescriptor extends ApiDescriptor> = keyof ApiParams<TDescriptor>;
-export type ApiMapInitLax<TApiSurface extends ApiSurface> = ApiMapInitLaxItem<TApiSurface>[];
+/** Type alias for a tuple of parameter types for a descriptor. */
+export type ApiOrderedParams<TDescriptor extends ApiDescriptor, TParamNames extends ApiParamNames<TDescriptor>[]> = {
+ [index in keyof TParamNames]: ApiParams<TDescriptor>[TParamNames[index]];
+};
-export type ApiMapInitLaxItem<TApiSurface extends ApiSurface> = [
- name: ApiNames<TApiSurface>,
- handler: ApiHandlerAny<TApiSurface>,
-];
+/** Type alias for the return member of a descriptor. */
+export type ApiReturn<TDescriptor extends ApiDescriptor> = TDescriptor['return'];
-type ApiMapInitItem<TApiSurface extends ApiSurface, TName extends ApiNames<TApiSurface>> = [
- name: TName,
- handler: ApiHandler<TApiSurface[TName]>,
-];
+/** A type representing a synchronous handler. */
+export type ApiHandlerSync<TDescriptor extends ApiDescriptor, TExtraParams extends ApiTExtraParams = ApiExtraParamsDefault> = (params: ApiParams<TDescriptor>, ...extraParams: TExtraParams) => ApiReturn<TDescriptor>;
+
+/** A type representing an asynchronous handler. */
+export type ApiHandlerAsync<TDescriptor extends ApiDescriptor, TExtraParams extends ApiTExtraParams = ApiExtraParamsDefault> = (params: ApiParams<TDescriptor>, ...extraParams: TExtraParams) => Promise<ApiReturn<TDescriptor>>;
+
+/** A type representing a generic handler. */
+export type ApiHandler<TDescriptor extends ApiDescriptor, TExtraParams extends ApiTExtraParams = ApiExtraParamsDefault> = (params: ApiParams<TDescriptor>, ...extraParams: TExtraParams) => ApiReturn<TDescriptor> | Promise<ApiReturn<TDescriptor>>;
+
+/** A union of all of the handlers for a given surface. */
+export type ApiHandlerAny<TSurface extends ApiSurface, TExtraParams extends ApiTExtraParams = ApiExtraParamsDefault> = ApiHandlerSurface<TSurface, TExtraParams>[ApiNames<TSurface>];
+
+/** A union of all of the names for a given surface. */
+export type ApiNames<TSurface extends ApiSurface> = keyof TSurface;
+
+/** A mapping of names to the corresponding handler function. */
+export type ApiMap<TSurface extends ApiSurface, TExtraParams extends ApiTExtraParams = ApiExtraParamsDefault> = Map<ApiNames<TSurface>, ApiHandlerAny<TSurface, TExtraParams>>;
+
+/** The initialization array structure for populating an API map. */
+export type ApiMapInit<TSurface extends ApiSurface, TExtraParams extends ApiTExtraParams = ApiExtraParamsDefault> = ApiMapInitItemAny<TSurface, TExtraParams>[];
+
+/** The type for a public API function, using a parameters object. */
+export type ApiFunction<TSurface extends ApiSurface, TName extends ApiNames<TSurface>> = (
+ params: ApiParams<TSurface[TName]>,
+) => Promise<ApiReturn<TSurface[TName]>>;
+
+/** The type for a public API function, using ordered parameters. */
+export type ApiFunctionOrdered<TSurface extends ApiSurface, TName extends ApiNames<TSurface>, TParamNames extends ApiParamNames<TSurface[TName]>[]> = (
+ ...params: ApiOrderedParams<TSurface[TName], TParamNames>,
+) => Promise<ApiReturn<TSurface[TName]>>;
+
+/** Type alias for a union of all params types. */
+export type ApiParamsAny<TSurface extends ApiSurface> = ApiParams<TSurface[keyof TSurface]>;
-type ApiMapInitItemAny<TApiSurface extends ApiSurface> = {[key in ApiNames<TApiSurface>]: ApiMapInitItem<TApiSurface, key>}[ApiNames<TApiSurface>];
+/** Type alias for a union of all return types. */
+export type ApiReturnAny<TSurface extends ApiSurface> = ApiReturn<TSurface[keyof TSurface]>;
diff --git a/types/ext/offscreen.d.ts b/types/ext/offscreen.d.ts
index 451f5f9e..d67733bb 100644
--- a/types/ext/offscreen.d.ts
+++ b/types/ext/offscreen.d.ts
@@ -22,7 +22,7 @@ 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';
-import type {ApiMap, ApiMapInit, ApiHandler, ApiParams, ApiReturn} from './api-map';
+import type {ApiMap, ApiMapInit, ApiHandler, ApiParams, ApiReturn, ApiNames} from './api-map';
type OffscreenApiSurface = {
databasePrepareOffscreen: {
@@ -99,7 +99,7 @@ export type Message<TName extends MessageType> = (
{action: TName, params: OffscreenApiParams<TName>}
);
-export type MessageType = keyof OffscreenApiSurface;
+export type MessageType = ApiNames<OffscreenApiSurface>;
export type FindKanjiOptionsOffscreen = Omit<Translation.FindKanjiOptions, 'enabledDictionaryMap'> & {
enabledDictionaryMap: [
@@ -126,8 +126,8 @@ export type OffscreenApiMap = ApiMap<OffscreenApiSurface>;
export type OffscreenApiMapInit = ApiMapInit<OffscreenApiSurface>;
-export type OffscreenApiHandler<TName extends keyof OffscreenApiSurface> = ApiHandler<OffscreenApiSurface[TName]>;
+export type OffscreenApiHandler<TName extends MessageType> = ApiHandler<OffscreenApiSurface[TName]>;
-export type OffscreenApiParams<TName extends keyof OffscreenApiSurface> = ApiParams<OffscreenApiSurface, TName>;
+export type OffscreenApiParams<TName extends MessageType> = ApiParams<OffscreenApiSurface[TName]>;
-export type OffscreenApiReturn<TName extends keyof OffscreenApiSurface> = ApiReturn<OffscreenApiSurface, TName>;
+export type OffscreenApiReturn<TName extends MessageType> = ApiReturn<OffscreenApiSurface[TName]>;