1+ import { on } from '@ember/modifier' ;
2+ import type { AST } from '@glimmer/syntax' ;
13import { assert } from '@ember/debug' ;
24import {
35 RESOLUTION_MODE_TRANSFORMS ,
46 STRICT_MODE_KEYWORDS ,
57 STRICT_MODE_TRANSFORMS ,
68} from './plugins/index' ;
7- import type { EmberPrecompileOptions , PluginFunc } from './types' ;
9+ import type { EmberPrecompileOptions , JSUtils , PluginFunc } from './types' ;
810import COMPONENT_NAME_SIMPLE_DASHERIZE_CACHE from './dasherize-component-name' ;
911
1012let USER_PLUGINS : PluginFunc [ ] = [ ] ;
@@ -13,11 +15,19 @@ function malformedComponentLookup(string: string) {
1315 return string . indexOf ( '::' ) === - 1 && string . indexOf ( ':' ) > - 1 ;
1416}
1517
18+ export const keywords = {
19+ on,
20+ } ;
21+
22+ type Options = EmberPrecompileOptions &
23+ Partial < EmberPrecompileOptions > & {
24+ meta ?: EmberPrecompileOptions [ 'meta' ] & { jsutils ?: JSUtils } ;
25+ } ;
26+
1627function buildCompileOptions ( _options : EmberPrecompileOptions ) : EmberPrecompileOptions {
1728 let moduleName = _options . moduleName ;
1829
19- let options : EmberPrecompileOptions & Partial < EmberPrecompileOptions > = {
20- meta : { } ,
30+ let options : Options = {
2131 isProduction : false ,
2232 plugins : { ast : [ ] } ,
2333 ..._options ,
@@ -34,6 +44,34 @@ function buildCompileOptions(_options: EmberPrecompileOptions): EmberPrecompileO
3444 } ,
3545 } ;
3646
47+ options . meta ||= { } ;
48+ options . meta . jsutils ||= {
49+ /**
50+ * NOTE: when stepping through lexicalScope, or other callbacks here,
51+ * we first detect the keywords as "not in scope",
52+ * and that is what we want, so that we can import them.
53+ */
54+ bindImport (
55+ module : string ,
56+ name : string ,
57+ node : AST . ElementModifierStatement | AST . MustacheStatement | AST . SubExpression
58+ ) {
59+ if ( module === '@ember/modifier' && name === 'on' ) {
60+ /**
61+ * We rely on an old JS technique of assiging properties to functions.
62+ * Since template() is what was used to runtime-compile the template,
63+ * we know it to be in scope.
64+ */
65+ if ( node . path . type === 'PathExpression' ) {
66+ node . path . original = 'template.on' ;
67+ return ;
68+ }
69+ }
70+
71+ throw new Error ( `Unknown import ${ name } from module ${ module } ` ) ;
72+ } ,
73+ } ;
74+
3775 if ( 'eval' in options ) {
3876 const localScopeEvaluator = options . eval as ( value : string ) => unknown ;
3977 const globalScopeEvaluator = ( value : string ) => new Function ( `return ${ value } ;` ) ( ) ;
@@ -52,7 +90,7 @@ function buildCompileOptions(_options: EmberPrecompileOptions): EmberPrecompileO
5290 if ( 'scope' in options ) {
5391 const scope = ( options . scope as ( ) => Record < string , unknown > ) ( ) ;
5492
55- options . lexicalScope = ( variable : string ) => variable in scope ;
93+ options . lexicalScope = ( variable : string ) => variable in scope || variable in keywords ;
5694
5795 delete options . scope ;
5896 }
0 commit comments