* Ingest an `@for` block into the given `ViewCompilation`.
(unit: ViewCompilationUnit, forBlock: t.ForLoopBlock)
| 1020 | * Ingest an `@for` block into the given `ViewCompilation`. |
| 1021 | */ |
| 1022 | function ingestForBlock(unit: ViewCompilationUnit, forBlock: t.ForLoopBlock): void { |
| 1023 | const repeaterView = unit.job.allocateView(unit.xref); |
| 1024 | |
| 1025 | // We copy TemplateDefinitionBuilder's scheme of creating names for `$count` and `$index` |
| 1026 | // that are suffixed with special information, to disambiguate which level of nested loop |
| 1027 | // the below aliases refer to. |
| 1028 | // TODO: We should refactor Template Pipeline's variable phases to gracefully handle |
| 1029 | // shadowing, and arbitrarily many levels of variables depending on each other. |
| 1030 | const indexName = `ɵ$index_${repeaterView.xref}`; |
| 1031 | const countName = `ɵ$count_${repeaterView.xref}`; |
| 1032 | const indexVarNames = new Set<string>(); |
| 1033 | |
| 1034 | // Set all the context variables and aliases available in the repeater. |
| 1035 | repeaterView.contextVariables.set(forBlock.item.name, forBlock.item.value); |
| 1036 | |
| 1037 | for (const variable of forBlock.contextVariables) { |
| 1038 | if (variable.value === '$index') { |
| 1039 | indexVarNames.add(variable.name); |
| 1040 | } |
| 1041 | if (variable.name === '$index') { |
| 1042 | repeaterView.contextVariables.set('$index', variable.value).set(indexName, variable.value); |
| 1043 | } else if (variable.name === '$count') { |
| 1044 | repeaterView.contextVariables.set('$count', variable.value).set(countName, variable.value); |
| 1045 | } else { |
| 1046 | repeaterView.aliases.add({ |
| 1047 | kind: ir.SemanticVariableKind.Alias, |
| 1048 | name: null, |
| 1049 | identifier: variable.name, |
| 1050 | expression: getComputedForLoopVariableExpression(variable, indexName, countName), |
| 1051 | }); |
| 1052 | } |
| 1053 | } |
| 1054 | |
| 1055 | let track: o.Expression; |
| 1056 | |
| 1057 | if (forBlock.trackBy === null) { |
| 1058 | // `@for` without a `track` is invalid and it produces a parser error. |
| 1059 | // Put a placeholder here so we don't need to account for it throughout the pipeline. |
| 1060 | track = o.variable('$index'); |
| 1061 | } else { |
| 1062 | track = convertAst( |
| 1063 | forBlock.trackBy, |
| 1064 | unit.job, |
| 1065 | convertSourceSpan(forBlock.trackBy.span, forBlock.sourceSpan), |
| 1066 | ); |
| 1067 | } |
| 1068 | |
| 1069 | ingestNodes(repeaterView, forBlock.children); |
| 1070 | |
| 1071 | let emptyView: ViewCompilationUnit | null = null; |
| 1072 | let emptyTagName: string | null = null; |
| 1073 | if (forBlock.empty !== null) { |
| 1074 | emptyView = unit.job.allocateView(unit.xref); |
| 1075 | ingestNodes(emptyView, forBlock.empty.children); |
| 1076 | emptyTagName = ingestControlFlowInsertionPoint(unit, emptyView.xref, forBlock.empty); |
| 1077 | } |
| 1078 | |
| 1079 | const varNames: ir.RepeaterVarNames = { |
no test coverage detected