Resolve Element for block-param-yielded curried sub-components#18
Open
Resolve Element for block-param-yielded curried sub-components#18
Element for block-param-yielded curried sub-components#18Conversation
Pattern: `<SelectBase as |C|><C.Options>...</C.Options></SelectBase>`, where SelectBase yields a curried sub-component (`C.Options`) that renders `<select>`. At runtime `<option>` children are correctly inside `<select>`. Statically, Glint's emit surfaces `emitComponent(...).element` as `any` for the curried ref, so our resolver fell through to `'transparent'` — the `<option>` children floated to `<SelectBase>`'s `<div>` and `element-permitted-content` FP-fired. The componentRef expression's *type* (the first argument to `__glintDSL__.resolve(...)`) is `TOC<OptionsSig>` — a generic with the Signature as its first type-argument. Read `Element` off `aliasTypeArguments[0]` directly, the same way the existing class-form path reads `.element` off the call type. Same recovery also helps the `: TOC<S> =` annotation form (covered already by fix/fp-toc-satisfies-element via the satisfies-walk-back — this path is more direct). Surfaced by ecosystem CI on HDS (107× `<option>` not permitted under `<div>`, all from `<HdsFormSelectBase as |C|><C.Options>...</C.Options>`).
5 tasks
There was a problem hiding this comment.
Pull request overview
This PR improves Glint-based element resolution for Ember templates by recovering a component’s rendered DOM tag from the type of the component reference expression when Glint’s emitted emitComponent(...).element is any/unknown (notably for block-param-yielded curried sub-components like <C.Options>).
Changes:
- Add a fallback resolution path that extracts
Signature['Element']fromcomponentRef’s generic type arguments (e.g.TOC<OptionsSig>) and maps it to an HTML tag. - Add a new cross-file fixture covering the
<SelectBase as |C|><C.Options>...</C.Options></SelectBase>pattern. - Add an integration test asserting
<C.Options>resolves to'select'incomponentTagMap.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| lib/glint.ts | Adds resolveElementFromComponentRefType fallback when .element is any/unknown, enabling correct tag resolution for yielded curried refs. |
| test/glint.test.ts | Adds an integration test that verifies <C.Options> resolves to 'select'. |
| test/glint-fixtures/yielded-curried-component.gts | Adds a fixture exercising a yielded curried sub-component with Element: HTMLSelectElement. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Per Copilot review on #18: 1. Removed the reference to resolveElementFromSatisfiesTOC from the inline comment — that helper exists on a sibling branch (fix/fp-toc-satisfies-element / PR #16) but not on this one. Stale on its own. 2. Added a fallback path for when TOC's type-args land on a TypeReference rather than aliasTypeArguments (i.e., when TOC is declared as `interface TOC<S>` instead of `type TOC<S> = …`). The public `checker.getTypeArguments(refType as TypeReference)` covers that case. aliasTypeArguments handles the type-alias form.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Pattern:
<SelectBase as |C|><C.Options>...</C.Options></SelectBase>, whereSelectBaseyields a curried sub-component (C.Options) that renders<select>. At runtime<option>children are correctly inside<select>. Statically, Glint's emit surfacesemitComponent(...).elementasanyfor the curried ref, so the resolver fell through to'transparent'—<option>children floated to<SelectBase>'s<div>andelement-permitted-contentFP-fired.The componentRef expression (the first argument to
__glintDSL__.resolve(...)) has typeTOC<OptionsSig>— a generic with the Signature as its first type-argument.resolveElementFromComponentRefTypereadsElementoffaliasTypeArguments[0]directly, the same way the class-form path reads.elementoff the call type.Discovery
Glint's emit for the consumer template is roughly:
(emitComponent(...)).elementisanyfor this shape (Glint's TOC overload doesn't fully propagate through block-param dereferences). ButgetTypeAtLocation(C?.Options)returnsTOC<OptionsSig>— confirmed via debug logging during this investigation. From therealiasTypeArguments[0]isOptionsSig, which hasElement: HTMLSelectElementas a property.Surfaced by
Ecosystem CI on
hashicorp/design-system— the largest single FP cluster: 107×<option>not permitted under<div>, all from<HdsFormSelectBase as |C|><C.Options>...</C.Options></HdsFormSelectBase>-style invocations across the showcase.Test plan
componentTagMapresolves<C.Options>→'select'against the fixturenpm test— 128/128 passingnpm run typecheck:tests— cleannpm run build— cleanCompanion
Stacks naturally with #16 (
fix/fp-toc-satisfies-element) — both target the unknown/any element-type fallback. This one covers the curried block-param yield case and theconst X: TOC<Sig> = …annotation form (viaaliasTypeArguments); #16 covers the... satisfies TOC<Sig>form (via walking the variable declaration).