aboutsummaryrefslogtreecommitdiff
path: root/ext/js
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2023-12-22 20:27:10 -0500
committerGitHub <noreply@github.com>2023-12-23 01:27:10 +0000
commita72b53de011d35602c0f68577c30e28386046583 (patch)
tree0fd3f2e38b36b81c773bd518c99ce5f01cae32eb /ext/js
parentcb4499fd8ab0322fa3ab706adfb46caf21c57eec (diff)
Type safety for TemplateRendererProxy (#428)
* Type safety for TemplateRendererProxy * Simplify
Diffstat (limited to 'ext/js')
-rw-r--r--ext/js/templates/sandbox/template-renderer-frame-api.js51
-rw-r--r--ext/js/templates/template-renderer-proxy.js36
2 files changed, 36 insertions, 51 deletions
diff --git a/ext/js/templates/sandbox/template-renderer-frame-api.js b/ext/js/templates/sandbox/template-renderer-frame-api.js
index 56cedb97..28303e51 100644
--- a/ext/js/templates/sandbox/template-renderer-frame-api.js
+++ b/ext/js/templates/sandbox/template-renderer-frame-api.js
@@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import {ExtensionError} from '../../core/extension-error.js';
+import {createApiMap, invokeApiMapHandler} from '../../core/api-map.js';
import {parseJson} from '../../core/json.js';
export class TemplateRendererFrameApi {
@@ -26,12 +26,12 @@ export class TemplateRendererFrameApi {
constructor(templateRenderer) {
/** @type {import('./template-renderer.js').TemplateRenderer} */
this._templateRenderer = templateRenderer;
- /** @type {import('core').MessageHandlerMap} */
- this._windowMessageHandlers = new Map(/** @type {import('core').MessageHandlerMapInit} */ ([
+ /** @type {import('template-renderer-proxy').FrontendApiMap} */
+ this._windowMessageHandlers = createApiMap([
['render', this._onRender.bind(this)],
['renderMulti', this._onRenderMulti.bind(this)],
['getModifiedData', this._onGetModifiedData.bind(this)]
- ]));
+ ]);
}
/**
@@ -39,43 +39,19 @@ export class TemplateRendererFrameApi {
*/
prepare() {
window.addEventListener('message', this._onWindowMessage.bind(this), false);
- this._postMessage(window.parent, 'ready', {}, null);
+ this._postMessage(window.parent, 'ready', void 0, null);
}
// Private
/**
- * @param {MessageEvent<import('template-renderer-frame-api').MessageData>} e
+ * @param {MessageEvent<import('template-renderer-proxy').FrontendMessageAny>} e
*/
_onWindowMessage(e) {
const {source, data: {action, params, id}} = e;
- const messageHandler = this._windowMessageHandlers.get(action);
- if (typeof messageHandler === 'undefined') { return; }
-
- this._onWindowMessageInner(messageHandler, action, params, /** @type {Window} */ (source), id);
- }
-
- /**
- * @param {import('core').MessageHandler} handler
- * @param {string} action
- * @param {import('core').SerializableObject} params
- * @param {Window} source
- * @param {?string} id
- */
- async _onWindowMessageInner(handler, action, params, source, id) {
- let response;
- try {
- let result = handler(params);
- if (result instanceof Promise) {
- result = await result;
- }
- response = {result};
- } catch (error) {
- response = {error: ExtensionError.serialize(error)};
- }
-
- if (typeof id === 'undefined') { return; }
- this._postMessage(source, `${action}.response`, response, id);
+ invokeApiMapHandler(this._windowMessageHandlers, action, params, [], (response) => {
+ this._postMessage(/** @type {Window} */ (source), 'response', response, id);
+ });
}
/**
@@ -113,12 +89,15 @@ export class TemplateRendererFrameApi {
}
/**
+ * @template {import('template-renderer-proxy').BackendApiNames} TName
* @param {Window} target
- * @param {string} action
- * @param {import('core').SerializableObject} params
+ * @param {TName} action
+ * @param {import('template-renderer-proxy').BackendApiParams<TName>} params
* @param {?string} id
*/
_postMessage(target, action, params, id) {
- target.postMessage(/** @type {import('template-renderer-frame-api').MessageData} */ ({action, params, id}), '*');
+ /** @type {import('template-renderer-proxy').BackendMessageAny} */
+ const data = {action, params, id};
+ target.postMessage(data, '*');
}
}
diff --git a/ext/js/templates/template-renderer-proxy.js b/ext/js/templates/template-renderer-proxy.js
index 7cbab3c8..25fe8fb1 100644
--- a/ext/js/templates/template-renderer-proxy.js
+++ b/ext/js/templates/template-renderer-proxy.js
@@ -43,7 +43,7 @@ export class TemplateRendererProxy {
*/
async render(template, data, type) {
await this._prepareFrame();
- return /** @type {import('template-renderer').RenderResult} */ (await this._invoke('render', {template, data, type}));
+ return await this._invoke('render', {template, data, type});
}
/**
@@ -52,7 +52,7 @@ export class TemplateRendererProxy {
*/
async renderMulti(items) {
await this._prepareFrame();
- return /** @type {import('core').Response<import('template-renderer').RenderResult>[]} */ (await this._invoke('renderMulti', {items}));
+ return await this._invoke('renderMulti', {items});
}
/**
@@ -62,7 +62,7 @@ export class TemplateRendererProxy {
*/
async getModifiedData(data, type) {
await this._prepareFrame();
- return /** @type {import('anki-templates').NoteData} */ (await this._invoke('getModifiedData', {data, type}));
+ return await this._invoke('getModifiedData', {data, type});
}
// Private
@@ -124,14 +124,14 @@ export class TemplateRendererProxy {
updateState(0x2);
};
/**
- * @param {MessageEvent<unknown>} e
+ * @param {MessageEvent<import('template-renderer-proxy').BackendMessageAny>} e
*/
const onWindowMessage = (e) => {
if ((state & 0x5) !== 0x1) { return; }
const frameWindow = frame.contentWindow;
if (frameWindow === null || frameWindow !== e.source) { return; }
const {data} = e;
- if (!(typeof data === 'object' && data !== null && /** @type {import('core').SerializableObject} */ (data).action === 'ready')) { return; }
+ if (!(typeof data === 'object' && data !== null && data.action === 'ready')) { return; }
updateState(0x4);
};
@@ -160,10 +160,11 @@ export class TemplateRendererProxy {
}
/**
- * @param {string} action
- * @param {import('core').SerializableObject} params
+ * @template {import('template-renderer-proxy').FrontendApiNames} TName
+ * @param {TName} action
+ * @param {import('template-renderer-proxy').FrontendApiParams<TName>} params
* @param {?number} [timeout]
- * @returns {Promise<unknown>}
+ * @returns {Promise<import('template-renderer-proxy').FrontendApiReturn<TName>>}
*/
_invoke(action, params, timeout = null) {
return new Promise((resolve, reject) => {
@@ -189,8 +190,9 @@ export class TemplateRendererProxy {
timer = null;
}
};
+
/**
- * @param {MessageEvent<unknown>} event
+ * @param {MessageEvent<import('template-renderer-proxy').BackendMessageAny>} event
*/
const onMessage = (event) => {
if (event.source !== frameWindow) { return; }
@@ -198,21 +200,23 @@ export class TemplateRendererProxy {
if (
typeof data !== 'object' ||
data === null ||
- /** @type {import('core').SerializableObject} */ (data).id !== id ||
- /** @type {import('core').SerializableObject} */ (data).action !== `${action}.response`
+ data.id !== id ||
+ data.action !== 'response'
) {
return;
}
- const response = /** @type {import('core').SerializableObject} */ (data).params;
+ // This type should probably be able to be inferred without a cast, but for some reason it isn't.
+ const responseData = /** @type {import('template-renderer-proxy').BackendMessage<'response'>} */ (data);
+ const response = responseData.params;
if (typeof response !== 'object' || response === null) { return; }
cleanup();
- const {error} = /** @type {import('core').Response} */ (response);
+ const {error} = response;
if (error) {
reject(ExtensionError.deserialize(error));
} else {
- resolve(/** @type {import('core').Response} */ (response).result);
+ resolve(/** @type {import('template-renderer-proxy').FrontendApiReturn<TName>} */ (response.result));
}
};
@@ -224,7 +228,9 @@ export class TemplateRendererProxy {
this._invocations.add(invocation);
window.addEventListener('message', onMessage, false);
- frameWindow.postMessage({action, params, id}, '*');
+ /** @type {import('template-renderer-proxy').FrontendMessage<TName>} */
+ const requestMessage = {action, params, id};
+ frameWindow.postMessage(requestMessage, '*');
});
}