()
| 59 | } |
| 60 | |
| 61 | override execute(): null { |
| 62 | // An `if` will be constructed, within which the template's children will be type checked. The |
| 63 | // `if` is used for two reasons: it creates a new syntactic scope, isolating variables declared |
| 64 | // in the template's TCB from the outer context, and it allows any directives on the templates |
| 65 | // to perform type narrowing of either expressions or the template's context. |
| 66 | // |
| 67 | // The guard is the `if` block's condition. It's usually set to `true` but directives that exist |
| 68 | // on the template can trigger extra guard expressions that serve to narrow types within the |
| 69 | // `if`. `guard` is calculated by starting with `true` and adding other conditions as needed. |
| 70 | // Collect these into `guards` by processing the directives. |
| 71 | |
| 72 | // By default the guard is simply `true`. |
| 73 | let guard: TcbExpr | null = null; |
| 74 | const directiveGuards: TcbExpr[] = []; |
| 75 | |
| 76 | this.addDirectiveGuards( |
| 77 | directiveGuards, |
| 78 | this.template, |
| 79 | this.tcb.boundTarget.getDirectivesOfNode(this.template), |
| 80 | ); |
| 81 | |
| 82 | for (const directive of this.template.directives) { |
| 83 | this.addDirectiveGuards( |
| 84 | directiveGuards, |
| 85 | directive, |
| 86 | this.tcb.boundTarget.getDirectivesOfNode(directive), |
| 87 | ); |
| 88 | } |
| 89 | |
| 90 | // If there are any guards from directives, use them instead. |
| 91 | if (directiveGuards.length > 0) { |
| 92 | // Pop the first value and use it as the initializer to reduce(). This way, a single guard |
| 93 | // will be used on its own, but two or more will be combined into binary AND expressions. |
| 94 | guard = directiveGuards.reduce( |
| 95 | (expr, dirGuard) => new TcbExpr(`${expr.print()} && ${dirGuard.print()}`), |
| 96 | directiveGuards.pop()!, |
| 97 | ); |
| 98 | } |
| 99 | |
| 100 | // Create a new Scope for the template. This constructs the list of operations for the template |
| 101 | // children, as well as tracks bindings within the template. |
| 102 | const tmplScope = this.scope.createChildScope( |
| 103 | this.scope, |
| 104 | this.template, |
| 105 | this.template.children, |
| 106 | guard, |
| 107 | ); |
| 108 | |
| 109 | // Render the template's `Scope` into its statements. |
| 110 | const statements = tmplScope.render(); |
| 111 | if (statements.length === 0) { |
| 112 | // As an optimization, don't generate the scope's block if it has no statements. This is |
| 113 | // beneficial for templates that contain for example `<span *ngIf="first"></span>`, in which |
| 114 | // case there's no need to render the `NgIf` guard expression. This seems like a minor |
| 115 | // improvement, however it reduces the number of flow-node antecedents that TypeScript needs |
| 116 | // to keep into account for such cases, resulting in an overall reduction of |
| 117 | // type-checking time. |
| 118 | return null; |
nothing calls this directly
no test coverage detected