feat: Expose method types to plugin fnWrap & improve events errors#980
Conversation
Adds an extra parameter to a plugin’s `fnWrap` method which it can used to know which hook is being wrapped.
- Errors for any event called outside a move or hook (e.g. from `endIf` or `turn.order.next`). - Errors for stage events in a phase’s `onBegin` (previously these were just ignored, which was hard to debug).
|
Another option could be: const plugin = {
name: 'discerning-wrapper',
fnWrap: (fn) => (...args) => {
if (fn._fnType === GameMethod.Turn.ON_MOVE) {
console.log('Looks like this is an onMove hook.);
}
return fn(...args);
},
}; |
|
Can we change from a string to an enum, in order to gain type safety? |
Sure. I liked the expressiveness of the enum-like object ( What do you think about @cristiands7’s suggestion? I like that it’s a more “private” approach, but am a little wary of this kind of |
|
Here’s a summary of the scenarios that now produce errors. Some of these were previously harmless/ignored silently, so may produce breaks in some games, but hopefully this extra diagnostic information will steer people to better understanding the game flow.
Which hooks support which events
✅ = supported ❌ = not supported (The state does not actually error in the |
Here’s an attempt to close #979. Feedback very much wanted and if you want to pick this up and iterate on it, you’re welcome to as I likely won’t have much time in the next couple of weeks.
Also closes #981.
Approach
When wrapping game hooks (
onBegin,onMove,onEnd), provide a unique string to the plugin interface so that it knows which hook is being wrapped. (These unique strings are from a kind of custom enum accessed likeGameMethod.Phase.ON_BEGINorGameMethod.MOVE.)A plugin’s
fnWrapthen receives this string in addition to the function to wrap, so it can change behaviour appropriately.In the events plugin we store this string, like we do with the turn/phase details and use it when processing events. This is actually pretty nice because we can give more informative errors. The main drawback is that this depends on
fnWrapwhich is not applied to triggers (likeendIf) and other game methods (liketurn.order.first), so the best we can do is error if the hook type isundefined(which is probably OK, because only hooks should be used for events) without knowing exactly what method triggered the error.Notes
I don’t particularly like that this exposes something new to the public plugin API, but I couldn’t really see how to do this otherwise as that is how the events plugin is built. One alternative could be to only expose this new data via some separate plugin field, like
_internal_fnWrap, which would still be public but marked as private. Not sure exactly what the best approach is, but happy to see alternative approaches.To-do
GameMethodobject properly, so that plugin authors can import it. Probably from theboardgame.io/corepackage?CC: @cristiands7 — Happy to hear your thoughts too!