Add rfc931: 'native' option to preserve template() in output#115
Open
NullVoxPopuli-ai-agent wants to merge 3 commits into
Open
Add rfc931: 'native' option to preserve template() in output#115NullVoxPopuli-ai-agent wants to merge 3 commits into
NullVoxPopuli-ai-agent wants to merge 3 commits into
Conversation
Adds an `rfc931` option controlling how the RFC 931 `template()` API (from `@ember/template-compiler`) is emitted: - "polyfilled" (default): existing behavior — lower `template()` to `precompileTemplate`/`createTemplateFactory` + `setComponentTemplate` + `templateOnly`, for runtimes without native `template()` support. - "native": preserve the `template()` call for runtimes that implement `@ember/template-compiler` natively (Ember 6+). AST transforms still run, and the implicit `eval` form is normalized into the explicit `scope` form. This only affects `targetFormat: 'hbs'`. With `targetFormat: 'wire'` the template is fully compiled to the standard wire format, which already runs on native runtimes, so `native` has no effect there. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Covers the real gjs/gts path: content-tag preprocesses <template> into the implicit eval form, then rfc931: 'native' + targetFormat: 'hbs' keeps the template() call and converts eval -> scope. Asserts both the expression form and the class-member form. content-tag aliases its import (`template as template_<hash>`); native mode preserves that alias, so a normalizeContentTagImport helper maps it back to `template` for stable assertions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes the last coverage gap: real <template> gjs is preprocessed by content-tag into the implicit eval form, then compiled all the way to the wire format with targetFormat: 'wire'. Confirms eval -> wire end-to-end (existing wire tests only exercised the explicit scope form). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
faebc72 to
28070da
Compare
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
Adds an
rfc931option that controls how the RFC 931template()API (imported from@ember/template-compiler) is emitted:"polyfilled"(default) — existing behavior.template()is lowered to the older, widely-supported primitives (precompileTemplate/createTemplateFactoryplussetComponentTemplateandtemplateOnly) so the output runs on Ember versions that don't natively understandtemplate()."native"— thetemplate()call is preserved in the output, for runtimes that implement@ember/template-compilernatively (Ember 6+). AST transforms still run, and the implicitevalform is normalized into the explicitscopeform.Findings / design notes
I read through RFC 931, the discussion thread, the existing plugin, the in-progress draft #109, and ember-source's native implementation of
@ember/template-compiler. Key conclusions that shaped the design:template()only ever takes a string. ember-source's nativetemplate(templateString, options)callsglimmerPrecompile(templateString, ...)at runtime — it never accepts a precompiled wire factory. So "preservingtemplate()" is only meaningful when the body stays as an HBS string, i.e.targetFormat: 'hbs'.targetFormat: 'wire'needs no special native handling. The standard wire output —setComponentTemplate(createTemplateFactory(...), component ?? templateOnly())— is exactly what nativetemplate()produces internally, and it already runs on native runtimes. Wrapping a wire factory back into atemplate()call would not execute on Ember (it expects a string). Sorfc931: 'native'only changeshbs-target output; inwireit falls back to the normal compiled form.eval → scope normalization is the useful work in native mode. The implicit (
eval) form is the intermediate emitted bycontent-tag; converting it to the explicitscopeform (via the existing implicitScopeLocalsmachinery +updateScope) produces the canonical, statically-analyzable, publishable form.componentand the user'sstrictoption are preserved untouched;evalis dropped.Implementation
@ember/template-compilermodule config'srfc931Supportnow resolves to the user'srfc931choice ('polyfilled'|'native') inconfiguredModules.updateCallForm(thehbspath) gains anativebranch that keeps thetemplate()callee and its import, dropseval, and letsupdateScopeappend the explicitscope.wirepath and import cleanup are unchanged.Tests
Adds a
native rfc931suite covering: template-only and class-backed components (static block + out-of-classcomponent:), eval→scope conversion,strictpreservation, multiple templates per module, no-options template-only, and thewirefallback. Full suite: 137 passing, lint clean.🤖 Generated with Claude Code