-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Collision: Expand defer into map/reduce, add support for initializer aggregation, aggregating asynchronous methods and be backwards compatible. #80
base: master
Are you sure you want to change the base?
Conversation
Looks like CI is failing because I bumped @typescript-eslint/eslint-plugin and @typescript-eslint/parser to version 4 (latest). Version 2 (used in master) doesn't support no-shadow so I had to bump it for eslint to have no complaints. Might be able to bump master to version 4 without any dire consequences. |
A single async initializer must also be proxied
Collision: opts.stamp must be coerced to CollisionStamp in reducer Collision: Add hasAggregates(), getAggregates() and setAggregates() to Collision stamp Collision: Make collision composer a named function Collision: Add isAggregateDomainItem(), getDomainItemAggregates(), setDomainItemAggregates() Collision: Simplify make*ProxyFunction() Collision: Initializers are now aggregated properly Collision: Tests now check aggregate arrays are properly formed
Hello @PopGoesTheWza |
@koresar should be good. |
Great! I'll test the PR on my laptop (when it's not midnight, which is now). |
That last commit wraps up support for methods and initializers with all tests passing. There are a few parts that could probably be written cleaner but I don't see those as blockers. |
I have half implemented some more tests for the newly exposed methods on the Collision stamp and some exception throwing in those methods when things aren't right. Will push those up ASAP. |
@sammys can you add the updated |
…and setAggregates() + tests
@PopGoesTheWza That explains it. I've pushed package-lock.json with the completed implementation of *Aggregates() methods on Collision stamp. There are still errors in other @stamp packages so we're not out of the woods yet. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this PR requires the README documentation to be updated?
Collision: Remove *.d.ts that was accidentally committed Collision: Re-enable prettier/prettier in index.ts and reformat to match rules Collision: In context @typescript-eslint/no-shadow added
I have couple of suggestions.
|
I will be updating the README as soon as I get an all clear for the implementation. |
Collision: Rename validateHasGetSetArguments() to validateDomainAndItemName() Collision: Revert type changes in @stamp/compose
I believe that last commit covers all the change requests. Let me know if I missed something. Are there any remaining concerns that I need to address before updating README? |
Thanks @sammys. This PR is on a good track. Last commit fails on build. Pro tip, run a EDIT The build error are cause from the changes in |
There are build issues in other packages but I didn't think those are related to this PR. I'll sort it out |
Collision: Bump Typescript to >= 3.8.0 Collision: Fix named/required use of if (this?.compose) since it never returns false Collision: Add return types to two functions in collision/index.ts Collision: Update ComposeProperty repeated declaration in shortcut/index.ts Collision: Update collision settings in __tests__/privatize-plus-collision.js
@PopGoesTheWza Sorry, I saw your edit after I had committed my changes already. Only one of the errors was caused by the changes in |
I have yet told you @sammys that the current master is not what's published to NPM. The current I don't know what it means, but I thought you need to know this Sam. I've added few more comments. Some important, but most are minor. In the next message I'll explain what's wrong with async initialisers. |
The async initializers were pretty difficult to implement in accordance with the specification. Here is my code from 5 years ago before the Spec was born: https://github.com/stampit-org/stampit/pull/133/files#diff-30f7af44dd75ee293d1a3bdab338b6604a66ce8cbc1f666444d6c982f0c7eb5dR128-R177 That little code disallowed inter-stamp operability/composability. Stamps declare that you can mish-mash anything and get your object instances from it. Which become untrue. What I see in your current implementation:
Now, don't get me wrong, I really want to add async initialiser to stamps! This would be a very very very "class-beating" argument! Let's add async initiliazers in a more thought through manner we do here - discuss, update specs, update I have a great idea how we can extend the specification to your needs!
Meaning we would detect if at least one initalizer is const isAsyncfunc = f => f.constructor.name == 'AsyncFunction' If yes - then return a Let me quickly hack through this piece of code. See my comments below. if (initializers && initializers.length > 0) {
let returnedValue: void | object;
const args = [options, ...moreArgs];
for (let i = 0; i < initializers.length; i++) {
const initializer = initializers[i];
if (isFunction<Initializer>(initializer)) {
// New code
if (isAsyncFunc(initializer) return new Promise(async resolve => {
for (; i < initializers.length; i++) {
const initializer = initializers[i];
if (isFunction<Initializer>(initializer)) {
returnedValue = await initializer.call(instance, options, { // await !!!
instance,
stamp: Stamp as Stamp,
args,
});
if (returnedValue !== undefined) instance = returnedValue;
}
}
resolve(instance);
});
returnedValue = initializer.call(instance, options, {
instance,
stamp: Stamp as Stamp,
args,
});
if (returnedValue !== undefined) instance = returnedValue;
}
} Looks like (not sure though) this way we won't break stamp interoperability and will be new spec compliant. WDYT? |
Or even better. Do not rely on semi-stable if (initializers && initializers.length > 0) {
let returnedValue: void | object;
const args = [options, ...moreArgs];
for (let i = 0; i < initializers.length; i++) {
const initializer = initializers[i];
if (isFunction<Initializer>(initializer)) {
returnedValue = initializer.call(instance, options, {
instance,
stamp: Stamp as Stamp,
args,
});
// New code
if (isFunction(returnedValue?.then)) return returnedValue.then(asyncReturnedValue => {
for (i++; i < initializers.length; i++) {
const initializer = initializers[i];
if (isFunction<Initializer>(initializer)) {
asyncReturnedValue = await initializer.call(instance, options, { // await !!!
instance,
stamp: Stamp as Stamp,
args,
});
if (asyncReturnedValue !== undefined) instance = asyncReturnedValue;
}
}
return instance;
});
if (returnedValue !== undefined) instance = returnedValue;
}
} |
Also, I found the commit where we dropped Promises support. Here it is: stampit-org/stampit@d639cb3#diff-30f7af44dd75ee293d1a3bdab338b6604a66ce8cbc1f666444d6c982f0c7eb5dL125 But there is nothing that can stop us now! :) |
Here was another query from someone to add async initialisers support: stampit-org/stamp-specification#120 |
Here is an opinion on why async initialisers are bad: stampit-org/stamp-specification#109 (comment) |
Last comment for today. I've created this RFC: stampit-org/stamp-specification#129 |
@koresar Thanks for digging all that up for me to look through. I'll go through it with a fresh mind. While the mind is not fresh I'll get this PR ready hehe. Oh... and... Having async initialiser support inside compose would be WAY better than it being in collision! |
…ring to Stamp specification) Collision: Rejig if (this?.compose...) to if (isStamp(this)...)
Most recent commit has new tests for sync and async initialisers throwing at beginning, middle and end of the chain. I changed nothing in the
Would be interesting to me from an academic standpoint to see just how many of those tests fail.
It does intentionally break those other packages. I might be totally off base here... I see collision as a utility stamp right now. Due to that perspective the implementation in this PR is intended to be an aggregation behaviour and not a core async solution. As such, I included the code as a temporary solution for those needing the behaviour before the specs etc reach maturity. Although, related to those packages you listed, there's a little more reasoning behind my madness... In my limited Stamps experience, ordering initialisers (or methods for that matter) in a stamp's reducer became icky when many stamps having this behaviour are composed together. E.g. many stamps expecting "mine goes first". Which one actually does go first? Yes, this can be resolved with a reducer in each level of composition. It can't be built into compose because AFAICT it can't rely on composition order in many cases because it is application specific. When faced with this conundrum I asked myself the question, is a declarative style (a.k.a collision managed) better than the reducer style (a.k.a standard compose)? What I concluded was that the latter (standard compose) is currently bound by composition ordering and the former (collision) is independent of composition ordering provided collision's reducer is always last. My experience is so limited that I can't extrapolate all this into "we can do composition order independent declarative tweaking this way using the current Stamp specification". Or, perhaps, the specification can be extended to support this.
I'm looking forward to helping make this happen! In the meantime, since it is a project goal to support async initialisers, having the PR async initialiser behaviour published either in @stamp/collision (or in another official stamp) would give people an officially supported way to play with async initialised Stamps so they can feel the power! @koresar it's your call! |
I've hit one of these more complex scenarios in the project I'm working on and, as you expected, it does fail. In the current PR implementation the async reduce doesn't properly handle when an initialiser returns non-undefined. I've implemented a fix that appears to handle it properly. While it does run properly in the project it fails tests for some very bizarre reason and that's why I haven't yet committed anything to the PR. Working on it. |
… what's there already Allow 'this' to be stamp or descriptor for collisionGetAggregates() and collisionSetAggregates()
For #45. Will add details in here if need be.