@angular/compiler 20.2.0-next.1 → 20.2.0-next.3

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v20.2.0-next.1
2
+ * @license Angular v20.2.0-next.3
3
3
  * (c) 2010-2025 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -2812,7 +2812,18 @@ class Identifiers {
2812
2812
  static pipeBind4 = { name: 'ɵɵpipeBind4', moduleName: CORE };
2813
2813
  static pipeBindV = { name: 'ɵɵpipeBindV', moduleName: CORE };
2814
2814
  static domProperty = { name: 'ɵɵdomProperty', moduleName: CORE };
2815
+ static ariaProperty = { name: 'ɵɵariaProperty', moduleName: CORE };
2815
2816
  static property = { name: 'ɵɵproperty', moduleName: CORE };
2817
+ static animationEnterListener = {
2818
+ name: 'ɵɵanimateEnterListener',
2819
+ moduleName: CORE,
2820
+ };
2821
+ static animationLeaveListener = {
2822
+ name: 'ɵɵanimateLeaveListener',
2823
+ moduleName: CORE,
2824
+ };
2825
+ static animationEnter = { name: 'ɵɵanimateEnter', moduleName: CORE };
2826
+ static animationLeave = { name: 'ɵɵanimateLeave', moduleName: CORE };
2816
2827
  static i18n = { name: 'ɵɵi18n', moduleName: CORE };
2817
2828
  static i18nAttributes = { name: 'ɵɵi18nAttributes', moduleName: CORE };
2818
2829
  static i18nExp = { name: 'ɵɵi18nExp', moduleName: CORE };
@@ -2956,6 +2967,10 @@ class Identifiers {
2956
2967
  name: 'ɵɵExternalStylesFeature',
2957
2968
  moduleName: CORE,
2958
2969
  };
2970
+ static AnimationsFeature = {
2971
+ name: 'ɵɵAnimationsFeature',
2972
+ moduleName: CORE,
2973
+ };
2959
2974
  static listener = { name: 'ɵɵlistener', moduleName: CORE };
2960
2975
  static getInheritedFactory = {
2961
2976
  name: 'ɵɵgetInheritedFactory',
@@ -4538,6 +4553,7 @@ class ParsedProperty {
4538
4553
  valueSpan;
4539
4554
  isLiteral;
4540
4555
  isLegacyAnimation;
4556
+ isAnimation;
4541
4557
  constructor(name, expression, type, sourceSpan, keySpan, valueSpan) {
4542
4558
  this.name = name;
4543
4559
  this.expression = expression;
@@ -4547,6 +4563,7 @@ class ParsedProperty {
4547
4563
  this.valueSpan = valueSpan;
4548
4564
  this.isLiteral = this.type === ParsedPropertyType.LITERAL_ATTR;
4549
4565
  this.isLegacyAnimation = this.type === ParsedPropertyType.LEGACY_ANIMATION;
4566
+ this.isAnimation = this.type === ParsedPropertyType.ANIMATION;
4550
4567
  }
4551
4568
  }
4552
4569
  var ParsedPropertyType;
@@ -4555,6 +4572,7 @@ var ParsedPropertyType;
4555
4572
  ParsedPropertyType[ParsedPropertyType["LITERAL_ATTR"] = 1] = "LITERAL_ATTR";
4556
4573
  ParsedPropertyType[ParsedPropertyType["LEGACY_ANIMATION"] = 2] = "LEGACY_ANIMATION";
4557
4574
  ParsedPropertyType[ParsedPropertyType["TWO_WAY"] = 3] = "TWO_WAY";
4575
+ ParsedPropertyType[ParsedPropertyType["ANIMATION"] = 4] = "ANIMATION";
4558
4576
  })(ParsedPropertyType || (ParsedPropertyType = {}));
4559
4577
  var ParsedEventType;
4560
4578
  (function (ParsedEventType) {
@@ -4564,6 +4582,8 @@ var ParsedEventType;
4564
4582
  ParsedEventType[ParsedEventType["LegacyAnimation"] = 1] = "LegacyAnimation";
4565
4583
  // Event side of a two-way binding (e.g. `[(property)]="expression"`).
4566
4584
  ParsedEventType[ParsedEventType["TwoWay"] = 2] = "TwoWay";
4585
+ // Animation specific event
4586
+ ParsedEventType[ParsedEventType["Animation"] = 3] = "Animation";
4567
4587
  })(ParsedEventType || (ParsedEventType = {}));
4568
4588
  class ParsedEvent {
4569
4589
  name;
@@ -4614,6 +4634,8 @@ var BindingType;
4614
4634
  BindingType[BindingType["LegacyAnimation"] = 4] = "LegacyAnimation";
4615
4635
  // Property side of a two-way binding (e.g. `[(property)]="expression"`).
4616
4636
  BindingType[BindingType["TwoWay"] = 5] = "TwoWay";
4637
+ // A binding to an animation CSS class or function (e.g. `[animate.leave]="expression"`).
4638
+ BindingType[BindingType["Animation"] = 6] = "Animation";
4617
4639
  })(BindingType || (BindingType = {}));
4618
4640
  class BoundElementProperty {
4619
4641
  name;
@@ -8744,6 +8766,22 @@ var OpKind;
8744
8766
  * Creation op that attaches the location at which an element was defined in a template to it.
8745
8767
  */
8746
8768
  OpKind[OpKind["SourceLocation"] = 52] = "SourceLocation";
8769
+ /**
8770
+ * An operation to bind animation css classes to an element.
8771
+ */
8772
+ OpKind[OpKind["Animation"] = 53] = "Animation";
8773
+ /**
8774
+ * An operation to bind animation css classes to an element.
8775
+ */
8776
+ OpKind[OpKind["AnimationString"] = 54] = "AnimationString";
8777
+ /**
8778
+ * An operation to bind animation css classes to an element.
8779
+ */
8780
+ OpKind[OpKind["AnimationBinding"] = 55] = "AnimationBinding";
8781
+ /**
8782
+ * An operation to bind animation events to an element.
8783
+ */
8784
+ OpKind[OpKind["AnimationListener"] = 56] = "AnimationListener";
8747
8785
  })(OpKind || (OpKind = {}));
8748
8786
  /**
8749
8787
  * Distinguishes different kinds of IR expressions.
@@ -8934,6 +8972,10 @@ var BindingKind;
8934
8972
  * Property side of a two-way binding.
8935
8973
  */
8936
8974
  BindingKind[BindingKind["TwoWayProperty"] = 7] = "TwoWayProperty";
8975
+ /**
8976
+ * Property side of an animation binding.
8977
+ */
8978
+ BindingKind[BindingKind["Animation"] = 8] = "Animation";
8937
8979
  })(BindingKind || (BindingKind = {}));
8938
8980
  /**
8939
8981
  * Enumeration of possible times i18n params can be resolved.
@@ -9174,13 +9216,13 @@ function createBindingOp(target, kind, name, expression, unit, securityContext,
9174
9216
  /**
9175
9217
  * Create a `PropertyOp`.
9176
9218
  */
9177
- function createPropertyOp(target, name, expression, isLegacyAnimationTrigger, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
9219
+ function createPropertyOp(target, name, expression, bindingKind, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
9178
9220
  return {
9179
9221
  kind: OpKind.Property,
9180
9222
  target,
9181
9223
  name,
9182
9224
  expression,
9183
- isLegacyAnimationTrigger,
9225
+ bindingKind,
9184
9226
  securityContext,
9185
9227
  sanitizer: null,
9186
9228
  isStructuralTemplateAttribute,
@@ -9331,6 +9373,24 @@ function createRepeaterOp(repeaterCreate, targetSlot, collection, sourceSpan) {
9331
9373
  ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
9332
9374
  };
9333
9375
  }
9376
+ /**
9377
+ * Create an `AnimationBindingOp`.
9378
+ */
9379
+ function createAnimationBindingOp(name, target, animationKind, expression, securityContext, sourceSpan, animationBindingKind) {
9380
+ return {
9381
+ kind: OpKind.AnimationBinding,
9382
+ name,
9383
+ target,
9384
+ animationKind,
9385
+ expression,
9386
+ i18nMessage: null,
9387
+ securityContext,
9388
+ sanitizer: null,
9389
+ sourceSpan,
9390
+ animationBindingKind,
9391
+ ...NEW_OP,
9392
+ };
9393
+ }
9334
9394
  function createDeferWhenOp(target, expr, modifier, sourceSpan) {
9335
9395
  return {
9336
9396
  kind: OpKind.DeferWhen,
@@ -10161,6 +10221,8 @@ function transformExpressionsInOp(op, transform, flags) {
10161
10221
  case OpKind.StyleMap:
10162
10222
  case OpKind.ClassProp:
10163
10223
  case OpKind.ClassMap:
10224
+ case OpKind.AnimationString:
10225
+ case OpKind.AnimationBinding:
10164
10226
  case OpKind.Binding:
10165
10227
  if (op.expression instanceof Interpolation) {
10166
10228
  transformExpressionsInInterpolation(op.expression, transform, flags);
@@ -10213,6 +10275,8 @@ function transformExpressionsInOp(op, transform, flags) {
10213
10275
  op.contextValue = transformExpressionsInExpression(op.contextValue, transform, flags);
10214
10276
  }
10215
10277
  break;
10278
+ case OpKind.Animation:
10279
+ case OpKind.AnimationListener:
10216
10280
  case OpKind.Listener:
10217
10281
  case OpKind.TwoWayListener:
10218
10282
  for (const innerOp of op.handlerOps) {
@@ -10864,6 +10928,43 @@ function createTextOp(xref, initialValue, icuPlaceholder, sourceSpan) {
10864
10928
  ...NEW_OP,
10865
10929
  };
10866
10930
  }
10931
+ /**
10932
+ * Create an `AnimationOp`.
10933
+ */
10934
+ function createAnimationStringOp(name, target, animationKind, expression, securityContext, sourceSpan) {
10935
+ return {
10936
+ kind: OpKind.AnimationString,
10937
+ name,
10938
+ target,
10939
+ animationKind,
10940
+ expression,
10941
+ i18nMessage: null,
10942
+ securityContext,
10943
+ sanitizer: null,
10944
+ sourceSpan,
10945
+ ...NEW_OP,
10946
+ };
10947
+ }
10948
+ /**
10949
+ * Create an `AnimationOp`.
10950
+ */
10951
+ function createAnimationOp(name, target, animationKind, callbackOps, securityContext, sourceSpan) {
10952
+ const handlerOps = new OpList();
10953
+ handlerOps.push(callbackOps);
10954
+ return {
10955
+ kind: OpKind.Animation,
10956
+ name,
10957
+ target,
10958
+ animationKind,
10959
+ handlerOps,
10960
+ handlerFnName: null,
10961
+ i18nMessage: null,
10962
+ securityContext,
10963
+ sanitizer: null,
10964
+ sourceSpan,
10965
+ ...NEW_OP,
10966
+ };
10967
+ }
10867
10968
  /**
10868
10969
  * Create a `ListenerOp`. Host bindings reuse all the listener logic.
10869
10970
  */
@@ -10887,6 +10988,28 @@ function createListenerOp(target, targetSlot, name, tag, handlerOps, legacyAnima
10887
10988
  ...NEW_OP,
10888
10989
  };
10889
10990
  }
10991
+ /**
10992
+ * Create a `ListenerOp`. Host bindings reuse all the listener logic.
10993
+ */
10994
+ function createAnimationListenerOp(target, targetSlot, name, tag, handlerOps, animationKind, eventTarget, hostListener, sourceSpan) {
10995
+ const handlerList = new OpList();
10996
+ handlerList.push(handlerOps);
10997
+ return {
10998
+ kind: OpKind.AnimationListener,
10999
+ target,
11000
+ targetSlot,
11001
+ tag,
11002
+ hostListener,
11003
+ name,
11004
+ animationKind,
11005
+ handlerOps: handlerList,
11006
+ handlerFnName: null,
11007
+ consumesDollarEvent: false,
11008
+ eventTarget,
11009
+ sourceSpan,
11010
+ ...NEW_OP,
11011
+ };
11012
+ }
10890
11013
  /**
10891
11014
  * Create a `TwoWayListenerOp`.
10892
11015
  */
@@ -11136,12 +11259,12 @@ function createSourceLocationOp(templatePath, locations) {
11136
11259
  };
11137
11260
  }
11138
11261
 
11139
- function createDomPropertyOp(name, expression, isLegacyAnimationTrigger, i18nContext, securityContext, sourceSpan) {
11262
+ function createDomPropertyOp(name, expression, bindingKind, i18nContext, securityContext, sourceSpan) {
11140
11263
  return {
11141
11264
  kind: OpKind.DomProperty,
11142
11265
  name,
11143
11266
  expression,
11144
- isLegacyAnimationTrigger,
11267
+ bindingKind,
11145
11268
  i18nContext,
11146
11269
  securityContext,
11147
11270
  sanitizer: null,
@@ -11308,7 +11431,10 @@ class CompilationUnit {
11308
11431
  *ops() {
11309
11432
  for (const op of this.create) {
11310
11433
  yield op;
11311
- if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
11434
+ if (op.kind === OpKind.Listener ||
11435
+ op.kind === OpKind.Animation ||
11436
+ op.kind === OpKind.AnimationListener ||
11437
+ op.kind === OpKind.TwoWayListener) {
11312
11438
  for (const listenerOp of op.handlerOps) {
11313
11439
  yield listenerOp;
11314
11440
  }
@@ -11588,7 +11714,8 @@ function extractAttributes(job) {
11588
11714
  extractAttributeOp(unit, op, elements);
11589
11715
  break;
11590
11716
  case OpKind.Property:
11591
- if (!op.isLegacyAnimationTrigger) {
11717
+ if (op.bindingKind !== BindingKind.LegacyAnimation &&
11718
+ op.bindingKind !== BindingKind.Animation) {
11592
11719
  let bindingKind;
11593
11720
  if (op.i18nMessage !== null && op.templateKind === null) {
11594
11721
  // If the binding has an i18n context, it is an i18n attribute, and should have that
@@ -11606,14 +11733,14 @@ function extractAttributes(job) {
11606
11733
  createExtractedAttributeOp(op.target, bindingKind, null, op.name,
11607
11734
  /* expression */ null,
11608
11735
  /* i18nContext */ null,
11609
- /* i18nMessage */ null, op.securityContext), lookupElement$2(elements, op.target));
11736
+ /* i18nMessage */ null, op.securityContext), lookupElement$3(elements, op.target));
11610
11737
  }
11611
11738
  break;
11612
11739
  case OpKind.TwoWayProperty:
11613
11740
  OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.TwoWayProperty, null, op.name,
11614
11741
  /* expression */ null,
11615
11742
  /* i18nContext */ null,
11616
- /* i18nMessage */ null, op.securityContext), lookupElement$2(elements, op.target));
11743
+ /* i18nMessage */ null, op.securityContext), lookupElement$3(elements, op.target));
11617
11744
  break;
11618
11745
  case OpKind.StyleProp:
11619
11746
  case OpKind.ClassProp:
@@ -11626,7 +11753,7 @@ function extractAttributes(job) {
11626
11753
  OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name,
11627
11754
  /* expression */ null,
11628
11755
  /* i18nContext */ null,
11629
- /* i18nMessage */ null, SecurityContext.STYLE), lookupElement$2(elements, op.target));
11756
+ /* i18nMessage */ null, SecurityContext.STYLE), lookupElement$3(elements, op.target));
11630
11757
  }
11631
11758
  break;
11632
11759
  case OpKind.Listener:
@@ -11646,7 +11773,7 @@ function extractAttributes(job) {
11646
11773
  unit.create.push(extractedAttributeOp);
11647
11774
  }
11648
11775
  else {
11649
- OpList.insertBefore(extractedAttributeOp, lookupElement$2(elements, op.target));
11776
+ OpList.insertBefore(extractedAttributeOp, lookupElement$3(elements, op.target));
11650
11777
  }
11651
11778
  }
11652
11779
  break;
@@ -11657,7 +11784,7 @@ function extractAttributes(job) {
11657
11784
  /* expression */ null,
11658
11785
  /* i18nContext */ null,
11659
11786
  /* i18nMessage */ null, SecurityContext.NONE);
11660
- OpList.insertBefore(extractedAttributeOp, lookupElement$2(elements, op.target));
11787
+ OpList.insertBefore(extractedAttributeOp, lookupElement$3(elements, op.target));
11661
11788
  }
11662
11789
  break;
11663
11790
  }
@@ -11667,7 +11794,7 @@ function extractAttributes(job) {
11667
11794
  /**
11668
11795
  * Looks up an element in the given map by xref ID.
11669
11796
  */
11670
- function lookupElement$2(elements, xref) {
11797
+ function lookupElement$3(elements, xref) {
11671
11798
  const el = elements.get(xref);
11672
11799
  if (el === undefined) {
11673
11800
  throw new Error('All attributes should have an element-like target.');
@@ -11695,7 +11822,7 @@ function extractAttributeOp(unit, op, elements) {
11695
11822
  unit.create.push(extractedAttributeOp);
11696
11823
  }
11697
11824
  else {
11698
- const ownerOp = lookupElement$2(elements, op.target);
11825
+ const ownerOp = lookupElement$3(elements, op.target);
11699
11826
  OpList.insertBefore(extractedAttributeOp, ownerOp);
11700
11827
  }
11701
11828
  OpList.remove(op);
@@ -11705,7 +11832,7 @@ function extractAttributeOp(unit, op, elements) {
11705
11832
  /**
11706
11833
  * Looks up an element in the given map by xref ID.
11707
11834
  */
11708
- function lookupElement$1(elements, xref) {
11835
+ function lookupElement$2(elements, xref) {
11709
11836
  const el = elements.get(xref);
11710
11837
  if (el === undefined) {
11711
11838
  throw new Error('All attributes should have an element-like target.');
@@ -11731,21 +11858,27 @@ function specializeBindings(job) {
11731
11858
  case BindingKind.Attribute:
11732
11859
  if (op.name === 'ngNonBindable') {
11733
11860
  OpList.remove(op);
11734
- const target = lookupElement$1(elements, op.target);
11861
+ const target = lookupElement$2(elements, op.target);
11735
11862
  target.nonBindable = true;
11736
11863
  }
11864
+ else if (op.name.startsWith('animate.')) {
11865
+ OpList.replace(op, createAnimationBindingOp(op.name, op.target, op.name === 'animate.enter' ? "enter" /* ir.AnimationKind.ENTER */ : "leave" /* ir.AnimationKind.LEAVE */, op.expression, op.securityContext, op.sourceSpan, 0 /* ir.AnimationBindingKind.STRING */));
11866
+ }
11737
11867
  else {
11738
11868
  const [namespace, name] = splitNsName(op.name);
11739
11869
  OpList.replace(op, createAttributeOp(op.target, namespace, name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplateAttribute, op.templateKind, op.i18nMessage, op.sourceSpan));
11740
11870
  }
11741
11871
  break;
11872
+ case BindingKind.Animation:
11873
+ OpList.replace(op, createAnimationBindingOp(op.name, op.target, op.name === 'animate.enter' ? "enter" /* ir.AnimationKind.ENTER */ : "leave" /* ir.AnimationKind.LEAVE */, op.expression, op.securityContext, op.sourceSpan, 1 /* ir.AnimationBindingKind.VALUE */));
11874
+ break;
11742
11875
  case BindingKind.Property:
11743
11876
  case BindingKind.LegacyAnimation:
11744
11877
  if (job.kind === CompilationJobKind.Host) {
11745
- OpList.replace(op, createDomPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.LegacyAnimation, op.i18nContext, op.securityContext, op.sourceSpan));
11878
+ OpList.replace(op, createDomPropertyOp(op.name, op.expression, op.bindingKind, op.i18nContext, op.securityContext, op.sourceSpan));
11746
11879
  }
11747
11880
  else {
11748
- OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.LegacyAnimation, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
11881
+ OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
11749
11882
  }
11750
11883
  break;
11751
11884
  case BindingKind.TwoWayProperty:
@@ -11767,6 +11900,7 @@ function specializeBindings(job) {
11767
11900
  }
11768
11901
 
11769
11902
  const CHAIN_COMPATIBILITY = new Map([
11903
+ [Identifiers.ariaProperty, Identifiers.ariaProperty],
11770
11904
  [Identifiers.attribute, Identifiers.attribute],
11771
11905
  [Identifiers.classProp, Identifiers.classProp],
11772
11906
  [Identifiers.element, Identifiers.element],
@@ -11797,6 +11931,10 @@ const CHAIN_COMPATIBILITY = new Map([
11797
11931
  [Identifiers.domElementContainerEnd, Identifiers.domElementContainerEnd],
11798
11932
  [Identifiers.domListener, Identifiers.domListener],
11799
11933
  [Identifiers.domTemplate, Identifiers.domTemplate],
11934
+ [Identifiers.animationEnter, Identifiers.animationEnter],
11935
+ [Identifiers.animationLeave, Identifiers.animationLeave],
11936
+ [Identifiers.animationEnterListener, Identifiers.animationEnterListener],
11937
+ [Identifiers.animationLeaveListener, Identifiers.animationLeaveListener],
11800
11938
  ]);
11801
11939
  /**
11802
11940
  * Chaining results in repeated call expressions, causing a deep AST of receiver expressions. To prevent running out of
@@ -12217,6 +12355,52 @@ function serializeAttributes({ attributes, bindings, classes, i18n, projectAs, s
12217
12355
  return literalArr(attrArray);
12218
12356
  }
12219
12357
 
12358
+ /**
12359
+ * Looks up an element in the given map by xref ID.
12360
+ */
12361
+ function lookupElement$1(elements, xref) {
12362
+ const el = elements.get(xref);
12363
+ if (el === undefined) {
12364
+ throw new Error('All attributes should have an element-like target.');
12365
+ }
12366
+ return el;
12367
+ }
12368
+ function convertAnimations(job) {
12369
+ const elements = new Map();
12370
+ for (const unit of job.units) {
12371
+ for (const op of unit.create) {
12372
+ if (!isElementOrContainerOp(op)) {
12373
+ continue;
12374
+ }
12375
+ elements.set(op.xref, op);
12376
+ }
12377
+ }
12378
+ for (const unit of job.units) {
12379
+ for (const op of unit.ops()) {
12380
+ if (op.kind === OpKind.AnimationBinding) {
12381
+ const createAnimationOp = getAnimationOp(op);
12382
+ if (job.kind === CompilationJobKind.Host) {
12383
+ unit.create.push(createAnimationOp);
12384
+ }
12385
+ else {
12386
+ OpList.insertAfter(createAnimationOp, lookupElement$1(elements, op.target));
12387
+ }
12388
+ OpList.remove(op);
12389
+ }
12390
+ }
12391
+ }
12392
+ }
12393
+ function getAnimationOp(op) {
12394
+ if (op.animationBindingKind === 0 /* ir.AnimationBindingKind.STRING */) {
12395
+ // this is a simple string case
12396
+ return createAnimationStringOp(op.name, op.target, op.name === 'animate.enter' ? "enter" /* ir.AnimationKind.ENTER */ : "leave" /* ir.AnimationKind.LEAVE */, op.expression, op.securityContext, op.sourceSpan);
12397
+ }
12398
+ else {
12399
+ const expression = op.expression;
12400
+ return createAnimationOp(op.name, op.target, op.name === 'animate.enter' ? "enter" /* ir.AnimationKind.ENTER */ : "leave" /* ir.AnimationKind.LEAVE */, [createStatementOp(new ReturnStatement(expression, expression.sourceSpan))], op.securityContext, op.sourceSpan);
12401
+ }
12402
+ }
12403
+
12220
12404
  /**
12221
12405
  * Some binding instructions in the update block may actually correspond to i18n bindings. In that
12222
12406
  * case, they should be replaced with i18nExp instructions for the dynamic portions.
@@ -13105,6 +13289,8 @@ function recursivelyProcessView(view, parentScope) {
13105
13289
  op.trackByOps.prepend(generateVariablesInScopeForView(view, scope, false));
13106
13290
  }
13107
13291
  break;
13292
+ case OpKind.Animation:
13293
+ case OpKind.AnimationListener:
13108
13294
  case OpKind.Listener:
13109
13295
  case OpKind.TwoWayListener:
13110
13296
  // Prepend variables to listener handler functions.
@@ -13187,7 +13373,7 @@ function getScopeForView(view, parent) {
13187
13373
  * This is a recursive process, as views inherit variables available from their parent view, which
13188
13374
  * itself may have inherited variables, etc.
13189
13375
  */
13190
- function generateVariablesInScopeForView(view, scope, isListener) {
13376
+ function generateVariablesInScopeForView(view, scope, isCallback) {
13191
13377
  const newOps = [];
13192
13378
  if (scope.view !== view.xref) {
13193
13379
  // Before generating variables for a parent view, we need to switch to the context of the parent
@@ -13211,7 +13397,7 @@ function generateVariablesInScopeForView(view, scope, isListener) {
13211
13397
  for (const ref of scope.references) {
13212
13398
  newOps.push(createVariableOp(view.job.allocateXrefId(), ref.variable, new ReferenceExpr(ref.targetId, ref.targetSlot, ref.offset), VariableFlags.None));
13213
13399
  }
13214
- if (scope.view !== view.xref || isListener) {
13400
+ if (scope.view !== view.xref || isCallback) {
13215
13401
  for (const decl of scope.letDeclarations) {
13216
13402
  newOps.push(createVariableOp(view.job.allocateXrefId(), decl.variable, new ContextLetReferenceExpr(decl.targetId, decl.targetSlot), VariableFlags.None));
13217
13403
  }
@@ -16510,6 +16696,23 @@ class _Tokenizer {
16510
16696
  return isNameEnd(code);
16511
16697
  };
16512
16698
  }
16699
+ else if (attrNameStart === $LBRACKET) {
16700
+ let openBrackets = 0;
16701
+ // Be more permissive for which characters are allowed inside square-bracketed attributes,
16702
+ // because they usually end up being bound as attribute values. Some third-party packages
16703
+ // like Tailwind take advantage of this.
16704
+ nameEndPredicate = (code) => {
16705
+ if (code === $LBRACKET) {
16706
+ openBrackets++;
16707
+ }
16708
+ else if (code === $RBRACKET) {
16709
+ openBrackets--;
16710
+ }
16711
+ // Only check for name-ending characters if the brackets are balanced or mismatched.
16712
+ // Also interrupt the matching on new lines.
16713
+ return openBrackets <= 0 ? isNameEnd(code) : isNewLine(code);
16714
+ };
16715
+ }
16513
16716
  else {
16514
16717
  nameEndPredicate = isNameEnd;
16515
16718
  }
@@ -18621,7 +18824,7 @@ class Parser {
18621
18824
  parseAction(input, parseSourceSpan, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
18622
18825
  const errors = [];
18623
18826
  this._checkNoInterpolation(errors, input, parseSourceSpan, interpolationConfig);
18624
- const sourceToLex = this._stripComments(input);
18827
+ const { stripped: sourceToLex } = this._stripComments(input);
18625
18828
  const tokens = this._lexer.tokenize(sourceToLex);
18626
18829
  const ast = new _ParseAST(input, parseSourceSpan, absoluteOffset, tokens, 1 /* ParseFlags.Action */, errors, 0, this._supportsDirectPipeReferences).parseChain();
18627
18830
  return new ASTWithSource(ast, input, getLocation(parseSourceSpan), absoluteOffset, errors);
@@ -18648,7 +18851,7 @@ class Parser {
18648
18851
  }
18649
18852
  _parseBindingAst(input, parseSourceSpan, absoluteOffset, interpolationConfig, errors) {
18650
18853
  this._checkNoInterpolation(errors, input, parseSourceSpan, interpolationConfig);
18651
- const sourceToLex = this._stripComments(input);
18854
+ const { stripped: sourceToLex } = this._stripComments(input);
18652
18855
  const tokens = this._lexer.tokenize(sourceToLex);
18653
18856
  return new _ParseAST(input, parseSourceSpan, absoluteOffset, tokens, 0 /* ParseFlags.None */, errors, 0, this._supportsDirectPipeReferences).parseChain();
18654
18857
  }
@@ -18699,8 +18902,13 @@ class Parser {
18699
18902
  // indexes inside the tokens.
18700
18903
  const expressionSpan = interpolatedTokens?.[i * 2 + 1]?.sourceSpan;
18701
18904
  const expressionText = expressions[i].text;
18702
- const sourceToLex = this._stripComments(expressionText);
18905
+ const { stripped: sourceToLex, hasComments } = this._stripComments(expressionText);
18703
18906
  const tokens = this._lexer.tokenize(sourceToLex);
18907
+ if (hasComments && sourceToLex.trim().length === 0 && tokens.length === 0) {
18908
+ // Empty expressions error are handled futher down, here we only take care of the comment case
18909
+ errors.push(getParseError('Interpolation expression cannot only contain a comment', input, `at column ${expressions[i].start} in`, parseSourceSpan));
18910
+ continue;
18911
+ }
18704
18912
  const ast = new _ParseAST(expressionSpan ? expressionText : input, expressionSpan || parseSourceSpan, absoluteOffset, tokens, 0 /* ParseFlags.None */, errors, offsets[i], this._supportsDirectPipeReferences).parseChain();
18705
18913
  expressionNodes.push(ast);
18706
18914
  }
@@ -18712,7 +18920,7 @@ class Parser {
18712
18920
  * This is used for parsing the switch expression in ICUs.
18713
18921
  */
18714
18922
  parseInterpolationExpression(expression, parseSourceSpan, absoluteOffset) {
18715
- const sourceToLex = this._stripComments(expression);
18923
+ const { stripped: sourceToLex } = this._stripComments(expression);
18716
18924
  const tokens = this._lexer.tokenize(sourceToLex);
18717
18925
  const errors = [];
18718
18926
  const ast = new _ParseAST(expression, parseSourceSpan, absoluteOffset, tokens, 0 /* ParseFlags.None */, errors, 0, this._supportsDirectPipeReferences).parseChain();
@@ -18800,7 +19008,9 @@ class Parser {
18800
19008
  }
18801
19009
  _stripComments(input) {
18802
19010
  const i = this._commentStart(input);
18803
- return i != null ? input.substring(0, i) : input;
19011
+ return i != null
19012
+ ? { stripped: input.substring(0, i), hasComments: true }
19013
+ : { stripped: input, hasComments: false };
18804
19014
  }
18805
19015
  _commentStart(input) {
18806
19016
  let outerQuote = null;
@@ -20433,6 +20643,44 @@ const _ATTR_TO_PROP = new Map(Object.entries({
20433
20643
  'innerHtml': 'innerHTML',
20434
20644
  'readonly': 'readOnly',
20435
20645
  'tabindex': 'tabIndex',
20646
+ // https://www.w3.org/TR/wai-aria-1.2/#accessibilityroleandproperties-correspondence
20647
+ 'aria-atomic': 'ariaAtomic',
20648
+ 'aria-autocomplete': 'ariaAutoComplete',
20649
+ 'aria-busy': 'ariaBusy',
20650
+ 'aria-checked': 'ariaChecked',
20651
+ 'aria-colcount': 'ariaColCount',
20652
+ 'aria-colindex': 'ariaColIndex',
20653
+ 'aria-colspan': 'ariaColSpan',
20654
+ 'aria-current': 'ariaCurrent',
20655
+ 'aria-disabled': 'ariaDisabled',
20656
+ 'aria-expanded': 'ariaExpanded',
20657
+ 'aria-haspopup': 'ariaHasPopup',
20658
+ 'aria-hidden': 'ariaHidden',
20659
+ 'aria-invalid': 'ariaInvalid',
20660
+ 'aria-keyshortcuts': 'ariaKeyShortcuts',
20661
+ 'aria-label': 'ariaLabel',
20662
+ 'aria-level': 'ariaLevel',
20663
+ 'aria-live': 'ariaLive',
20664
+ 'aria-modal': 'ariaModal',
20665
+ 'aria-multiline': 'ariaMultiLine',
20666
+ 'aria-multiselectable': 'ariaMultiSelectable',
20667
+ 'aria-orientation': 'ariaOrientation',
20668
+ 'aria-placeholder': 'ariaPlaceholder',
20669
+ 'aria-posinset': 'ariaPosInSet',
20670
+ 'aria-pressed': 'ariaPressed',
20671
+ 'aria-readonly': 'ariaReadOnly',
20672
+ 'aria-required': 'ariaRequired',
20673
+ 'aria-roledescription': 'ariaRoleDescription',
20674
+ 'aria-rowcount': 'ariaRowCount',
20675
+ 'aria-rowindex': 'ariaRowIndex',
20676
+ 'aria-rowspan': 'ariaRowSpan',
20677
+ 'aria-selected': 'ariaSelected',
20678
+ 'aria-setsize': 'ariaSetSize',
20679
+ 'aria-sort': 'ariaSort',
20680
+ 'aria-valuemax': 'ariaValueMax',
20681
+ 'aria-valuemin': 'ariaValueMin',
20682
+ 'aria-valuenow': 'ariaValueNow',
20683
+ 'aria-valuetext': 'ariaValueText',
20436
20684
  }));
20437
20685
  // Invert _ATTR_TO_PROP.
20438
20686
  const _PROP_TO_ATTR = Array.from(_ATTR_TO_PROP).reduce((inverted, [propertyName, attributeName]) => {
@@ -22379,10 +22627,33 @@ function addNamesToView(unit, baseName, state, compatibility) {
22379
22627
  switch (op.kind) {
22380
22628
  case OpKind.Property:
22381
22629
  case OpKind.DomProperty:
22382
- if (op.isLegacyAnimationTrigger) {
22630
+ if (op.bindingKind === BindingKind.LegacyAnimation) {
22383
22631
  op.name = '@' + op.name;
22384
22632
  }
22385
22633
  break;
22634
+ case OpKind.Animation:
22635
+ if (op.handlerFnName === null) {
22636
+ const animationKind = op.name.replace('.', '');
22637
+ op.handlerFnName = `${unit.fnName}_${animationKind}_cb`;
22638
+ op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
22639
+ }
22640
+ break;
22641
+ case OpKind.AnimationListener:
22642
+ if (op.handlerFnName !== null) {
22643
+ break;
22644
+ }
22645
+ if (!op.hostListener && op.targetSlot.slot === null) {
22646
+ throw new Error(`Expected a slot to be assigned`);
22647
+ }
22648
+ const animationKind = op.name.replace('.', '');
22649
+ if (op.hostListener) {
22650
+ op.handlerFnName = `${baseName}_${animationKind}_HostBindingHandler`;
22651
+ }
22652
+ else {
22653
+ op.handlerFnName = `${unit.fnName}_${op.tag.replace('-', '_')}_${animationKind}_${op.targetSlot.slot}_listener`;
22654
+ }
22655
+ op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
22656
+ break;
22386
22657
  case OpKind.Listener:
22387
22658
  if (op.handlerFnName !== null) {
22388
22659
  break;
@@ -22540,7 +22811,10 @@ function stripImportant(name) {
22540
22811
  function mergeNextContextExpressions(job) {
22541
22812
  for (const unit of job.units) {
22542
22813
  for (const op of unit.create) {
22543
- if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
22814
+ if (op.kind === OpKind.Listener ||
22815
+ op.kind === OpKind.Animation ||
22816
+ op.kind === OpKind.AnimationListener ||
22817
+ op.kind === OpKind.TwoWayListener) {
22544
22818
  mergeNextContextsInOps(op.handlerOps);
22545
22819
  }
22546
22820
  }
@@ -22661,7 +22935,9 @@ function kindWithInterpolationTest(kind, interpolation) {
22661
22935
  }
22662
22936
  function basicListenerKindTest(op) {
22663
22937
  return ((op.kind === OpKind.Listener && !(op.hostListener && op.isLegacyAnimationListener)) ||
22664
- op.kind === OpKind.TwoWayListener);
22938
+ op.kind === OpKind.TwoWayListener ||
22939
+ op.kind === OpKind.Animation ||
22940
+ op.kind === OpKind.AnimationListener);
22665
22941
  }
22666
22942
  function nonInterpolationPropertyKindTest(op) {
22667
22943
  return ((op.kind === OpKind.Property || op.kind === OpKind.TwoWayProperty) &&
@@ -22708,6 +22984,7 @@ const UPDATE_HOST_ORDERING = [
22708
22984
  const handledOpKinds = new Set([
22709
22985
  OpKind.Listener,
22710
22986
  OpKind.TwoWayListener,
22987
+ OpKind.AnimationListener,
22711
22988
  OpKind.StyleMap,
22712
22989
  OpKind.ClassMap,
22713
22990
  OpKind.StyleProp,
@@ -22716,6 +22993,7 @@ const handledOpKinds = new Set([
22716
22993
  OpKind.TwoWayProperty,
22717
22994
  OpKind.DomProperty,
22718
22995
  OpKind.Attribute,
22996
+ OpKind.Animation,
22719
22997
  ]);
22720
22998
  /**
22721
22999
  * Many type of operations have ordering constraints that must be respected. For example, a
@@ -23406,6 +23684,9 @@ function i18nAttributes(slot, i18nAttributesConfig) {
23406
23684
  const args = [literal(slot), literal(i18nAttributesConfig)];
23407
23685
  return call(Identifiers.i18nAttributes, args, null);
23408
23686
  }
23687
+ function ariaProperty(name, expression, sourceSpan) {
23688
+ return propertyBase(Identifiers.ariaProperty, name, expression, null, sourceSpan);
23689
+ }
23409
23690
  function property(name, expression, sanitizer, sourceSpan) {
23410
23691
  return propertyBase(Identifiers.property, name, expression, sanitizer, sourceSpan);
23411
23692
  }
@@ -23519,6 +23800,36 @@ function i18nApply(slot, sourceSpan) {
23519
23800
  function domProperty(name, expression, sanitizer, sourceSpan) {
23520
23801
  return propertyBase(Identifiers.domProperty, name, expression, sanitizer, sourceSpan);
23521
23802
  }
23803
+ function animation(animationKind, handlerFn, sanitizer, sourceSpan) {
23804
+ const args = [handlerFn];
23805
+ if (sanitizer !== null) {
23806
+ args.push(sanitizer);
23807
+ }
23808
+ const identifier = animationKind === "enter" /* ir.AnimationKind.ENTER */
23809
+ ? Identifiers.animationEnter
23810
+ : Identifiers.animationLeave;
23811
+ return call(identifier, args, sourceSpan);
23812
+ }
23813
+ function animationString(animationKind, expression, sanitizer, sourceSpan) {
23814
+ const value = expression instanceof Interpolation
23815
+ ? interpolationToExpression(expression, sourceSpan)
23816
+ : expression;
23817
+ const args = [value];
23818
+ if (sanitizer !== null) {
23819
+ args.push(sanitizer);
23820
+ }
23821
+ const identifier = animationKind === "enter" /* ir.AnimationKind.ENTER */
23822
+ ? Identifiers.animationEnter
23823
+ : Identifiers.animationLeave;
23824
+ return call(identifier, args, sourceSpan);
23825
+ }
23826
+ function animationListener(animationKind, handlerFn, eventTargetResolver, sourceSpan) {
23827
+ const args = [handlerFn];
23828
+ const identifier = animationKind === "enter" /* ir.AnimationKind.ENTER */
23829
+ ? Identifiers.animationEnterListener
23830
+ : Identifiers.animationLeaveListener;
23831
+ return call(identifier, args, sourceSpan);
23832
+ }
23522
23833
  function syntheticHostProperty(name, expression, sourceSpan) {
23523
23834
  return call(Identifiers.syntheticHostProperty, [literal(name), expression], sourceSpan);
23524
23835
  }
@@ -23652,6 +23963,7 @@ function callVariadicInstruction(config, baseArgs, interpolationArgs, extraArgs,
23652
23963
  return createStatementOp(callVariadicInstructionExpr(config, baseArgs, interpolationArgs, extraArgs, sourceSpan).toStmt());
23653
23964
  }
23654
23965
 
23966
+ const ARIA_PREFIX = 'aria';
23655
23967
  /**
23656
23968
  * Map of target resolvers for event listeners.
23657
23969
  */
@@ -23765,6 +24077,18 @@ function reifyCreateOperations(unit, ops) {
23765
24077
  case OpKind.DeclareLet:
23766
24078
  OpList.replace(op, declareLet(op.handle.slot, op.sourceSpan));
23767
24079
  break;
24080
+ case OpKind.AnimationString:
24081
+ OpList.replace(op, animationString(op.animationKind, op.expression, op.sanitizer, op.sourceSpan));
24082
+ break;
24083
+ case OpKind.Animation:
24084
+ const animationCallbackFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps,
24085
+ /* consumesDollarEvent */ false);
24086
+ OpList.replace(op, animation(op.animationKind, animationCallbackFn, op.sanitizer, op.sourceSpan));
24087
+ break;
24088
+ case OpKind.AnimationListener:
24089
+ const animationListenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
24090
+ OpList.replace(op, animationListener(op.animationKind, animationListenerFn, null, op.sourceSpan));
24091
+ break;
23768
24092
  case OpKind.Listener:
23769
24093
  const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
23770
24094
  const eventTargetResolver = op.eventTarget
@@ -23943,9 +24267,11 @@ function reifyUpdateOperations(unit, ops) {
23943
24267
  OpList.replace(op, advance(op.delta, op.sourceSpan));
23944
24268
  break;
23945
24269
  case OpKind.Property:
23946
- OpList.replace(op, unit.job.mode === TemplateCompilationMode.DomOnly && !op.isLegacyAnimationTrigger
23947
- ? domProperty(DOM_PROPERTY_REMAPPING.get(op.name) ?? op.name, op.expression, op.sanitizer, op.sourceSpan)
23948
- : property(op.name, op.expression, op.sanitizer, op.sourceSpan));
24270
+ OpList.replace(op, unit.job.mode === TemplateCompilationMode.DomOnly &&
24271
+ op.bindingKind !== BindingKind.LegacyAnimation &&
24272
+ op.bindingKind !== BindingKind.Animation
24273
+ ? reifyDomProperty(op)
24274
+ : reifyProperty(op));
23949
24275
  break;
23950
24276
  case OpKind.TwoWayProperty:
23951
24277
  OpList.replace(op, twoWayProperty(op.name, op.expression, op.sanitizer, op.sourceSpan));
@@ -23979,11 +24305,12 @@ function reifyUpdateOperations(unit, ops) {
23979
24305
  throw new Error('not yet handled');
23980
24306
  }
23981
24307
  else {
23982
- if (op.isLegacyAnimationTrigger) {
24308
+ if (op.bindingKind === BindingKind.LegacyAnimation ||
24309
+ op.bindingKind === BindingKind.Animation) {
23983
24310
  OpList.replace(op, syntheticHostProperty(op.name, op.expression, op.sourceSpan));
23984
24311
  }
23985
24312
  else {
23986
- OpList.replace(op, domProperty(DOM_PROPERTY_REMAPPING.get(op.name) ?? op.name, op.expression, op.sanitizer, op.sourceSpan));
24313
+ OpList.replace(op, reifyDomProperty(op));
23987
24314
  }
23988
24315
  }
23989
24316
  break;
@@ -24015,6 +24342,61 @@ function reifyUpdateOperations(unit, ops) {
24015
24342
  }
24016
24343
  }
24017
24344
  }
24345
+ /**
24346
+ * Converts an ARIA property name to its corresponding attribute name, if necessary.
24347
+ *
24348
+ * For example, converts `ariaLabel` to `aria-label`.
24349
+ *
24350
+ * https://www.w3.org/TR/wai-aria-1.2/#accessibilityroleandproperties-correspondence
24351
+ *
24352
+ * This must be kept in sync with the the function of the same name in
24353
+ * packages/core/src/render3/instructions/aria_property.ts.
24354
+ *
24355
+ * @param name A property name that starts with `aria`.
24356
+ * @returns The corresponding attribute name.
24357
+ */
24358
+ function ariaAttrName(name) {
24359
+ return name.charAt(ARIA_PREFIX.length) !== '-'
24360
+ ? ARIA_PREFIX + '-' + name.slice(ARIA_PREFIX.length).toLowerCase()
24361
+ : name; // Property already has attribute name.
24362
+ }
24363
+ /**
24364
+ * Returns whether `name` is an ARIA property (or attribute) name.
24365
+ *
24366
+ * This is a heuristic based on whether name begins with and is longer than `aria`. For example,
24367
+ * this returns true for both `ariaLabel` and `aria-label`.
24368
+ */
24369
+ function isAriaProperty(name) {
24370
+ return name.startsWith(ARIA_PREFIX) && name.length > ARIA_PREFIX.length;
24371
+ }
24372
+ /**
24373
+ * Reifies a DOM property binding operation.
24374
+ *
24375
+ * This is an optimized version of {@link reifyProperty} that avoids unnecessarily trying to bind
24376
+ * to directive inputs at runtime for views that don't import any directives.
24377
+ *
24378
+ * @param op A property binding operation.
24379
+ * @returns A statement to update the property at runtime.
24380
+ */
24381
+ function reifyDomProperty(op) {
24382
+ return isAriaProperty(op.name)
24383
+ ? attribute(ariaAttrName(op.name), op.expression, null, null, op.sourceSpan)
24384
+ : domProperty(DOM_PROPERTY_REMAPPING.get(op.name) ?? op.name, op.expression, op.sanitizer, op.sourceSpan);
24385
+ }
24386
+ /**
24387
+ * Reifies a property binding operation.
24388
+ *
24389
+ * The returned statement attempts to bind to directive inputs before falling back to a DOM
24390
+ * property.
24391
+ *
24392
+ * @param op A property binding operation.
24393
+ * @returns A statement to update the property at runtime.
24394
+ */
24395
+ function reifyProperty(op) {
24396
+ return isAriaProperty(op.name)
24397
+ ? ariaProperty(op.name, op.expression, op.sourceSpan)
24398
+ : property(op.name, op.expression, op.sanitizer, op.sourceSpan);
24399
+ }
24018
24400
  function reifyIrExpression(expr) {
24019
24401
  if (!isIrExpression(expr)) {
24020
24402
  return expr;
@@ -24256,6 +24638,8 @@ function processLexicalScope$1(view, ops) {
24256
24638
  break;
24257
24639
  }
24258
24640
  break;
24641
+ case OpKind.Animation:
24642
+ case OpKind.AnimationListener:
24259
24643
  case OpKind.Listener:
24260
24644
  case OpKind.TwoWayListener:
24261
24645
  processLexicalScope$1(view, op.handlerOps);
@@ -24321,11 +24705,13 @@ function resolveDollarEvent(job) {
24321
24705
  }
24322
24706
  function transformDollarEvent(ops) {
24323
24707
  for (const op of ops) {
24324
- if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
24708
+ if (op.kind === OpKind.Listener ||
24709
+ op.kind === OpKind.TwoWayListener ||
24710
+ op.kind === OpKind.AnimationListener) {
24325
24711
  transformExpressionsInOp(op, (expr) => {
24326
24712
  if (expr instanceof LexicalReadExpr && expr.name === '$event') {
24327
24713
  // Two-way listeners always consume `$event` so they omit this field.
24328
- if (op.kind === OpKind.Listener) {
24714
+ if (op.kind === OpKind.Listener || op.kind === OpKind.AnimationListener) {
24329
24715
  op.consumesDollarEvent = true;
24330
24716
  }
24331
24717
  return new ReadVarExpr(expr.name);
@@ -24716,6 +25102,8 @@ function processLexicalScope(unit, ops, savedView) {
24716
25102
  break;
24717
25103
  }
24718
25104
  break;
25105
+ case OpKind.Animation:
25106
+ case OpKind.AnimationListener:
24719
25107
  case OpKind.Listener:
24720
25108
  case OpKind.TwoWayListener:
24721
25109
  // Listener functions have separate variable declarations, so process them as a separate
@@ -24733,7 +25121,10 @@ function processLexicalScope(unit, ops, savedView) {
24733
25121
  // scope. Also, look for `ir.RestoreViewExpr`s and match them with the snapshotted view context
24734
25122
  // variable.
24735
25123
  for (const op of ops) {
24736
- if (op.kind == OpKind.Listener || op.kind === OpKind.TwoWayListener) {
25124
+ if (op.kind == OpKind.Listener ||
25125
+ op.kind === OpKind.TwoWayListener ||
25126
+ op.kind === OpKind.Animation ||
25127
+ op.kind === OpKind.AnimationListener) {
24737
25128
  // Listeners were already processed above with their own scopes.
24738
25129
  continue;
24739
25130
  }
@@ -24902,7 +25293,10 @@ function saveAndRestoreView(job) {
24902
25293
  }, new GetCurrentViewExpr(), VariableFlags.None),
24903
25294
  ]);
24904
25295
  for (const op of unit.create) {
24905
- if (op.kind !== OpKind.Listener && op.kind !== OpKind.TwoWayListener) {
25296
+ if (op.kind !== OpKind.Listener &&
25297
+ op.kind !== OpKind.TwoWayListener &&
25298
+ op.kind !== OpKind.Animation &&
25299
+ op.kind !== OpKind.AnimationListener) {
24906
25300
  continue;
24907
25301
  }
24908
25302
  // Embedded views always need the save/restore view operation.
@@ -25222,7 +25616,10 @@ function generateTemporaries(ops) {
25222
25616
  // Add declarations for the temp vars.
25223
25617
  generatedStatements.push(...Array.from(new Set(defs.values())).map((name) => createStatementOp(new DeclareVarStmt(name))));
25224
25618
  opCount++;
25225
- if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
25619
+ if (op.kind === OpKind.Listener ||
25620
+ op.kind === OpKind.Animation ||
25621
+ op.kind === OpKind.AnimationListener ||
25622
+ op.kind === OpKind.TwoWayListener) {
25226
25623
  op.handlerOps.prepend(generateTemporaries(op.handlerOps));
25227
25624
  }
25228
25625
  else if (op.kind === OpKind.RepeaterCreate && op.trackByOps !== null) {
@@ -25566,7 +25963,10 @@ function optimizeVariables(job) {
25566
25963
  inlineAlwaysInlineVariables(unit.create);
25567
25964
  inlineAlwaysInlineVariables(unit.update);
25568
25965
  for (const op of unit.create) {
25569
- if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
25966
+ if (op.kind === OpKind.Listener ||
25967
+ op.kind === OpKind.Animation ||
25968
+ op.kind === OpKind.AnimationListener ||
25969
+ op.kind === OpKind.TwoWayListener) {
25570
25970
  inlineAlwaysInlineVariables(op.handlerOps);
25571
25971
  }
25572
25972
  else if (op.kind === OpKind.RepeaterCreate && op.trackByOps !== null) {
@@ -25576,7 +25976,10 @@ function optimizeVariables(job) {
25576
25976
  optimizeVariablesInOpList(unit.create, job.compatibility);
25577
25977
  optimizeVariablesInOpList(unit.update, job.compatibility);
25578
25978
  for (const op of unit.create) {
25579
- if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
25979
+ if (op.kind === OpKind.Listener ||
25980
+ op.kind === OpKind.Animation ||
25981
+ op.kind === OpKind.AnimationListener ||
25982
+ op.kind === OpKind.TwoWayListener) {
25580
25983
  optimizeVariablesInOpList(op.handlerOps, job.compatibility);
25581
25984
  }
25582
25985
  else if (op.kind === OpKind.RepeaterCreate && op.trackByOps !== null) {
@@ -26013,6 +26416,7 @@ const phases = [
26013
26416
  { kind: CompilationJobKind.Both, fn: deduplicateTextBindings },
26014
26417
  { kind: CompilationJobKind.Both, fn: specializeStyleBindings },
26015
26418
  { kind: CompilationJobKind.Both, fn: specializeBindings },
26419
+ { kind: CompilationJobKind.Both, fn: convertAnimations },
26016
26420
  { kind: CompilationJobKind.Both, fn: extractAttributes },
26017
26421
  { kind: CompilationJobKind.Tmpl, fn: createI18nContexts },
26018
26422
  { kind: CompilationJobKind.Both, fn: parseExtractedStyles },
@@ -26172,6 +26576,8 @@ const compatibilityMode = CompatibilityMode.TemplateDefinitionBuilder;
26172
26576
  const domSchema = new DomElementSchemaRegistry();
26173
26577
  // Tag name of the `ng-template` element.
26174
26578
  const NG_TEMPLATE_TAG_NAME = 'ng-template';
26579
+ // prefix for any animation binding
26580
+ const ANIMATE_PREFIX$1 = 'animate.';
26175
26581
  function isI18nRootNode(meta) {
26176
26582
  return meta instanceof Message;
26177
26583
  }
@@ -26204,6 +26610,9 @@ function ingestHostBinding(input, bindingParser, constantPool) {
26204
26610
  if (property.isLegacyAnimation) {
26205
26611
  bindingKind = BindingKind.LegacyAnimation;
26206
26612
  }
26613
+ if (property.isAnimation) {
26614
+ bindingKind = BindingKind.Animation;
26615
+ }
26207
26616
  const securityContexts = bindingParser
26208
26617
  .calcPossibleSecurityContexts(input.componentSelector, property.name, bindingKind === BindingKind.Attribute)
26209
26618
  .filter((context) => context !== SecurityContext.NONE);
@@ -26870,6 +27279,7 @@ const BINDING_KINDS = new Map([
26870
27279
  [BindingType.Class, BindingKind.ClassName],
26871
27280
  [BindingType.Style, BindingKind.StyleProperty],
26872
27281
  [BindingType.LegacyAnimation, BindingKind.LegacyAnimation],
27282
+ [BindingType.Animation, BindingKind.Animation],
26873
27283
  ]);
26874
27284
  /**
26875
27285
  * Checks whether the given template is a plain ng-template (as opposed to another kind of template
@@ -26934,6 +27344,9 @@ function ingestElementBindings(unit, op, element) {
26934
27344
  if (output.type === ParsedEventType.TwoWay) {
26935
27345
  unit.create.push(createTwoWayListenerOp(op.xref, op.handle, output.name, op.tag, makeTwoWayListenerHandlerOps(unit, output.handler, output.handlerSpan), output.sourceSpan));
26936
27346
  }
27347
+ else if (output.type === ParsedEventType.Animation) {
27348
+ unit.create.push(createAnimationListenerOp(op.xref, op.handle, output.name, op.tag, makeListenerHandlerOps(unit, output.handler, output.handlerSpan), output.name.endsWith('enter') ? "enter" /* ir.AnimationKind.ENTER */ : "leave" /* ir.AnimationKind.LEAVE */, output.target, false, output.sourceSpan));
27349
+ }
26937
27350
  else {
26938
27351
  unit.create.push(createListenerOp(op.xref, op.handle, output.name, op.tag, makeListenerHandlerOps(unit, output.handler, output.handlerSpan), output.phase, output.target, false, output.sourceSpan));
26939
27352
  }
@@ -27042,7 +27455,9 @@ function createTemplateBinding(view, xref, type, name, value, unit, securityCont
27042
27455
  }
27043
27456
  }
27044
27457
  if (!isTextBinding &&
27045
- (type === BindingType.Attribute || type === BindingType.LegacyAnimation)) {
27458
+ (type === BindingType.Attribute ||
27459
+ type === BindingType.LegacyAnimation ||
27460
+ type === BindingType.Animation)) {
27046
27461
  // Again, this binding doesn't really target the ng-template; it actually targets the element
27047
27462
  // inside the structural template. In the case of non-text attribute or animation bindings,
27048
27463
  // the binding doesn't even show up on the ng-template const array, so we just skip it
@@ -27200,14 +27615,18 @@ function ingestControlFlowInsertionPoint(unit, xref, node) {
27200
27615
  if (root !== null) {
27201
27616
  // Collect the static attributes for content projection purposes.
27202
27617
  for (const attr of root.attributes) {
27203
- const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
27204
- unit.update.push(createBindingOp(xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
27618
+ if (!attr.name.startsWith(ANIMATE_PREFIX$1)) {
27619
+ const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
27620
+ unit.update.push(createBindingOp(xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
27621
+ }
27205
27622
  }
27206
27623
  // Also collect the inputs since they participate in content projection as well.
27207
27624
  // Note that TDB used to collect the outputs as well, but it wasn't passing them into
27208
27625
  // the template instruction. Here we just don't collect them.
27209
27626
  for (const attr of root.inputs) {
27210
- if (attr.type !== BindingType.LegacyAnimation && attr.type !== BindingType.Attribute) {
27627
+ if (attr.type !== BindingType.LegacyAnimation &&
27628
+ attr.type !== BindingType.Animation &&
27629
+ attr.type !== BindingType.Attribute) {
27211
27630
  const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
27212
27631
  unit.create.push(createExtractedAttributeOp(xref, BindingKind.Property, null, attr.name, null, null, null, securityContext));
27213
27632
  }
@@ -27425,6 +27844,7 @@ class HtmlParser extends Parser$1 {
27425
27844
 
27426
27845
  const PROPERTY_PARTS_SEPARATOR = '.';
27427
27846
  const ATTRIBUTE_PREFIX = 'attr';
27847
+ const ANIMATE_PREFIX = 'animate';
27428
27848
  const CLASS_PREFIX = 'class';
27429
27849
  const STYLE_PREFIX = 'style';
27430
27850
  const TEMPLATE_ATTR_PREFIX$1 = '*';
@@ -27624,6 +28044,9 @@ class BindingParser {
27624
28044
  if (isLegacyAnimationProp) {
27625
28045
  this._parseLegacyAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
27626
28046
  }
28047
+ else if (name.startsWith(ANIMATE_PREFIX)) {
28048
+ this._parseAnimation(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
28049
+ }
27627
28050
  else {
27628
28051
  this._parsePropertyAst(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), isPartOfAssignmentBinding, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
27629
28052
  }
@@ -27640,6 +28063,10 @@ class BindingParser {
27640
28063
  targetMatchableAttrs.push([name, ast.source]);
27641
28064
  targetProps.push(new ParsedProperty(name, ast, isPartOfAssignmentBinding ? ParsedPropertyType.TWO_WAY : ParsedPropertyType.DEFAULT, sourceSpan, keySpan, valueSpan));
27642
28065
  }
28066
+ _parseAnimation(name, ast, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
28067
+ targetMatchableAttrs.push([name, ast.source]);
28068
+ targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
28069
+ }
27643
28070
  _parseLegacyAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
27644
28071
  if (name.length === 0) {
27645
28072
  this._reportError('Animation trigger is missing', sourceSpan);
@@ -27702,6 +28129,11 @@ class BindingParser {
27702
28129
  bindingType = BindingType.Style;
27703
28130
  securityContexts = [SecurityContext.STYLE];
27704
28131
  }
28132
+ else if (parts[0] == ANIMATE_PREFIX) {
28133
+ boundPropertyName = boundProp.name;
28134
+ bindingType = BindingType.Animation;
28135
+ securityContexts = [SecurityContext.NONE];
28136
+ }
27705
28137
  }
27706
28138
  // If not a special case, use the full property name
27707
28139
  if (boundPropertyName === null) {
@@ -27716,7 +28148,6 @@ class BindingParser {
27716
28148
  }
27717
28149
  return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
27718
28150
  }
27719
- // TODO: keySpan should be required but was made optional to avoid changing VE parser.
27720
28151
  parseEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
27721
28152
  if (name.length === 0) {
27722
28153
  this._reportError(`Event name is missing in binding`, sourceSpan);
@@ -27772,7 +28203,14 @@ class BindingParser {
27772
28203
  if (isAssignmentEvent && isValid && !this._isAllowedAssignmentEvent(ast)) {
27773
28204
  this._reportError('Unsupported expression in a two-way binding', sourceSpan);
27774
28205
  }
27775
- targetEvents.push(new ParsedEvent(eventName, target, isAssignmentEvent ? ParsedEventType.TwoWay : ParsedEventType.Regular, ast, sourceSpan, handlerSpan, keySpan));
28206
+ let eventType = ParsedEventType.Regular;
28207
+ if (isAssignmentEvent) {
28208
+ eventType = ParsedEventType.TwoWay;
28209
+ }
28210
+ if (name.startsWith(ANIMATE_PREFIX)) {
28211
+ eventType = ParsedEventType.Animation;
28212
+ }
28213
+ targetEvents.push(new ParsedEvent(eventName, target, eventType, ast, sourceSpan, handlerSpan, keySpan));
27776
28214
  // Don't detect directives for event names for now,
27777
28215
  // so don't add the event name to the matchableAttrs
27778
28216
  }
@@ -27830,11 +28268,25 @@ class BindingParser {
27830
28268
  return this._isAllowedAssignmentEvent(ast.args[0]);
27831
28269
  }
27832
28270
  if (ast instanceof PropertyRead || ast instanceof KeyedRead) {
27833
- return true;
28271
+ if (!hasRecursiveSafeReceiver(ast)) {
28272
+ return true;
28273
+ }
27834
28274
  }
27835
28275
  return false;
27836
28276
  }
27837
28277
  }
28278
+ function hasRecursiveSafeReceiver(ast) {
28279
+ if (ast instanceof SafePropertyRead || ast instanceof SafeKeyedRead) {
28280
+ return true;
28281
+ }
28282
+ if (ast instanceof ParenthesizedExpression) {
28283
+ return hasRecursiveSafeReceiver(ast.expression);
28284
+ }
28285
+ if (ast instanceof PropertyRead || ast instanceof KeyedRead || ast instanceof Call) {
28286
+ return hasRecursiveSafeReceiver(ast.receiver);
28287
+ }
28288
+ return false;
28289
+ }
27838
28290
  function isLegacyAnimationLabel(name) {
27839
28291
  return name[0] == '@';
27840
28292
  }
@@ -29343,7 +29795,7 @@ class HtmlAstToIvyAst {
29343
29795
  const identifier = bindParts[IDENT_KW_IDX];
29344
29796
  const keySpan = createKeySpan(srcSpan, bindParts[KW_BINDON_IDX], identifier);
29345
29797
  this.bindingParser.parsePropertyBinding(identifier, value, false, true, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
29346
- this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan);
29798
+ this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan, absoluteOffset);
29347
29799
  }
29348
29800
  else if (bindParts[KW_AT_IDX]) {
29349
29801
  const keySpan = createKeySpan(srcSpan, '', name);
@@ -29374,7 +29826,7 @@ class HtmlAstToIvyAst {
29374
29826
  const keySpan = createKeySpan(srcSpan, delims.start, identifier);
29375
29827
  if (delims.start === BINDING_DELIMS.BANANA_BOX.start) {
29376
29828
  this.bindingParser.parsePropertyBinding(identifier, value, false, true, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
29377
- this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan);
29829
+ this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan, absoluteOffset);
29378
29830
  }
29379
29831
  else if (delims.start === BINDING_DELIMS.PROPERTY.start) {
29380
29832
  this.bindingParser.parsePropertyBinding(identifier, value, false, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
@@ -29494,7 +29946,7 @@ class HtmlAstToIvyAst {
29494
29946
  }
29495
29947
  references.push(new Reference(identifier, value, sourceSpan, keySpan, valueSpan));
29496
29948
  }
29497
- parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, boundEvents, keySpan) {
29949
+ parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, boundEvents, keySpan, absoluteOffset) {
29498
29950
  const events = [];
29499
29951
  this.bindingParser.parseEvent(`${name}Change`, expression,
29500
29952
  /* isAssignmentEvent */ true, sourceSpan, valueSpan || sourceSpan, targetMatchableAttrs, events, keySpan);
@@ -29722,9 +30174,184 @@ function makeBindingParser(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG, s
29722
30174
  return new BindingParser(new Parser(new Lexer(), selectorlessEnabled), interpolationConfig, elementRegistry, []);
29723
30175
  }
29724
30176
 
30177
+ /*!
30178
+ * @license
30179
+ * Copyright Google LLC All Rights Reserved.
30180
+ *
30181
+ * Use of this source code is governed by an MIT-style license that can be
30182
+ * found in the LICENSE file at https://angular.dev/license
30183
+ */
30184
+ /**
30185
+ * Visitor that traverses all template and expression AST nodes in a template.
30186
+ * Useful for cases where every single node needs to be visited.
30187
+ */
30188
+ class CombinedRecursiveAstVisitor extends RecursiveAstVisitor {
30189
+ visit(node) {
30190
+ if (node instanceof ASTWithSource) {
30191
+ this.visit(node.ast);
30192
+ }
30193
+ else {
30194
+ node.visit(this);
30195
+ }
30196
+ }
30197
+ visitElement(element) {
30198
+ this.visitAllTemplateNodes(element.attributes);
30199
+ this.visitAllTemplateNodes(element.inputs);
30200
+ this.visitAllTemplateNodes(element.outputs);
30201
+ this.visitAllTemplateNodes(element.directives);
30202
+ this.visitAllTemplateNodes(element.references);
30203
+ this.visitAllTemplateNodes(element.children);
30204
+ }
30205
+ visitTemplate(template) {
30206
+ this.visitAllTemplateNodes(template.attributes);
30207
+ this.visitAllTemplateNodes(template.inputs);
30208
+ this.visitAllTemplateNodes(template.outputs);
30209
+ this.visitAllTemplateNodes(template.directives);
30210
+ this.visitAllTemplateNodes(template.templateAttrs);
30211
+ this.visitAllTemplateNodes(template.variables);
30212
+ this.visitAllTemplateNodes(template.references);
30213
+ this.visitAllTemplateNodes(template.children);
30214
+ }
30215
+ visitContent(content) {
30216
+ this.visitAllTemplateNodes(content.children);
30217
+ }
30218
+ visitBoundAttribute(attribute) {
30219
+ this.visit(attribute.value);
30220
+ }
30221
+ visitBoundEvent(attribute) {
30222
+ this.visit(attribute.handler);
30223
+ }
30224
+ visitBoundText(text) {
30225
+ this.visit(text.value);
30226
+ }
30227
+ visitIcu(icu) {
30228
+ Object.keys(icu.vars).forEach((key) => this.visit(icu.vars[key]));
30229
+ Object.keys(icu.placeholders).forEach((key) => this.visit(icu.placeholders[key]));
30230
+ }
30231
+ visitDeferredBlock(deferred) {
30232
+ deferred.visitAll(this);
30233
+ }
30234
+ visitDeferredTrigger(trigger) {
30235
+ if (trigger instanceof BoundDeferredTrigger) {
30236
+ this.visit(trigger.value);
30237
+ }
30238
+ }
30239
+ visitDeferredBlockPlaceholder(block) {
30240
+ this.visitAllTemplateNodes(block.children);
30241
+ }
30242
+ visitDeferredBlockError(block) {
30243
+ this.visitAllTemplateNodes(block.children);
30244
+ }
30245
+ visitDeferredBlockLoading(block) {
30246
+ this.visitAllTemplateNodes(block.children);
30247
+ }
30248
+ visitSwitchBlock(block) {
30249
+ this.visit(block.expression);
30250
+ this.visitAllTemplateNodes(block.cases);
30251
+ }
30252
+ visitSwitchBlockCase(block) {
30253
+ block.expression && this.visit(block.expression);
30254
+ this.visitAllTemplateNodes(block.children);
30255
+ }
30256
+ visitForLoopBlock(block) {
30257
+ block.item.visit(this);
30258
+ this.visitAllTemplateNodes(block.contextVariables);
30259
+ this.visit(block.expression);
30260
+ this.visitAllTemplateNodes(block.children);
30261
+ block.empty?.visit(this);
30262
+ }
30263
+ visitForLoopBlockEmpty(block) {
30264
+ this.visitAllTemplateNodes(block.children);
30265
+ }
30266
+ visitIfBlock(block) {
30267
+ this.visitAllTemplateNodes(block.branches);
30268
+ }
30269
+ visitIfBlockBranch(block) {
30270
+ block.expression && this.visit(block.expression);
30271
+ block.expressionAlias?.visit(this);
30272
+ this.visitAllTemplateNodes(block.children);
30273
+ }
30274
+ visitLetDeclaration(decl) {
30275
+ this.visit(decl.value);
30276
+ }
30277
+ visitComponent(component) {
30278
+ this.visitAllTemplateNodes(component.attributes);
30279
+ this.visitAllTemplateNodes(component.inputs);
30280
+ this.visitAllTemplateNodes(component.outputs);
30281
+ this.visitAllTemplateNodes(component.directives);
30282
+ this.visitAllTemplateNodes(component.references);
30283
+ this.visitAllTemplateNodes(component.children);
30284
+ }
30285
+ visitDirective(directive) {
30286
+ this.visitAllTemplateNodes(directive.attributes);
30287
+ this.visitAllTemplateNodes(directive.inputs);
30288
+ this.visitAllTemplateNodes(directive.outputs);
30289
+ this.visitAllTemplateNodes(directive.references);
30290
+ }
30291
+ visitVariable(variable) { }
30292
+ visitReference(reference) { }
30293
+ visitTextAttribute(attribute) { }
30294
+ visitText(text) { }
30295
+ visitUnknownBlock(block) { }
30296
+ visitAllTemplateNodes(nodes) {
30297
+ for (const node of nodes) {
30298
+ this.visit(node);
30299
+ }
30300
+ }
30301
+ }
30302
+
30303
+ /*!
30304
+ * @license
30305
+ * Copyright Google LLC All Rights Reserved.
30306
+ *
30307
+ * Use of this source code is governed by an MIT-style license that can be
30308
+ * found in the LICENSE file at https://angular.dev/license
30309
+ */
30310
+ const ANIMATE_LEAVE$1 = `animate.leave`;
30311
+ /**
30312
+ * Analyzes a component's template to determine if it's using animate.enter
30313
+ * or animate.leave syntax.
30314
+ */
30315
+ function analyzeTemplateForAnimations(template) {
30316
+ const analyzer = new AnimationsAnalyzer();
30317
+ visitAll$1(analyzer, template);
30318
+ // The template is considered selectorless only if there
30319
+ // are direct references to directives or pipes.
30320
+ return analyzer.hasAnimations;
30321
+ }
30322
+ /**
30323
+ * Visitor that traverses all the template nodes and
30324
+ * expressions to look for selectorless references.
30325
+ */
30326
+ class AnimationsAnalyzer extends CombinedRecursiveAstVisitor {
30327
+ hasAnimations = false;
30328
+ visitElement(element) {
30329
+ // check for regular strings
30330
+ for (const attr of element.attributes) {
30331
+ if (attr.name === ANIMATE_LEAVE$1) {
30332
+ this.hasAnimations = true;
30333
+ }
30334
+ }
30335
+ // check for attribute bindings
30336
+ for (const input of element.inputs) {
30337
+ if (input.name === ANIMATE_LEAVE$1) {
30338
+ this.hasAnimations = true;
30339
+ }
30340
+ }
30341
+ // check for event bindings
30342
+ for (const output of element.outputs) {
30343
+ if (output.name === ANIMATE_LEAVE$1) {
30344
+ this.hasAnimations = true;
30345
+ }
30346
+ }
30347
+ super.visitElement(element);
30348
+ }
30349
+ }
30350
+
29725
30351
  const COMPONENT_VARIABLE = '%COMP%';
29726
30352
  const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
29727
30353
  const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
30354
+ const ANIMATE_LEAVE = `animate.leave`;
29728
30355
  function baseDirectiveFields(meta, constantPool, bindingParser) {
29729
30356
  const definitionMap = new DefinitionMap();
29730
30357
  const selectors = parseSelectorToR3Selector(meta.selector);
@@ -29758,6 +30385,11 @@ function baseDirectiveFields(meta, constantPool, bindingParser) {
29758
30385
  }
29759
30386
  return definitionMap;
29760
30387
  }
30388
+ function hasAnimationHostBinding(meta) {
30389
+ return (meta.host.attributes[ANIMATE_LEAVE] !== undefined ||
30390
+ meta.host.properties[ANIMATE_LEAVE] !== undefined ||
30391
+ meta.host.listeners[ANIMATE_LEAVE] !== undefined);
30392
+ }
29761
30393
  /**
29762
30394
  * Add features to the definition map.
29763
30395
  */
@@ -29792,6 +30424,12 @@ function addFeatures(definitionMap, meta) {
29792
30424
  const externalStyleNodes = meta.externalStyles.map((externalStyle) => literal(externalStyle));
29793
30425
  features.push(importExpr(Identifiers.ExternalStylesFeature).callFn([literalArr(externalStyleNodes)]));
29794
30426
  }
30427
+ const template = meta.template;
30428
+ if (hasAnimationHostBinding(meta) || (template && template.nodes.length > 0)) {
30429
+ if (hasAnimationHostBinding(meta) || analyzeTemplateForAnimations(template.nodes)) {
30430
+ features.push(importExpr(Identifiers.AnimationsFeature).callFn([]));
30431
+ }
30432
+ }
29795
30433
  if (features.length) {
29796
30434
  definitionMap.set('features', literalArr(features));
29797
30435
  }
@@ -30251,132 +30889,6 @@ function compileDeferResolverFunction(meta) {
30251
30889
  return arrowFn([], literalArr(depExpressions));
30252
30890
  }
30253
30891
 
30254
- /*!
30255
- * @license
30256
- * Copyright Google LLC All Rights Reserved.
30257
- *
30258
- * Use of this source code is governed by an MIT-style license that can be
30259
- * found in the LICENSE file at https://angular.dev/license
30260
- */
30261
- /**
30262
- * Visitor that traverses all template and expression AST nodes in a template.
30263
- * Useful for cases where every single node needs to be visited.
30264
- */
30265
- class CombinedRecursiveAstVisitor extends RecursiveAstVisitor {
30266
- visit(node) {
30267
- if (node instanceof ASTWithSource) {
30268
- this.visit(node.ast);
30269
- }
30270
- else {
30271
- node.visit(this);
30272
- }
30273
- }
30274
- visitElement(element) {
30275
- this.visitAllTemplateNodes(element.attributes);
30276
- this.visitAllTemplateNodes(element.inputs);
30277
- this.visitAllTemplateNodes(element.outputs);
30278
- this.visitAllTemplateNodes(element.directives);
30279
- this.visitAllTemplateNodes(element.references);
30280
- this.visitAllTemplateNodes(element.children);
30281
- }
30282
- visitTemplate(template) {
30283
- this.visitAllTemplateNodes(template.attributes);
30284
- this.visitAllTemplateNodes(template.inputs);
30285
- this.visitAllTemplateNodes(template.outputs);
30286
- this.visitAllTemplateNodes(template.directives);
30287
- this.visitAllTemplateNodes(template.templateAttrs);
30288
- this.visitAllTemplateNodes(template.variables);
30289
- this.visitAllTemplateNodes(template.references);
30290
- this.visitAllTemplateNodes(template.children);
30291
- }
30292
- visitContent(content) {
30293
- this.visitAllTemplateNodes(content.children);
30294
- }
30295
- visitBoundAttribute(attribute) {
30296
- this.visit(attribute.value);
30297
- }
30298
- visitBoundEvent(attribute) {
30299
- this.visit(attribute.handler);
30300
- }
30301
- visitBoundText(text) {
30302
- this.visit(text.value);
30303
- }
30304
- visitIcu(icu) {
30305
- Object.keys(icu.vars).forEach((key) => this.visit(icu.vars[key]));
30306
- Object.keys(icu.placeholders).forEach((key) => this.visit(icu.placeholders[key]));
30307
- }
30308
- visitDeferredBlock(deferred) {
30309
- deferred.visitAll(this);
30310
- }
30311
- visitDeferredTrigger(trigger) {
30312
- if (trigger instanceof BoundDeferredTrigger) {
30313
- this.visit(trigger.value);
30314
- }
30315
- }
30316
- visitDeferredBlockPlaceholder(block) {
30317
- this.visitAllTemplateNodes(block.children);
30318
- }
30319
- visitDeferredBlockError(block) {
30320
- this.visitAllTemplateNodes(block.children);
30321
- }
30322
- visitDeferredBlockLoading(block) {
30323
- this.visitAllTemplateNodes(block.children);
30324
- }
30325
- visitSwitchBlock(block) {
30326
- this.visit(block.expression);
30327
- this.visitAllTemplateNodes(block.cases);
30328
- }
30329
- visitSwitchBlockCase(block) {
30330
- block.expression && this.visit(block.expression);
30331
- this.visitAllTemplateNodes(block.children);
30332
- }
30333
- visitForLoopBlock(block) {
30334
- block.item.visit(this);
30335
- this.visitAllTemplateNodes(block.contextVariables);
30336
- this.visit(block.expression);
30337
- this.visitAllTemplateNodes(block.children);
30338
- block.empty?.visit(this);
30339
- }
30340
- visitForLoopBlockEmpty(block) {
30341
- this.visitAllTemplateNodes(block.children);
30342
- }
30343
- visitIfBlock(block) {
30344
- this.visitAllTemplateNodes(block.branches);
30345
- }
30346
- visitIfBlockBranch(block) {
30347
- block.expression && this.visit(block.expression);
30348
- block.expressionAlias?.visit(this);
30349
- this.visitAllTemplateNodes(block.children);
30350
- }
30351
- visitLetDeclaration(decl) {
30352
- this.visit(decl.value);
30353
- }
30354
- visitComponent(component) {
30355
- this.visitAllTemplateNodes(component.attributes);
30356
- this.visitAllTemplateNodes(component.inputs);
30357
- this.visitAllTemplateNodes(component.outputs);
30358
- this.visitAllTemplateNodes(component.directives);
30359
- this.visitAllTemplateNodes(component.references);
30360
- this.visitAllTemplateNodes(component.children);
30361
- }
30362
- visitDirective(directive) {
30363
- this.visitAllTemplateNodes(directive.attributes);
30364
- this.visitAllTemplateNodes(directive.inputs);
30365
- this.visitAllTemplateNodes(directive.outputs);
30366
- this.visitAllTemplateNodes(directive.references);
30367
- }
30368
- visitVariable(variable) { }
30369
- visitReference(reference) { }
30370
- visitTextAttribute(attribute) { }
30371
- visitText(text) { }
30372
- visitUnknownBlock(block) { }
30373
- visitAllTemplateNodes(nodes) {
30374
- for (const node of nodes) {
30375
- this.visit(node);
30376
- }
30377
- }
30378
- }
30379
-
30380
30892
  /**
30381
30893
  * Computes a difference between full list (first argument) and
30382
30894
  * list of items that should be excluded from the full list (second
@@ -31699,7 +32211,7 @@ function convertDeclareComponentFacadeToMetadata(decl, typeSourceSpan, sourceMap
31699
32211
  declarations.push(...decl.directives.map((dir) => convertDirectiveDeclarationToMetadata(dir)));
31700
32212
  decl.pipes && declarations.push(...convertPipeMapToMetadata(decl.pipes));
31701
32213
  }
31702
- const hasDirectiveDependencies = declarations.every(({ kind }) => kind === R3TemplateDependencyKind.Directive || kind === R3TemplateDependencyKind.NgModule);
32214
+ const hasDirectiveDependencies = declarations.some(({ kind }) => kind === R3TemplateDependencyKind.Directive || kind === R3TemplateDependencyKind.NgModule);
31703
32215
  return {
31704
32216
  ...convertDeclareDirectiveFacadeToMetadata(decl, typeSourceSpan),
31705
32217
  template,
@@ -33757,7 +34269,7 @@ const MINIMUM_PARTIAL_LINKER_DEFER_SUPPORT_VERSION = '18.0.0';
33757
34269
  function compileDeclareClassMetadata(metadata) {
33758
34270
  const definitionMap = new DefinitionMap();
33759
34271
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
33760
- definitionMap.set('version', literal('20.2.0-next.1'));
34272
+ definitionMap.set('version', literal('20.2.0-next.3'));
33761
34273
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33762
34274
  definitionMap.set('type', metadata.type);
33763
34275
  definitionMap.set('decorators', metadata.decorators);
@@ -33775,7 +34287,7 @@ function compileComponentDeclareClassMetadata(metadata, dependencies) {
33775
34287
  callbackReturnDefinitionMap.set('ctorParameters', metadata.ctorParameters ?? literal(null));
33776
34288
  callbackReturnDefinitionMap.set('propDecorators', metadata.propDecorators ?? literal(null));
33777
34289
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_DEFER_SUPPORT_VERSION));
33778
- definitionMap.set('version', literal('20.2.0-next.1'));
34290
+ definitionMap.set('version', literal('20.2.0-next.3'));
33779
34291
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33780
34292
  definitionMap.set('type', metadata.type);
33781
34293
  definitionMap.set('resolveDeferredDeps', compileComponentMetadataAsyncResolver(dependencies));
@@ -33870,7 +34382,7 @@ function createDirectiveDefinitionMap(meta) {
33870
34382
  const definitionMap = new DefinitionMap();
33871
34383
  const minVersion = getMinimumVersionForPartialOutput(meta);
33872
34384
  definitionMap.set('minVersion', literal(minVersion));
33873
- definitionMap.set('version', literal('20.2.0-next.1'));
34385
+ definitionMap.set('version', literal('20.2.0-next.3'));
33874
34386
  // e.g. `type: MyDirective`
33875
34387
  definitionMap.set('type', meta.type.value);
33876
34388
  if (meta.isStandalone !== undefined) {
@@ -34286,7 +34798,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
34286
34798
  function compileDeclareFactoryFunction(meta) {
34287
34799
  const definitionMap = new DefinitionMap();
34288
34800
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
34289
- definitionMap.set('version', literal('20.2.0-next.1'));
34801
+ definitionMap.set('version', literal('20.2.0-next.3'));
34290
34802
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34291
34803
  definitionMap.set('type', meta.type.value);
34292
34804
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -34321,7 +34833,7 @@ function compileDeclareInjectableFromMetadata(meta) {
34321
34833
  function createInjectableDefinitionMap(meta) {
34322
34834
  const definitionMap = new DefinitionMap();
34323
34835
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
34324
- definitionMap.set('version', literal('20.2.0-next.1'));
34836
+ definitionMap.set('version', literal('20.2.0-next.3'));
34325
34837
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34326
34838
  definitionMap.set('type', meta.type.value);
34327
34839
  // Only generate providedIn property if it has a non-null value
@@ -34372,7 +34884,7 @@ function compileDeclareInjectorFromMetadata(meta) {
34372
34884
  function createInjectorDefinitionMap(meta) {
34373
34885
  const definitionMap = new DefinitionMap();
34374
34886
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
34375
- definitionMap.set('version', literal('20.2.0-next.1'));
34887
+ definitionMap.set('version', literal('20.2.0-next.3'));
34376
34888
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34377
34889
  definitionMap.set('type', meta.type.value);
34378
34890
  definitionMap.set('providers', meta.providers);
@@ -34405,7 +34917,7 @@ function createNgModuleDefinitionMap(meta) {
34405
34917
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
34406
34918
  }
34407
34919
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
34408
- definitionMap.set('version', literal('20.2.0-next.1'));
34920
+ definitionMap.set('version', literal('20.2.0-next.3'));
34409
34921
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34410
34922
  definitionMap.set('type', meta.type.value);
34411
34923
  // We only generate the keys in the metadata if the arrays contain values.
@@ -34456,7 +34968,7 @@ function compileDeclarePipeFromMetadata(meta) {
34456
34968
  function createPipeDefinitionMap(meta) {
34457
34969
  const definitionMap = new DefinitionMap();
34458
34970
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
34459
- definitionMap.set('version', literal('20.2.0-next.1'));
34971
+ definitionMap.set('version', literal('20.2.0-next.3'));
34460
34972
  definitionMap.set('ngImport', importExpr(Identifiers.core));
34461
34973
  // e.g. `type: MyPipe`
34462
34974
  definitionMap.set('type', meta.type.value);
@@ -34612,7 +35124,7 @@ function compileHmrUpdateCallback(definitions, constantStatements, meta) {
34612
35124
  * @description
34613
35125
  * Entry point for all public APIs of the compiler package.
34614
35126
  */
34615
- const VERSION = new Version('20.2.0-next.1');
35127
+ const VERSION = new Version('20.2.0-next.3');
34616
35128
 
34617
35129
  //////////////////////////////////////
34618
35130
  // THIS FILE HAS GLOBAL SIDE EFFECT //