Skip to content

Commit f4dc41a

Browse files
NullVoxPopuliclaude
andcommitted
feat: propagate invocation-site names for dynamic components in debugRenderTree
For dynamic component invocations like `<this.Foo>` and `<@Greeting>`, the debug render tree now shows the invocation-site name instead of '(unknown template-only component)'. This works by extracting the Reference's debugLabel in VM_RESOLVE_DYNAMIC_COMPONENT_OP and VM_RESOLVE_CURRIED_COMPONENT_OP, and setting it as the ComponentDefinition's debugName when no name is already present. - `<this.Foo>` → name: "Foo" - `<@Greeting>` → name: "Greeting" Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 87d55e6 commit f4dc41a

2 files changed

Lines changed: 24 additions & 2 deletions

File tree

packages/@glimmer-workspace/integration-tests/test/debug-render-tree-test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,10 @@ class DebugRenderTreeTest extends RenderTest {
185185

186186
this.assert.ok(componentNode, 'found a component child node');
187187

188+
// For <@Greeting>, the invocation-site name "Greeting" is used
188189
this.assert.strictEqual(
189190
componentNode?.name,
190-
'HelloWorld',
191+
'Greeting',
191192
`dynamic <@X> component name (got "${componentNode?.name}")`
192193
);
193194
}

packages/@glimmer/runtime/lib/compiled/opcodes/component.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,9 @@ APPEND_OPCODES.add(VM_PUSH_COMPONENT_DEFINITION_OP, (vm, { op1: handle }) => {
154154

155155
APPEND_OPCODES.add(VM_RESOLVE_DYNAMIC_COMPONENT_OP, (vm, { op1: _isStrict }) => {
156156
let stack = vm.stack;
157+
let ref = check(stack.pop(), CheckReference);
157158
let component = check(
158-
valueForRef(check(stack.pop(), CheckReference)),
159+
valueForRef(ref),
159160
CheckOr(CheckString, CheckCurriedComponentDefinition)
160161
);
161162
let constants = vm.constants;
@@ -182,6 +183,14 @@ APPEND_OPCODES.add(VM_RESOLVE_DYNAMIC_COMPONENT_OP, (vm, { op1: _isStrict }) =>
182183
definition = constants.component(component, owner);
183184
}
184185

186+
if (DEBUG && !isCurriedValue(definition) && !definition.resolvedName && !definition.debugName) {
187+
let debugLabel = ref.debugLabel;
188+
if (debugLabel) {
189+
// Extract the last segment of the path (e.g. "this.Foo" → "Foo", "Foo" → "Foo")
190+
definition.debugName = debugLabel.split('.').pop();
191+
}
192+
}
193+
185194
stack.push(definition);
186195
});
187196

@@ -217,6 +226,18 @@ APPEND_OPCODES.add(VM_RESOLVE_CURRIED_COMPONENT_OP, (vm) => {
217226
}
218227
}
219228

229+
if (DEBUG && definition && !isCurriedValue(definition) && !definition.resolvedName && !definition.debugName) {
230+
let debugLabel = ref.debugLabel;
231+
if (debugLabel) {
232+
// Extract the component name from the arg path (e.g. "@Greeting" → "Greeting")
233+
let name = debugLabel.split('.').pop()!;
234+
if (name.startsWith('@')) {
235+
name = name.slice(1);
236+
}
237+
definition.debugName = name;
238+
}
239+
}
240+
220241
stack.push(definition);
221242
});
222243

0 commit comments

Comments
 (0)