-
Notifications
You must be signed in to change notification settings - Fork 190
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
delegate modifiers debug name & instance #1591
base: main
Are you sure you want to change the base?
Changes from all commits
544d222
56d1454
c66cae8
3c7f0de
b32c947
2d67837
8105426
2262c85
566e047
25d103d
01399dd
d02dedf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -32,13 +32,12 @@ export function modifierCapabilities<Version extends keyof ModifierCapabilitiesV | |||||||||||||||||
}); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
export interface CustomModifierState<ModifierInstance> { | ||||||||||||||||||
export interface CustomModifierState<ModifierStateBucket> { | ||||||||||||||||||
tag: UpdatableTag; | ||||||||||||||||||
element: SimpleElement; | ||||||||||||||||||
modifier: ModifierInstance; | ||||||||||||||||||
delegate: ModifierManager<ModifierInstance>; | ||||||||||||||||||
modifier: ModifierStateBucket; | ||||||||||||||||||
delegate: ModifierManager<ModifierStateBucket>; | ||||||||||||||||||
args: Arguments; | ||||||||||||||||||
debugName?: string; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/** | ||||||||||||||||||
|
@@ -65,12 +64,12 @@ export interface CustomModifierState<ModifierInstance> { | |||||||||||||||||
* `updateModifier()` - invoked when the arguments passed to a modifier change | ||||||||||||||||||
* `destroyModifier()` - invoked when the modifier is about to be destroyed | ||||||||||||||||||
*/ | ||||||||||||||||||
export class CustomModifierManager<O extends Owner, ModifierInstance> | ||||||||||||||||||
implements InternalModifierManager<CustomModifierState<ModifierInstance>> | ||||||||||||||||||
export class CustomModifierManager<O extends Owner, ModifierStateBucket> | ||||||||||||||||||
implements InternalModifierManager<CustomModifierState<ModifierStateBucket>> | ||||||||||||||||||
{ | ||||||||||||||||||
private componentManagerDelegates = new WeakMap<O, ModifierManager<ModifierInstance>>(); | ||||||||||||||||||
private componentManagerDelegates = new WeakMap<O, ModifierManager<ModifierStateBucket>>(); | ||||||||||||||||||
|
||||||||||||||||||
constructor(private factory: ManagerFactory<O, ModifierManager<ModifierInstance>>) {} | ||||||||||||||||||
constructor(private factory: ManagerFactory<O, ModifierManager<ModifierStateBucket>>) {} | ||||||||||||||||||
|
||||||||||||||||||
private getDelegateFor(owner: O) { | ||||||||||||||||||
let { componentManagerDelegates } = this; | ||||||||||||||||||
|
@@ -99,41 +98,44 @@ export class CustomModifierManager<O extends Owner, ModifierInstance> | |||||||||||||||||
let delegate = this.getDelegateFor(owner); | ||||||||||||||||||
|
||||||||||||||||||
let args = argsProxyFor(capturedArgs, 'modifier'); | ||||||||||||||||||
let instance: ModifierInstance = delegate.createModifier(definition, args); | ||||||||||||||||||
let modifier: ModifierStateBucket = delegate.createModifier(definition, args); | ||||||||||||||||||
|
||||||||||||||||||
let tag = createUpdatableTag(); | ||||||||||||||||||
let state: CustomModifierState<ModifierInstance>; | ||||||||||||||||||
let state: CustomModifierState<ModifierStateBucket>; | ||||||||||||||||||
|
||||||||||||||||||
state = { | ||||||||||||||||||
tag, | ||||||||||||||||||
element, | ||||||||||||||||||
delegate, | ||||||||||||||||||
args, | ||||||||||||||||||
modifier: instance, | ||||||||||||||||||
modifier, | ||||||||||||||||||
}; | ||||||||||||||||||
|
||||||||||||||||||
registerDestructor(state, () => delegate.destroyModifier(instance, args)); | ||||||||||||||||||
registerDestructor(state, () => delegate.destroyModifier(modifier, args)); | ||||||||||||||||||
|
||||||||||||||||||
return state; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
getDebugName(definition: object) { | ||||||||||||||||||
if (typeof definition === 'function') { | ||||||||||||||||||
return definition.name || definition.toString(); | ||||||||||||||||||
} else { | ||||||||||||||||||
return '<unknown>'; | ||||||||||||||||||
const delegate = this.factory.prototype; | ||||||||||||||||||
if (typeof delegate?.getDebugName === 'function') { | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how about making getDebugName static? @chancancode There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, the various names we use ("delegate" vs "manager" vs "internal manager" vs ...) is a bit confusing but I think what is going on is:
I suppose the short term fix is to pass the owner here. Other than making the internal API looking a bit random, there isn't really a real problem – realistically when we want to generate an error message based on just the definition (error during construction), we almost certainly are going to have an owner as well. The API awkwardness is also contained in this internal version of the API, and people implementing the custom managers API won't really need to see that. Perhaps in the long term it can be revisited if Ember really needs DI on the managers, and can we just make them truly static. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, I tried that, the problem is in
there is no direct way to access the owner, nor vm.owner(), maybe more changes would be requried? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oof, sorry this has been rough. It's the code equivalent of random bureaucracy. Notionally we have the information, just not consistently threaded/easily accessible. Since we narrowed this problem down to these private APIs (I think, this class is private, right?), I don't really care that much about the API surface. I think the API surface of what we call the "delegate" here is important (that's what people actually implement right?), and I think we got that down pretty good. As long as we don't affect the public API, we can do anything (that is type safe, etc) for this wrapper class. Maybe we keep glimmer-vm/packages/@glimmer/runtime/lib/compiled/opcodes/dom.ts Lines 147 to 153 in 34888e9
For what its worth I think a lot of this up is overdue for a cleanup/rethink pass, especially for the manages stuff. The pure form of the idea is good, but we made some decisions along the way that incidentally complicated things a fair bit. |
||||||||||||||||||
return delegate.getDebugName(definition); | ||||||||||||||||||
} | ||||||||||||||||||
return (definition as any).name || '<unknown>'; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
getDebugInstance({ modifier }: CustomModifierState<ModifierInstance>) { | ||||||||||||||||||
return modifier; | ||||||||||||||||||
getDebugInstance({ delegate, modifier }: CustomModifierState<ModifierStateBucket>) { | ||||||||||||||||||
if (typeof delegate?.getDebugInstance === 'function') { | ||||||||||||||||||
return delegate.getDebugInstance(modifier); | ||||||||||||||||||
} | ||||||||||||||||||
return modifier || delegate; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
getTag({ tag }: CustomModifierState<ModifierInstance>) { | ||||||||||||||||||
getTag({ tag }: CustomModifierState<ModifierStateBucket>) { | ||||||||||||||||||
return tag; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
install({ element, args, modifier, delegate }: CustomModifierState<ModifierInstance>) { | ||||||||||||||||||
install({ element, args, modifier, delegate }: CustomModifierState<ModifierStateBucket>) { | ||||||||||||||||||
let { capabilities } = delegate; | ||||||||||||||||||
|
||||||||||||||||||
if (capabilities.disableAutoTracking === true) { | ||||||||||||||||||
|
@@ -143,7 +145,7 @@ export class CustomModifierManager<O extends Owner, ModifierInstance> | |||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
update({ args, modifier, delegate }: CustomModifierState<ModifierInstance>) { | ||||||||||||||||||
update({ args, modifier, delegate }: CustomModifierState<ModifierStateBucket>) { | ||||||||||||||||||
let { capabilities } = delegate; | ||||||||||||||||||
|
||||||||||||||||||
if (capabilities.disableAutoTracking === true) { | ||||||||||||||||||
|
@@ -153,7 +155,7 @@ export class CustomModifierManager<O extends Owner, ModifierInstance> | |||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
getDestroyable(state: CustomModifierState<ModifierInstance>) { | ||||||||||||||||||
getDestroyable(state: CustomModifierState<ModifierStateBucket>) { | ||||||||||||||||||
return state; | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
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.
renamed the type here to be the same as in modifier.d.ts file