From 86fa869b20b0f1ce01247b5a37d6a5cb83318ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 6 Jul 2021 10:26:44 +0200 Subject: [PATCH] Actually using Type Guards in queries received by WA. --- front/src/Api/Events/IframeEvent.ts | 47 +++++++++++++++++++++++------ front/src/Api/IframeListener.ts | 10 +++--- maps/tests/Variables/variables.json | 20 +----------- 3 files changed, 45 insertions(+), 32 deletions(-) diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 54319fd3..0d995255 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -1,3 +1,4 @@ +import * as tg from "generic-type-guard"; import type { GameStateEvent } from "./GameStateEvent"; import type { ButtonClickedEvent } from "./ButtonClickedEvent"; import type { ChatEvent } from "./ChatEvent"; @@ -19,6 +20,9 @@ import type { MenuItemRegisterEvent } from "./ui/MenuItemRegisterEvent"; import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent"; import type { SetTilesEvent } from "./SetTilesEvent"; import type { SetVariableEvent } from "./SetVariableEvent"; +import {isGameStateEvent} from "./GameStateEvent"; +import {isMapDataEvent} from "./MapDataEvent"; +import {isSetVariableEvent} from "./SetVariableEvent"; export interface TypedMessageEvent extends MessageEvent { data: T; @@ -81,20 +85,32 @@ export const isIframeResponseEventWrapper = (event: { /** - * List event types sent from an iFrame to WorkAdventure that expect a unique answer from WorkAdventure along the type for the answer from WorkAdventure to the iFrame + * List event types sent from an iFrame to WorkAdventure that expect a unique answer from WorkAdventure along the type for the answer from WorkAdventure to the iFrame. + * Types are defined using Type guards that will actually bused to enforce and check types. */ -export type IframeQueryMap = { +export const iframeQueryMapTypeGuards = { getState: { - query: undefined, - answer: GameStateEvent, + query: tg.isUndefined, + answer: isGameStateEvent, }, getMapData: { - query: undefined, - answer: MapDataEvent, + query: tg.isUndefined, + answer: isMapDataEvent, }, setVariable: { - query: SetVariableEvent, - answer: void + query: isSetVariableEvent, + answer: tg.isUndefined, + }, +} + +type GuardedType = T extends (x: unknown) => x is (infer T) ? T : never; +type IframeQueryMapTypeGuardsType = typeof iframeQueryMapTypeGuards; +type UnknownToVoid = undefined extends T ? void : T; + +export type IframeQueryMap = { + [key in keyof IframeQueryMapTypeGuardsType]: { + query: GuardedType + answer: UnknownToVoid> } } @@ -108,8 +124,21 @@ export interface IframeQueryWrapper { query: IframeQuery; } +export const isIframeQueryKey = (type: string): type is keyof IframeQueryMap => { + return type in iframeQueryMapTypeGuards; +} + // eslint-disable-next-line @typescript-eslint/no-explicit-any -export const isIframeQuery = (event: any): event is IframeQuery => typeof event.type === 'string'; +export const isIframeQuery = (event: any): event is IframeQuery => { + const type = event.type; + if (typeof type !== 'string') { + return false; + } + if (!isIframeQueryKey(type)) { + return false; + } + return iframeQueryMapTypeGuards[type].query(event.data); +} // eslint-disable-next-line @typescript-eslint/no-explicit-any export const isIframeQueryWrapper = (event: any): event is IframeQueryWrapper => typeof event.id === 'number' && isIframeQuery(event.query); diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index ee969721..9c61bdf8 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -168,13 +168,15 @@ class IframeListener { return; } - const errorHandler = (reason: any) => { + const errorHandler = (reason: unknown) => { console.error('An error occurred while responding to an iFrame query.', reason); - let reasonMsg: string; + let reasonMsg: string = ''; if (reason instanceof Error) { reasonMsg = reason.message; - } else { - reasonMsg = reason.toString(); + } else if (typeof reason === 'object') { + reasonMsg = reason ? reason.toString() : ''; + } else if (typeof reason === 'string') { + reasonMsg = reason; } iframe?.contentWindow?.postMessage({ diff --git a/maps/tests/Variables/variables.json b/maps/tests/Variables/variables.json index 94d40560..d74e90cc 100644 --- a/maps/tests/Variables/variables.json +++ b/maps/tests/Variables/variables.json @@ -14,24 +14,6 @@ "x":0, "y":0 }, - { - "data":[0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - "height":10, - "id":6, - "name":"triggerZone", - "opacity":1, - "properties":[ - { - "name":"zone", - "type":"string", - "value":"myTrigger" - }], - "type":"tilelayer", - "visible":true, - "width":10, - "x":0, - "y":0 - }, { "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "height":10, @@ -58,7 +40,7 @@ { "fontfamily":"Sans Serif", "pixelsize":11, - "text":"Test:\nTODO", + "text":"Test:\nOpen your console\n\nResult:\nYou should see a list of tests performed and results associated.", "wrap":true }, "type":"",