Add feature decorator system #13
No reviewers
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: profectus/Profectus#13
Loading…
Reference in a new issue
No description provided.
Delete branch "main"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
While features have always let you define additional typing to add new methods and values to them, they haven't had a good way to actually process the extra data without wrapping the
createFeature()
call inside another wrapper function. This decorator system aims to solve that problem, allowing the input data to require additional keys to be present for the additional functionality, as well as adding any extra persistent or computed fields that may be useful.What is the purpose in splitting this type up like that?
I feel the decorators shouldn't have to be coded into the feature themselves if at all possible. I feel like the great potential of this feature would be being able to distribute the decorator file itself to other devs and it being fully self contained.
I think implementing a generic way for decorators to modify JSX functions should probably take form in two different ways: A way to wrap the JSX function (so the decorator is expected to render the JSX function somewhere inside it's own), as well as a way for each decorator to add a JSX function that the default JSX function is expected to render somewhere (probably at the end) - similar to how the options menu has options injected in when features are used.
I think the specific decorators probably belong in their own files, or in
common.tsx
if they're particularly small and useful enough to be included as part of the "base" project (as effects would be, but maybe not the bonusAmounts/completions).Seeing this case here also made me notice that currently the type is not set automatically by using the decorator. Would it be possible to have each decorator include a "transformation" type, that takes the previous type and augments/changes it? Then Each of the outputs (like
Repeatable<T>
for this function) could be replaced with something likeApplyDecorators<Repeatable<T>, D>
where D is the chain of transformation types from the decorators arrayYeah, I put this here because you wanted it to show the bonus amount in the feature if possible, but in the end, this was the only feature that was doable in. I'll try out having insertion points for the JSX functions, although it might just be a thing where if you want to use them, you should be either writing your own full display function or even swapping out the component (which is what the
getGatheredProps
function is for).This was because I was expecting the decorators to need to know the typing of the objects that were coming in, but I think this could be safely undone, and the decorators forcing additional typing on the
OptionFunc
s would still work.This is the point where the decorators are a bit annoying, and the current typing system feels frail enough that I'm scared to try adding to it. There is also the problem that the typing needs to come from somewhere, but all the current functionality is through observer calls, where the modifications to the object itself are only really known to the call that did those modifications.
Using these decorators does at least force you to change up the typing of the OptionsFunc you pass in, which is the main reason I have stuff like
GenericEffectFeature
andBonusAmountFeatureOptions
being exported from the decorators - so while the decorators themselves are actually pretty dumb and don't know anything except what they specifically work on, the input object does at least need to have those values, and it does guide how to manually set the output type.Ok scratch that on them forcing you to have the proper typing on the input function - the typescript version and takeover mode are being weird, I'm going to need to take another proper look at getting the typing functional
Taking a better look at this, specifically - this
as GenericRepeatable & GenericBonusAmountFeature
bit here is because it's on the general display function. While the error notification for including a decorator without its corresponding Options type is entirely useless at the moment, fixing those errors does require adding extra typing to thecreateFeature
call (createUpgrade<UpgradeOptions & EffectFeatureOptions>
), which does let those extra values be used inside thecreateFeature
call without any additional casting.Ok, on further efforts, this does need to be split - the decorators do need access to the OptionsFunc, after it's been called, in order to have the decorator's typing merged into the
createFeature
function. Without this, you just get mismatched type errors upon trying to use any decorator at all, only fixable by manually applying the enhanced type every time it's used - which completely bypasses the purpose of these.I appreciate the documentation! Especially with examples of how to get proper typing. Hopefully most people will be creating a util function for creating groups of similar features so they can just handle the typing stuff once.
Please change this back to util/bignum
I'm not a huge fan of adding these separators and #region comments since nowhere else in the project has them
While I wish it could do the types automatically, with the docs you wrote I think this is fine for now
Heh, guess that's what I get for just letting it mass-import everything
Trust me, I've made this same mistake so many times. I wish I had a better way to hint to the IDE what the default export is expected to be called
Are you still planning on implementing this for this PR, or do you think it belongs in a separate PR?
Just getting the rest of the stuff sorted out as best I can before focusing on this. Probably going to need to push it to its own thing, but there's a chance it's at least partially doable without overhauling how displays are built.