@angular/compiler 17.0.0-next.4 → 17.0.0-next.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  2. package/esm2022/src/render3/partial/directive.mjs +1 -1
  3. package/esm2022/src/render3/partial/factory.mjs +1 -1
  4. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  5. package/esm2022/src/render3/partial/injector.mjs +1 -1
  6. package/esm2022/src/render3/partial/ng_module.mjs +1 -1
  7. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  8. package/esm2022/src/render3/r3_ast.mjs +10 -3
  9. package/esm2022/src/render3/r3_control_flow.mjs +16 -9
  10. package/esm2022/src/render3/r3_deferred_triggers.mjs +7 -7
  11. package/esm2022/src/render3/r3_module_compiler.mjs +9 -11
  12. package/esm2022/src/render3/view/compiler.mjs +4 -1
  13. package/esm2022/src/render3/view/t2_api.mjs +1 -1
  14. package/esm2022/src/render3/view/t2_binder.mjs +178 -78
  15. package/esm2022/src/render3/view/template.mjs +32 -46
  16. package/esm2022/src/template/pipeline/ir/src/enums.mjs +14 -7
  17. package/esm2022/src/template/pipeline/ir/src/expression.mjs +3 -1
  18. package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +28 -3
  19. package/esm2022/src/template/pipeline/src/compilation.mjs +6 -1
  20. package/esm2022/src/template/pipeline/src/conversion.mjs +7 -1
  21. package/esm2022/src/template/pipeline/src/emit.mjs +7 -1
  22. package/esm2022/src/template/pipeline/src/ingest.mjs +16 -3
  23. package/esm2022/src/template/pipeline/src/instruction.mjs +19 -3
  24. package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +22 -29
  25. package/esm2022/src/template/pipeline/src/phases/generate_projection_def.mjs +46 -0
  26. package/esm2022/src/template/pipeline/src/phases/i18n_const_collection.mjs +33 -0
  27. package/esm2022/src/template/pipeline/src/phases/phase_remove_content_selectors.mjs +39 -0
  28. package/esm2022/src/template/pipeline/src/phases/reify.mjs +11 -2
  29. package/esm2022/src/version.mjs +1 -1
  30. package/fesm2022/compiler.mjs +516 -247
  31. package/fesm2022/compiler.mjs.map +1 -1
  32. package/fesm2022/testing.mjs +1 -1
  33. package/index.d.ts +53 -40
  34. package/package.json +3 -3
  35. package/testing/index.d.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v17.0.0-next.4
2
+ * @license Angular v17.0.0-next.5
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -3801,6 +3801,10 @@ class IdleDeferredTrigger extends DeferredTrigger {
3801
3801
  class ImmediateDeferredTrigger extends DeferredTrigger {
3802
3802
  }
3803
3803
  class HoverDeferredTrigger extends DeferredTrigger {
3804
+ constructor(reference, sourceSpan) {
3805
+ super(sourceSpan);
3806
+ this.reference = reference;
3807
+ }
3804
3808
  }
3805
3809
  class TimerDeferredTrigger extends DeferredTrigger {
3806
3810
  constructor(delay, sourceSpan) {
@@ -3913,8 +3917,8 @@ class SwitchBlockCase {
3913
3917
  }
3914
3918
  }
3915
3919
  class ForLoopBlock {
3916
- constructor(itemName, expression, trackBy, contextVariables, children, empty, sourceSpan, startSourceSpan, endSourceSpan) {
3917
- this.itemName = itemName;
3920
+ constructor(item, expression, trackBy, contextVariables, children, empty, sourceSpan, startSourceSpan, endSourceSpan) {
3921
+ this.item = item;
3918
3922
  this.expression = expression;
3919
3923
  this.trackBy = trackBy;
3920
3924
  this.contextVariables = contextVariables;
@@ -4067,6 +4071,8 @@ class RecursiveVisitor$1 {
4067
4071
  visitAll$1(this, block.children);
4068
4072
  }
4069
4073
  visitForLoopBlock(block) {
4074
+ block.item.visit(this);
4075
+ visitAll$1(this, Object.values(block.contextVariables));
4070
4076
  visitAll$1(this, block.children);
4071
4077
  block.empty?.visit(this);
4072
4078
  }
@@ -4078,6 +4084,7 @@ class RecursiveVisitor$1 {
4078
4084
  }
4079
4085
  visitIfBlockBranch(block) {
4080
4086
  visitAll$1(this, block.children);
4087
+ block.expressionAlias?.visit(this);
4081
4088
  }
4082
4089
  visitContent(content) { }
4083
4090
  visitVariable(variable) { }
@@ -5876,16 +5883,11 @@ function compileNgModule(meta) {
5876
5883
  const statements = [];
5877
5884
  const definitionMap = new DefinitionMap();
5878
5885
  definitionMap.set('type', meta.type.value);
5879
- // Assign bootstrap definition
5880
- if (meta.kind === R3NgModuleMetadataKind.Global) {
5881
- if (meta.bootstrap.length > 0) {
5882
- definitionMap.set('bootstrap', refsToArray(meta.bootstrap, meta.containsForwardDecls));
5883
- }
5884
- }
5885
- else {
5886
- if (meta.bootstrapExpression) {
5887
- definitionMap.set('bootstrap', meta.bootstrapExpression);
5888
- }
5886
+ // Assign bootstrap definition. In local compilation mode (i.e., for
5887
+ // `R3NgModuleMetadataKind.LOCAL`) we assign the bootstrap field using the runtime
5888
+ // `ɵɵsetNgModuleScope`.
5889
+ if (meta.kind === R3NgModuleMetadataKind.Global && meta.bootstrap.length > 0) {
5890
+ definitionMap.set('bootstrap', refsToArray(meta.bootstrap, meta.containsForwardDecls));
5889
5891
  }
5890
5892
  if (meta.selectorScopeMode === R3SelectorScopeMode.Inline) {
5891
5893
  // If requested to emit scope information inline, pass the `declarations`, `imports` and
@@ -6004,6 +6006,9 @@ function generateSetNgModuleScopeCall(meta) {
6004
6006
  scopeMap.set('exports', meta.exportsExpression);
6005
6007
  }
6006
6008
  }
6009
+ if (meta.kind === R3NgModuleMetadataKind.Local && meta.bootstrapExpression) {
6010
+ scopeMap.set('bootstrap', meta.bootstrapExpression);
6011
+ }
6007
6012
  if (Object.keys(scopeMap.values).length === 0) {
6008
6013
  return null;
6009
6014
  }
@@ -8766,19 +8771,26 @@ var OpKind;
8766
8771
  * A namespace change, which causes the subsequent elements to be processed as either HTML or SVG.
8767
8772
  */
8768
8773
  OpKind[OpKind["Namespace"] = 28] = "Namespace";
8774
+ /**
8775
+ * Configure a content projeciton definition for the view.
8776
+ */
8777
+ OpKind[OpKind["ProjectionDef"] = 29] = "ProjectionDef";
8778
+ /**
8779
+ * Create a content projection slot.
8780
+ */
8781
+ OpKind[OpKind["Projection"] = 30] = "Projection";
8769
8782
  /**
8770
8783
  * The start of an i18n block.
8771
8784
  */
8772
- OpKind[OpKind["I18nStart"] = 29] = "I18nStart";
8785
+ OpKind[OpKind["I18nStart"] = 31] = "I18nStart";
8773
8786
  /**
8774
8787
  * A self-closing i18n on a single element.
8775
8788
  */
8776
- OpKind[OpKind["I18n"] = 30] = "I18n";
8789
+ OpKind[OpKind["I18n"] = 32] = "I18n";
8777
8790
  /**
8778
8791
  * The end of an i18n block.
8779
8792
  */
8780
- OpKind[OpKind["I18nEnd"] = 31] = "I18nEnd";
8781
- // TODO: Add Host Listeners, and possibly other host ops also.
8793
+ OpKind[OpKind["I18nEnd"] = 33] = "I18nEnd";
8782
8794
  })(OpKind || (OpKind = {}));
8783
8795
  /**
8784
8796
  * Distinguishes different kinds of IR expressions.
@@ -8890,8 +8902,8 @@ var SemanticVariableKind;
8890
8902
  })(SemanticVariableKind || (SemanticVariableKind = {}));
8891
8903
  /**
8892
8904
  * Whether to compile in compatibilty mode. In compatibility mode, the template pipeline will
8893
- * attempt to match the output of `TemplateDefinitionBuilder` as exactly as possible, at the cost of
8894
- * producing quirky or larger code in some cases.
8905
+ * attempt to match the output of `TemplateDefinitionBuilder` as exactly as possible, at the cost
8906
+ * of producing quirky or larger code in some cases.
8895
8907
  */
8896
8908
  var CompatibilityMode;
8897
8909
  (function (CompatibilityMode) {
@@ -9881,6 +9893,8 @@ function transformExpressionsInOp(op, transform, flags) {
9881
9893
  transformExpressionsInExpression(op.tagNameParams[placeholder], transform, flags);
9882
9894
  }
9883
9895
  break;
9896
+ case OpKind.Projection:
9897
+ case OpKind.ProjectionDef:
9884
9898
  case OpKind.Element:
9885
9899
  case OpKind.ElementStart:
9886
9900
  case OpKind.ElementEnd:
@@ -10271,7 +10285,8 @@ class OpList {
10271
10285
  * The set of OpKinds that represent the creation of an element or container
10272
10286
  */
10273
10287
  const elementContainerOpKinds = new Set([
10274
- OpKind.Element, OpKind.ElementStart, OpKind.Container, OpKind.ContainerStart, OpKind.Template
10288
+ OpKind.Element, OpKind.ElementStart, OpKind.Container, OpKind.ContainerStart, OpKind.Template,
10289
+ OpKind.Projection
10275
10290
  ]);
10276
10291
  /**
10277
10292
  * Checks whether the given operation represents the creation of an element or container.
@@ -10300,12 +10315,13 @@ function createElementStartOp(tag, xref, namespace, i18n, sourceSpan) {
10300
10315
  /**
10301
10316
  * Create a `TemplateOp`.
10302
10317
  */
10303
- function createTemplateOp(xref, tag, namespace, i18n, sourceSpan) {
10318
+ function createTemplateOp(xref, tag, namespace, controlFlow, i18n, sourceSpan) {
10304
10319
  return {
10305
10320
  kind: OpKind.Template,
10306
10321
  xref,
10307
10322
  attributes: null,
10308
10323
  tag,
10324
+ controlFlow,
10309
10325
  decls: null,
10310
10326
  vars: null,
10311
10327
  localRefs: [],
@@ -10399,6 +10415,29 @@ function createNamespaceOp(namespace) {
10399
10415
  ...NEW_OP,
10400
10416
  };
10401
10417
  }
10418
+ function createProjectionDefOp(def) {
10419
+ return {
10420
+ kind: OpKind.ProjectionDef,
10421
+ def,
10422
+ ...NEW_OP,
10423
+ };
10424
+ }
10425
+ function createProjectionOp(xref, selector) {
10426
+ return {
10427
+ kind: OpKind.Projection,
10428
+ xref,
10429
+ selector,
10430
+ projectionSlotIndex: 0,
10431
+ attributes: null,
10432
+ localRefs: [],
10433
+ nonBindable: false,
10434
+ i18n: undefined,
10435
+ sourceSpan: null,
10436
+ ...NEW_OP,
10437
+ ...TRAIT_CONSUMES_SLOT,
10438
+ ...TRAIT_USES_SLOT_INDEX,
10439
+ };
10440
+ }
10402
10441
  /**
10403
10442
  * Create an `ExtractedAttributeOp`.
10404
10443
  */
@@ -10501,6 +10540,11 @@ class ComponentCompilationJob extends CompilationJob {
10501
10540
  this.kind = CompilationJobKind.Tmpl;
10502
10541
  this.fnSuffix = 'Template';
10503
10542
  this.views = new Map();
10543
+ /**
10544
+ * Causes ngContentSelectors to be emitted, for content projection slots in the view. Possibly a
10545
+ * reference into the constant pool.
10546
+ */
10547
+ this.contentSelectors = null;
10504
10548
  /**
10505
10549
  * Constant expressions used by operations within this component's compilation.
10506
10550
  *
@@ -10806,7 +10850,7 @@ function phaseAttributeExtraction(job) {
10806
10850
  break;
10807
10851
  case OpKind.Property:
10808
10852
  if (!op.isAnimationTrigger) {
10809
- OpList.insertBefore(createExtractedAttributeOp(op.target, op.isTemplate ? BindingKind.Template : BindingKind.Property, op.name, null), lookupElement$2(elements, op.target));
10853
+ OpList.insertBefore(createExtractedAttributeOp(op.target, op.isTemplate ? BindingKind.Template : BindingKind.Property, op.name, null), lookupElement$3(elements, op.target));
10810
10854
  }
10811
10855
  break;
10812
10856
  case OpKind.StyleProp:
@@ -10816,7 +10860,7 @@ function phaseAttributeExtraction(job) {
10816
10860
  // mode.
10817
10861
  if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
10818
10862
  op.expression instanceof EmptyExpr) {
10819
- OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null), lookupElement$2(elements, op.target));
10863
+ OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null), lookupElement$3(elements, op.target));
10820
10864
  }
10821
10865
  break;
10822
10866
  case OpKind.Listener:
@@ -10828,7 +10872,7 @@ function phaseAttributeExtraction(job) {
10828
10872
  unit.create.push(extractedAttributeOp);
10829
10873
  }
10830
10874
  else {
10831
- OpList.insertBefore(extractedAttributeOp, lookupElement$2(elements, op.target));
10875
+ OpList.insertBefore(extractedAttributeOp, lookupElement$3(elements, op.target));
10832
10876
  }
10833
10877
  }
10834
10878
  break;
@@ -10839,7 +10883,7 @@ function phaseAttributeExtraction(job) {
10839
10883
  /**
10840
10884
  * Looks up an element in the given map by xref ID.
10841
10885
  */
10842
- function lookupElement$2(elements, xref) {
10886
+ function lookupElement$3(elements, xref) {
10843
10887
  const el = elements.get(xref);
10844
10888
  if (el === undefined) {
10845
10889
  throw new Error('All attributes should have an element-like target.');
@@ -10877,7 +10921,7 @@ function extractAttributeOp(unit, op, elements) {
10877
10921
  unit.create.push(extractedAttributeOp);
10878
10922
  }
10879
10923
  else {
10880
- const ownerOp = lookupElement$2(elements, op.target);
10924
+ const ownerOp = lookupElement$3(elements, op.target);
10881
10925
  OpList.insertBefore(extractedAttributeOp, ownerOp);
10882
10926
  }
10883
10927
  OpList.remove(op);
@@ -10887,7 +10931,7 @@ function extractAttributeOp(unit, op, elements) {
10887
10931
  /**
10888
10932
  * Looks up an element in the given map by xref ID.
10889
10933
  */
10890
- function lookupElement$1(elements, xref) {
10934
+ function lookupElement$2(elements, xref) {
10891
10935
  const el = elements.get(xref);
10892
10936
  if (el === undefined) {
10893
10937
  throw new Error('All attributes should have an element-like target.');
@@ -10913,7 +10957,7 @@ function phaseBindingSpecialization(job) {
10913
10957
  case BindingKind.Attribute:
10914
10958
  if (op.name === 'ngNonBindable') {
10915
10959
  OpList.remove(op);
10916
- const target = lookupElement$1(elements, op.target);
10960
+ const target = lookupElement$2(elements, op.target);
10917
10961
  target.nonBindable = true;
10918
10962
  }
10919
10963
  else {
@@ -11098,38 +11142,65 @@ function mergeNsAndName(prefix, localName) {
11098
11142
  return prefix ? `:${prefix}:${localName}` : localName;
11099
11143
  }
11100
11144
 
11145
+ const BINARY_OPERATORS = new Map([
11146
+ ['&&', BinaryOperator.And],
11147
+ ['>', BinaryOperator.Bigger],
11148
+ ['>=', BinaryOperator.BiggerEquals],
11149
+ ['&', BinaryOperator.BitwiseAnd],
11150
+ ['/', BinaryOperator.Divide],
11151
+ ['==', BinaryOperator.Equals],
11152
+ ['===', BinaryOperator.Identical],
11153
+ ['<', BinaryOperator.Lower],
11154
+ ['<=', BinaryOperator.LowerEquals],
11155
+ ['-', BinaryOperator.Minus],
11156
+ ['%', BinaryOperator.Modulo],
11157
+ ['*', BinaryOperator.Multiply],
11158
+ ['!=', BinaryOperator.NotEquals],
11159
+ ['!==', BinaryOperator.NotIdentical],
11160
+ ['??', BinaryOperator.NullishCoalesce],
11161
+ ['||', BinaryOperator.Or],
11162
+ ['+', BinaryOperator.Plus],
11163
+ ]);
11164
+ const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
11165
+ function namespaceForKey(namespacePrefixKey) {
11166
+ if (namespacePrefixKey === null) {
11167
+ return Namespace.HTML;
11168
+ }
11169
+ return NAMESPACES.get(namespacePrefixKey) ?? Namespace.HTML;
11170
+ }
11171
+ function keyForNamespace(namespace) {
11172
+ for (const [k, n] of NAMESPACES.entries()) {
11173
+ if (n === namespace) {
11174
+ return k;
11175
+ }
11176
+ }
11177
+ return null; // No namespace prefix for HTML
11178
+ }
11179
+ function prefixWithNamespace(strippedTag, namespace) {
11180
+ if (namespace === Namespace.HTML) {
11181
+ return strippedTag;
11182
+ }
11183
+ return `:${keyForNamespace(namespace)}:${strippedTag}`;
11184
+ }
11185
+ function literalOrArrayLiteral(value) {
11186
+ if (Array.isArray(value)) {
11187
+ return literalArr(value.map(literalOrArrayLiteral));
11188
+ }
11189
+ return literal(value, INFERRED_TYPE);
11190
+ }
11191
+
11101
11192
  /**
11102
11193
  * Converts the semantic attributes of element-like operations (elements, templates) into constant
11103
11194
  * array expressions, and lifts them into the overall component `consts`.
11104
11195
  */
11105
11196
  function phaseConstCollection(job) {
11106
- if (job instanceof ComponentCompilationJob) {
11107
- // Serialize the extracted messages into the const array.
11108
- const messageConstIndices = {};
11109
- for (const unit of job.units) {
11110
- for (const op of unit.create) {
11111
- if (op.kind === OpKind.ExtractedMessage) {
11112
- messageConstIndices[op.owner] = job.addConst(op.expression, op.statements);
11113
- OpList.remove(op);
11114
- }
11115
- }
11116
- }
11117
- // Assign const index to i18n ops that messages were extracted from.
11118
- for (const unit of job.units) {
11119
- for (const op of unit.create) {
11120
- if (op.kind === OpKind.I18nStart && messageConstIndices[op.xref] !== undefined) {
11121
- op.messageIndex = messageConstIndices[op.xref];
11122
- }
11123
- }
11124
- }
11125
- }
11126
11197
  // Collect all extracted attributes.
11127
- const elementAttributes = new Map();
11198
+ const allElementAttributes = new Map();
11128
11199
  for (const unit of job.units) {
11129
11200
  for (const op of unit.create) {
11130
11201
  if (op.kind === OpKind.ExtractedAttribute) {
11131
- const attributes = elementAttributes.get(op.target) || new ElementAttributes();
11132
- elementAttributes.set(op.target, attributes);
11202
+ const attributes = allElementAttributes.get(op.target) || new ElementAttributes();
11203
+ allElementAttributes.set(op.target, attributes);
11133
11204
  attributes.add(op.bindingKind, op.name, op.expression);
11134
11205
  OpList.remove(op);
11135
11206
  }
@@ -11139,9 +11210,8 @@ function phaseConstCollection(job) {
11139
11210
  if (job instanceof ComponentCompilationJob) {
11140
11211
  for (const unit of job.units) {
11141
11212
  for (const op of unit.create) {
11142
- if (op.kind === OpKind.Element || op.kind === OpKind.ElementStart ||
11143
- op.kind === OpKind.Template) {
11144
- const attributes = elementAttributes.get(op.xref);
11213
+ if (isElementOrContainerOp(op)) {
11214
+ const attributes = allElementAttributes.get(op.xref);
11145
11215
  if (attributes !== undefined) {
11146
11216
  const attrArray = serializeAttributes(attributes);
11147
11217
  if (attrArray.entries.length > 0) {
@@ -11155,7 +11225,7 @@ function phaseConstCollection(job) {
11155
11225
  else if (job instanceof HostBindingCompilationJob) {
11156
11226
  // TODO: If the host binding case further diverges, we may want to split it into its own
11157
11227
  // phase.
11158
- for (const [xref, attributes] of elementAttributes.entries()) {
11228
+ for (const [xref, attributes] of allElementAttributes.entries()) {
11159
11229
  if (xref !== job.root.xref) {
11160
11230
  throw new Error(`An attribute would be const collected into the host binding's template function, but is not associated with the root xref.`);
11161
11231
  }
@@ -11202,6 +11272,15 @@ class ElementAttributes {
11202
11272
  return;
11203
11273
  }
11204
11274
  this.known.add(name);
11275
+ if (name === 'ngProjectAs') {
11276
+ if (value === null || !(value instanceof LiteralExpr) || (value.value == null) ||
11277
+ (typeof value.value?.toString() !== 'string')) {
11278
+ throw Error('ngProjectAs must have a string literal value');
11279
+ }
11280
+ this.projectAs = value.value.toString();
11281
+ // TODO: TemplateDefinitionBuilder allows `ngProjectAs` to also be assigned as a literal
11282
+ // attribute. Is this sane?
11283
+ }
11205
11284
  const array = this.arrayFor(kind);
11206
11285
  array.push(...getAttributeNameLiterals$1(name));
11207
11286
  if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
@@ -11237,7 +11316,10 @@ function getAttributeNameLiterals$1(name) {
11237
11316
  function serializeAttributes({ attributes, bindings, classes, i18n, projectAs, styles, template }) {
11238
11317
  const attrArray = [...attributes];
11239
11318
  if (projectAs !== null) {
11240
- attrArray.push(literal(5 /* core.AttributeMarker.ProjectAs */), literal(projectAs));
11319
+ // Parse the attribute value into a CssSelectorList. Note that we only take the
11320
+ // first selector, because we don't support multiple selectors in ngProjectAs.
11321
+ const parsedR3Selector = parseSelectorToR3Selector(projectAs)[0];
11322
+ attrArray.push(literal(5 /* core.AttributeMarker.ProjectAs */), literalOrArrayLiteral(parsedR3Selector));
11241
11323
  }
11242
11324
  if (classes.length > 0) {
11243
11325
  attrArray.push(literal(1 /* core.AttributeMarker.Classes */), ...classes);
@@ -18882,47 +18964,6 @@ function hyphenate(value) {
18882
18964
  .toLowerCase();
18883
18965
  }
18884
18966
 
18885
- const BINARY_OPERATORS = new Map([
18886
- ['&&', BinaryOperator.And],
18887
- ['>', BinaryOperator.Bigger],
18888
- ['>=', BinaryOperator.BiggerEquals],
18889
- ['&', BinaryOperator.BitwiseAnd],
18890
- ['/', BinaryOperator.Divide],
18891
- ['==', BinaryOperator.Equals],
18892
- ['===', BinaryOperator.Identical],
18893
- ['<', BinaryOperator.Lower],
18894
- ['<=', BinaryOperator.LowerEquals],
18895
- ['-', BinaryOperator.Minus],
18896
- ['%', BinaryOperator.Modulo],
18897
- ['*', BinaryOperator.Multiply],
18898
- ['!=', BinaryOperator.NotEquals],
18899
- ['!==', BinaryOperator.NotIdentical],
18900
- ['??', BinaryOperator.NullishCoalesce],
18901
- ['||', BinaryOperator.Or],
18902
- ['+', BinaryOperator.Plus],
18903
- ]);
18904
- const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
18905
- function namespaceForKey(namespacePrefixKey) {
18906
- if (namespacePrefixKey === null) {
18907
- return Namespace.HTML;
18908
- }
18909
- return NAMESPACES.get(namespacePrefixKey) ?? Namespace.HTML;
18910
- }
18911
- function keyForNamespace(namespace) {
18912
- for (const [k, n] of NAMESPACES.entries()) {
18913
- if (n === namespace) {
18914
- return k;
18915
- }
18916
- }
18917
- return null; // No namespace prefix for HTML
18918
- }
18919
- function prefixWithNamespace(strippedTag, namespace) {
18920
- if (namespace === Namespace.HTML) {
18921
- return strippedTag;
18922
- }
18923
- return `:${keyForNamespace(namespace)}:${strippedTag}`;
18924
- }
18925
-
18926
18967
  /**
18927
18968
  * Generate names for functions and variables across all views.
18928
18969
  *
@@ -19156,7 +19197,7 @@ function phaseNoListenersOnTemplates(job) {
19156
19197
  /**
19157
19198
  * Looks up an element in the given map by xref ID.
19158
19199
  */
19159
- function lookupElement(elements, xref) {
19200
+ function lookupElement$1(elements, xref) {
19160
19201
  const el = elements.get(xref);
19161
19202
  if (el === undefined) {
19162
19203
  throw new Error('All attributes should have an element-like target.');
@@ -19185,7 +19226,7 @@ function phaseNonbindable(job) {
19185
19226
  OpList.insertAfter(createDisableBindingsOp(op.xref), op);
19186
19227
  }
19187
19228
  if ((op.kind === OpKind.ElementEnd || op.kind === OpKind.ContainerEnd) &&
19188
- lookupElement(elements, op.xref).nonBindable) {
19229
+ lookupElement$1(elements, op.xref).nonBindable) {
19189
19230
  OpList.insertBefore(createEnableBindingsOp(op.xref), op);
19190
19231
  }
19191
19232
  }
@@ -19523,8 +19564,11 @@ function elementContainerEnd() {
19523
19564
  }
19524
19565
  function template(slot, templateFnRef, decls, vars, tag, constIndex, sourceSpan) {
19525
19566
  const args = [literal(slot), templateFnRef, literal(decls), literal(vars)];
19526
- if (tag != null && constIndex != null) {
19527
- args.push(literal(tag), literal(constIndex));
19567
+ if (tag !== null) {
19568
+ args.push(literal(tag));
19569
+ if (constIndex !== null) {
19570
+ args.push(literal(constIndex));
19571
+ }
19528
19572
  }
19529
19573
  return call(Identifiers.templateCreate, args, sourceSpan);
19530
19574
  }
@@ -19594,6 +19638,19 @@ function text(slot, initialValue, sourceSpan) {
19594
19638
  }
19595
19639
  return call(Identifiers.text, args, sourceSpan);
19596
19640
  }
19641
+ function projectionDef(def) {
19642
+ return call(Identifiers.projectionDef, def ? [def] : [], null);
19643
+ }
19644
+ function projection(slot, projectionSlotIndex, attributes) {
19645
+ const args = [literal(slot)];
19646
+ if (projectionSlotIndex !== 0 || attributes !== null) {
19647
+ args.push(literal(projectionSlotIndex));
19648
+ if (attributes != null) {
19649
+ args.push(literal(attributes));
19650
+ }
19651
+ }
19652
+ return call(Identifiers.projection, args, null);
19653
+ }
19597
19654
  function i18nStart(slot, constIndex) {
19598
19655
  return call(Identifiers.i18nStart, [literal(slot), literal(constIndex)], null);
19599
19656
  }
@@ -19984,7 +20041,7 @@ function reifyCreateOperations(unit, ops) {
19984
20041
  throw new Error(`AssertionError: must be compiling a component`);
19985
20042
  }
19986
20043
  const childView = unit.job.views.get(op.xref);
19987
- OpList.replace(op, template(op.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.sourceSpan));
20044
+ OpList.replace(op, template(op.slot, variable(childView.fnName), childView.decls, childView.vars, op.controlFlow ? null : op.tag, op.attributes, op.sourceSpan));
19988
20045
  break;
19989
20046
  case OpKind.DisableBindings:
19990
20047
  OpList.replace(op, disableBindings());
@@ -20021,6 +20078,15 @@ function reifyCreateOperations(unit, ops) {
20021
20078
  break;
20022
20079
  }
20023
20080
  break;
20081
+ case OpKind.ProjectionDef:
20082
+ OpList.replace(op, projectionDef(op.def));
20083
+ break;
20084
+ case OpKind.Projection:
20085
+ if (op.slot === null) {
20086
+ throw new Error('No slot was assigned for project instruction');
20087
+ }
20088
+ OpList.replace(op, projection(op.slot, op.projectionSlotIndex, op.attributes));
20089
+ break;
20024
20090
  case OpKind.Statement:
20025
20091
  // Pass statement operations directly through.
20026
20092
  break;
@@ -21073,7 +21139,99 @@ function allowConservativeInlining(decl, target) {
21073
21139
  }
21074
21140
  }
21075
21141
 
21142
+ /**
21143
+ * Locate projection slots, populate the each component's `ngContentSelectors` literal field,
21144
+ * populate `project` arguments, and generate the required `projectionDef` instruction for the job's
21145
+ * root view.
21146
+ */
21147
+ function phaseGenerateProjectionDef(job) {
21148
+ // TODO: Why does TemplateDefinitionBuilder force a shared constant?
21149
+ const share = job.compatibility === CompatibilityMode.TemplateDefinitionBuilder;
21150
+ // Collect all selectors from this component, and its nested views. Also, assign each projection a
21151
+ // unique ascending projection slot index.
21152
+ const selectors = [];
21153
+ let projectionSlotIndex = 0;
21154
+ for (const unit of job.units) {
21155
+ for (const op of unit.create) {
21156
+ if (op.kind === OpKind.Projection) {
21157
+ selectors.push(op.selector);
21158
+ op.projectionSlotIndex = projectionSlotIndex++;
21159
+ }
21160
+ }
21161
+ }
21162
+ if (selectors.length > 0) {
21163
+ // Create the projectionDef array. If we only found a single wildcard selector, then we use the
21164
+ // default behavior with no arguments instead.
21165
+ let defExpr = null;
21166
+ if (selectors.length > 1 || selectors[0] !== '*') {
21167
+ const def = selectors.map(s => s === '*' ? s : parseSelectorToR3Selector(s));
21168
+ defExpr = job.pool.getConstLiteral(literalOrArrayLiteral(def), share);
21169
+ }
21170
+ // Create the ngContentSelectors constant.
21171
+ job.contentSelectors = job.pool.getConstLiteral(literalOrArrayLiteral(selectors), share);
21172
+ // The projection def instruction goes at the beginning of the root view, before any
21173
+ // `projection` instructions.
21174
+ job.root.create.prepend([createProjectionDefOp(defExpr)]);
21175
+ }
21176
+ }
21177
+
21178
+ /**
21179
+ * Lifts i18n properties into the consts array.
21180
+ */
21181
+ function phaseI18nConstCollection(job) {
21182
+ // Serialize the extracted messages into the const array.
21183
+ // TODO: Use `Map` instead of object.
21184
+ const messageConstIndices = {};
21185
+ for (const unit of job.units) {
21186
+ for (const op of unit.create) {
21187
+ if (op.kind === OpKind.ExtractedMessage) {
21188
+ messageConstIndices[op.owner] = job.addConst(op.expression, op.statements);
21189
+ OpList.remove(op);
21190
+ }
21191
+ }
21192
+ }
21193
+ // Assign const index to i18n ops that messages were extracted from.
21194
+ for (const unit of job.units) {
21195
+ for (const op of unit.create) {
21196
+ if (op.kind === OpKind.I18nStart && messageConstIndices[op.xref] !== undefined) {
21197
+ op.messageIndex = messageConstIndices[op.xref];
21198
+ }
21199
+ }
21200
+ }
21201
+ }
21202
+
21203
+ /**
21204
+ * Attributes of `ng-content` named 'select' are specifically removed, because they control which
21205
+ * content matches as a property of the `projection`, and are not a plain attribute.
21206
+ */
21207
+ function phaseRemoveContentSelectors(job) {
21208
+ for (const unit of job.units) {
21209
+ const elements = getElementsByXrefId(unit);
21210
+ for (const op of unit.update) {
21211
+ switch (op.kind) {
21212
+ case OpKind.Binding:
21213
+ const target = lookupElement(elements, op.target);
21214
+ if (op.name.toLowerCase() === 'select' && target.kind === OpKind.Projection) {
21215
+ OpList.remove(op);
21216
+ }
21217
+ continue;
21218
+ }
21219
+ }
21220
+ }
21221
+ }
21222
+ /**
21223
+ * Looks up an element in the given map by xref ID.
21224
+ */
21225
+ function lookupElement(elements, xref) {
21226
+ const el = elements.get(xref);
21227
+ if (el === undefined) {
21228
+ throw new Error('All attributes should have an element-like target.');
21229
+ }
21230
+ return el;
21231
+ }
21232
+
21076
21233
  const phases = [
21234
+ { kind: CompilationJobKind.Tmpl, fn: phaseRemoveContentSelectors },
21077
21235
  { kind: CompilationJobKind.Tmpl, fn: phaseGenerateI18nBlocks },
21078
21236
  { kind: CompilationJobKind.Tmpl, fn: phaseI18nTextExtraction },
21079
21237
  { kind: CompilationJobKind.Host, fn: phaseHostStylePropertyParsing },
@@ -21088,6 +21246,7 @@ const phases = [
21088
21246
  { kind: CompilationJobKind.Tmpl, fn: phasePipeCreation },
21089
21247
  { kind: CompilationJobKind.Tmpl, fn: phasePipeVariadic },
21090
21248
  { kind: CompilationJobKind.Both, fn: phasePureLiteralStructures },
21249
+ { kind: CompilationJobKind.Tmpl, fn: phaseGenerateProjectionDef },
21091
21250
  { kind: CompilationJobKind.Tmpl, fn: phaseGenerateVariables },
21092
21251
  { kind: CompilationJobKind.Tmpl, fn: phaseSaveRestoreView },
21093
21252
  { kind: CompilationJobKind.Tmpl, fn: phaseFindAnyCasts },
@@ -21102,6 +21261,7 @@ const phases = [
21102
21261
  { kind: CompilationJobKind.Tmpl, fn: phaseSlotAllocation },
21103
21262
  { kind: CompilationJobKind.Tmpl, fn: phaseResolveI18nPlaceholders },
21104
21263
  { kind: CompilationJobKind.Tmpl, fn: phaseI18nMessageExtraction },
21264
+ { kind: CompilationJobKind.Tmpl, fn: phaseI18nConstCollection },
21105
21265
  { kind: CompilationJobKind.Both, fn: phaseConstCollection },
21106
21266
  { kind: CompilationJobKind.Both, fn: phaseVarCounting },
21107
21267
  { kind: CompilationJobKind.Tmpl, fn: phaseGenerateAdvance },
@@ -21297,6 +21457,9 @@ function ingestNodes(unit, template) {
21297
21457
  else if (node instanceof Template) {
21298
21458
  ingestTemplate(unit, node);
21299
21459
  }
21460
+ else if (node instanceof Content) {
21461
+ ingestContent(unit, node);
21462
+ }
21300
21463
  else if (node instanceof Text$3) {
21301
21464
  ingestText(unit, node);
21302
21465
  }
@@ -21339,7 +21502,7 @@ function ingestTemplate(unit, tmpl) {
21339
21502
  [namespacePrefix, tagNameWithoutNamespace] = splitNsName(tmpl.tagName);
21340
21503
  }
21341
21504
  // TODO: validate the fallback tag name here.
21342
- const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace ?? 'ng-template', namespaceForKey(namespacePrefix), tmpl.i18n, tmpl.startSourceSpan);
21505
+ const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace ?? 'ng-template', namespaceForKey(namespacePrefix), false, tmpl.i18n, tmpl.startSourceSpan);
21343
21506
  unit.create.push(tplOp);
21344
21507
  ingestBindings(unit, tplOp, tmpl);
21345
21508
  ingestReferences(tplOp, tmpl);
@@ -21348,6 +21511,16 @@ function ingestTemplate(unit, tmpl) {
21348
21511
  childView.contextVariables.set(name, value);
21349
21512
  }
21350
21513
  }
21514
+ /**
21515
+ * Ingest a literal text node from the AST into the given `ViewCompilation`.
21516
+ */
21517
+ function ingestContent(unit, content) {
21518
+ const op = createProjectionOp(unit.job.allocateXrefId(), content.selector);
21519
+ for (const attr of content.attributes) {
21520
+ ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, true, false);
21521
+ }
21522
+ unit.create.push(op);
21523
+ }
21351
21524
  /**
21352
21525
  * Ingest a literal text node from the AST into the given `ViewCompilation`.
21353
21526
  */
@@ -21379,7 +21552,7 @@ function ingestSwitchBlock(unit, switchBlock) {
21379
21552
  const cView = unit.job.allocateView(unit.xref);
21380
21553
  if (!firstXref)
21381
21554
  firstXref = cView.xref;
21382
- unit.create.push(createTemplateOp(cView.xref, 'Case', Namespace.HTML, undefined, null));
21555
+ unit.create.push(createTemplateOp(cView.xref, 'Case', Namespace.HTML, true, undefined, null));
21383
21556
  const caseExpr = switchCase.expression ? convertAst(switchCase.expression, unit.job) : null;
21384
21557
  conditions.push([cView.xref, caseExpr]);
21385
21558
  ingestNodes(cView, switchCase.children);
@@ -22832,16 +23005,15 @@ function parseForLoopParameters(block, errors, bindingParser) {
22832
23005
  }
22833
23006
  const [, itemName, rawExpression] = match;
22834
23007
  const result = {
22835
- itemName,
23008
+ itemName: new Variable(itemName, '$implicit', expressionParam.sourceSpan, expressionParam.sourceSpan),
22836
23009
  trackBy: null,
22837
23010
  expression: parseBlockParameterToBinding(expressionParam, bindingParser, rawExpression),
22838
- context: null,
23011
+ context: {},
22839
23012
  };
22840
23013
  for (const param of secondaryParams) {
22841
23014
  const letMatch = param.expression.match(FOR_LOOP_LET_PATTERN);
22842
23015
  if (letMatch !== null) {
22843
- result.context = result.context || {};
22844
- parseLetParameter(param.sourceSpan, letMatch[1], result.context, errors);
23016
+ parseLetParameter(param.sourceSpan, letMatch[1], param.sourceSpan, result.context, errors);
22845
23017
  continue;
22846
23018
  }
22847
23019
  const trackMatch = param.expression.match(FOR_LOOP_TRACK_PATTERN);
@@ -22856,15 +23028,22 @@ function parseForLoopParameters(block, errors, bindingParser) {
22856
23028
  }
22857
23029
  errors.push(new ParseError(param.sourceSpan, `Unrecognized loop paramater "${param.expression}"`));
22858
23030
  }
23031
+ // Fill out any variables that haven't been defined explicitly.
23032
+ for (const variableName of ALLOWED_FOR_LOOP_LET_VARIABLES) {
23033
+ if (!result.context.hasOwnProperty(variableName)) {
23034
+ result.context[variableName] =
23035
+ new Variable(variableName, variableName, block.startSourceSpan, block.startSourceSpan);
23036
+ }
23037
+ }
22859
23038
  return result;
22860
23039
  }
22861
23040
  /** Parses the `let` parameter of a `for` loop block. */
22862
- function parseLetParameter(sourceSpan, expression, context, errors) {
23041
+ function parseLetParameter(sourceSpan, expression, span, context, errors) {
22863
23042
  const parts = expression.split(',');
22864
23043
  for (const part of parts) {
22865
23044
  const expressionParts = part.split('=');
22866
23045
  const name = expressionParts.length === 2 ? expressionParts[0].trim() : '';
22867
- const variableName = expressionParts.length === 2 ? expressionParts[1].trim() : '';
23046
+ const variableName = (expressionParts.length === 2 ? expressionParts[1].trim() : '');
22868
23047
  if (name.length === 0 || variableName.length === 0) {
22869
23048
  errors.push(new ParseError(sourceSpan, `Invalid for loop "let" parameter. Parameter should match the pattern "<name> = <variable name>"`));
22870
23049
  }
@@ -22875,7 +23054,7 @@ function parseLetParameter(sourceSpan, expression, context, errors) {
22875
23054
  errors.push(new ParseError(sourceSpan, `Duplicate "let" parameter variable "${variableName}"`));
22876
23055
  }
22877
23056
  else {
22878
- context[variableName] = name;
23057
+ context[variableName] = new Variable(name, variableName, span, span);
22879
23058
  }
22880
23059
  }
22881
23060
  }
@@ -22992,7 +23171,8 @@ function parseConditionalBlockParameters(block, errors, bindingParser) {
22992
23171
  errors.push(new ParseError(param.sourceSpan, 'Conditional can only have one "as" expression'));
22993
23172
  }
22994
23173
  else {
22995
- expressionAlias = aliasMatch[1].trim();
23174
+ const name = aliasMatch[1].trim();
23175
+ expressionAlias = new Variable(name, name, param.sourceSpan, param.sourceSpan);
22996
23176
  }
22997
23177
  }
22998
23178
  return { expression, expressionAlias };
@@ -23271,10 +23451,10 @@ function createTimerTrigger(parameters, sourceSpan) {
23271
23451
  return new TimerDeferredTrigger(delay, sourceSpan);
23272
23452
  }
23273
23453
  function createInteractionTrigger(parameters, sourceSpan) {
23274
- if (parameters.length > 1) {
23275
- throw new Error(`"${OnTriggerType.INTERACTION}" trigger can only have zero or one parameters`);
23454
+ if (parameters.length !== 1) {
23455
+ throw new Error(`"${OnTriggerType.INTERACTION}" trigger must have exactly one parameter`);
23276
23456
  }
23277
- return new InteractionDeferredTrigger(parameters[0] ?? null, sourceSpan);
23457
+ return new InteractionDeferredTrigger(parameters[0], sourceSpan);
23278
23458
  }
23279
23459
  function createImmediateTrigger(parameters, sourceSpan) {
23280
23460
  if (parameters.length > 0) {
@@ -23283,10 +23463,10 @@ function createImmediateTrigger(parameters, sourceSpan) {
23283
23463
  return new ImmediateDeferredTrigger(sourceSpan);
23284
23464
  }
23285
23465
  function createHoverTrigger(parameters, sourceSpan) {
23286
- if (parameters.length > 0) {
23287
- throw new Error(`"${OnTriggerType.HOVER}" trigger cannot have parameters`);
23466
+ if (parameters.length !== 1) {
23467
+ throw new Error(`"${OnTriggerType.HOVER}" trigger must have exactly one parameter`);
23288
23468
  }
23289
- return new HoverDeferredTrigger(sourceSpan);
23469
+ return new HoverDeferredTrigger(parameters[0], sourceSpan);
23290
23470
  }
23291
23471
  function createViewportTrigger(parameters, sourceSpan) {
23292
23472
  // TODO: the RFC has some more potential parameters for `viewport`.
@@ -25035,8 +25215,8 @@ class TemplateDefinitionBuilder {
25035
25215
  // If the branch has an alias, it'll be assigned directly to the container's context.
25036
25216
  // We define a variable referring directly to the context so that any nested usages can be
25037
25217
  // rewritten to refer to it.
25038
- const variables = expressionAlias ?
25039
- [new Variable(expressionAlias, DIRECT_CONTEXT_REFERENCE, sourceSpan, sourceSpan)] :
25218
+ const variables = expressionAlias !== null ?
25219
+ [new Variable(expressionAlias.name, DIRECT_CONTEXT_REFERENCE, expressionAlias.sourceSpan, expressionAlias.keySpan)] :
25040
25220
  undefined;
25041
25221
  return {
25042
25222
  index: this.createEmbeddedTemplateFn(null, children, '_Conditional', sourceSpan, variables),
@@ -25244,11 +25424,7 @@ class TemplateDefinitionBuilder {
25244
25424
  // Allocate one slot for the repeater metadata. The slots for the primary and empty block
25245
25425
  // are implicitly inferred by the runtime to index + 1 and index + 2.
25246
25426
  const blockIndex = this.allocateDataSlot();
25247
- const primaryData = this.prepareEmbeddedTemplateFn(block.children, '_For', [
25248
- new Variable(block.itemName, '$implicit', block.sourceSpan, block.sourceSpan),
25249
- new Variable(getLoopLocalName(block, '$index'), '$index', block.sourceSpan, block.sourceSpan),
25250
- new Variable(getLoopLocalName(block, '$count'), '$count', block.sourceSpan, block.sourceSpan),
25251
- ]);
25427
+ const primaryData = this.prepareEmbeddedTemplateFn(block.children, '_For', [block.item, block.contextVariables.$index, block.contextVariables.$count]);
25252
25428
  const emptyData = block.empty === null ?
25253
25429
  null :
25254
25430
  this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty');
@@ -25278,34 +25454,35 @@ class TemplateDefinitionBuilder {
25278
25454
  this.updateInstruction(block.sourceSpan, Identifiers.repeater, () => [literal(blockIndex), this.convertPropertyBinding(value)]);
25279
25455
  }
25280
25456
  registerComputedLoopVariables(block, bindingScope) {
25281
- const indexLocalName = getLoopLocalName(block, '$index');
25282
- const countLocalName = getLoopLocalName(block, '$count');
25457
+ const indexLocalName = block.contextVariables.$index.name;
25458
+ const countLocalName = block.contextVariables.$count.name;
25283
25459
  const level = bindingScope.bindingLevel;
25284
- bindingScope.set(level, getLoopLocalName(block, '$odd'), scope => scope.get(indexLocalName).modulo(literal(2)).notIdentical(literal(0)));
25285
- bindingScope.set(level, getLoopLocalName(block, '$even'), scope => scope.get(indexLocalName).modulo(literal(2)).identical(literal(0)));
25286
- bindingScope.set(level, getLoopLocalName(block, '$first'), scope => scope.get(indexLocalName).identical(literal(0)));
25287
- bindingScope.set(level, getLoopLocalName(block, '$last'), scope => scope.get(indexLocalName).identical(scope.get(countLocalName).minus(literal(1))));
25460
+ bindingScope.set(level, block.contextVariables.$odd.name, scope => scope.get(indexLocalName).modulo(literal(2)).notIdentical(literal(0)));
25461
+ bindingScope.set(level, block.contextVariables.$even.name, scope => scope.get(indexLocalName).modulo(literal(2)).identical(literal(0)));
25462
+ bindingScope.set(level, block.contextVariables.$first.name, scope => scope.get(indexLocalName).identical(literal(0)));
25463
+ bindingScope.set(level, block.contextVariables.$last.name, scope => scope.get(indexLocalName).identical(scope.get(countLocalName).minus(literal(1))));
25288
25464
  }
25289
25465
  optimizeTrackByFunction(block) {
25466
+ const indexLocalName = block.contextVariables.$index.name;
25467
+ const itemName = block.item.name;
25290
25468
  const ast = block.trackBy.ast;
25291
25469
  // Top-level access of `$index` uses the built in `repeaterTrackByIndex`.
25292
25470
  if (ast instanceof PropertyRead && ast.receiver instanceof ImplicitReceiver &&
25293
- ast.name === getLoopLocalName(block, '$index')) {
25471
+ ast.name === indexLocalName) {
25294
25472
  return { expression: importExpr(Identifiers.repeaterTrackByIndex), usesComponentInstance: false };
25295
25473
  }
25296
25474
  // Top-level access of the item uses the built in `repeaterTrackByIdentity`.
25297
25475
  if (ast instanceof PropertyRead && ast.receiver instanceof ImplicitReceiver &&
25298
- ast.name === block.itemName) {
25476
+ ast.name === itemName) {
25299
25477
  return { expression: importExpr(Identifiers.repeaterTrackByIdentity), usesComponentInstance: false };
25300
25478
  }
25301
25479
  // Top-level calls in the form of `fn($index, item)` can be passed in directly.
25302
25480
  if (ast instanceof Call && ast.receiver instanceof PropertyRead &&
25303
25481
  ast.receiver.receiver instanceof ImplicitReceiver && ast.args.length === 2) {
25304
25482
  const firstIsIndex = ast.args[0] instanceof PropertyRead &&
25305
- ast.args[0].receiver instanceof ImplicitReceiver &&
25306
- ast.args[0].name === getLoopLocalName(block, '$index');
25483
+ ast.args[0].receiver instanceof ImplicitReceiver && ast.args[0].name === indexLocalName;
25307
25484
  const secondIsItem = ast.args[1] instanceof PropertyRead &&
25308
- ast.args[1].receiver instanceof ImplicitReceiver && ast.args[1].name === block.itemName;
25485
+ ast.args[1].receiver instanceof ImplicitReceiver && ast.args[1].name === itemName;
25309
25486
  if (firstIsIndex && secondIsItem) {
25310
25487
  // If we're in the top-level component, we can access directly through `ctx`,
25311
25488
  // otherwise we have to get a hold of the component through `componentInstance()`.
@@ -25322,20 +25499,22 @@ class TemplateDefinitionBuilder {
25322
25499
  if (optimizedFn !== null) {
25323
25500
  return optimizedFn;
25324
25501
  }
25325
- // Referencing these requires access to the context which the tracking function
25326
- // might not have. `$index` is special because of backwards compatibility.
25327
- const bannedGlobals = new Set([
25328
- getLoopLocalName(block, '$count'), getLoopLocalName(block, '$first'),
25329
- getLoopLocalName(block, '$last'), getLoopLocalName(block, '$even'),
25330
- getLoopLocalName(block, '$odd')
25331
- ]);
25502
+ const contextVars = block.contextVariables;
25332
25503
  const scope = new TrackByBindingScope(this._bindingScope, {
25333
25504
  // Alias `$index` and the item name to `$index` and `$item` respectively.
25334
25505
  // This allows us to reuse pure functions that may have different item names,
25335
25506
  // but are otherwise identical.
25336
- [getLoopLocalName(block, '$index')]: '$index',
25337
- [block.itemName]: '$item',
25338
- }, bannedGlobals);
25507
+ [contextVars.$index.name]: '$index',
25508
+ [block.item.name]: '$item',
25509
+ // Accessing these variables in a tracking function will result in a template diagnostic.
25510
+ // We define them as globals so that their accesses are preserved verbatim instead of being
25511
+ // rewritten to the actual accesses.
25512
+ [contextVars.$count.name]: contextVars.$count.name,
25513
+ [contextVars.$first.name]: contextVars.$first.name,
25514
+ [contextVars.$last.name]: contextVars.$last.name,
25515
+ [contextVars.$even.name]: contextVars.$even.name,
25516
+ [contextVars.$odd.name]: contextVars.$odd.name,
25517
+ });
25339
25518
  const params = [new FnParam('$index'), new FnParam('$item')];
25340
25519
  const stmts = convertPureComponentScopeFunction(block.trackBy.ast, scope, variable(CONTEXT_NAME), 'track');
25341
25520
  const usesComponentInstance = scope.getComponentAccessCount() > 0;
@@ -25351,6 +25530,7 @@ class TemplateDefinitionBuilder {
25351
25530
  stmts[stmts.length - 1] = new ReturnStatement(lastStatement.expr);
25352
25531
  }
25353
25532
  }
25533
+ // This has to be a function expression, because `.bind` doesn't work on arrow functions.
25354
25534
  fn$1 = fn(params, stmts);
25355
25535
  }
25356
25536
  return {
@@ -25993,25 +26173,20 @@ class BindingScope {
25993
26173
  }
25994
26174
  /** Binding scope of a `track` function inside a `for` loop block. */
25995
26175
  class TrackByBindingScope extends BindingScope {
25996
- constructor(parentScope, globalAliases, bannedGlobals) {
26176
+ constructor(parentScope, globalAliases) {
25997
26177
  super(parentScope.bindingLevel + 1, parentScope);
25998
26178
  this.globalAliases = globalAliases;
25999
- this.bannedGlobals = bannedGlobals;
26000
26179
  this.componentAccessCount = 0;
26001
26180
  }
26002
26181
  get(name) {
26003
26182
  let current = this.parent;
26004
- // Verify that the expression isn't trying to access a variable from a parent scope.
26183
+ // Prevent accesses of template variables outside the `for` loop.
26005
26184
  while (current) {
26006
26185
  if (current.hasLocal(name)) {
26007
- this.forbiddenAccessError(name);
26186
+ return null;
26008
26187
  }
26009
26188
  current = current.parent;
26010
26189
  }
26011
- // If the variable is one of the banned globals, we have to throw.
26012
- if (this.bannedGlobals.has(name)) {
26013
- this.forbiddenAccessError(name);
26014
- }
26015
26190
  // Intercept any aliased globals.
26016
26191
  if (this.globalAliases[name]) {
26017
26192
  return variable(this.globalAliases[name]);
@@ -26024,11 +26199,6 @@ class TrackByBindingScope extends BindingScope {
26024
26199
  getComponentAccessCount() {
26025
26200
  return this.componentAccessCount;
26026
26201
  }
26027
- forbiddenAccessError(propertyName) {
26028
- // TODO(crisbeto): this should be done through template type checking once it is available.
26029
- throw new Error(`Accessing ${propertyName} inside of a track expression is not allowed. ` +
26030
- `Tracking expressions can only access the item, $index and properties on the containing component.`);
26031
- }
26032
26202
  }
26033
26203
  /**
26034
26204
  * Creates a `CssSelector` given a tag name and a map of attributes
@@ -26346,10 +26516,6 @@ function createClosureModeGuard() {
26346
26516
  .notIdentical(literal('undefined', STRING_TYPE))
26347
26517
  .and(variable(NG_I18N_CLOSURE_MODE));
26348
26518
  }
26349
- /** Determines the name that a built in loop context variable is available under. */
26350
- function getLoopLocalName(block, name) {
26351
- return block.contextVariables?.[name] || name;
26352
- }
26353
26519
 
26354
26520
  // This regex matches any binding names that contain the "attr." prefix, e.g. "attr.required"
26355
26521
  // If there is a match, the first matching group will contain the attribute name to bind.
@@ -26508,6 +26674,9 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
26508
26674
  transform(tpl, CompilationJobKind.Tmpl);
26509
26675
  // Finally we emit the template function:
26510
26676
  const templateFn = emitTemplateFn(tpl, constantPool);
26677
+ if (tpl.contentSelectors !== null) {
26678
+ definitionMap.set('ngContentSelectors', tpl.contentSelectors);
26679
+ }
26511
26680
  definitionMap.set('decls', literal(tpl.root.decls));
26512
26681
  definitionMap.set('vars', literal(tpl.root.vars));
26513
26682
  if (tpl.consts.length > 0) {
@@ -27735,7 +27904,7 @@ function publishFacade(global) {
27735
27904
  * @description
27736
27905
  * Entry point for all public APIs of the compiler package.
27737
27906
  */
27738
- const VERSION = new Version('17.0.0-next.4');
27907
+ const VERSION = new Version('17.0.0-next.5');
27739
27908
 
27740
27909
  class CompilerConfig {
27741
27910
  constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
@@ -29197,7 +29366,7 @@ class R3TargetBinder {
29197
29366
  // scopes in the template and makes them available for later use.
29198
29367
  const scope = Scope.apply(target.template);
29199
29368
  // Use the `Scope` to extract the entities present at every level of the template.
29200
- const templateEntities = extractTemplateEntities(scope);
29369
+ const scopedNodeEntities = extractScopedNodeEntities(scope);
29201
29370
  // Next, perform directive matching on the template using the `DirectiveBinder`. This returns:
29202
29371
  // - directives: Map of nodes (elements & ng-templates) to the directives on them.
29203
29372
  // - bindings: Map of inputs, outputs, and attributes to the directive/element that claims
@@ -29207,7 +29376,7 @@ class R3TargetBinder {
29207
29376
  // Finally, run the TemplateBinder to bind references, variables, and other entities within the
29208
29377
  // template. This extracts all the metadata that doesn't depend on directive matching.
29209
29378
  const { expressions, symbols, nestingLevel, usedPipes, eagerPipes, deferBlocks } = TemplateBinder.applyWithScope(target.template, scope);
29210
- return new R3BoundTarget(target, directives, eagerDirectives, bindings, references, expressions, symbols, nestingLevel, templateEntities, usedPipes, eagerPipes, deferBlocks);
29379
+ return new R3BoundTarget(target, directives, eagerDirectives, bindings, references, expressions, symbols, nestingLevel, scopedNodeEntities, usedPipes, eagerPipes, deferBlocks);
29211
29380
  }
29212
29381
  }
29213
29382
  /**
@@ -29218,17 +29387,19 @@ class R3TargetBinder {
29218
29387
  * be analyzed and have their child `Scope`s available in `childScopes`.
29219
29388
  */
29220
29389
  class Scope {
29221
- constructor(parentScope, template) {
29390
+ constructor(parentScope, rootNode) {
29222
29391
  this.parentScope = parentScope;
29223
- this.template = template;
29392
+ this.rootNode = rootNode;
29224
29393
  /**
29225
29394
  * Named members of the `Scope`, such as `Reference`s or `Variable`s.
29226
29395
  */
29227
29396
  this.namedEntities = new Map();
29228
29397
  /**
29229
- * Child `Scope`s for immediately nested `Template`s.
29398
+ * Child `Scope`s for immediately nested `ScopedNode`s.
29230
29399
  */
29231
29400
  this.childScopes = new Map();
29401
+ this.isDeferred =
29402
+ parentScope !== null && parentScope.isDeferred ? true : rootNode instanceof DeferredBlock;
29232
29403
  }
29233
29404
  static newRootScope() {
29234
29405
  return new Scope(null, null);
@@ -29243,18 +29414,35 @@ class Scope {
29243
29414
  return scope;
29244
29415
  }
29245
29416
  /**
29246
- * Internal method to process the template and populate the `Scope`.
29417
+ * Internal method to process the scoped node and populate the `Scope`.
29247
29418
  */
29248
- ingest(template) {
29249
- if (template instanceof Template) {
29419
+ ingest(nodeOrNodes) {
29420
+ if (nodeOrNodes instanceof Template) {
29250
29421
  // Variables on an <ng-template> are defined in the inner scope.
29251
- template.variables.forEach(node => this.visitVariable(node));
29422
+ nodeOrNodes.variables.forEach(node => this.visitVariable(node));
29252
29423
  // Process the nodes of the template.
29253
- template.children.forEach(node => node.visit(this));
29424
+ nodeOrNodes.children.forEach(node => node.visit(this));
29425
+ }
29426
+ else if (nodeOrNodes instanceof IfBlockBranch) {
29427
+ if (nodeOrNodes.expressionAlias !== null) {
29428
+ this.visitVariable(nodeOrNodes.expressionAlias);
29429
+ }
29430
+ nodeOrNodes.children.forEach(node => node.visit(this));
29431
+ }
29432
+ else if (nodeOrNodes instanceof ForLoopBlock) {
29433
+ this.visitVariable(nodeOrNodes.item);
29434
+ Object.values(nodeOrNodes.contextVariables).forEach(v => this.visitVariable(v));
29435
+ nodeOrNodes.children.forEach(node => node.visit(this));
29436
+ }
29437
+ else if (nodeOrNodes instanceof SwitchBlockCase || nodeOrNodes instanceof ForLoopBlockEmpty ||
29438
+ nodeOrNodes instanceof DeferredBlock || nodeOrNodes instanceof DeferredBlockError ||
29439
+ nodeOrNodes instanceof DeferredBlockPlaceholder ||
29440
+ nodeOrNodes instanceof DeferredBlockLoading) {
29441
+ nodeOrNodes.children.forEach(node => node.visit(this));
29254
29442
  }
29255
29443
  else {
29256
29444
  // No overarching `Template` instance, so process the nodes directly.
29257
- template.forEach(node => node.visit(this));
29445
+ nodeOrNodes.forEach(node => node.visit(this));
29258
29446
  }
29259
29447
  }
29260
29448
  visitElement(element) {
@@ -29268,9 +29456,7 @@ class Scope {
29268
29456
  // processing the template's child scope.
29269
29457
  template.references.forEach(node => this.visitReference(node));
29270
29458
  // Next, create an inner scope and process the template within it.
29271
- const scope = new Scope(this, template);
29272
- scope.ingest(template);
29273
- this.childScopes.set(template, scope);
29459
+ this.ingestScopedNode(template);
29274
29460
  }
29275
29461
  visitVariable(variable) {
29276
29462
  // Declare the variable if it's not already.
@@ -29281,38 +29467,38 @@ class Scope {
29281
29467
  this.maybeDeclare(reference);
29282
29468
  }
29283
29469
  visitDeferredBlock(deferred) {
29284
- deferred.children.forEach(node => node.visit(this));
29470
+ this.ingestScopedNode(deferred);
29285
29471
  deferred.placeholder?.visit(this);
29286
29472
  deferred.loading?.visit(this);
29287
29473
  deferred.error?.visit(this);
29288
29474
  }
29289
29475
  visitDeferredBlockPlaceholder(block) {
29290
- block.children.forEach(node => node.visit(this));
29476
+ this.ingestScopedNode(block);
29291
29477
  }
29292
29478
  visitDeferredBlockError(block) {
29293
- block.children.forEach(node => node.visit(this));
29479
+ this.ingestScopedNode(block);
29294
29480
  }
29295
29481
  visitDeferredBlockLoading(block) {
29296
- block.children.forEach(node => node.visit(this));
29482
+ this.ingestScopedNode(block);
29297
29483
  }
29298
29484
  visitSwitchBlock(block) {
29299
29485
  block.cases.forEach(node => node.visit(this));
29300
29486
  }
29301
29487
  visitSwitchBlockCase(block) {
29302
- block.children.forEach(node => node.visit(this));
29488
+ this.ingestScopedNode(block);
29303
29489
  }
29304
29490
  visitForLoopBlock(block) {
29305
- block.children.forEach(node => node.visit(this));
29491
+ this.ingestScopedNode(block);
29306
29492
  block.empty?.visit(this);
29307
29493
  }
29308
29494
  visitForLoopBlockEmpty(block) {
29309
- block.children.forEach(node => node.visit(this));
29495
+ this.ingestScopedNode(block);
29310
29496
  }
29311
29497
  visitIfBlock(block) {
29312
29498
  block.branches.forEach(node => node.visit(this));
29313
29499
  }
29314
29500
  visitIfBlockBranch(block) {
29315
- block.children.forEach(node => node.visit(this));
29501
+ this.ingestScopedNode(block);
29316
29502
  }
29317
29503
  // Unused visitors.
29318
29504
  visitContent(content) { }
@@ -29349,17 +29535,22 @@ class Scope {
29349
29535
  }
29350
29536
  }
29351
29537
  /**
29352
- * Get the child scope for a `Template`.
29538
+ * Get the child scope for a `ScopedNode`.
29353
29539
  *
29354
29540
  * This should always be defined.
29355
29541
  */
29356
- getChildScope(template) {
29357
- const res = this.childScopes.get(template);
29542
+ getChildScope(node) {
29543
+ const res = this.childScopes.get(node);
29358
29544
  if (res === undefined) {
29359
- throw new Error(`Assertion error: child scope for ${template} not found`);
29545
+ throw new Error(`Assertion error: child scope for ${node} not found`);
29360
29546
  }
29361
29547
  return res;
29362
29548
  }
29549
+ ingestScopedNode(node) {
29550
+ const scope = new Scope(this, node);
29551
+ scope.ingest(node);
29552
+ this.childScopes.set(node, scope);
29553
+ }
29363
29554
  }
29364
29555
  /**
29365
29556
  * Processes a template and matches directives on nodes (elements and templates).
@@ -29492,6 +29683,8 @@ class DirectiveBinder {
29492
29683
  block.children.forEach(node => node.visit(this));
29493
29684
  }
29494
29685
  visitForLoopBlock(block) {
29686
+ block.item.visit(this);
29687
+ Object.values(block.contextVariables).forEach(v => v.visit(this));
29495
29688
  block.children.forEach(node => node.visit(this));
29496
29689
  block.empty?.visit(this);
29497
29690
  }
@@ -29502,6 +29695,7 @@ class DirectiveBinder {
29502
29695
  block.branches.forEach(node => node.visit(this));
29503
29696
  }
29504
29697
  visitIfBlockBranch(block) {
29698
+ block.expressionAlias?.visit(this);
29505
29699
  block.children.forEach(node => node.visit(this));
29506
29700
  }
29507
29701
  // Unused visitors.
@@ -29527,7 +29721,7 @@ class DirectiveBinder {
29527
29721
  * by overridden methods from that visitor.
29528
29722
  */
29529
29723
  class TemplateBinder extends RecursiveAstVisitor {
29530
- constructor(bindings, symbols, usedPipes, eagerPipes, deferBlocks, nestingLevel, scope, template, level) {
29724
+ constructor(bindings, symbols, usedPipes, eagerPipes, deferBlocks, nestingLevel, scope, rootNode, level) {
29531
29725
  super();
29532
29726
  this.bindings = bindings;
29533
29727
  this.symbols = symbols;
@@ -29536,10 +29730,8 @@ class TemplateBinder extends RecursiveAstVisitor {
29536
29730
  this.deferBlocks = deferBlocks;
29537
29731
  this.nestingLevel = nestingLevel;
29538
29732
  this.scope = scope;
29539
- this.template = template;
29733
+ this.rootNode = rootNode;
29540
29734
  this.level = level;
29541
- // Indicates whether we are visiting elements within a {#defer} block
29542
- this.isInDeferBlock = false;
29543
29735
  // Save a bit of processing time by constructing this closure in advance.
29544
29736
  this.visitNode = (node) => node.visit(this);
29545
29737
  }
@@ -29579,18 +29771,39 @@ class TemplateBinder extends RecursiveAstVisitor {
29579
29771
  binder.ingest(nodes);
29580
29772
  return { expressions, symbols, nestingLevel, usedPipes, eagerPipes, deferBlocks };
29581
29773
  }
29582
- ingest(template) {
29583
- if (template instanceof Template) {
29774
+ ingest(nodeOrNodes) {
29775
+ if (nodeOrNodes instanceof Template) {
29584
29776
  // For <ng-template>s, process only variables and child nodes. Inputs, outputs, templateAttrs,
29585
29777
  // and references were all processed in the scope of the containing template.
29586
- template.variables.forEach(this.visitNode);
29587
- template.children.forEach(this.visitNode);
29778
+ nodeOrNodes.variables.forEach(this.visitNode);
29779
+ nodeOrNodes.children.forEach(this.visitNode);
29588
29780
  // Set the nesting level.
29589
- this.nestingLevel.set(template, this.level);
29781
+ this.nestingLevel.set(nodeOrNodes, this.level);
29782
+ }
29783
+ else if (nodeOrNodes instanceof IfBlockBranch) {
29784
+ if (nodeOrNodes.expressionAlias !== null) {
29785
+ this.visitNode(nodeOrNodes.expressionAlias);
29786
+ }
29787
+ nodeOrNodes.children.forEach(this.visitNode);
29788
+ this.nestingLevel.set(nodeOrNodes, this.level);
29789
+ }
29790
+ else if (nodeOrNodes instanceof ForLoopBlock) {
29791
+ this.visitNode(nodeOrNodes.item);
29792
+ Object.values(nodeOrNodes.contextVariables).forEach(v => this.visitNode(v));
29793
+ nodeOrNodes.trackBy.visit(this);
29794
+ nodeOrNodes.children.forEach(this.visitNode);
29795
+ this.nestingLevel.set(nodeOrNodes, this.level);
29796
+ }
29797
+ else if (nodeOrNodes instanceof SwitchBlockCase || nodeOrNodes instanceof ForLoopBlockEmpty ||
29798
+ nodeOrNodes instanceof DeferredBlock || nodeOrNodes instanceof DeferredBlockError ||
29799
+ nodeOrNodes instanceof DeferredBlockPlaceholder ||
29800
+ nodeOrNodes instanceof DeferredBlockLoading) {
29801
+ nodeOrNodes.children.forEach(node => node.visit(this));
29802
+ this.nestingLevel.set(nodeOrNodes, this.level);
29590
29803
  }
29591
29804
  else {
29592
29805
  // Visit each node from the top-level template.
29593
- template.forEach(this.visitNode);
29806
+ nodeOrNodes.forEach(this.visitNode);
29594
29807
  }
29595
29808
  }
29596
29809
  visitElement(element) {
@@ -29598,29 +29811,27 @@ class TemplateBinder extends RecursiveAstVisitor {
29598
29811
  element.inputs.forEach(this.visitNode);
29599
29812
  element.outputs.forEach(this.visitNode);
29600
29813
  element.children.forEach(this.visitNode);
29814
+ element.references.forEach(this.visitNode);
29601
29815
  }
29602
29816
  visitTemplate(template) {
29603
29817
  // First, visit inputs, outputs and template attributes of the template node.
29604
29818
  template.inputs.forEach(this.visitNode);
29605
29819
  template.outputs.forEach(this.visitNode);
29606
29820
  template.templateAttrs.forEach(this.visitNode);
29607
- // References are also evaluated in the outer context.
29608
29821
  template.references.forEach(this.visitNode);
29609
- // Next, recurse into the template using its scope, and bumping the nesting level up by one.
29610
- const childScope = this.scope.getChildScope(template);
29611
- const binder = new TemplateBinder(this.bindings, this.symbols, this.usedPipes, this.eagerPipes, this.deferBlocks, this.nestingLevel, childScope, template, this.level + 1);
29612
- binder.ingest(template);
29822
+ // Next, recurse into the template.
29823
+ this.ingestScopedNode(template);
29613
29824
  }
29614
29825
  visitVariable(variable) {
29615
29826
  // Register the `Variable` as a symbol in the current `Template`.
29616
- if (this.template !== null) {
29617
- this.symbols.set(variable, this.template);
29827
+ if (this.rootNode !== null) {
29828
+ this.symbols.set(variable, this.rootNode);
29618
29829
  }
29619
29830
  }
29620
29831
  visitReference(reference) {
29621
29832
  // Register the `Reference` as a symbol in the current `Template`.
29622
- if (this.template !== null) {
29623
- this.symbols.set(reference, this.template);
29833
+ if (this.rootNode !== null) {
29834
+ this.symbols.set(reference, this.rootNode);
29624
29835
  }
29625
29836
  }
29626
29837
  // Unused template visitors
@@ -29640,10 +29851,7 @@ class TemplateBinder extends RecursiveAstVisitor {
29640
29851
  }
29641
29852
  visitDeferredBlock(deferred) {
29642
29853
  this.deferBlocks.add(deferred);
29643
- const wasInDeferBlock = this.isInDeferBlock;
29644
- this.isInDeferBlock = true;
29645
- deferred.children.forEach(this.visitNode);
29646
- this.isInDeferBlock = wasInDeferBlock;
29854
+ this.ingestScopedNode(deferred);
29647
29855
  deferred.placeholder && this.visitNode(deferred.placeholder);
29648
29856
  deferred.loading && this.visitNode(deferred.loading);
29649
29857
  deferred.error && this.visitNode(deferred.error);
@@ -29654,13 +29862,13 @@ class TemplateBinder extends RecursiveAstVisitor {
29654
29862
  }
29655
29863
  }
29656
29864
  visitDeferredBlockPlaceholder(block) {
29657
- block.children.forEach(this.visitNode);
29865
+ this.ingestScopedNode(block);
29658
29866
  }
29659
29867
  visitDeferredBlockError(block) {
29660
- block.children.forEach(this.visitNode);
29868
+ this.ingestScopedNode(block);
29661
29869
  }
29662
29870
  visitDeferredBlockLoading(block) {
29663
- block.children.forEach(this.visitNode);
29871
+ this.ingestScopedNode(block);
29664
29872
  }
29665
29873
  visitSwitchBlock(block) {
29666
29874
  block.expression.visit(this);
@@ -29668,29 +29876,29 @@ class TemplateBinder extends RecursiveAstVisitor {
29668
29876
  }
29669
29877
  visitSwitchBlockCase(block) {
29670
29878
  block.expression?.visit(this);
29671
- block.children.forEach(this.visitNode);
29879
+ this.ingestScopedNode(block);
29672
29880
  }
29673
29881
  visitForLoopBlock(block) {
29674
29882
  block.expression.visit(this);
29675
- block.children.forEach(this.visitNode);
29883
+ this.ingestScopedNode(block);
29676
29884
  block.empty?.visit(this);
29677
29885
  }
29678
29886
  visitForLoopBlockEmpty(block) {
29679
- block.children.forEach(this.visitNode);
29887
+ this.ingestScopedNode(block);
29680
29888
  }
29681
29889
  visitIfBlock(block) {
29682
29890
  block.branches.forEach(node => node.visit(this));
29683
29891
  }
29684
29892
  visitIfBlockBranch(block) {
29685
29893
  block.expression?.visit(this);
29686
- block.children.forEach(node => node.visit(this));
29894
+ this.ingestScopedNode(block);
29687
29895
  }
29688
29896
  visitBoundText(text) {
29689
29897
  text.value.visit(this);
29690
29898
  }
29691
29899
  visitPipe(ast, context) {
29692
29900
  this.usedPipes.add(ast.name);
29693
- if (!this.isInDeferBlock) {
29901
+ if (!this.scope.isDeferred) {
29694
29902
  this.eagerPipes.add(ast.name);
29695
29903
  }
29696
29904
  return super.visitPipe(ast, context);
@@ -29698,18 +29906,23 @@ class TemplateBinder extends RecursiveAstVisitor {
29698
29906
  // These five types of AST expressions can refer to expression roots, which could be variables
29699
29907
  // or references in the current scope.
29700
29908
  visitPropertyRead(ast, context) {
29701
- this.maybeMap(context, ast, ast.name);
29909
+ this.maybeMap(ast, ast.name);
29702
29910
  return super.visitPropertyRead(ast, context);
29703
29911
  }
29704
29912
  visitSafePropertyRead(ast, context) {
29705
- this.maybeMap(context, ast, ast.name);
29913
+ this.maybeMap(ast, ast.name);
29706
29914
  return super.visitSafePropertyRead(ast, context);
29707
29915
  }
29708
29916
  visitPropertyWrite(ast, context) {
29709
- this.maybeMap(context, ast, ast.name);
29917
+ this.maybeMap(ast, ast.name);
29710
29918
  return super.visitPropertyWrite(ast, context);
29711
29919
  }
29712
- maybeMap(scope, ast, name) {
29920
+ ingestScopedNode(node) {
29921
+ const childScope = this.scope.getChildScope(node);
29922
+ const binder = new TemplateBinder(this.bindings, this.symbols, this.usedPipes, this.eagerPipes, this.deferBlocks, this.nestingLevel, childScope, node, this.level + 1);
29923
+ binder.ingest(node);
29924
+ }
29925
+ maybeMap(ast, name) {
29713
29926
  // If the receiver of the expression isn't the `ImplicitReceiver`, this isn't the root of an
29714
29927
  // `AST` expression that maps to a `Variable` or `Reference`.
29715
29928
  if (!(ast.receiver instanceof ImplicitReceiver)) {
@@ -29729,7 +29942,7 @@ class TemplateBinder extends RecursiveAstVisitor {
29729
29942
  * See `BoundTarget` for documentation on the individual methods.
29730
29943
  */
29731
29944
  class R3BoundTarget {
29732
- constructor(target, directives, eagerDirectives, bindings, references, exprTargets, symbols, nestingLevel, templateEntities, usedPipes, eagerPipes, deferredBlocks) {
29945
+ constructor(target, directives, eagerDirectives, bindings, references, exprTargets, symbols, nestingLevel, scopedNodeEntities, usedPipes, eagerPipes, deferredBlocks) {
29733
29946
  this.target = target;
29734
29947
  this.directives = directives;
29735
29948
  this.eagerDirectives = eagerDirectives;
@@ -29738,13 +29951,13 @@ class R3BoundTarget {
29738
29951
  this.exprTargets = exprTargets;
29739
29952
  this.symbols = symbols;
29740
29953
  this.nestingLevel = nestingLevel;
29741
- this.templateEntities = templateEntities;
29954
+ this.scopedNodeEntities = scopedNodeEntities;
29742
29955
  this.usedPipes = usedPipes;
29743
29956
  this.eagerPipes = eagerPipes;
29744
29957
  this.deferredBlocks = deferredBlocks;
29745
29958
  }
29746
- getEntitiesInTemplateScope(template) {
29747
- return this.templateEntities.get(template) ?? new Set();
29959
+ getEntitiesInScope(node) {
29960
+ return this.scopedNodeEntities.get(node) ?? new Set();
29748
29961
  }
29749
29962
  getDirectivesOfNode(node) {
29750
29963
  return this.directives.get(node) || null;
@@ -29758,11 +29971,11 @@ class R3BoundTarget {
29758
29971
  getExpressionTarget(expr) {
29759
29972
  return this.exprTargets.get(expr) || null;
29760
29973
  }
29761
- getTemplateOfSymbol(symbol) {
29974
+ getDefinitionNodeOfSymbol(symbol) {
29762
29975
  return this.symbols.get(symbol) || null;
29763
29976
  }
29764
- getNestingLevel(template) {
29765
- return this.nestingLevel.get(template) || 0;
29977
+ getNestingLevel(node) {
29978
+ return this.nestingLevel.get(node) || 0;
29766
29979
  }
29767
29980
  getUsedDirectives() {
29768
29981
  const set = new Set();
@@ -29782,23 +29995,79 @@ class R3BoundTarget {
29782
29995
  getDeferBlocks() {
29783
29996
  return Array.from(this.deferredBlocks);
29784
29997
  }
29998
+ getDeferredTriggerTarget(block, trigger) {
29999
+ // Only triggers that refer to DOM nodes can be resolved.
30000
+ if (!(trigger instanceof InteractionDeferredTrigger) &&
30001
+ !(trigger instanceof ViewportDeferredTrigger) &&
30002
+ !(trigger instanceof HoverDeferredTrigger)) {
30003
+ return null;
30004
+ }
30005
+ const name = trigger.reference;
30006
+ // TODO(crisbeto): account for `viewport` trigger without a `reference`.
30007
+ if (name === null) {
30008
+ return null;
30009
+ }
30010
+ const outsideRef = this.findEntityInScope(block, name);
30011
+ // First try to resolve the target in the scope of the main deferred block. Note that we
30012
+ // skip triggers defined inside the main block itself, because they might not exist yet.
30013
+ if (outsideRef instanceof Reference && this.getDefinitionNodeOfSymbol(outsideRef) !== block) {
30014
+ const target = this.getReferenceTarget(outsideRef);
30015
+ if (target !== null) {
30016
+ return this.referenceTargetToElement(target);
30017
+ }
30018
+ }
30019
+ // If the trigger couldn't be found in the main block, check the
30020
+ // placeholder block which is shown before the main block has loaded.
30021
+ if (block.placeholder !== null) {
30022
+ const refInPlaceholder = this.findEntityInScope(block.placeholder, name);
30023
+ const targetInPlaceholder = refInPlaceholder instanceof Reference ? this.getReferenceTarget(refInPlaceholder) : null;
30024
+ if (targetInPlaceholder !== null) {
30025
+ return this.referenceTargetToElement(targetInPlaceholder);
30026
+ }
30027
+ }
30028
+ return null;
30029
+ }
30030
+ /**
30031
+ * Finds an entity with a specific name in a scope.
30032
+ * @param rootNode Root node of the scope.
30033
+ * @param name Name of the entity.
30034
+ */
30035
+ findEntityInScope(rootNode, name) {
30036
+ const entities = this.getEntitiesInScope(rootNode);
30037
+ for (const entitity of entities) {
30038
+ if (entitity.name === name) {
30039
+ return entitity;
30040
+ }
30041
+ }
30042
+ return null;
30043
+ }
30044
+ /** Coerces a `ReferenceTarget` to an `Element`, if possible. */
30045
+ referenceTargetToElement(target) {
30046
+ if (target instanceof Element$1) {
30047
+ return target;
30048
+ }
30049
+ if (target instanceof Template) {
30050
+ return null;
30051
+ }
30052
+ return this.referenceTargetToElement(target.node);
30053
+ }
29785
30054
  }
29786
- function extractTemplateEntities(rootScope) {
30055
+ function extractScopedNodeEntities(rootScope) {
29787
30056
  const entityMap = new Map();
29788
30057
  function extractScopeEntities(scope) {
29789
- if (entityMap.has(scope.template)) {
29790
- return entityMap.get(scope.template);
30058
+ if (entityMap.has(scope.rootNode)) {
30059
+ return entityMap.get(scope.rootNode);
29791
30060
  }
29792
30061
  const currentEntities = scope.namedEntities;
29793
- let templateEntities;
30062
+ let entities;
29794
30063
  if (scope.parentScope !== null) {
29795
- templateEntities = new Map([...extractScopeEntities(scope.parentScope), ...currentEntities]);
30064
+ entities = new Map([...extractScopeEntities(scope.parentScope), ...currentEntities]);
29796
30065
  }
29797
30066
  else {
29798
- templateEntities = new Map(currentEntities);
30067
+ entities = new Map(currentEntities);
29799
30068
  }
29800
- entityMap.set(scope.template, templateEntities);
29801
- return templateEntities;
30069
+ entityMap.set(scope.rootNode, entities);
30070
+ return entities;
29802
30071
  }
29803
30072
  const scopesToProcess = [rootScope];
29804
30073
  while (scopesToProcess.length > 0) {
@@ -29893,7 +30162,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
29893
30162
  function compileDeclareClassMetadata(metadata) {
29894
30163
  const definitionMap = new DefinitionMap();
29895
30164
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
29896
- definitionMap.set('version', literal('17.0.0-next.4'));
30165
+ definitionMap.set('version', literal('17.0.0-next.5'));
29897
30166
  definitionMap.set('ngImport', importExpr(Identifiers.core));
29898
30167
  definitionMap.set('type', metadata.type);
29899
30168
  definitionMap.set('decorators', metadata.decorators);
@@ -30001,7 +30270,7 @@ function createDirectiveDefinitionMap(meta) {
30001
30270
  // in 16.1 is actually used.
30002
30271
  const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
30003
30272
  definitionMap.set('minVersion', literal(minVersion));
30004
- definitionMap.set('version', literal('17.0.0-next.4'));
30273
+ definitionMap.set('version', literal('17.0.0-next.5'));
30005
30274
  // e.g. `type: MyDirective`
30006
30275
  definitionMap.set('type', meta.type.value);
30007
30276
  if (meta.isStandalone) {
@@ -30232,7 +30501,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
30232
30501
  function compileDeclareFactoryFunction(meta) {
30233
30502
  const definitionMap = new DefinitionMap();
30234
30503
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
30235
- definitionMap.set('version', literal('17.0.0-next.4'));
30504
+ definitionMap.set('version', literal('17.0.0-next.5'));
30236
30505
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30237
30506
  definitionMap.set('type', meta.type.value);
30238
30507
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -30267,7 +30536,7 @@ function compileDeclareInjectableFromMetadata(meta) {
30267
30536
  function createInjectableDefinitionMap(meta) {
30268
30537
  const definitionMap = new DefinitionMap();
30269
30538
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
30270
- definitionMap.set('version', literal('17.0.0-next.4'));
30539
+ definitionMap.set('version', literal('17.0.0-next.5'));
30271
30540
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30272
30541
  definitionMap.set('type', meta.type.value);
30273
30542
  // Only generate providedIn property if it has a non-null value
@@ -30318,7 +30587,7 @@ function compileDeclareInjectorFromMetadata(meta) {
30318
30587
  function createInjectorDefinitionMap(meta) {
30319
30588
  const definitionMap = new DefinitionMap();
30320
30589
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
30321
- definitionMap.set('version', literal('17.0.0-next.4'));
30590
+ definitionMap.set('version', literal('17.0.0-next.5'));
30322
30591
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30323
30592
  definitionMap.set('type', meta.type.value);
30324
30593
  definitionMap.set('providers', meta.providers);
@@ -30351,7 +30620,7 @@ function createNgModuleDefinitionMap(meta) {
30351
30620
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
30352
30621
  }
30353
30622
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
30354
- definitionMap.set('version', literal('17.0.0-next.4'));
30623
+ definitionMap.set('version', literal('17.0.0-next.5'));
30355
30624
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30356
30625
  definitionMap.set('type', meta.type.value);
30357
30626
  // We only generate the keys in the metadata if the arrays contain values.
@@ -30402,7 +30671,7 @@ function compileDeclarePipeFromMetadata(meta) {
30402
30671
  function createPipeDefinitionMap(meta) {
30403
30672
  const definitionMap = new DefinitionMap();
30404
30673
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
30405
- definitionMap.set('version', literal('17.0.0-next.4'));
30674
+ definitionMap.set('version', literal('17.0.0-next.5'));
30406
30675
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30407
30676
  // e.g. `type: MyPipe`
30408
30677
  definitionMap.set('type', meta.type.value);