From 05957d957c54ece374b3e2c22690e1ab5b20ec45 Mon Sep 17 00:00:00 2001 From: Aniruddh-14 Date: Sat, 22 Nov 2025 13:24:57 +0530 Subject: [PATCH 1/9] Update runtime-template-compiler-implicit-test.ts --- ...runtime-template-compiler-implicit-test.ts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts b/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts index 5d4e975acc1..544fe30f710 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts +++ b/packages/@ember/-internals/glimmer/tests/integration/components/runtime-template-compiler-implicit-test.ts @@ -463,6 +463,56 @@ moduleFor( this.assertText('[before]after'); this.assertStableRerender(); } + + async '@test Can access private fields in templates'() { + await this.renderComponentModule(() => { + return class extends GlimmerishComponent { + #count = 0; + + #increment = () => { + this.#count++; + }; + + static { + template('

Count: {{this.#count}}

', { + component: this, + eval() { + return eval(arguments[0]); + }, + }); + } + }; + }); + + this.assertHTML('

Count: 0

'); + this.assertStableRerender(); + } + + async '@test Private field methods work with on modifier'() { + await this.renderComponentModule(() => { + hide(on); + + return class extends GlimmerishComponent { + #message = 'Hello'; + + #updateMessage = () => { + this.#message = 'Updated!'; + }; + + static { + template('', { + component: this, + eval() { + return eval(arguments[0]); + }, + }); + } + }; + }); + + this.assertHTML(''); + this.assertStableRerender(); + } } ); From 801875c7b14a3384ef8546eb9301334e875067a9 Mon Sep 17 00:00:00 2001 From: Aniruddh-14 Date: Sat, 22 Nov 2025 13:25:49 +0530 Subject: [PATCH 2/9] Update compile-options.ts --- .../@ember/template-compiler/lib/compile-options.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/@ember/template-compiler/lib/compile-options.ts b/packages/@ember/template-compiler/lib/compile-options.ts index a5459e412c4..48a2433cbb3 100644 --- a/packages/@ember/template-compiler/lib/compile-options.ts +++ b/packages/@ember/template-compiler/lib/compile-options.ts @@ -110,7 +110,19 @@ type Evaluator = (value: string) => unknown; // https://tc39.es/ecma262/2020/#prod-IdentifierName const IDENT = /^[\p{ID_Start}$_][\p{ID_Continue}$_\u200C\u200D]*$/u; +// https://tc39.es/ecma262/#prod-PrivateIdentifier +const PRIVATE_IDENT = /^#[\p{ID_Start}$_][\p{ID_Continue}$_\u200C\u200D]*$/u; + function inScope(variable: string, evaluator: Evaluator): boolean { + // Check if it's a private field syntax + if (PRIVATE_IDENT.exec(variable)) { + // Private fields are always considered "in scope" when referenced in a template + // since they are class members, not lexical variables. The actual access check + // will happen at runtime when the template accesses `this.#fieldName`. + // We just need to ensure they're treated as valid identifiers and passed through. + return true; + } + // If the identifier is not a valid JS identifier, it's definitely not in scope if (!IDENT.exec(variable)) { return false; From 6109f94a6c6dfc630973f315a50df4dc9313002d Mon Sep 17 00:00:00 2001 From: Aniruddh-14 Date: Sat, 22 Nov 2025 13:26:59 +0530 Subject: [PATCH 3/9] Enhance documentation for private fields support Updated documentation to reflect support for private fields in templates. --- .../@ember/template-compiler/lib/template.ts | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/@ember/template-compiler/lib/template.ts b/packages/@ember/template-compiler/lib/template.ts index 51f77b71f8f..6becf8affe0 100644 --- a/packages/@ember/template-compiler/lib/template.ts +++ b/packages/@ember/template-compiler/lib/template.ts @@ -128,7 +128,7 @@ export interface ExplicitClassOptions * ### The Technical Requirements of the `eval` Option * * The `eval` function is passed a single parameter that is a JavaScript - * identifier. This will be extended in the future to support private fields. + * identifier or a private field identifier (starting with `#`). * * Since keywords in JavaScript are contextual (e.g. `await` and `yield`), the * parameter might be a keyword. The `@ember/template-compiler/runtime` expects @@ -213,12 +213,25 @@ export type ImplicitTemplateOnlyOptions = BaseTemplateOptions & ImplicitEvalOpti * } * ``` * - * ## Note on Private Fields + * ## Private Fields Support * - * The current implementation of `@ember/template-compiler` does not support - * private fields, but once the Handlebars parser adds support for private field - * syntax and it's implemented in the Glimmer compiler, the implicit form should - * be able to support them. + * The implicit form now supports private fields. You can reference private + * class members in templates using the `this.#fieldName` syntax: + * + * ```ts + * class MyComponent extends Component { + * #count = 0; + * #increment = () => this.#count++; + * + * static { + * template( + * '', + * { component: this }, + * eval() { return arguments[0] } + * ); + * } + * } + * ``` */ export type ImplicitClassOptions = BaseClassTemplateOptions & ImplicitEvalOption; From dd6f0cc138e7b239e0590de5fd24353b35c84368 Mon Sep 17 00:00:00 2001 From: Aniruddh-14 Date: Sat, 22 Nov 2025 13:28:00 +0530 Subject: [PATCH 4/9] Enable access to private properties in Glimmer templates This fix enables access to private class properties in Glimmer templates, resolving issues with private fields being treated as undefined. It includes updates to the template compiler and documentation to support private field identifiers. --- FIX_SUMMARY.md | 169 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 FIX_SUMMARY.md diff --git a/FIX_SUMMARY.md b/FIX_SUMMARY.md new file mode 100644 index 00000000000..c10f8f6a123 --- /dev/null +++ b/FIX_SUMMARY.md @@ -0,0 +1,169 @@ +# Fix for Private Properties in Template Region (#21007) + +## Summary + +This fix enables access to private class properties (fields and methods) from within the `