* Represents a binding scope within a template. * * Any variables, references, or other named entities declared within the template will * be captured and available by name in `namedEntities`. Additionally, child templates will * be analyzed and have their child `Scope`s available in `childScope
| 279 | * be analyzed and have their child `Scope`s available in `childScopes`. |
| 280 | */ |
| 281 | class Scope implements Visitor { |
| 282 | /** |
| 283 | * Named members of the `Scope`, such as `Reference`s or `Variable`s. |
| 284 | */ |
| 285 | readonly namedEntities = new Map<string, TemplateEntity>(); |
| 286 | |
| 287 | /** |
| 288 | * Set of element-like nodes that belong to this scope. |
| 289 | */ |
| 290 | readonly elementLikeInScope = new Set<Element | Component>(); |
| 291 | |
| 292 | /** |
| 293 | * Child `Scope`s for immediately nested `ScopedNode`s. |
| 294 | */ |
| 295 | readonly childScopes = new Map<ScopedNode, Scope>(); |
| 296 | |
| 297 | /** Whether this scope is deferred or if any of its ancestors are deferred. */ |
| 298 | readonly isDeferred: boolean; |
| 299 | |
| 300 | private constructor( |
| 301 | readonly parentScope: Scope | null, |
| 302 | readonly rootNode: ScopedNode | null, |
| 303 | ) { |
| 304 | this.isDeferred = |
| 305 | parentScope !== null && parentScope.isDeferred ? true : rootNode instanceof DeferredBlock; |
| 306 | } |
| 307 | |
| 308 | static newRootScope(): Scope { |
| 309 | return new Scope(null, null); |
| 310 | } |
| 311 | |
| 312 | /** |
| 313 | * Process a template (either as a `Template` sub-template with variables, or a plain array of |
| 314 | * template `Node`s) and construct its `Scope`. |
| 315 | */ |
| 316 | static apply(template: ScopedNode | Node[]): Scope { |
| 317 | const scope = Scope.newRootScope(); |
| 318 | scope.ingest(template); |
| 319 | return scope; |
| 320 | } |
| 321 | |
| 322 | /** |
| 323 | * Internal method to process the scoped node and populate the `Scope`. |
| 324 | */ |
| 325 | private ingest(nodeOrNodes: ScopedNode | Node[]): void { |
| 326 | if (nodeOrNodes instanceof Template) { |
| 327 | // Variables on an <ng-template> are defined in the inner scope. |
| 328 | nodeOrNodes.variables.forEach((node) => this.visitVariable(node)); |
| 329 | |
| 330 | // Process the nodes of the template. |
| 331 | nodeOrNodes.children.forEach((node) => node.visit(this)); |
| 332 | } else if (nodeOrNodes instanceof IfBlockBranch) { |
| 333 | if (nodeOrNodes.expressionAlias !== null) { |
| 334 | this.visitVariable(nodeOrNodes.expressionAlias); |
| 335 | } |
| 336 | nodeOrNodes.children.forEach((node) => node.visit(this)); |
| 337 | } else if (nodeOrNodes instanceof ForLoopBlock) { |
| 338 | this.visitVariable(nodeOrNodes.item); |
nothing calls this directly
no outgoing calls
no test coverage detected
searching dependent graphs…