66 * found in the LICENSE file at https://angular.io/license
77 */
88
9+ import { TmplAstLetDeclaration } from '../../compiler' ;
910import {
1011 AST ,
1112 BindingPipe ,
@@ -14,6 +15,7 @@ import {
1415 PropertyWrite ,
1516 RecursiveAstVisitor ,
1617 SafePropertyRead ,
18+ ThisReceiver ,
1719} from '../../expression_parser/ast' ;
1820import { SelectorMatcher } from '../../selector' ;
1921import {
@@ -56,6 +58,7 @@ import {
5658 ScopedNode ,
5759 Target ,
5860 TargetBinder ,
61+ TemplateEntity ,
5962} from './t2_api' ;
6063import { createCssSelectorFromNode } from './util' ;
6164
@@ -125,7 +128,7 @@ class Scope implements Visitor {
125128 /**
126129 * Named members of the `Scope`, such as `Reference`s or `Variable`s.
127130 */
128- readonly namedEntities = new Map < string , Reference | Variable > ( ) ;
131+ readonly namedEntities = new Map < string , TemplateEntity > ( ) ;
129132
130133 /**
131134 * Set of elements that belong to this scope.
@@ -275,7 +278,7 @@ class Scope implements Visitor {
275278 }
276279
277280 visitLetDeclaration ( decl : LetDeclaration ) {
278- // TODO(crisbeto): needs further integration
281+ this . maybeDeclare ( decl ) ;
279282 }
280283
281284 // Unused visitors.
@@ -288,7 +291,7 @@ class Scope implements Visitor {
288291 visitDeferredTrigger ( trigger : DeferredTrigger ) { }
289292 visitUnknownBlock ( block : UnknownBlock ) { }
290293
291- private maybeDeclare ( thing : Reference | Variable ) {
294+ private maybeDeclare ( thing : TemplateEntity ) {
292295 // Declare something with a name, as long as that name isn't taken.
293296 if ( ! this . namedEntities . has ( thing . name ) ) {
294297 this . namedEntities . set ( thing . name , thing ) ;
@@ -300,7 +303,7 @@ class Scope implements Visitor {
300303 *
301304 * This can recurse into a parent `Scope` if it's available.
302305 */
303- lookup ( name : string ) : Reference | Variable | null {
306+ lookup ( name : string ) : TemplateEntity | null {
304307 if ( this . namedEntities . has ( name ) ) {
305308 // Found in the local scope.
306309 return this . namedEntities . get ( name ) ! ;
@@ -541,10 +544,6 @@ class DirectiveBinder<DirectiveT extends DirectiveMeta> implements Visitor {
541544 content . children . forEach ( ( child ) => child . visit ( this ) ) ;
542545 }
543546
544- visitLetDeclaration ( decl : LetDeclaration ) {
545- // TODO(crisbeto): needs further integration
546- }
547-
548547 // Unused visitors.
549548 visitVariable ( variable : Variable ) : void { }
550549 visitReference ( reference : Reference ) : void { }
@@ -557,6 +556,7 @@ class DirectiveBinder<DirectiveT extends DirectiveMeta> implements Visitor {
557556 visitIcu ( icu : Icu ) : void { }
558557 visitDeferredTrigger ( trigger : DeferredTrigger ) : void { }
559558 visitUnknownBlock ( block : UnknownBlock ) { }
559+ visitLetDeclaration ( decl : LetDeclaration ) { }
560560}
561561
562562/**
@@ -572,8 +572,8 @@ class TemplateBinder extends RecursiveAstVisitor implements Visitor {
572572 private visitNode : ( node : Node ) => void ;
573573
574574 private constructor (
575- private bindings : Map < AST , Reference | Variable > ,
576- private symbols : Map < Reference | Variable , ScopedNode > ,
575+ private bindings : Map < AST , TemplateEntity > ,
576+ private symbols : Map < TemplateEntity , ScopedNode > ,
577577 private usedPipes : Set < string > ,
578578 private eagerPipes : Set < string > ,
579579 private deferBlocks : [ DeferredBlock , Scope ] [ ] ,
@@ -615,15 +615,15 @@ class TemplateBinder extends RecursiveAstVisitor implements Visitor {
615615 nodes : Node [ ] ,
616616 scope : Scope ,
617617 ) : {
618- expressions : Map < AST , Reference | Variable > ;
619- symbols : Map < Variable | Reference , Template > ;
618+ expressions : Map < AST , TemplateEntity > ;
619+ symbols : Map < TemplateEntity , Template > ;
620620 nestingLevel : Map < ScopedNode , number > ;
621621 usedPipes : Set < string > ;
622622 eagerPipes : Set < string > ;
623623 deferBlocks : [ DeferredBlock , Scope ] [ ] ;
624624 } {
625- const expressions = new Map < AST , Reference | Variable > ( ) ;
626- const symbols = new Map < Variable | Reference , Template > ( ) ;
625+ const expressions = new Map < AST , TemplateEntity > ( ) ;
626+ const symbols = new Map < TemplateEntity , Template > ( ) ;
627627 const nestingLevel = new Map < ScopedNode , number > ( ) ;
628628 const usedPipes = new Set < string > ( ) ;
629629 const eagerPipes = new Set < string > ( ) ;
@@ -803,8 +803,11 @@ class TemplateBinder extends RecursiveAstVisitor implements Visitor {
803803 }
804804
805805 visitLetDeclaration ( decl : LetDeclaration ) {
806- // TODO(crisbeto): needs further integration
807806 decl . value . visit ( this ) ;
807+
808+ if ( this . rootNode !== null ) {
809+ this . symbols . set ( decl , this . rootNode ) ;
810+ }
808811 }
809812
810813 override visitPipe ( ast : BindingPipe , context : any ) : any {
@@ -858,7 +861,15 @@ class TemplateBinder extends RecursiveAstVisitor implements Visitor {
858861
859862 // Check whether the name exists in the current scope. If so, map it. Otherwise, the name is
860863 // probably a property on the top-level component context.
861- let target = this . scope . lookup ( name ) ;
864+ const target = this . scope . lookup ( name ) ;
865+
866+ // It's not allowed to read template entities via `this`, however it previously worked by
867+ // accident (see #55115). Since `@let` declarations are new, we can fix it from the beginning,
868+ // whereas pre-existing template entities will be fixed in #55115.
869+ if ( target instanceof TmplAstLetDeclaration && ast . receiver instanceof ThisReceiver ) {
870+ return ;
871+ }
872+
862873 if ( target !== null ) {
863874 this . bindings . set ( ast , target ) ;
864875 }
@@ -889,10 +900,10 @@ export class R3BoundTarget<DirectiveT extends DirectiveMeta> implements BoundTar
889900 BoundAttribute | BoundEvent | Reference | TextAttribute ,
890901 { directive : DirectiveT ; node : Element | Template } | Element | Template
891902 > ,
892- private exprTargets : Map < AST , Reference | Variable > ,
893- private symbols : Map < Reference | Variable , Template > ,
903+ private exprTargets : Map < AST , TemplateEntity > ,
904+ private symbols : Map < TemplateEntity , Template > ,
894905 private nestingLevel : Map < ScopedNode , number > ,
895- private scopedNodeEntities : Map < ScopedNode | null , ReadonlySet < Reference | Variable > > ,
906+ private scopedNodeEntities : Map < ScopedNode | null , ReadonlySet < TemplateEntity > > ,
896907 private usedPipes : Set < string > ,
897908 private eagerPipes : Set < string > ,
898909 rawDeferred : [ DeferredBlock , Scope ] [ ] ,
@@ -901,7 +912,7 @@ export class R3BoundTarget<DirectiveT extends DirectiveMeta> implements BoundTar
901912 this . deferredScopes = new Map ( rawDeferred ) ;
902913 }
903914
904- getEntitiesInScope ( node : ScopedNode | null ) : ReadonlySet < Reference | Variable > {
915+ getEntitiesInScope ( node : ScopedNode | null ) : ReadonlySet < TemplateEntity > {
905916 return this . scopedNodeEntities . get ( node ) ?? new Set ( ) ;
906917 }
907918
@@ -919,11 +930,11 @@ export class R3BoundTarget<DirectiveT extends DirectiveMeta> implements BoundTar
919930 return this . bindings . get ( binding ) || null ;
920931 }
921932
922- getExpressionTarget ( expr : AST ) : Reference | Variable | null {
933+ getExpressionTarget ( expr : AST ) : TemplateEntity | null {
923934 return this . exprTargets . get ( expr ) || null ;
924935 }
925936
926- getDefinitionNodeOfSymbol ( symbol : Reference | Variable ) : ScopedNode | null {
937+ getDefinitionNodeOfSymbol ( symbol : TemplateEntity ) : ScopedNode | null {
927938 return this . symbols . get ( symbol ) || null ;
928939 }
929940
@@ -1046,7 +1057,7 @@ export class R3BoundTarget<DirectiveT extends DirectiveMeta> implements BoundTar
10461057 * @param rootNode Root node of the scope.
10471058 * @param name Name of the entity.
10481059 */
1049- private findEntityInScope ( rootNode : ScopedNode , name : string ) : Reference | Variable | null {
1060+ private findEntityInScope ( rootNode : ScopedNode , name : string ) : TemplateEntity | null {
10501061 const entities = this . getEntitiesInScope ( rootNode ) ;
10511062
10521063 for ( const entity of entities ) {
@@ -1072,19 +1083,17 @@ export class R3BoundTarget<DirectiveT extends DirectiveMeta> implements BoundTar
10721083 }
10731084}
10741085
1075- function extractScopedNodeEntities (
1076- rootScope : Scope ,
1077- ) : Map < ScopedNode | null , Set < Reference | Variable > > {
1078- const entityMap = new Map < ScopedNode | null , Map < string , Reference | Variable > > ( ) ;
1086+ function extractScopedNodeEntities ( rootScope : Scope ) : Map < ScopedNode | null , Set < TemplateEntity > > {
1087+ const entityMap = new Map < ScopedNode | null , Map < string , TemplateEntity > > ( ) ;
10791088
1080- function extractScopeEntities ( scope : Scope ) : Map < string , Reference | Variable > {
1089+ function extractScopeEntities ( scope : Scope ) : Map < string , TemplateEntity > {
10811090 if ( entityMap . has ( scope . rootNode ) ) {
10821091 return entityMap . get ( scope . rootNode ) ! ;
10831092 }
10841093
10851094 const currentEntities = scope . namedEntities ;
10861095
1087- let entities : Map < string , Reference | Variable > ;
1096+ let entities : Map < string , TemplateEntity > ;
10881097 if ( scope . parentScope !== null ) {
10891098 entities = new Map ( [ ...extractScopeEntities ( scope . parentScope ) , ...currentEntities ] ) ;
10901099 } else {
@@ -1104,7 +1113,7 @@ function extractScopedNodeEntities(
11041113 extractScopeEntities ( scope ) ;
11051114 }
11061115
1107- const templateEntities = new Map < ScopedNode | null , Set < Reference | Variable > > ( ) ;
1116+ const templateEntities = new Map < ScopedNode | null , Set < TemplateEntity > > ( ) ;
11081117 for ( const [ template , entities ] of entityMap ) {
11091118 templateEntities . set ( template , new Set ( entities . values ( ) ) ) ;
11101119 }
0 commit comments