Skip to content
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

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

patricklx
Copy link
Contributor

@patricklx patricklx commented Jun 25, 2024

currently arrow functions or functions without name are displayed with their whole implementation source code

closes #1589

@NullVoxPopuli
Copy link
Contributor

what will this look like?

@patricklx
Copy link
Contributor Author

what will this look like?

{{my-modifier fn}} is how it can look like.

Currently... look at you limber site :) it's a good example

@NullVoxPopuli
Copy link
Contributor

I see!
image

looks like anything that fixes this is good for me

@patricklx patricklx changed the title fix arrow modifiers debug name delegate modifiers debug name & instance Jun 26, 2024
@patricklx
Copy link
Contributor Author

@NullVoxPopuli actually, current release of inspector cannot handle latest ember... need nightly:
Screenshot 2024-06-27 at 10 39 38

@@ -504,7 +504,7 @@ export class ComponentElementOperations implements ElementOperations {
}

let { element, constructing } = vm.elements();
let name = manager.getDebugName(definition.state);
let name = manager.getDebugName(state, definition.state);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why definition.state here, if the argument is 'definition' (for modifiers)?

Is this an inconsistency between modifiers and components managers?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what i understand: Because state is from the 'main' manager, and definition.state is from the delegate. And state has the delegate needed to delegate to function call

@wycats
Copy link
Contributor

wycats commented Jul 11, 2024

This looks good to me. Let's do it!

@@ -22,7 +22,7 @@ export interface InternalModifierManager<
// the modifier's update hooks need to be called (if at all).
getTag(modifier: TModifierInstanceState): UpdatableTag | null;

getDebugName(Modifier: TModifierDefinitionState): string;
getDebugName(Modifier: TModifierDefinitionState, definition: object): string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems fishy, what is that second arg?

@@ -32,13 +32,13 @@ export function modifierCapabilities<Version extends keyof ModifierCapabilitiesV
});
}

export interface CustomModifierState<ModifierInstance> {
export interface CustomModifierState<ModifierStateBucket> {
Copy link
Contributor Author

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

args: Arguments;
debugName?: string;
definition?: object;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we'd need to store it since it gets passed in?

@NullVoxPopuli
Copy link
Contributor

Seems good
image

args: Arguments;
debugName?: string;
definition?: object;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this still needed?

Copy link
Contributor

@NullVoxPopuli NullVoxPopuli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tiny cleanup thing, otherwise 👍

@patricklx patricklx force-pushed the patch-8 branch 2 times, most recently from 2ed0c4a to f6a3550 Compare October 18, 2024 15:38
} else {
return '<unknown>';
const delegate = this.factory.prototype;
if (typeof delegate?.getDebugName === 'function') {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about making getDebugName static? @chancancode

Copy link
Contributor

Choose a reason for hiding this comment

The 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:

  1. Fundamentally, as far as Glimmer is concerned:

    • Modifier managers (~= factories..?) are static are are used to decide how to instantiate things and make other policy decisions
    • Modifier definitions – a class, a function, etc, but can be whatever the manager knows how to instantiate; you can make a modifier manager that knows to to use the POJO { name: "my-modifier" } as a modifier
    • Modifier instance – in the case of a class, this would possibly be the instance, but it's generalized into whatever the "instantiated thing" is and the manager may use that to store its own state/metadata as well, ultimately we treat this as an "opaque state bucket"
  2. As discussed in previous iterations of this PR, we want the ability to name a modifier "statically" – in this context meaning just the "definition" (class, function, etc), as opposed to the instance. This allows this naming feature to be used in more cases, such as the error message when we failed to construct an instance

  3. So far so good. However, Ember introduced a wrinkle to this – it extended the managers interface to allow dependency injection, so managers are no longer truly static, but rather static as in "one per owner (app/engine/etc)". Which is what you are noticing here.

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.

Copy link
Contributor Author

@patricklx patricklx Oct 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I tried that, the problem is in

definition.resolvedName || manager.getDebugName(definition.state)

there is no direct way to access the owner, nor vm.owner(), maybe more changes would be requried?

Copy link
Contributor

Choose a reason for hiding this comment

The 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 getDebugName(owner, definition) and getDebugNameFromInstance(instance) in this internal class and call it a day for now. For reference: this is the kind of place we may want to use the former, which we do have the owner:

let capturedArgs = args.capture();
let state = manager.create(
owner,
expect(constructing, 'BUG: ElementModifier could not find the element it applies to'),
definition.state,
capturedArgs
);

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.

currently arrow functions or functions without name as displayed with their whole implementation
NullVoxPopuli
NullVoxPopuli previously approved these changes Oct 19, 2024
@NullVoxPopuli NullVoxPopuli dismissed their stale review October 22, 2024 22:45

Dismissing because we want to go more in a direction that exposes what the user typed, rather than try to derive debug aliases / names from existing runtime information --- here is an example: #1634 -- @wycats is currently thinking about this PR and is actively workingish on it -- this way when folks import something and alias it, we use the alias name, rather than the name it was defined with (current behavior as implemented)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants