@angular/core 20.2.0-next.0 → 20.2.0-next.2

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 (69) hide show
  1. package/api.d.d.ts +1 -1
  2. package/chrome_dev_tools_performance.d.d.ts +1 -1
  3. package/discovery.d.d.ts +1 -1
  4. package/event_dispatcher.d.d.ts +1 -1
  5. package/fesm2022/attribute.mjs +1 -1
  6. package/fesm2022/attribute.mjs.map +1 -1
  7. package/fesm2022/core.mjs +26 -9
  8. package/fesm2022/core.mjs.map +1 -1
  9. package/fesm2022/debug_node.mjs +647 -15
  10. package/fesm2022/debug_node.mjs.map +1 -1
  11. package/fesm2022/not_found.mjs +1 -1
  12. package/fesm2022/not_found.mjs.map +1 -1
  13. package/fesm2022/primitives/di.mjs +1 -1
  14. package/fesm2022/primitives/di.mjs.map +1 -1
  15. package/fesm2022/primitives/event-dispatch.mjs +1 -1
  16. package/fesm2022/primitives/event-dispatch.mjs.map +1 -1
  17. package/fesm2022/primitives/signals.mjs +1 -1
  18. package/fesm2022/primitives/signals.mjs.map +1 -1
  19. package/fesm2022/resource.mjs +8 -5
  20. package/fesm2022/resource.mjs.map +1 -1
  21. package/fesm2022/root_effect_scheduler.mjs +126 -53
  22. package/fesm2022/root_effect_scheduler.mjs.map +1 -1
  23. package/fesm2022/rxjs-interop.mjs +2 -2
  24. package/fesm2022/rxjs-interop.mjs.map +1 -1
  25. package/fesm2022/signal.mjs +1 -1
  26. package/fesm2022/signal.mjs.map +1 -1
  27. package/fesm2022/testing.mjs +16 -8
  28. package/fesm2022/testing.mjs.map +1 -1
  29. package/fesm2022/untracked.mjs +1 -1
  30. package/fesm2022/untracked.mjs.map +1 -1
  31. package/fesm2022/weak_ref.mjs +1 -1
  32. package/fesm2022/weak_ref.mjs.map +1 -1
  33. package/graph.d.d.ts +1 -1
  34. package/index.d.ts +162 -3
  35. package/package.json +2 -2
  36. package/primitives/di/index.d.ts +1 -1
  37. package/primitives/event-dispatch/index.d.ts +1 -1
  38. package/primitives/signals/index.d.ts +1 -1
  39. package/rxjs-interop/index.d.ts +1 -1
  40. package/schematics/bundles/{apply_import_manager-B0fYYMpr.cjs → apply_import_manager-Bkosyy2x.cjs} +3 -3
  41. package/schematics/bundles/{checker-DLInMAS3.cjs → checker-Cfq29XaS.cjs} +1294 -530
  42. package/schematics/bundles/cleanup-unused-imports.cjs +5 -5
  43. package/schematics/bundles/{compiler_host-Doj9KVJf.cjs → compiler_host-CSrf1kFh.cjs} +2 -2
  44. package/schematics/bundles/control-flow-migration.cjs +3 -3
  45. package/schematics/bundles/document-core.cjs +5 -5
  46. package/schematics/bundles/imports-CIX-JgAN.cjs +1 -1
  47. package/schematics/bundles/{index-BmuUS1AB.cjs → index-DYbdsCUu.cjs} +80 -43
  48. package/schematics/bundles/{index-Bp8sCiq1.cjs → index-DwmX8Ifa.cjs} +4 -4
  49. package/schematics/bundles/inject-flags.cjs +5 -5
  50. package/schematics/bundles/inject-migration.cjs +3 -3
  51. package/schematics/bundles/leading_space-D9nQ8UQC.cjs +1 -1
  52. package/schematics/bundles/{migrate_ts_type_references-CmZ0155c.cjs → migrate_ts_type_references-C7NB9fZH.cjs} +5 -441
  53. package/schematics/bundles/ng_decorators-B5HCqr20.cjs +1 -1
  54. package/schematics/bundles/nodes-B16H9JUd.cjs +1 -1
  55. package/schematics/bundles/output-migration.cjs +6 -6
  56. package/schematics/bundles/{project_paths-D2SJWT7x.cjs → project_paths-5CoqAjNK.cjs} +3 -3
  57. package/schematics/bundles/project_tsconfig_paths-CDVxT6Ov.cjs +1 -1
  58. package/schematics/bundles/property_name-BBwFuqMe.cjs +1 -1
  59. package/schematics/bundles/route-lazy-loading.cjs +3 -3
  60. package/schematics/bundles/self-closing-tags-migration.cjs +4 -4
  61. package/schematics/bundles/signal-input-migration.cjs +8 -8
  62. package/schematics/bundles/signal-queries-migration.cjs +7 -7
  63. package/schematics/bundles/signals.cjs +7 -7
  64. package/schematics/bundles/standalone-migration.cjs +4 -4
  65. package/schematics/bundles/symbol-VPWguRxr.cjs +1 -1
  66. package/schematics/bundles/test-bed-get.cjs +4 -4
  67. package/signal.d.d.ts +1 -1
  68. package/testing/index.d.ts +12 -2
  69. package/weak_ref.d.d.ts +1 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v20.2.0-next.0
3
+ * @license Angular v20.2.0-next.2
4
4
  * (c) 2010-2025 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
@@ -2693,7 +2693,18 @@ class Identifiers {
2693
2693
  static pipeBind4 = { name: 'ɵɵpipeBind4', moduleName: CORE };
2694
2694
  static pipeBindV = { name: 'ɵɵpipeBindV', moduleName: CORE };
2695
2695
  static domProperty = { name: 'ɵɵdomProperty', moduleName: CORE };
2696
+ static ariaProperty = { name: 'ɵɵariaProperty', moduleName: CORE };
2696
2697
  static property = { name: 'ɵɵproperty', moduleName: CORE };
2698
+ static animationEnterListener = {
2699
+ name: 'ɵɵanimateEnterListener',
2700
+ moduleName: CORE,
2701
+ };
2702
+ static animationLeaveListener = {
2703
+ name: 'ɵɵanimateLeaveListener',
2704
+ moduleName: CORE,
2705
+ };
2706
+ static animationEnter = { name: 'ɵɵanimateEnter', moduleName: CORE };
2707
+ static animationLeave = { name: 'ɵɵanimateLeave', moduleName: CORE };
2697
2708
  static i18n = { name: 'ɵɵi18n', moduleName: CORE };
2698
2709
  static i18nAttributes = { name: 'ɵɵi18nAttributes', moduleName: CORE };
2699
2710
  static i18nExp = { name: 'ɵɵi18nExp', moduleName: CORE };
@@ -2837,6 +2848,10 @@ class Identifiers {
2837
2848
  name: 'ɵɵExternalStylesFeature',
2838
2849
  moduleName: CORE,
2839
2850
  };
2851
+ static AnimationsFeature = {
2852
+ name: 'ɵɵAnimationsFeature',
2853
+ moduleName: CORE,
2854
+ };
2840
2855
  static listener = { name: 'ɵɵlistener', moduleName: CORE };
2841
2856
  static getInheritedFactory = {
2842
2857
  name: 'ɵɵgetInheritedFactory',
@@ -2868,6 +2883,7 @@ class Identifiers {
2868
2883
  static InputSignalBrandWriteType = { name: 'ɵINPUT_SIGNAL_BRAND_WRITE_TYPE', moduleName: CORE };
2869
2884
  static UnwrapDirectiveSignalInputs = { name: 'ɵUnwrapDirectiveSignalInputs', moduleName: CORE };
2870
2885
  static unwrapWritableSignal = { name: 'ɵunwrapWritableSignal', moduleName: CORE };
2886
+ static assertType = { name: 'ɵassertType', moduleName: CORE };
2871
2887
  }
2872
2888
 
2873
2889
  const DASH_CASE_REGEXP = /-+([a-z0-9])/g;
@@ -4411,6 +4427,7 @@ class ParsedProperty {
4411
4427
  valueSpan;
4412
4428
  isLiteral;
4413
4429
  isLegacyAnimation;
4430
+ isAnimation;
4414
4431
  constructor(name, expression, type, sourceSpan, keySpan, valueSpan) {
4415
4432
  this.name = name;
4416
4433
  this.expression = expression;
@@ -4420,6 +4437,7 @@ class ParsedProperty {
4420
4437
  this.valueSpan = valueSpan;
4421
4438
  this.isLiteral = this.type === ParsedPropertyType.LITERAL_ATTR;
4422
4439
  this.isLegacyAnimation = this.type === ParsedPropertyType.LEGACY_ANIMATION;
4440
+ this.isAnimation = this.type === ParsedPropertyType.ANIMATION;
4423
4441
  }
4424
4442
  }
4425
4443
  var ParsedPropertyType;
@@ -4428,6 +4446,7 @@ var ParsedPropertyType;
4428
4446
  ParsedPropertyType[ParsedPropertyType["LITERAL_ATTR"] = 1] = "LITERAL_ATTR";
4429
4447
  ParsedPropertyType[ParsedPropertyType["LEGACY_ANIMATION"] = 2] = "LEGACY_ANIMATION";
4430
4448
  ParsedPropertyType[ParsedPropertyType["TWO_WAY"] = 3] = "TWO_WAY";
4449
+ ParsedPropertyType[ParsedPropertyType["ANIMATION"] = 4] = "ANIMATION";
4431
4450
  })(ParsedPropertyType || (ParsedPropertyType = {}));
4432
4451
  exports.ParsedEventType = void 0;
4433
4452
  (function (ParsedEventType) {
@@ -4437,6 +4456,8 @@ exports.ParsedEventType = void 0;
4437
4456
  ParsedEventType[ParsedEventType["LegacyAnimation"] = 1] = "LegacyAnimation";
4438
4457
  // Event side of a two-way binding (e.g. `[(property)]="expression"`).
4439
4458
  ParsedEventType[ParsedEventType["TwoWay"] = 2] = "TwoWay";
4459
+ // Animation specific event
4460
+ ParsedEventType[ParsedEventType["Animation"] = 3] = "Animation";
4440
4461
  })(exports.ParsedEventType || (exports.ParsedEventType = {}));
4441
4462
  class ParsedEvent {
4442
4463
  name;
@@ -4487,6 +4508,8 @@ exports.BindingType = void 0;
4487
4508
  BindingType[BindingType["LegacyAnimation"] = 4] = "LegacyAnimation";
4488
4509
  // Property side of a two-way binding (e.g. `[(property)]="expression"`).
4489
4510
  BindingType[BindingType["TwoWay"] = 5] = "TwoWay";
4511
+ // A binding to an animation CSS class or function (e.g. `[animate.leave]="expression"`).
4512
+ BindingType[BindingType["Animation"] = 6] = "Animation";
4490
4513
  })(exports.BindingType || (exports.BindingType = {}));
4491
4514
  class BoundElementProperty {
4492
4515
  name;
@@ -4689,8 +4712,9 @@ let Element$1 = class Element {
4689
4712
  sourceSpan;
4690
4713
  startSourceSpan;
4691
4714
  endSourceSpan;
4715
+ isVoid;
4692
4716
  i18n;
4693
- constructor(name, attributes, inputs, outputs, directives, children, references, isSelfClosing, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
4717
+ constructor(name, attributes, inputs, outputs, directives, children, references, isSelfClosing, sourceSpan, startSourceSpan, endSourceSpan, isVoid, i18n) {
4694
4718
  this.name = name;
4695
4719
  this.attributes = attributes;
4696
4720
  this.inputs = inputs;
@@ -4702,6 +4726,7 @@ let Element$1 = class Element {
4702
4726
  this.sourceSpan = sourceSpan;
4703
4727
  this.startSourceSpan = startSourceSpan;
4704
4728
  this.endSourceSpan = endSourceSpan;
4729
+ this.isVoid = isVoid;
4705
4730
  this.i18n = i18n;
4706
4731
  }
4707
4732
  visit(visitor) {
@@ -8615,6 +8640,22 @@ var OpKind;
8615
8640
  * Creation op that attaches the location at which an element was defined in a template to it.
8616
8641
  */
8617
8642
  OpKind[OpKind["SourceLocation"] = 52] = "SourceLocation";
8643
+ /**
8644
+ * An operation to bind animation css classes to an element.
8645
+ */
8646
+ OpKind[OpKind["Animation"] = 53] = "Animation";
8647
+ /**
8648
+ * An operation to bind animation css classes to an element.
8649
+ */
8650
+ OpKind[OpKind["AnimationString"] = 54] = "AnimationString";
8651
+ /**
8652
+ * An operation to bind animation css classes to an element.
8653
+ */
8654
+ OpKind[OpKind["AnimationBinding"] = 55] = "AnimationBinding";
8655
+ /**
8656
+ * An operation to bind animation events to an element.
8657
+ */
8658
+ OpKind[OpKind["AnimationListener"] = 56] = "AnimationListener";
8618
8659
  })(OpKind || (OpKind = {}));
8619
8660
  /**
8620
8661
  * Distinguishes different kinds of IR expressions.
@@ -8805,6 +8846,10 @@ var BindingKind;
8805
8846
  * Property side of a two-way binding.
8806
8847
  */
8807
8848
  BindingKind[BindingKind["TwoWayProperty"] = 7] = "TwoWayProperty";
8849
+ /**
8850
+ * Property side of an animation binding.
8851
+ */
8852
+ BindingKind[BindingKind["Animation"] = 8] = "Animation";
8808
8853
  })(BindingKind || (BindingKind = {}));
8809
8854
  /**
8810
8855
  * Enumeration of possible times i18n params can be resolved.
@@ -9045,13 +9090,13 @@ function createBindingOp(target, kind, name, expression, unit, securityContext,
9045
9090
  /**
9046
9091
  * Create a `PropertyOp`.
9047
9092
  */
9048
- function createPropertyOp(target, name, expression, isLegacyAnimationTrigger, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
9093
+ function createPropertyOp(target, name, expression, bindingKind, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
9049
9094
  return {
9050
9095
  kind: OpKind.Property,
9051
9096
  target,
9052
9097
  name,
9053
9098
  expression,
9054
- isLegacyAnimationTrigger,
9099
+ bindingKind,
9055
9100
  securityContext,
9056
9101
  sanitizer: null,
9057
9102
  isStructuralTemplateAttribute,
@@ -9202,6 +9247,24 @@ function createRepeaterOp(repeaterCreate, targetSlot, collection, sourceSpan) {
9202
9247
  ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
9203
9248
  };
9204
9249
  }
9250
+ /**
9251
+ * Create an `AnimationBindingOp`.
9252
+ */
9253
+ function createAnimationBindingOp(name, target, animationKind, expression, securityContext, sourceSpan, animationBindingKind) {
9254
+ return {
9255
+ kind: OpKind.AnimationBinding,
9256
+ name,
9257
+ target,
9258
+ animationKind,
9259
+ expression,
9260
+ i18nMessage: null,
9261
+ securityContext,
9262
+ sanitizer: null,
9263
+ sourceSpan,
9264
+ animationBindingKind,
9265
+ ...NEW_OP,
9266
+ };
9267
+ }
9205
9268
  function createDeferWhenOp(target, expr, modifier, sourceSpan) {
9206
9269
  return {
9207
9270
  kind: OpKind.DeferWhen,
@@ -10032,6 +10095,8 @@ function transformExpressionsInOp(op, transform, flags) {
10032
10095
  case OpKind.StyleMap:
10033
10096
  case OpKind.ClassProp:
10034
10097
  case OpKind.ClassMap:
10098
+ case OpKind.AnimationString:
10099
+ case OpKind.AnimationBinding:
10035
10100
  case OpKind.Binding:
10036
10101
  if (op.expression instanceof Interpolation) {
10037
10102
  transformExpressionsInInterpolation(op.expression, transform, flags);
@@ -10084,6 +10149,8 @@ function transformExpressionsInOp(op, transform, flags) {
10084
10149
  op.contextValue = transformExpressionsInExpression(op.contextValue, transform, flags);
10085
10150
  }
10086
10151
  break;
10152
+ case OpKind.Animation:
10153
+ case OpKind.AnimationListener:
10087
10154
  case OpKind.Listener:
10088
10155
  case OpKind.TwoWayListener:
10089
10156
  for (const innerOp of op.handlerOps) {
@@ -10735,6 +10802,43 @@ function createTextOp(xref, initialValue, icuPlaceholder, sourceSpan) {
10735
10802
  ...NEW_OP,
10736
10803
  };
10737
10804
  }
10805
+ /**
10806
+ * Create an `AnimationOp`.
10807
+ */
10808
+ function createAnimationStringOp(name, target, animationKind, expression, securityContext, sourceSpan) {
10809
+ return {
10810
+ kind: OpKind.AnimationString,
10811
+ name,
10812
+ target,
10813
+ animationKind,
10814
+ expression,
10815
+ i18nMessage: null,
10816
+ securityContext,
10817
+ sanitizer: null,
10818
+ sourceSpan,
10819
+ ...NEW_OP,
10820
+ };
10821
+ }
10822
+ /**
10823
+ * Create an `AnimationOp`.
10824
+ */
10825
+ function createAnimationOp(name, target, animationKind, callbackOps, securityContext, sourceSpan) {
10826
+ const handlerOps = new OpList();
10827
+ handlerOps.push(callbackOps);
10828
+ return {
10829
+ kind: OpKind.Animation,
10830
+ name,
10831
+ target,
10832
+ animationKind,
10833
+ handlerOps,
10834
+ handlerFnName: null,
10835
+ i18nMessage: null,
10836
+ securityContext,
10837
+ sanitizer: null,
10838
+ sourceSpan,
10839
+ ...NEW_OP,
10840
+ };
10841
+ }
10738
10842
  /**
10739
10843
  * Create a `ListenerOp`. Host bindings reuse all the listener logic.
10740
10844
  */
@@ -10758,6 +10862,28 @@ function createListenerOp(target, targetSlot, name, tag, handlerOps, legacyAnima
10758
10862
  ...NEW_OP,
10759
10863
  };
10760
10864
  }
10865
+ /**
10866
+ * Create a `ListenerOp`. Host bindings reuse all the listener logic.
10867
+ */
10868
+ function createAnimationListenerOp(target, targetSlot, name, tag, handlerOps, animationKind, eventTarget, hostListener, sourceSpan) {
10869
+ const handlerList = new OpList();
10870
+ handlerList.push(handlerOps);
10871
+ return {
10872
+ kind: OpKind.AnimationListener,
10873
+ target,
10874
+ targetSlot,
10875
+ tag,
10876
+ hostListener,
10877
+ name,
10878
+ animationKind,
10879
+ handlerOps: handlerList,
10880
+ handlerFnName: null,
10881
+ consumesDollarEvent: false,
10882
+ eventTarget,
10883
+ sourceSpan,
10884
+ ...NEW_OP,
10885
+ };
10886
+ }
10761
10887
  /**
10762
10888
  * Create a `TwoWayListenerOp`.
10763
10889
  */
@@ -11007,12 +11133,12 @@ function createSourceLocationOp(templatePath, locations) {
11007
11133
  };
11008
11134
  }
11009
11135
 
11010
- function createDomPropertyOp(name, expression, isLegacyAnimationTrigger, i18nContext, securityContext, sourceSpan) {
11136
+ function createDomPropertyOp(name, expression, bindingKind, i18nContext, securityContext, sourceSpan) {
11011
11137
  return {
11012
11138
  kind: OpKind.DomProperty,
11013
11139
  name,
11014
11140
  expression,
11015
- isLegacyAnimationTrigger,
11141
+ bindingKind,
11016
11142
  i18nContext,
11017
11143
  securityContext,
11018
11144
  sanitizer: null,
@@ -11179,7 +11305,10 @@ class CompilationUnit {
11179
11305
  *ops() {
11180
11306
  for (const op of this.create) {
11181
11307
  yield op;
11182
- if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
11308
+ if (op.kind === OpKind.Listener ||
11309
+ op.kind === OpKind.Animation ||
11310
+ op.kind === OpKind.AnimationListener ||
11311
+ op.kind === OpKind.TwoWayListener) {
11183
11312
  for (const listenerOp of op.handlerOps) {
11184
11313
  yield listenerOp;
11185
11314
  }
@@ -11459,7 +11588,8 @@ function extractAttributes(job) {
11459
11588
  extractAttributeOp(unit, op, elements);
11460
11589
  break;
11461
11590
  case OpKind.Property:
11462
- if (!op.isLegacyAnimationTrigger) {
11591
+ if (op.bindingKind !== BindingKind.LegacyAnimation &&
11592
+ op.bindingKind !== BindingKind.Animation) {
11463
11593
  let bindingKind;
11464
11594
  if (op.i18nMessage !== null && op.templateKind === null) {
11465
11595
  // If the binding has an i18n context, it is an i18n attribute, and should have that
@@ -11477,14 +11607,14 @@ function extractAttributes(job) {
11477
11607
  createExtractedAttributeOp(op.target, bindingKind, null, op.name,
11478
11608
  /* expression */ null,
11479
11609
  /* i18nContext */ null,
11480
- /* i18nMessage */ null, op.securityContext), lookupElement$2(elements, op.target));
11610
+ /* i18nMessage */ null, op.securityContext), lookupElement$3(elements, op.target));
11481
11611
  }
11482
11612
  break;
11483
11613
  case OpKind.TwoWayProperty:
11484
11614
  OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.TwoWayProperty, null, op.name,
11485
11615
  /* expression */ null,
11486
11616
  /* i18nContext */ null,
11487
- /* i18nMessage */ null, op.securityContext), lookupElement$2(elements, op.target));
11617
+ /* i18nMessage */ null, op.securityContext), lookupElement$3(elements, op.target));
11488
11618
  break;
11489
11619
  case OpKind.StyleProp:
11490
11620
  case OpKind.ClassProp:
@@ -11497,7 +11627,7 @@ function extractAttributes(job) {
11497
11627
  OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name,
11498
11628
  /* expression */ null,
11499
11629
  /* i18nContext */ null,
11500
- /* i18nMessage */ null, SecurityContext.STYLE), lookupElement$2(elements, op.target));
11630
+ /* i18nMessage */ null, SecurityContext.STYLE), lookupElement$3(elements, op.target));
11501
11631
  }
11502
11632
  break;
11503
11633
  case OpKind.Listener:
@@ -11517,7 +11647,7 @@ function extractAttributes(job) {
11517
11647
  unit.create.push(extractedAttributeOp);
11518
11648
  }
11519
11649
  else {
11520
- OpList.insertBefore(extractedAttributeOp, lookupElement$2(elements, op.target));
11650
+ OpList.insertBefore(extractedAttributeOp, lookupElement$3(elements, op.target));
11521
11651
  }
11522
11652
  }
11523
11653
  break;
@@ -11528,7 +11658,7 @@ function extractAttributes(job) {
11528
11658
  /* expression */ null,
11529
11659
  /* i18nContext */ null,
11530
11660
  /* i18nMessage */ null, SecurityContext.NONE);
11531
- OpList.insertBefore(extractedAttributeOp, lookupElement$2(elements, op.target));
11661
+ OpList.insertBefore(extractedAttributeOp, lookupElement$3(elements, op.target));
11532
11662
  }
11533
11663
  break;
11534
11664
  }
@@ -11538,7 +11668,7 @@ function extractAttributes(job) {
11538
11668
  /**
11539
11669
  * Looks up an element in the given map by xref ID.
11540
11670
  */
11541
- function lookupElement$2(elements, xref) {
11671
+ function lookupElement$3(elements, xref) {
11542
11672
  const el = elements.get(xref);
11543
11673
  if (el === undefined) {
11544
11674
  throw new Error('All attributes should have an element-like target.');
@@ -11566,7 +11696,7 @@ function extractAttributeOp(unit, op, elements) {
11566
11696
  unit.create.push(extractedAttributeOp);
11567
11697
  }
11568
11698
  else {
11569
- const ownerOp = lookupElement$2(elements, op.target);
11699
+ const ownerOp = lookupElement$3(elements, op.target);
11570
11700
  OpList.insertBefore(extractedAttributeOp, ownerOp);
11571
11701
  }
11572
11702
  OpList.remove(op);
@@ -11576,7 +11706,7 @@ function extractAttributeOp(unit, op, elements) {
11576
11706
  /**
11577
11707
  * Looks up an element in the given map by xref ID.
11578
11708
  */
11579
- function lookupElement$1(elements, xref) {
11709
+ function lookupElement$2(elements, xref) {
11580
11710
  const el = elements.get(xref);
11581
11711
  if (el === undefined) {
11582
11712
  throw new Error('All attributes should have an element-like target.');
@@ -11602,21 +11732,27 @@ function specializeBindings(job) {
11602
11732
  case BindingKind.Attribute:
11603
11733
  if (op.name === 'ngNonBindable') {
11604
11734
  OpList.remove(op);
11605
- const target = lookupElement$1(elements, op.target);
11735
+ const target = lookupElement$2(elements, op.target);
11606
11736
  target.nonBindable = true;
11607
11737
  }
11738
+ else if (op.name.startsWith('animate.')) {
11739
+ 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 */));
11740
+ }
11608
11741
  else {
11609
11742
  const [namespace, name] = splitNsName(op.name);
11610
11743
  OpList.replace(op, createAttributeOp(op.target, namespace, name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplateAttribute, op.templateKind, op.i18nMessage, op.sourceSpan));
11611
11744
  }
11612
11745
  break;
11746
+ case BindingKind.Animation:
11747
+ 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 */));
11748
+ break;
11613
11749
  case BindingKind.Property:
11614
11750
  case BindingKind.LegacyAnimation:
11615
11751
  if (job.kind === CompilationJobKind.Host) {
11616
- OpList.replace(op, createDomPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.LegacyAnimation, op.i18nContext, op.securityContext, op.sourceSpan));
11752
+ OpList.replace(op, createDomPropertyOp(op.name, op.expression, op.bindingKind, op.i18nContext, op.securityContext, op.sourceSpan));
11617
11753
  }
11618
11754
  else {
11619
- 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));
11755
+ OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
11620
11756
  }
11621
11757
  break;
11622
11758
  case BindingKind.TwoWayProperty:
@@ -11638,6 +11774,7 @@ function specializeBindings(job) {
11638
11774
  }
11639
11775
 
11640
11776
  const CHAIN_COMPATIBILITY = new Map([
11777
+ [Identifiers.ariaProperty, Identifiers.ariaProperty],
11641
11778
  [Identifiers.attribute, Identifiers.attribute],
11642
11779
  [Identifiers.classProp, Identifiers.classProp],
11643
11780
  [Identifiers.element, Identifiers.element],
@@ -11668,6 +11805,10 @@ const CHAIN_COMPATIBILITY = new Map([
11668
11805
  [Identifiers.domElementContainerEnd, Identifiers.domElementContainerEnd],
11669
11806
  [Identifiers.domListener, Identifiers.domListener],
11670
11807
  [Identifiers.domTemplate, Identifiers.domTemplate],
11808
+ [Identifiers.animationEnter, Identifiers.animationEnter],
11809
+ [Identifiers.animationLeave, Identifiers.animationLeave],
11810
+ [Identifiers.animationEnterListener, Identifiers.animationEnterListener],
11811
+ [Identifiers.animationLeaveListener, Identifiers.animationLeaveListener],
11671
11812
  ]);
11672
11813
  /**
11673
11814
  * Chaining results in repeated call expressions, causing a deep AST of receiver expressions. To prevent running out of
@@ -12088,6 +12229,52 @@ function serializeAttributes({ attributes, bindings, classes, i18n, projectAs, s
12088
12229
  return literalArr(attrArray);
12089
12230
  }
12090
12231
 
12232
+ /**
12233
+ * Looks up an element in the given map by xref ID.
12234
+ */
12235
+ function lookupElement$1(elements, xref) {
12236
+ const el = elements.get(xref);
12237
+ if (el === undefined) {
12238
+ throw new Error('All attributes should have an element-like target.');
12239
+ }
12240
+ return el;
12241
+ }
12242
+ function convertAnimations(job) {
12243
+ const elements = new Map();
12244
+ for (const unit of job.units) {
12245
+ for (const op of unit.create) {
12246
+ if (!isElementOrContainerOp(op)) {
12247
+ continue;
12248
+ }
12249
+ elements.set(op.xref, op);
12250
+ }
12251
+ }
12252
+ for (const unit of job.units) {
12253
+ for (const op of unit.ops()) {
12254
+ if (op.kind === OpKind.AnimationBinding) {
12255
+ const createAnimationOp = getAnimationOp(op);
12256
+ if (job.kind === CompilationJobKind.Host) {
12257
+ unit.create.push(createAnimationOp);
12258
+ }
12259
+ else {
12260
+ OpList.insertAfter(createAnimationOp, lookupElement$1(elements, op.target));
12261
+ }
12262
+ OpList.remove(op);
12263
+ }
12264
+ }
12265
+ }
12266
+ }
12267
+ function getAnimationOp(op) {
12268
+ if (op.animationBindingKind === 0 /* ir.AnimationBindingKind.STRING */) {
12269
+ // this is a simple string case
12270
+ return createAnimationStringOp(op.name, op.target, op.name === 'animate.enter' ? "enter" /* ir.AnimationKind.ENTER */ : "leave" /* ir.AnimationKind.LEAVE */, op.expression, op.securityContext, op.sourceSpan);
12271
+ }
12272
+ else {
12273
+ const expression = op.expression;
12274
+ 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);
12275
+ }
12276
+ }
12277
+
12091
12278
  /**
12092
12279
  * Some binding instructions in the update block may actually correspond to i18n bindings. In that
12093
12280
  * case, they should be replaced with i18nExp instructions for the dynamic portions.
@@ -12985,6 +13172,8 @@ function recursivelyProcessView(view, parentScope) {
12985
13172
  op.trackByOps.prepend(generateVariablesInScopeForView(view, scope, false));
12986
13173
  }
12987
13174
  break;
13175
+ case OpKind.Animation:
13176
+ case OpKind.AnimationListener:
12988
13177
  case OpKind.Listener:
12989
13178
  case OpKind.TwoWayListener:
12990
13179
  // Prepend variables to listener handler functions.
@@ -13067,7 +13256,7 @@ function getScopeForView(view, parent) {
13067
13256
  * This is a recursive process, as views inherit variables available from their parent view, which
13068
13257
  * itself may have inherited variables, etc.
13069
13258
  */
13070
- function generateVariablesInScopeForView(view, scope, isListener) {
13259
+ function generateVariablesInScopeForView(view, scope, isCallback) {
13071
13260
  const newOps = [];
13072
13261
  if (scope.view !== view.xref) {
13073
13262
  // Before generating variables for a parent view, we need to switch to the context of the parent
@@ -13091,7 +13280,7 @@ function generateVariablesInScopeForView(view, scope, isListener) {
13091
13280
  for (const ref of scope.references) {
13092
13281
  newOps.push(createVariableOp(view.job.allocateXrefId(), ref.variable, new ReferenceExpr(ref.targetId, ref.targetSlot, ref.offset), VariableFlags.None));
13093
13282
  }
13094
- if (scope.view !== view.xref || isListener) {
13283
+ if (scope.view !== view.xref || isCallback) {
13095
13284
  for (const decl of scope.letDeclarations) {
13096
13285
  newOps.push(createVariableOp(view.job.allocateXrefId(), decl.variable, new ContextLetReferenceExpr(decl.targetId, decl.targetSlot), VariableFlags.None));
13097
13286
  }
@@ -13321,7 +13510,8 @@ class Element extends NodeWithI18n {
13321
13510
  isSelfClosing;
13322
13511
  startSourceSpan;
13323
13512
  endSourceSpan;
13324
- constructor(name, attrs, directives, children, isSelfClosing, sourceSpan, startSourceSpan, endSourceSpan = null, i18n) {
13513
+ isVoid;
13514
+ constructor(name, attrs, directives, children, isSelfClosing, sourceSpan, startSourceSpan, endSourceSpan = null, isVoid, i18n) {
13325
13515
  super(sourceSpan, i18n);
13326
13516
  this.name = name;
13327
13517
  this.attrs = attrs;
@@ -13330,6 +13520,7 @@ class Element extends NodeWithI18n {
13330
13520
  this.isSelfClosing = isSelfClosing;
13331
13521
  this.startSourceSpan = startSourceSpan;
13332
13522
  this.endSourceSpan = endSourceSpan;
13523
+ this.isVoid = isVoid;
13333
13524
  }
13334
13525
  visit(visitor, context) {
13335
13526
  return visitor.visitElement(this, context);
@@ -15667,6 +15858,19 @@ var CharacterReferenceType;
15667
15858
  CharacterReferenceType["HEX"] = "hexadecimal";
15668
15859
  CharacterReferenceType["DEC"] = "decimal";
15669
15860
  })(CharacterReferenceType || (CharacterReferenceType = {}));
15861
+ const SUPPORTED_BLOCKS = [
15862
+ '@if',
15863
+ '@else', // Covers `@else if` as well
15864
+ '@for',
15865
+ '@switch',
15866
+ '@case',
15867
+ '@default',
15868
+ '@empty',
15869
+ '@defer',
15870
+ '@placeholder',
15871
+ '@loading',
15872
+ '@error',
15873
+ ];
15670
15874
  // See https://www.w3.org/TR/html51/syntax.html#writing-html-documents
15671
15875
  class _Tokenizer {
15672
15876
  _getTagDefinition;
@@ -15757,10 +15961,10 @@ class _Tokenizer {
15757
15961
  // don't want to advance in case it's not `@let`.
15758
15962
  this._cursor.peek() === $AT &&
15759
15963
  !this._inInterpolation &&
15760
- this._attemptStr('@let')) {
15964
+ this._isLetStart()) {
15761
15965
  this._consumeLetDeclaration(start);
15762
15966
  }
15763
- else if (this._tokenizeBlocks && this._attemptCharCode($AT)) {
15967
+ else if (this._tokenizeBlocks && this._isBlockStart()) {
15764
15968
  this._consumeBlockStart(start);
15765
15969
  }
15766
15970
  else if (this._tokenizeBlocks &&
@@ -15800,6 +16004,7 @@ class _Tokenizer {
15800
16004
  return this._cursor.getChars(nameCursor).trim();
15801
16005
  }
15802
16006
  _consumeBlockStart(start) {
16007
+ this._requireCharCode($AT);
15803
16008
  this._beginToken(24 /* TokenType.BLOCK_OPEN_START */, start);
15804
16009
  const startToken = this._endToken([this._getBlockName()]);
15805
16010
  if (this._cursor.peek() === $LPAREN) {
@@ -15872,6 +16077,7 @@ class _Tokenizer {
15872
16077
  }
15873
16078
  }
15874
16079
  _consumeLetDeclaration(start) {
16080
+ this._requireStr('@let');
15875
16081
  this._beginToken(29 /* TokenType.LET_START */, start);
15876
16082
  // Require at least one white space after the `@let`.
15877
16083
  if (isWhitespace(this._cursor.peek())) {
@@ -16085,6 +16291,27 @@ class _Tokenizer {
16085
16291
  this._cursor.advance();
16086
16292
  return char;
16087
16293
  }
16294
+ _peekStr(chars) {
16295
+ const len = chars.length;
16296
+ if (this._cursor.charsLeft() < len) {
16297
+ return false;
16298
+ }
16299
+ const cursor = this._cursor.clone();
16300
+ for (let i = 0; i < len; i++) {
16301
+ if (cursor.peek() !== chars.charCodeAt(i)) {
16302
+ return false;
16303
+ }
16304
+ cursor.advance();
16305
+ }
16306
+ return true;
16307
+ }
16308
+ _isBlockStart() {
16309
+ return (this._cursor.peek() === $AT &&
16310
+ SUPPORTED_BLOCKS.some((blockName) => this._peekStr(blockName)));
16311
+ }
16312
+ _isLetStart() {
16313
+ return this._cursor.peek() === $AT && this._peekStr('@let');
16314
+ }
16088
16315
  _consumeEntity(textTokenType) {
16089
16316
  this._beginToken(9 /* TokenType.ENCODED_ENTITY */);
16090
16317
  const start = this._cursor.clone();
@@ -16352,6 +16579,23 @@ class _Tokenizer {
16352
16579
  return isNameEnd(code);
16353
16580
  };
16354
16581
  }
16582
+ else if (attrNameStart === $LBRACKET) {
16583
+ let openBrackets = 0;
16584
+ // Be more permissive for which characters are allowed inside square-bracketed attributes,
16585
+ // because they usually end up being bound as attribute values. Some third-party packages
16586
+ // like Tailwind take advantage of this.
16587
+ nameEndPredicate = (code) => {
16588
+ if (code === $LBRACKET) {
16589
+ openBrackets++;
16590
+ }
16591
+ else if (code === $RBRACKET) {
16592
+ openBrackets--;
16593
+ }
16594
+ // Only check for name-ending characters if the brackets are balanced or mismatched.
16595
+ // Also interrupt the matching on new lines.
16596
+ return openBrackets <= 0 ? isNameEnd(code) : isNewLine(code);
16597
+ };
16598
+ }
16355
16599
  else {
16356
16600
  nameEndPredicate = isNameEnd;
16357
16601
  }
@@ -16631,7 +16875,7 @@ class _Tokenizer {
16631
16875
  if (this._tokenizeBlocks &&
16632
16876
  !this._inInterpolation &&
16633
16877
  !this._isInExpansion() &&
16634
- (this._cursor.peek() === $AT || this._cursor.peek() === $RBRACE)) {
16878
+ (this._isBlockStart() || this._isLetStart() || this._cursor.peek() === $RBRACE)) {
16635
16879
  return true;
16636
16880
  }
16637
16881
  return false;
@@ -17268,13 +17512,13 @@ class _TreeBuilder {
17268
17512
  const directives = [];
17269
17513
  this._consumeAttributesAndDirectives(attrs, directives);
17270
17514
  const fullName = this._getElementFullName(startTagToken, this._getClosestElementLikeParent());
17515
+ const tagDef = this._getTagDefinition(fullName);
17271
17516
  let selfClosing = false;
17272
17517
  // Note: There could have been a tokenizer error
17273
17518
  // so that we don't get a token for the end tag...
17274
17519
  if (this._peek.type === 2 /* TokenType.TAG_OPEN_END_VOID */) {
17275
17520
  this._advance();
17276
17521
  selfClosing = true;
17277
- const tagDef = this._getTagDefinition(fullName);
17278
17522
  if (!(tagDef?.canSelfClose || getNsPrefix(fullName) !== null || tagDef?.isVoid)) {
17279
17523
  this.errors.push(TreeError.create(fullName, startTagToken.sourceSpan, `Only void, custom and foreign elements can be self closed "${startTagToken.parts[1]}"`));
17280
17524
  }
@@ -17287,7 +17531,7 @@ class _TreeBuilder {
17287
17531
  const span = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
17288
17532
  // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
17289
17533
  const startSpan = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
17290
- const el = new Element(fullName, attrs, directives, [], selfClosing, span, startSpan, undefined);
17534
+ const el = new Element(fullName, attrs, directives, [], selfClosing, span, startSpan, undefined, tagDef?.isVoid ?? false);
17291
17535
  const parent = this._getContainer();
17292
17536
  const isClosedByChild = parent !== null && !!this._getTagDefinition(parent)?.isClosedByChild(el.name);
17293
17537
  this._pushContainer(el, isClosedByChild);
@@ -17730,11 +17974,11 @@ class WhitespaceVisitor {
17730
17974
  if (SKIP_WS_TRIM_TAGS.has(element.name) || hasPreserveWhitespacesAttr(element.attrs)) {
17731
17975
  // don't descent into elements where we need to preserve whitespaces
17732
17976
  // but still visit all attributes to eliminate one used as a market to preserve WS
17733
- const newElement = new Element(element.name, visitAllWithSiblings(this, element.attrs), visitAllWithSiblings(this, element.directives), element.children, element.isSelfClosing, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
17977
+ const newElement = new Element(element.name, visitAllWithSiblings(this, element.attrs), visitAllWithSiblings(this, element.directives), element.children, element.isSelfClosing, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.isVoid, element.i18n);
17734
17978
  this.originalNodeMap?.set(newElement, element);
17735
17979
  return newElement;
17736
17980
  }
17737
- const newElement = new Element(element.name, element.attrs, element.directives, visitAllWithSiblings(this, element.children), element.isSelfClosing, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
17981
+ const newElement = new Element(element.name, element.attrs, element.directives, visitAllWithSiblings(this, element.children), element.isSelfClosing, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.isVoid, element.i18n);
17738
17982
  this.originalNodeMap?.set(newElement, element);
17739
17983
  return newElement;
17740
17984
  }
@@ -19381,12 +19625,13 @@ class _ParseAST {
19381
19625
  else {
19382
19626
  if (this.isAssignmentOperator(this.next)) {
19383
19627
  const operation = this.next.strValue;
19384
- this.advance();
19385
19628
  if (!(this.parseFlags & 1 /* ParseFlags.Action */)) {
19629
+ this.advance();
19386
19630
  this.error('Bindings cannot contain assignments');
19387
19631
  return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
19388
19632
  }
19389
19633
  const receiver = new PropertyRead(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id);
19634
+ this.advance();
19390
19635
  const value = this.parseConditional();
19391
19636
  return new Binary(this.span(start), this.sourceSpan(start), operation, receiver, value);
19392
19637
  }
@@ -19505,12 +19750,13 @@ class _ParseAST {
19505
19750
  this.expectCharacter($RBRACKET);
19506
19751
  if (this.isAssignmentOperator(this.next)) {
19507
19752
  const operation = this.next.strValue;
19508
- this.advance();
19509
19753
  if (isSafe) {
19754
+ this.advance();
19510
19755
  this.error("The '?.' operator cannot be used in the assignment");
19511
19756
  }
19512
19757
  else {
19513
19758
  const binaryReceiver = new KeyedRead(this.span(start), this.sourceSpan(start), receiver, key);
19759
+ this.advance();
19514
19760
  const value = this.parseConditional();
19515
19761
  return new Binary(this.span(start), this.sourceSpan(start), operation, binaryReceiver, value);
19516
19762
  }
@@ -20273,6 +20519,44 @@ const _ATTR_TO_PROP = new Map(Object.entries({
20273
20519
  'innerHtml': 'innerHTML',
20274
20520
  'readonly': 'readOnly',
20275
20521
  'tabindex': 'tabIndex',
20522
+ // https://www.w3.org/TR/wai-aria-1.2/#accessibilityroleandproperties-correspondence
20523
+ 'aria-atomic': 'ariaAtomic',
20524
+ 'aria-autocomplete': 'ariaAutoComplete',
20525
+ 'aria-busy': 'ariaBusy',
20526
+ 'aria-checked': 'ariaChecked',
20527
+ 'aria-colcount': 'ariaColCount',
20528
+ 'aria-colindex': 'ariaColIndex',
20529
+ 'aria-colspan': 'ariaColSpan',
20530
+ 'aria-current': 'ariaCurrent',
20531
+ 'aria-disabled': 'ariaDisabled',
20532
+ 'aria-expanded': 'ariaExpanded',
20533
+ 'aria-haspopup': 'ariaHasPopup',
20534
+ 'aria-hidden': 'ariaHidden',
20535
+ 'aria-invalid': 'ariaInvalid',
20536
+ 'aria-keyshortcuts': 'ariaKeyShortcuts',
20537
+ 'aria-label': 'ariaLabel',
20538
+ 'aria-level': 'ariaLevel',
20539
+ 'aria-live': 'ariaLive',
20540
+ 'aria-modal': 'ariaModal',
20541
+ 'aria-multiline': 'ariaMultiLine',
20542
+ 'aria-multiselectable': 'ariaMultiSelectable',
20543
+ 'aria-orientation': 'ariaOrientation',
20544
+ 'aria-placeholder': 'ariaPlaceholder',
20545
+ 'aria-posinset': 'ariaPosInSet',
20546
+ 'aria-pressed': 'ariaPressed',
20547
+ 'aria-readonly': 'ariaReadOnly',
20548
+ 'aria-required': 'ariaRequired',
20549
+ 'aria-roledescription': 'ariaRoleDescription',
20550
+ 'aria-rowcount': 'ariaRowCount',
20551
+ 'aria-rowindex': 'ariaRowIndex',
20552
+ 'aria-rowspan': 'ariaRowSpan',
20553
+ 'aria-selected': 'ariaSelected',
20554
+ 'aria-setsize': 'ariaSetSize',
20555
+ 'aria-sort': 'ariaSort',
20556
+ 'aria-valuemax': 'ariaValueMax',
20557
+ 'aria-valuemin': 'ariaValueMin',
20558
+ 'aria-valuenow': 'ariaValueNow',
20559
+ 'aria-valuetext': 'ariaValueText',
20276
20560
  }));
20277
20561
  // Invert _ATTR_TO_PROP.
20278
20562
  const _PROP_TO_ATTR = Array.from(_ATTR_TO_PROP).reduce((inverted, [propertyName, attributeName]) => {
@@ -22219,10 +22503,33 @@ function addNamesToView(unit, baseName, state, compatibility) {
22219
22503
  switch (op.kind) {
22220
22504
  case OpKind.Property:
22221
22505
  case OpKind.DomProperty:
22222
- if (op.isLegacyAnimationTrigger) {
22506
+ if (op.bindingKind === BindingKind.LegacyAnimation) {
22223
22507
  op.name = '@' + op.name;
22224
22508
  }
22225
22509
  break;
22510
+ case OpKind.Animation:
22511
+ if (op.handlerFnName === null) {
22512
+ const animationKind = op.name.replace('.', '');
22513
+ op.handlerFnName = `${unit.fnName}_${animationKind}_cb`;
22514
+ op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
22515
+ }
22516
+ break;
22517
+ case OpKind.AnimationListener:
22518
+ if (op.handlerFnName !== null) {
22519
+ break;
22520
+ }
22521
+ if (!op.hostListener && op.targetSlot.slot === null) {
22522
+ throw new Error(`Expected a slot to be assigned`);
22523
+ }
22524
+ const animationKind = op.name.replace('.', '');
22525
+ if (op.hostListener) {
22526
+ op.handlerFnName = `${baseName}_${animationKind}_HostBindingHandler`;
22527
+ }
22528
+ else {
22529
+ op.handlerFnName = `${unit.fnName}_${op.tag.replace('-', '_')}_${animationKind}_${op.targetSlot.slot}_listener`;
22530
+ }
22531
+ op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
22532
+ break;
22226
22533
  case OpKind.Listener:
22227
22534
  if (op.handlerFnName !== null) {
22228
22535
  break;
@@ -22380,7 +22687,10 @@ function stripImportant(name) {
22380
22687
  function mergeNextContextExpressions(job) {
22381
22688
  for (const unit of job.units) {
22382
22689
  for (const op of unit.create) {
22383
- if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
22690
+ if (op.kind === OpKind.Listener ||
22691
+ op.kind === OpKind.Animation ||
22692
+ op.kind === OpKind.AnimationListener ||
22693
+ op.kind === OpKind.TwoWayListener) {
22384
22694
  mergeNextContextsInOps(op.handlerOps);
22385
22695
  }
22386
22696
  }
@@ -22501,7 +22811,9 @@ function kindWithInterpolationTest(kind, interpolation) {
22501
22811
  }
22502
22812
  function basicListenerKindTest(op) {
22503
22813
  return ((op.kind === OpKind.Listener && !(op.hostListener && op.isLegacyAnimationListener)) ||
22504
- op.kind === OpKind.TwoWayListener);
22814
+ op.kind === OpKind.TwoWayListener ||
22815
+ op.kind === OpKind.Animation ||
22816
+ op.kind === OpKind.AnimationListener);
22505
22817
  }
22506
22818
  function nonInterpolationPropertyKindTest(op) {
22507
22819
  return ((op.kind === OpKind.Property || op.kind === OpKind.TwoWayProperty) &&
@@ -22548,6 +22860,7 @@ const UPDATE_HOST_ORDERING = [
22548
22860
  const handledOpKinds = new Set([
22549
22861
  OpKind.Listener,
22550
22862
  OpKind.TwoWayListener,
22863
+ OpKind.AnimationListener,
22551
22864
  OpKind.StyleMap,
22552
22865
  OpKind.ClassMap,
22553
22866
  OpKind.StyleProp,
@@ -22556,6 +22869,7 @@ const handledOpKinds = new Set([
22556
22869
  OpKind.TwoWayProperty,
22557
22870
  OpKind.DomProperty,
22558
22871
  OpKind.Attribute,
22872
+ OpKind.Animation,
22559
22873
  ]);
22560
22874
  /**
22561
22875
  * Many type of operations have ordering constraints that must be respected. For example, a
@@ -23246,6 +23560,9 @@ function i18nAttributes(slot, i18nAttributesConfig) {
23246
23560
  const args = [literal(slot), literal(i18nAttributesConfig)];
23247
23561
  return call(Identifiers.i18nAttributes, args, null);
23248
23562
  }
23563
+ function ariaProperty(name, expression, sourceSpan) {
23564
+ return propertyBase(Identifiers.ariaProperty, name, expression, null, sourceSpan);
23565
+ }
23249
23566
  function property(name, expression, sanitizer, sourceSpan) {
23250
23567
  return propertyBase(Identifiers.property, name, expression, sanitizer, sourceSpan);
23251
23568
  }
@@ -23359,6 +23676,36 @@ function i18nApply(slot, sourceSpan) {
23359
23676
  function domProperty(name, expression, sanitizer, sourceSpan) {
23360
23677
  return propertyBase(Identifiers.domProperty, name, expression, sanitizer, sourceSpan);
23361
23678
  }
23679
+ function animation(animationKind, handlerFn, sanitizer, sourceSpan) {
23680
+ const args = [handlerFn];
23681
+ if (sanitizer !== null) {
23682
+ args.push(sanitizer);
23683
+ }
23684
+ const identifier = animationKind === "enter" /* ir.AnimationKind.ENTER */
23685
+ ? Identifiers.animationEnter
23686
+ : Identifiers.animationLeave;
23687
+ return call(identifier, args, sourceSpan);
23688
+ }
23689
+ function animationString(animationKind, expression, sanitizer, sourceSpan) {
23690
+ const value = expression instanceof Interpolation
23691
+ ? interpolationToExpression(expression, sourceSpan)
23692
+ : expression;
23693
+ const args = [value];
23694
+ if (sanitizer !== null) {
23695
+ args.push(sanitizer);
23696
+ }
23697
+ const identifier = animationKind === "enter" /* ir.AnimationKind.ENTER */
23698
+ ? Identifiers.animationEnter
23699
+ : Identifiers.animationLeave;
23700
+ return call(identifier, args, sourceSpan);
23701
+ }
23702
+ function animationListener(animationKind, handlerFn, eventTargetResolver, sourceSpan) {
23703
+ const args = [handlerFn];
23704
+ const identifier = animationKind === "enter" /* ir.AnimationKind.ENTER */
23705
+ ? Identifiers.animationEnterListener
23706
+ : Identifiers.animationLeaveListener;
23707
+ return call(identifier, args, sourceSpan);
23708
+ }
23362
23709
  function syntheticHostProperty(name, expression, sourceSpan) {
23363
23710
  return call(Identifiers.syntheticHostProperty, [literal(name), expression], sourceSpan);
23364
23711
  }
@@ -23492,6 +23839,7 @@ function callVariadicInstruction(config, baseArgs, interpolationArgs, extraArgs,
23492
23839
  return createStatementOp(callVariadicInstructionExpr(config, baseArgs, interpolationArgs, extraArgs, sourceSpan).toStmt());
23493
23840
  }
23494
23841
 
23842
+ const ARIA_PREFIX = 'aria';
23495
23843
  /**
23496
23844
  * Map of target resolvers for event listeners.
23497
23845
  */
@@ -23605,6 +23953,18 @@ function reifyCreateOperations(unit, ops) {
23605
23953
  case OpKind.DeclareLet:
23606
23954
  OpList.replace(op, declareLet(op.handle.slot, op.sourceSpan));
23607
23955
  break;
23956
+ case OpKind.AnimationString:
23957
+ OpList.replace(op, animationString(op.animationKind, op.expression, op.sanitizer, op.sourceSpan));
23958
+ break;
23959
+ case OpKind.Animation:
23960
+ const animationCallbackFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps,
23961
+ /* consumesDollarEvent */ false);
23962
+ OpList.replace(op, animation(op.animationKind, animationCallbackFn, op.sanitizer, op.sourceSpan));
23963
+ break;
23964
+ case OpKind.AnimationListener:
23965
+ const animationListenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
23966
+ OpList.replace(op, animationListener(op.animationKind, animationListenerFn, null, op.sourceSpan));
23967
+ break;
23608
23968
  case OpKind.Listener:
23609
23969
  const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
23610
23970
  const eventTargetResolver = op.eventTarget
@@ -23783,9 +24143,11 @@ function reifyUpdateOperations(unit, ops) {
23783
24143
  OpList.replace(op, advance(op.delta, op.sourceSpan));
23784
24144
  break;
23785
24145
  case OpKind.Property:
23786
- OpList.replace(op, unit.job.mode === TemplateCompilationMode.DomOnly && !op.isLegacyAnimationTrigger
23787
- ? domProperty(DOM_PROPERTY_REMAPPING.get(op.name) ?? op.name, op.expression, op.sanitizer, op.sourceSpan)
23788
- : property(op.name, op.expression, op.sanitizer, op.sourceSpan));
24146
+ OpList.replace(op, unit.job.mode === TemplateCompilationMode.DomOnly &&
24147
+ op.bindingKind !== BindingKind.LegacyAnimation &&
24148
+ op.bindingKind !== BindingKind.Animation
24149
+ ? reifyDomProperty(op)
24150
+ : reifyProperty(op));
23789
24151
  break;
23790
24152
  case OpKind.TwoWayProperty:
23791
24153
  OpList.replace(op, twoWayProperty(op.name, op.expression, op.sanitizer, op.sourceSpan));
@@ -23819,11 +24181,12 @@ function reifyUpdateOperations(unit, ops) {
23819
24181
  throw new Error('not yet handled');
23820
24182
  }
23821
24183
  else {
23822
- if (op.isLegacyAnimationTrigger) {
24184
+ if (op.bindingKind === BindingKind.LegacyAnimation ||
24185
+ op.bindingKind === BindingKind.Animation) {
23823
24186
  OpList.replace(op, syntheticHostProperty(op.name, op.expression, op.sourceSpan));
23824
24187
  }
23825
24188
  else {
23826
- OpList.replace(op, domProperty(DOM_PROPERTY_REMAPPING.get(op.name) ?? op.name, op.expression, op.sanitizer, op.sourceSpan));
24189
+ OpList.replace(op, reifyDomProperty(op));
23827
24190
  }
23828
24191
  }
23829
24192
  break;
@@ -23855,6 +24218,61 @@ function reifyUpdateOperations(unit, ops) {
23855
24218
  }
23856
24219
  }
23857
24220
  }
24221
+ /**
24222
+ * Converts an ARIA property name to its corresponding attribute name, if necessary.
24223
+ *
24224
+ * For example, converts `ariaLabel` to `aria-label`.
24225
+ *
24226
+ * https://www.w3.org/TR/wai-aria-1.2/#accessibilityroleandproperties-correspondence
24227
+ *
24228
+ * This must be kept in sync with the the function of the same name in
24229
+ * packages/core/src/render3/instructions/aria_property.ts.
24230
+ *
24231
+ * @param name A property name that starts with `aria`.
24232
+ * @returns The corresponding attribute name.
24233
+ */
24234
+ function ariaAttrName(name) {
24235
+ return name.charAt(ARIA_PREFIX.length) !== '-'
24236
+ ? ARIA_PREFIX + '-' + name.slice(ARIA_PREFIX.length).toLowerCase()
24237
+ : name; // Property already has attribute name.
24238
+ }
24239
+ /**
24240
+ * Returns whether `name` is an ARIA property (or attribute) name.
24241
+ *
24242
+ * This is a heuristic based on whether name begins with and is longer than `aria`. For example,
24243
+ * this returns true for both `ariaLabel` and `aria-label`.
24244
+ */
24245
+ function isAriaProperty(name) {
24246
+ return name.startsWith(ARIA_PREFIX) && name.length > ARIA_PREFIX.length;
24247
+ }
24248
+ /**
24249
+ * Reifies a DOM property binding operation.
24250
+ *
24251
+ * This is an optimized version of {@link reifyProperty} that avoids unnecessarily trying to bind
24252
+ * to directive inputs at runtime for views that don't import any directives.
24253
+ *
24254
+ * @param op A property binding operation.
24255
+ * @returns A statement to update the property at runtime.
24256
+ */
24257
+ function reifyDomProperty(op) {
24258
+ return isAriaProperty(op.name)
24259
+ ? attribute(ariaAttrName(op.name), op.expression, null, null, op.sourceSpan)
24260
+ : domProperty(DOM_PROPERTY_REMAPPING.get(op.name) ?? op.name, op.expression, op.sanitizer, op.sourceSpan);
24261
+ }
24262
+ /**
24263
+ * Reifies a property binding operation.
24264
+ *
24265
+ * The returned statement attempts to bind to directive inputs before falling back to a DOM
24266
+ * property.
24267
+ *
24268
+ * @param op A property binding operation.
24269
+ * @returns A statement to update the property at runtime.
24270
+ */
24271
+ function reifyProperty(op) {
24272
+ return isAriaProperty(op.name)
24273
+ ? ariaProperty(op.name, op.expression, op.sourceSpan)
24274
+ : property(op.name, op.expression, op.sanitizer, op.sourceSpan);
24275
+ }
23858
24276
  function reifyIrExpression(expr) {
23859
24277
  if (!isIrExpression(expr)) {
23860
24278
  return expr;
@@ -24096,6 +24514,8 @@ function processLexicalScope$1(view, ops) {
24096
24514
  break;
24097
24515
  }
24098
24516
  break;
24517
+ case OpKind.Animation:
24518
+ case OpKind.AnimationListener:
24099
24519
  case OpKind.Listener:
24100
24520
  case OpKind.TwoWayListener:
24101
24521
  processLexicalScope$1(view, op.handlerOps);
@@ -24161,11 +24581,13 @@ function resolveDollarEvent(job) {
24161
24581
  }
24162
24582
  function transformDollarEvent(ops) {
24163
24583
  for (const op of ops) {
24164
- if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
24584
+ if (op.kind === OpKind.Listener ||
24585
+ op.kind === OpKind.TwoWayListener ||
24586
+ op.kind === OpKind.AnimationListener) {
24165
24587
  transformExpressionsInOp(op, (expr) => {
24166
24588
  if (expr instanceof LexicalReadExpr && expr.name === '$event') {
24167
24589
  // Two-way listeners always consume `$event` so they omit this field.
24168
- if (op.kind === OpKind.Listener) {
24590
+ if (op.kind === OpKind.Listener || op.kind === OpKind.AnimationListener) {
24169
24591
  op.consumesDollarEvent = true;
24170
24592
  }
24171
24593
  return new ReadVarExpr(expr.name);
@@ -24556,6 +24978,8 @@ function processLexicalScope(unit, ops, savedView) {
24556
24978
  break;
24557
24979
  }
24558
24980
  break;
24981
+ case OpKind.Animation:
24982
+ case OpKind.AnimationListener:
24559
24983
  case OpKind.Listener:
24560
24984
  case OpKind.TwoWayListener:
24561
24985
  // Listener functions have separate variable declarations, so process them as a separate
@@ -24573,7 +24997,10 @@ function processLexicalScope(unit, ops, savedView) {
24573
24997
  // scope. Also, look for `ir.RestoreViewExpr`s and match them with the snapshotted view context
24574
24998
  // variable.
24575
24999
  for (const op of ops) {
24576
- if (op.kind == OpKind.Listener || op.kind === OpKind.TwoWayListener) {
25000
+ if (op.kind == OpKind.Listener ||
25001
+ op.kind === OpKind.TwoWayListener ||
25002
+ op.kind === OpKind.Animation ||
25003
+ op.kind === OpKind.AnimationListener) {
24577
25004
  // Listeners were already processed above with their own scopes.
24578
25005
  continue;
24579
25006
  }
@@ -24742,7 +25169,10 @@ function saveAndRestoreView(job) {
24742
25169
  }, new GetCurrentViewExpr(), VariableFlags.None),
24743
25170
  ]);
24744
25171
  for (const op of unit.create) {
24745
- if (op.kind !== OpKind.Listener && op.kind !== OpKind.TwoWayListener) {
25172
+ if (op.kind !== OpKind.Listener &&
25173
+ op.kind !== OpKind.TwoWayListener &&
25174
+ op.kind !== OpKind.Animation &&
25175
+ op.kind !== OpKind.AnimationListener) {
24746
25176
  continue;
24747
25177
  }
24748
25178
  // Embedded views always need the save/restore view operation.
@@ -25062,7 +25492,10 @@ function generateTemporaries(ops) {
25062
25492
  // Add declarations for the temp vars.
25063
25493
  generatedStatements.push(...Array.from(new Set(defs.values())).map((name) => createStatementOp(new DeclareVarStmt(name))));
25064
25494
  opCount++;
25065
- if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
25495
+ if (op.kind === OpKind.Listener ||
25496
+ op.kind === OpKind.Animation ||
25497
+ op.kind === OpKind.AnimationListener ||
25498
+ op.kind === OpKind.TwoWayListener) {
25066
25499
  op.handlerOps.prepend(generateTemporaries(op.handlerOps));
25067
25500
  }
25068
25501
  else if (op.kind === OpKind.RepeaterCreate && op.trackByOps !== null) {
@@ -25406,7 +25839,10 @@ function optimizeVariables(job) {
25406
25839
  inlineAlwaysInlineVariables(unit.create);
25407
25840
  inlineAlwaysInlineVariables(unit.update);
25408
25841
  for (const op of unit.create) {
25409
- if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
25842
+ if (op.kind === OpKind.Listener ||
25843
+ op.kind === OpKind.Animation ||
25844
+ op.kind === OpKind.AnimationListener ||
25845
+ op.kind === OpKind.TwoWayListener) {
25410
25846
  inlineAlwaysInlineVariables(op.handlerOps);
25411
25847
  }
25412
25848
  else if (op.kind === OpKind.RepeaterCreate && op.trackByOps !== null) {
@@ -25416,7 +25852,10 @@ function optimizeVariables(job) {
25416
25852
  optimizeVariablesInOpList(unit.create, job.compatibility);
25417
25853
  optimizeVariablesInOpList(unit.update, job.compatibility);
25418
25854
  for (const op of unit.create) {
25419
- if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
25855
+ if (op.kind === OpKind.Listener ||
25856
+ op.kind === OpKind.Animation ||
25857
+ op.kind === OpKind.AnimationListener ||
25858
+ op.kind === OpKind.TwoWayListener) {
25420
25859
  optimizeVariablesInOpList(op.handlerOps, job.compatibility);
25421
25860
  }
25422
25861
  else if (op.kind === OpKind.RepeaterCreate && op.trackByOps !== null) {
@@ -25853,6 +26292,7 @@ const phases = [
25853
26292
  { kind: CompilationJobKind.Both, fn: deduplicateTextBindings },
25854
26293
  { kind: CompilationJobKind.Both, fn: specializeStyleBindings },
25855
26294
  { kind: CompilationJobKind.Both, fn: specializeBindings },
26295
+ { kind: CompilationJobKind.Both, fn: convertAnimations },
25856
26296
  { kind: CompilationJobKind.Both, fn: extractAttributes },
25857
26297
  { kind: CompilationJobKind.Tmpl, fn: createI18nContexts },
25858
26298
  { kind: CompilationJobKind.Both, fn: parseExtractedStyles },
@@ -26012,6 +26452,8 @@ const compatibilityMode = CompatibilityMode.TemplateDefinitionBuilder;
26012
26452
  const domSchema = new DomElementSchemaRegistry();
26013
26453
  // Tag name of the `ng-template` element.
26014
26454
  const NG_TEMPLATE_TAG_NAME = 'ng-template';
26455
+ // prefix for any animation binding
26456
+ const ANIMATE_PREFIX$1 = 'animate.';
26015
26457
  function isI18nRootNode(meta) {
26016
26458
  return meta instanceof Message;
26017
26459
  }
@@ -26044,6 +26486,9 @@ function ingestHostBinding(input, bindingParser, constantPool) {
26044
26486
  if (property.isLegacyAnimation) {
26045
26487
  bindingKind = BindingKind.LegacyAnimation;
26046
26488
  }
26489
+ if (property.isAnimation) {
26490
+ bindingKind = BindingKind.Animation;
26491
+ }
26047
26492
  const securityContexts = bindingParser
26048
26493
  .calcPossibleSecurityContexts(input.componentSelector, property.name, bindingKind === BindingKind.Attribute)
26049
26494
  .filter((context) => context !== SecurityContext.NONE);
@@ -26710,6 +27155,7 @@ const BINDING_KINDS = new Map([
26710
27155
  [exports.BindingType.Class, BindingKind.ClassName],
26711
27156
  [exports.BindingType.Style, BindingKind.StyleProperty],
26712
27157
  [exports.BindingType.LegacyAnimation, BindingKind.LegacyAnimation],
27158
+ [exports.BindingType.Animation, BindingKind.Animation],
26713
27159
  ]);
26714
27160
  /**
26715
27161
  * Checks whether the given template is a plain ng-template (as opposed to another kind of template
@@ -26774,6 +27220,9 @@ function ingestElementBindings(unit, op, element) {
26774
27220
  if (output.type === exports.ParsedEventType.TwoWay) {
26775
27221
  unit.create.push(createTwoWayListenerOp(op.xref, op.handle, output.name, op.tag, makeTwoWayListenerHandlerOps(unit, output.handler, output.handlerSpan), output.sourceSpan));
26776
27222
  }
27223
+ else if (output.type === exports.ParsedEventType.Animation) {
27224
+ 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));
27225
+ }
26777
27226
  else {
26778
27227
  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));
26779
27228
  }
@@ -26882,7 +27331,9 @@ function createTemplateBinding(view, xref, type, name, value, unit, securityCont
26882
27331
  }
26883
27332
  }
26884
27333
  if (!isTextBinding &&
26885
- (type === exports.BindingType.Attribute || type === exports.BindingType.LegacyAnimation)) {
27334
+ (type === exports.BindingType.Attribute ||
27335
+ type === exports.BindingType.LegacyAnimation ||
27336
+ type === exports.BindingType.Animation)) {
26886
27337
  // Again, this binding doesn't really target the ng-template; it actually targets the element
26887
27338
  // inside the structural template. In the case of non-text attribute or animation bindings,
26888
27339
  // the binding doesn't even show up on the ng-template const array, so we just skip it
@@ -27040,14 +27491,18 @@ function ingestControlFlowInsertionPoint(unit, xref, node) {
27040
27491
  if (root !== null) {
27041
27492
  // Collect the static attributes for content projection purposes.
27042
27493
  for (const attr of root.attributes) {
27043
- const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
27044
- unit.update.push(createBindingOp(xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
27494
+ if (!attr.name.startsWith(ANIMATE_PREFIX$1)) {
27495
+ const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
27496
+ unit.update.push(createBindingOp(xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
27497
+ }
27045
27498
  }
27046
27499
  // Also collect the inputs since they participate in content projection as well.
27047
27500
  // Note that TDB used to collect the outputs as well, but it wasn't passing them into
27048
27501
  // the template instruction. Here we just don't collect them.
27049
27502
  for (const attr of root.inputs) {
27050
- if (attr.type !== exports.BindingType.LegacyAnimation && attr.type !== exports.BindingType.Attribute) {
27503
+ if (attr.type !== exports.BindingType.LegacyAnimation &&
27504
+ attr.type !== exports.BindingType.Animation &&
27505
+ attr.type !== exports.BindingType.Attribute) {
27051
27506
  const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME, attr.name, true);
27052
27507
  unit.create.push(createExtractedAttributeOp(xref, BindingKind.Property, null, attr.name, null, null, null, securityContext));
27053
27508
  }
@@ -27259,6 +27714,7 @@ class HtmlParser extends Parser$1 {
27259
27714
 
27260
27715
  const PROPERTY_PARTS_SEPARATOR = '.';
27261
27716
  const ATTRIBUTE_PREFIX = 'attr';
27717
+ const ANIMATE_PREFIX = 'animate';
27262
27718
  const CLASS_PREFIX = 'class';
27263
27719
  const STYLE_PREFIX = 'style';
27264
27720
  const TEMPLATE_ATTR_PREFIX$1 = '*';
@@ -27458,6 +27914,9 @@ class BindingParser {
27458
27914
  if (isLegacyAnimationProp) {
27459
27915
  this._parseLegacyAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
27460
27916
  }
27917
+ else if (name.startsWith(ANIMATE_PREFIX)) {
27918
+ this._parseAnimation(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
27919
+ }
27461
27920
  else {
27462
27921
  this._parsePropertyAst(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), isPartOfAssignmentBinding, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
27463
27922
  }
@@ -27474,6 +27933,10 @@ class BindingParser {
27474
27933
  targetMatchableAttrs.push([name, ast.source]);
27475
27934
  targetProps.push(new ParsedProperty(name, ast, isPartOfAssignmentBinding ? ParsedPropertyType.TWO_WAY : ParsedPropertyType.DEFAULT, sourceSpan, keySpan, valueSpan));
27476
27935
  }
27936
+ _parseAnimation(name, ast, sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
27937
+ targetMatchableAttrs.push([name, ast.source]);
27938
+ targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
27939
+ }
27477
27940
  _parseLegacyAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps) {
27478
27941
  if (name.length === 0) {
27479
27942
  this._reportError('Animation trigger is missing', sourceSpan);
@@ -27536,6 +27999,11 @@ class BindingParser {
27536
27999
  bindingType = exports.BindingType.Style;
27537
28000
  securityContexts = [SecurityContext.STYLE];
27538
28001
  }
28002
+ else if (parts[0] == ANIMATE_PREFIX) {
28003
+ boundPropertyName = boundProp.name;
28004
+ bindingType = exports.BindingType.Animation;
28005
+ securityContexts = [SecurityContext.NONE];
28006
+ }
27539
28007
  }
27540
28008
  // If not a special case, use the full property name
27541
28009
  if (boundPropertyName === null) {
@@ -27550,7 +28018,6 @@ class BindingParser {
27550
28018
  }
27551
28019
  return new BoundElementProperty(boundPropertyName, bindingType, securityContexts[0], boundProp.expression, unit, boundProp.sourceSpan, boundProp.keySpan, boundProp.valueSpan);
27552
28020
  }
27553
- // TODO: keySpan should be required but was made optional to avoid changing VE parser.
27554
28021
  parseEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
27555
28022
  if (name.length === 0) {
27556
28023
  this._reportError(`Event name is missing in binding`, sourceSpan);
@@ -27606,7 +28073,14 @@ class BindingParser {
27606
28073
  if (isAssignmentEvent && isValid && !this._isAllowedAssignmentEvent(ast)) {
27607
28074
  this._reportError('Unsupported expression in a two-way binding', sourceSpan);
27608
28075
  }
27609
- targetEvents.push(new ParsedEvent(eventName, target, isAssignmentEvent ? exports.ParsedEventType.TwoWay : exports.ParsedEventType.Regular, ast, sourceSpan, handlerSpan, keySpan));
28076
+ let eventType = exports.ParsedEventType.Regular;
28077
+ if (isAssignmentEvent) {
28078
+ eventType = exports.ParsedEventType.TwoWay;
28079
+ }
28080
+ if (name.startsWith(ANIMATE_PREFIX)) {
28081
+ eventType = exports.ParsedEventType.Animation;
28082
+ }
28083
+ targetEvents.push(new ParsedEvent(eventName, target, eventType, ast, sourceSpan, handlerSpan, keySpan));
27610
28084
  // Don't detect directives for event names for now,
27611
28085
  // so don't add the event name to the matchableAttrs
27612
28086
  }
@@ -28865,7 +29339,7 @@ class HtmlAstToIvyAst {
28865
29339
  }
28866
29340
  else {
28867
29341
  const attrs = this.categorizePropertyAttributes(element.name, parsedProperties, i18nAttrsMeta);
28868
- parsedElement = new Element$1(element.name, attributes, attrs.bound, boundEvents, directives, children, references, element.isSelfClosing, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.i18n);
29342
+ parsedElement = new Element$1(element.name, attributes, attrs.bound, boundEvents, directives, children, references, element.isSelfClosing, element.sourceSpan, element.startSourceSpan, element.endSourceSpan, element.isVoid, element.i18n);
28869
29343
  }
28870
29344
  if (elementHasInlineTemplate) {
28871
29345
  // If this node is an inline-template (e.g. has *ngFor) then we need to create a template
@@ -29177,7 +29651,7 @@ class HtmlAstToIvyAst {
29177
29651
  const identifier = bindParts[IDENT_KW_IDX];
29178
29652
  const keySpan = createKeySpan(srcSpan, bindParts[KW_BINDON_IDX], identifier);
29179
29653
  this.bindingParser.parsePropertyBinding(identifier, value, false, true, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
29180
- this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan);
29654
+ this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan, absoluteOffset);
29181
29655
  }
29182
29656
  else if (bindParts[KW_AT_IDX]) {
29183
29657
  const keySpan = createKeySpan(srcSpan, '', name);
@@ -29208,7 +29682,7 @@ class HtmlAstToIvyAst {
29208
29682
  const keySpan = createKeySpan(srcSpan, delims.start, identifier);
29209
29683
  if (delims.start === BINDING_DELIMS.BANANA_BOX.start) {
29210
29684
  this.bindingParser.parsePropertyBinding(identifier, value, false, true, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
29211
- this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan);
29685
+ this.parseAssignmentEvent(identifier, value, srcSpan, attribute.valueSpan, matchableAttributes, boundEvents, keySpan, absoluteOffset);
29212
29686
  }
29213
29687
  else if (delims.start === BINDING_DELIMS.PROPERTY.start) {
29214
29688
  this.bindingParser.parsePropertyBinding(identifier, value, false, false, srcSpan, absoluteOffset, attribute.valueSpan, matchableAttributes, parsedProperties, keySpan);
@@ -29328,7 +29802,7 @@ class HtmlAstToIvyAst {
29328
29802
  }
29329
29803
  references.push(new Reference$1(identifier, value, sourceSpan, keySpan, valueSpan));
29330
29804
  }
29331
- parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, boundEvents, keySpan) {
29805
+ parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, boundEvents, keySpan, absoluteOffset) {
29332
29806
  const events = [];
29333
29807
  this.bindingParser.parseEvent(`${name}Change`, expression,
29334
29808
  /* isAssignmentEvent */ true, sourceSpan, valueSpan || sourceSpan, targetMatchableAttrs, events, keySpan);
@@ -29371,7 +29845,7 @@ class NonBindableVisitor {
29371
29845
  /* inputs */ [],
29372
29846
  /* outputs */ [],
29373
29847
  /* directives */ [], children,
29374
- /* references */ [], ast.isSelfClosing, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
29848
+ /* references */ [], ast.isSelfClosing, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.isVoid);
29375
29849
  }
29376
29850
  visitComment(comment) {
29377
29851
  return null;
@@ -29412,7 +29886,7 @@ class NonBindableVisitor {
29412
29886
  /* inputs */ [],
29413
29887
  /* outputs */ [],
29414
29888
  /* directives */ [], children,
29415
- /* references */ [], ast.isSelfClosing, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
29889
+ /* references */ [], ast.isSelfClosing, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, false);
29416
29890
  }
29417
29891
  visitDirective(directive, context) {
29418
29892
  return null;
@@ -29556,9 +30030,184 @@ function makeBindingParser(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG, s
29556
30030
  return new BindingParser(new Parser(new Lexer(), selectorlessEnabled), interpolationConfig, elementRegistry, []);
29557
30031
  }
29558
30032
 
30033
+ /*!
30034
+ * @license
30035
+ * Copyright Google LLC All Rights Reserved.
30036
+ *
30037
+ * Use of this source code is governed by an MIT-style license that can be
30038
+ * found in the LICENSE file at https://angular.dev/license
30039
+ */
30040
+ /**
30041
+ * Visitor that traverses all template and expression AST nodes in a template.
30042
+ * Useful for cases where every single node needs to be visited.
30043
+ */
30044
+ class CombinedRecursiveAstVisitor extends RecursiveAstVisitor {
30045
+ visit(node) {
30046
+ if (node instanceof ASTWithSource) {
30047
+ this.visit(node.ast);
30048
+ }
30049
+ else {
30050
+ node.visit(this);
30051
+ }
30052
+ }
30053
+ visitElement(element) {
30054
+ this.visitAllTemplateNodes(element.attributes);
30055
+ this.visitAllTemplateNodes(element.inputs);
30056
+ this.visitAllTemplateNodes(element.outputs);
30057
+ this.visitAllTemplateNodes(element.directives);
30058
+ this.visitAllTemplateNodes(element.references);
30059
+ this.visitAllTemplateNodes(element.children);
30060
+ }
30061
+ visitTemplate(template) {
30062
+ this.visitAllTemplateNodes(template.attributes);
30063
+ this.visitAllTemplateNodes(template.inputs);
30064
+ this.visitAllTemplateNodes(template.outputs);
30065
+ this.visitAllTemplateNodes(template.directives);
30066
+ this.visitAllTemplateNodes(template.templateAttrs);
30067
+ this.visitAllTemplateNodes(template.variables);
30068
+ this.visitAllTemplateNodes(template.references);
30069
+ this.visitAllTemplateNodes(template.children);
30070
+ }
30071
+ visitContent(content) {
30072
+ this.visitAllTemplateNodes(content.children);
30073
+ }
30074
+ visitBoundAttribute(attribute) {
30075
+ this.visit(attribute.value);
30076
+ }
30077
+ visitBoundEvent(attribute) {
30078
+ this.visit(attribute.handler);
30079
+ }
30080
+ visitBoundText(text) {
30081
+ this.visit(text.value);
30082
+ }
30083
+ visitIcu(icu) {
30084
+ Object.keys(icu.vars).forEach((key) => this.visit(icu.vars[key]));
30085
+ Object.keys(icu.placeholders).forEach((key) => this.visit(icu.placeholders[key]));
30086
+ }
30087
+ visitDeferredBlock(deferred) {
30088
+ deferred.visitAll(this);
30089
+ }
30090
+ visitDeferredTrigger(trigger) {
30091
+ if (trigger instanceof BoundDeferredTrigger) {
30092
+ this.visit(trigger.value);
30093
+ }
30094
+ }
30095
+ visitDeferredBlockPlaceholder(block) {
30096
+ this.visitAllTemplateNodes(block.children);
30097
+ }
30098
+ visitDeferredBlockError(block) {
30099
+ this.visitAllTemplateNodes(block.children);
30100
+ }
30101
+ visitDeferredBlockLoading(block) {
30102
+ this.visitAllTemplateNodes(block.children);
30103
+ }
30104
+ visitSwitchBlock(block) {
30105
+ this.visit(block.expression);
30106
+ this.visitAllTemplateNodes(block.cases);
30107
+ }
30108
+ visitSwitchBlockCase(block) {
30109
+ block.expression && this.visit(block.expression);
30110
+ this.visitAllTemplateNodes(block.children);
30111
+ }
30112
+ visitForLoopBlock(block) {
30113
+ block.item.visit(this);
30114
+ this.visitAllTemplateNodes(block.contextVariables);
30115
+ this.visit(block.expression);
30116
+ this.visitAllTemplateNodes(block.children);
30117
+ block.empty?.visit(this);
30118
+ }
30119
+ visitForLoopBlockEmpty(block) {
30120
+ this.visitAllTemplateNodes(block.children);
30121
+ }
30122
+ visitIfBlock(block) {
30123
+ this.visitAllTemplateNodes(block.branches);
30124
+ }
30125
+ visitIfBlockBranch(block) {
30126
+ block.expression && this.visit(block.expression);
30127
+ block.expressionAlias?.visit(this);
30128
+ this.visitAllTemplateNodes(block.children);
30129
+ }
30130
+ visitLetDeclaration(decl) {
30131
+ this.visit(decl.value);
30132
+ }
30133
+ visitComponent(component) {
30134
+ this.visitAllTemplateNodes(component.attributes);
30135
+ this.visitAllTemplateNodes(component.inputs);
30136
+ this.visitAllTemplateNodes(component.outputs);
30137
+ this.visitAllTemplateNodes(component.directives);
30138
+ this.visitAllTemplateNodes(component.references);
30139
+ this.visitAllTemplateNodes(component.children);
30140
+ }
30141
+ visitDirective(directive) {
30142
+ this.visitAllTemplateNodes(directive.attributes);
30143
+ this.visitAllTemplateNodes(directive.inputs);
30144
+ this.visitAllTemplateNodes(directive.outputs);
30145
+ this.visitAllTemplateNodes(directive.references);
30146
+ }
30147
+ visitVariable(variable) { }
30148
+ visitReference(reference) { }
30149
+ visitTextAttribute(attribute) { }
30150
+ visitText(text) { }
30151
+ visitUnknownBlock(block) { }
30152
+ visitAllTemplateNodes(nodes) {
30153
+ for (const node of nodes) {
30154
+ this.visit(node);
30155
+ }
30156
+ }
30157
+ }
30158
+
30159
+ /*!
30160
+ * @license
30161
+ * Copyright Google LLC All Rights Reserved.
30162
+ *
30163
+ * Use of this source code is governed by an MIT-style license that can be
30164
+ * found in the LICENSE file at https://angular.dev/license
30165
+ */
30166
+ const ANIMATE_LEAVE$1 = `animate.leave`;
30167
+ /**
30168
+ * Analyzes a component's template to determine if it's using animate.enter
30169
+ * or animate.leave syntax.
30170
+ */
30171
+ function analyzeTemplateForAnimations(template) {
30172
+ const analyzer = new AnimationsAnalyzer();
30173
+ visitAll$1(analyzer, template);
30174
+ // The template is considered selectorless only if there
30175
+ // are direct references to directives or pipes.
30176
+ return analyzer.hasAnimations;
30177
+ }
30178
+ /**
30179
+ * Visitor that traverses all the template nodes and
30180
+ * expressions to look for selectorless references.
30181
+ */
30182
+ class AnimationsAnalyzer extends CombinedRecursiveAstVisitor {
30183
+ hasAnimations = false;
30184
+ visitElement(element) {
30185
+ // check for regular strings
30186
+ for (const attr of element.attributes) {
30187
+ if (attr.name === ANIMATE_LEAVE$1) {
30188
+ this.hasAnimations = true;
30189
+ }
30190
+ }
30191
+ // check for attribute bindings
30192
+ for (const input of element.inputs) {
30193
+ if (input.name === ANIMATE_LEAVE$1) {
30194
+ this.hasAnimations = true;
30195
+ }
30196
+ }
30197
+ // check for event bindings
30198
+ for (const output of element.outputs) {
30199
+ if (output.name === ANIMATE_LEAVE$1) {
30200
+ this.hasAnimations = true;
30201
+ }
30202
+ }
30203
+ super.visitElement(element);
30204
+ }
30205
+ }
30206
+
29559
30207
  const COMPONENT_VARIABLE = '%COMP%';
29560
30208
  const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
29561
30209
  const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
30210
+ const ANIMATE_LEAVE = `animate.leave`;
29562
30211
  function baseDirectiveFields(meta, constantPool, bindingParser) {
29563
30212
  const definitionMap = new DefinitionMap();
29564
30213
  const selectors = parseSelectorToR3Selector(meta.selector);
@@ -29592,6 +30241,11 @@ function baseDirectiveFields(meta, constantPool, bindingParser) {
29592
30241
  }
29593
30242
  return definitionMap;
29594
30243
  }
30244
+ function hasAnimationHostBinding(meta) {
30245
+ return (meta.host.attributes[ANIMATE_LEAVE] !== undefined ||
30246
+ meta.host.properties[ANIMATE_LEAVE] !== undefined ||
30247
+ meta.host.listeners[ANIMATE_LEAVE] !== undefined);
30248
+ }
29595
30249
  /**
29596
30250
  * Add features to the definition map.
29597
30251
  */
@@ -29626,6 +30280,12 @@ function addFeatures(definitionMap, meta) {
29626
30280
  const externalStyleNodes = meta.externalStyles.map((externalStyle) => literal(externalStyle));
29627
30281
  features.push(importExpr(Identifiers.ExternalStylesFeature).callFn([literalArr(externalStyleNodes)]));
29628
30282
  }
30283
+ const template = meta.template;
30284
+ if (hasAnimationHostBinding(meta) || (template && template.nodes.length > 0)) {
30285
+ if (hasAnimationHostBinding(meta) || analyzeTemplateForAnimations(template.nodes)) {
30286
+ features.push(importExpr(Identifiers.AnimationsFeature).callFn([]));
30287
+ }
30288
+ }
29629
30289
  if (features.length) {
29630
30290
  definitionMap.set('features', literalArr(features));
29631
30291
  }
@@ -30066,132 +30726,6 @@ function compileDeferResolverFunction(meta) {
30066
30726
  return arrowFn([], literalArr(depExpressions));
30067
30727
  }
30068
30728
 
30069
- /*!
30070
- * @license
30071
- * Copyright Google LLC All Rights Reserved.
30072
- *
30073
- * Use of this source code is governed by an MIT-style license that can be
30074
- * found in the LICENSE file at https://angular.dev/license
30075
- */
30076
- /**
30077
- * Visitor that traverses all template and expression AST nodes in a template.
30078
- * Useful for cases where every single node needs to be visited.
30079
- */
30080
- class CombinedRecursiveAstVisitor extends RecursiveAstVisitor {
30081
- visit(node) {
30082
- if (node instanceof ASTWithSource) {
30083
- this.visit(node.ast);
30084
- }
30085
- else {
30086
- node.visit(this);
30087
- }
30088
- }
30089
- visitElement(element) {
30090
- this.visitAllTemplateNodes(element.attributes);
30091
- this.visitAllTemplateNodes(element.inputs);
30092
- this.visitAllTemplateNodes(element.outputs);
30093
- this.visitAllTemplateNodes(element.directives);
30094
- this.visitAllTemplateNodes(element.references);
30095
- this.visitAllTemplateNodes(element.children);
30096
- }
30097
- visitTemplate(template) {
30098
- this.visitAllTemplateNodes(template.attributes);
30099
- this.visitAllTemplateNodes(template.inputs);
30100
- this.visitAllTemplateNodes(template.outputs);
30101
- this.visitAllTemplateNodes(template.directives);
30102
- this.visitAllTemplateNodes(template.templateAttrs);
30103
- this.visitAllTemplateNodes(template.variables);
30104
- this.visitAllTemplateNodes(template.references);
30105
- this.visitAllTemplateNodes(template.children);
30106
- }
30107
- visitContent(content) {
30108
- this.visitAllTemplateNodes(content.children);
30109
- }
30110
- visitBoundAttribute(attribute) {
30111
- this.visit(attribute.value);
30112
- }
30113
- visitBoundEvent(attribute) {
30114
- this.visit(attribute.handler);
30115
- }
30116
- visitBoundText(text) {
30117
- this.visit(text.value);
30118
- }
30119
- visitIcu(icu) {
30120
- Object.keys(icu.vars).forEach((key) => this.visit(icu.vars[key]));
30121
- Object.keys(icu.placeholders).forEach((key) => this.visit(icu.placeholders[key]));
30122
- }
30123
- visitDeferredBlock(deferred) {
30124
- deferred.visitAll(this);
30125
- }
30126
- visitDeferredTrigger(trigger) {
30127
- if (trigger instanceof BoundDeferredTrigger) {
30128
- this.visit(trigger.value);
30129
- }
30130
- }
30131
- visitDeferredBlockPlaceholder(block) {
30132
- this.visitAllTemplateNodes(block.children);
30133
- }
30134
- visitDeferredBlockError(block) {
30135
- this.visitAllTemplateNodes(block.children);
30136
- }
30137
- visitDeferredBlockLoading(block) {
30138
- this.visitAllTemplateNodes(block.children);
30139
- }
30140
- visitSwitchBlock(block) {
30141
- this.visit(block.expression);
30142
- this.visitAllTemplateNodes(block.cases);
30143
- }
30144
- visitSwitchBlockCase(block) {
30145
- block.expression && this.visit(block.expression);
30146
- this.visitAllTemplateNodes(block.children);
30147
- }
30148
- visitForLoopBlock(block) {
30149
- block.item.visit(this);
30150
- this.visitAllTemplateNodes(block.contextVariables);
30151
- this.visit(block.expression);
30152
- this.visitAllTemplateNodes(block.children);
30153
- block.empty?.visit(this);
30154
- }
30155
- visitForLoopBlockEmpty(block) {
30156
- this.visitAllTemplateNodes(block.children);
30157
- }
30158
- visitIfBlock(block) {
30159
- this.visitAllTemplateNodes(block.branches);
30160
- }
30161
- visitIfBlockBranch(block) {
30162
- block.expression && this.visit(block.expression);
30163
- block.expressionAlias?.visit(this);
30164
- this.visitAllTemplateNodes(block.children);
30165
- }
30166
- visitLetDeclaration(decl) {
30167
- this.visit(decl.value);
30168
- }
30169
- visitComponent(component) {
30170
- this.visitAllTemplateNodes(component.attributes);
30171
- this.visitAllTemplateNodes(component.inputs);
30172
- this.visitAllTemplateNodes(component.outputs);
30173
- this.visitAllTemplateNodes(component.directives);
30174
- this.visitAllTemplateNodes(component.references);
30175
- this.visitAllTemplateNodes(component.children);
30176
- }
30177
- visitDirective(directive) {
30178
- this.visitAllTemplateNodes(directive.attributes);
30179
- this.visitAllTemplateNodes(directive.inputs);
30180
- this.visitAllTemplateNodes(directive.outputs);
30181
- this.visitAllTemplateNodes(directive.references);
30182
- }
30183
- visitVariable(variable) { }
30184
- visitReference(reference) { }
30185
- visitTextAttribute(attribute) { }
30186
- visitText(text) { }
30187
- visitUnknownBlock(block) { }
30188
- visitAllTemplateNodes(nodes) {
30189
- for (const node of nodes) {
30190
- this.visit(node);
30191
- }
30192
- }
30193
- }
30194
-
30195
30729
  /**
30196
30730
  * Processes `Target`s with a given set of directives and performs a binding operation, which
30197
30731
  * returns an object similar to TypeScript's `ts.TypeChecker` that contains knowledge about the
@@ -31451,7 +31985,7 @@ function convertDeclareComponentFacadeToMetadata(decl, typeSourceSpan, sourceMap
31451
31985
  declarations.push(...decl.directives.map((dir) => convertDirectiveDeclarationToMetadata(dir)));
31452
31986
  decl.pipes && declarations.push(...convertPipeMapToMetadata(decl.pipes));
31453
31987
  }
31454
- const hasDirectiveDependencies = declarations.every(({ kind }) => kind === exports.R3TemplateDependencyKind.Directive || kind === exports.R3TemplateDependencyKind.NgModule);
31988
+ const hasDirectiveDependencies = declarations.some(({ kind }) => kind === exports.R3TemplateDependencyKind.Directive || kind === exports.R3TemplateDependencyKind.NgModule);
31455
31989
  return {
31456
31990
  ...convertDeclareDirectiveFacadeToMetadata(decl, typeSourceSpan),
31457
31991
  template,
@@ -31819,7 +32353,7 @@ class _Visitor {
31819
32353
  this._init(_VisitorMode.Merge, interpolationConfig);
31820
32354
  this._translations = translations;
31821
32355
  // Construct a single fake root element
31822
- const wrapper = new Element('wrapper', [], [], nodes, false, undefined, undefined, undefined);
32356
+ const wrapper = new Element('wrapper', [], [], nodes, false, undefined, undefined, undefined, false);
31823
32357
  const translatedNode = wrapper.visit(this, null);
31824
32358
  if (this._inI18nBlock) {
31825
32359
  this._reportError(nodes[nodes.length - 1], 'Unclosed block');
@@ -31997,7 +32531,7 @@ class _Visitor {
31997
32531
  this._inImplicitNode = wasInImplicitNode;
31998
32532
  if (this._mode === _VisitorMode.Merge) {
31999
32533
  if (node instanceof Element) {
32000
- return new Element(node.name, this._translateAttributes(node), this._translateDirectives(node), childNodes, node.isSelfClosing, node.sourceSpan, node.startSourceSpan, node.endSourceSpan);
32534
+ return new Element(node.name, this._translateAttributes(node), this._translateDirectives(node), childNodes, node.isSelfClosing, node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.isVoid);
32001
32535
  }
32002
32536
  else {
32003
32537
  return new Component(node.componentName, node.tagName, node.fullName, this._translateAttributes(node), this._translateDirectives(node), childNodes, node.isSelfClosing, node.sourceSpan, node.startSourceSpan, node.endSourceSpan);
@@ -32228,7 +32762,7 @@ function isAttrNode(ast) {
32228
32762
  * @description
32229
32763
  * Entry point for all public APIs of the compiler package.
32230
32764
  */
32231
- new Version('20.2.0-next.0');
32765
+ new Version('20.2.0-next.2');
32232
32766
 
32233
32767
  //////////////////////////////////////
32234
32768
  // THIS FILE HAS GLOBAL SIDE EFFECT //
@@ -32761,6 +33295,20 @@ exports.ErrorCode = void 0;
32761
33295
  * A structural directive is used in a template, but the directive is not imported.
32762
33296
  */
32763
33297
  ErrorCode[ErrorCode["MISSING_STRUCTURAL_DIRECTIVE"] = 8116] = "MISSING_STRUCTURAL_DIRECTIVE";
33298
+ /**
33299
+ * A function in a text interpolation is not invoked.
33300
+ *
33301
+ * For example:
33302
+ * ```html
33303
+ * <p> {{ firstName }} </p>
33304
+ * ```
33305
+ *
33306
+ * The `firstName` function is not invoked. Instead, it should be:
33307
+ * ```html
33308
+ * <p> {{ firstName() }} </p>
33309
+ * ```
33310
+ */
33311
+ ErrorCode[ErrorCode["UNINVOKED_FUNCTION_IN_TEXT_INTERPOLATION"] = 8117] = "UNINVOKED_FUNCTION_IN_TEXT_INTERPOLATION";
32764
33312
  /**
32765
33313
  * The template type-checking engine would need to generate an inline type check block for a
32766
33314
  * component, but the current type-checking environment doesn't support it.
@@ -32922,6 +33470,7 @@ exports.ExtendedTemplateDiagnosticName = void 0;
32922
33470
  ExtendedTemplateDiagnosticName["UNINVOKED_TRACK_FUNCTION"] = "uninvokedTrackFunction";
32923
33471
  ExtendedTemplateDiagnosticName["UNUSED_STANDALONE_IMPORTS"] = "unusedStandaloneImports";
32924
33472
  ExtendedTemplateDiagnosticName["UNPARENTHESIZED_NULLISH_COALESCING"] = "unparenthesizedNullishCoalescing";
33473
+ ExtendedTemplateDiagnosticName["UNINVOKED_FUNCTION_IN_TEXT_INTERPOLATION"] = "uninvokedFunctionInTextInterpolation";
32925
33474
  })(exports.ExtendedTemplateDiagnosticName || (exports.ExtendedTemplateDiagnosticName = {}));
32926
33475
 
32927
33476
  /**
@@ -33248,7 +33797,7 @@ class NodeJSPathManipulation {
33248
33797
  // G3-ESM-MARKER: G3 uses CommonJS, but externally everything in ESM.
33249
33798
  // CommonJS/ESM interop for determining the current file name and containing dir.
33250
33799
  const isCommonJS = typeof __filename !== 'undefined';
33251
- const currentFileUrl = isCommonJS ? null : (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('checker-DLInMAS3.cjs', document.baseURI).href));
33800
+ const currentFileUrl = isCommonJS ? null : (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('checker-Cfq29XaS.cjs', document.baseURI).href));
33252
33801
  // Note, when this code loads in the browser, `url` may be an empty `{}` due to the Closure shims.
33253
33802
  const currentFileName = isCommonJS
33254
33803
  ? __filename
@@ -36668,75 +37217,83 @@ exports.PerfPhase = void 0;
36668
37217
  * Time spent computing template type-checking diagnostics.
36669
37218
  */
36670
37219
  PerfPhase[PerfPhase["TtcDiagnostics"] = 14] = "TtcDiagnostics";
37220
+ /**
37221
+ * Time spent computing template type-checking suggestion diagnostics.
37222
+ */
37223
+ PerfPhase[PerfPhase["TtcSuggestionDiagnostics"] = 15] = "TtcSuggestionDiagnostics";
36671
37224
  /**
36672
37225
  * Time spent getting a `Symbol` from the `TemplateTypeChecker`.
36673
37226
  */
36674
- PerfPhase[PerfPhase["TtcSymbol"] = 15] = "TtcSymbol";
37227
+ PerfPhase[PerfPhase["TtcSymbol"] = 16] = "TtcSymbol";
36675
37228
  /**
36676
37229
  * Time spent by the Angular Language Service calculating a "get references" or a renaming
36677
37230
  * operation.
36678
37231
  */
36679
- PerfPhase[PerfPhase["LsReferencesAndRenames"] = 16] = "LsReferencesAndRenames";
37232
+ PerfPhase[PerfPhase["LsReferencesAndRenames"] = 17] = "LsReferencesAndRenames";
36680
37233
  /**
36681
37234
  * Time spent by the Angular Language Service calculating a "quick info" operation.
36682
37235
  */
36683
- PerfPhase[PerfPhase["LsQuickInfo"] = 17] = "LsQuickInfo";
37236
+ PerfPhase[PerfPhase["LsQuickInfo"] = 18] = "LsQuickInfo";
36684
37237
  /**
36685
37238
  * Time spent by the Angular Language Service calculating a "get type definition" or "get
36686
37239
  * definition" operation.
36687
37240
  */
36688
- PerfPhase[PerfPhase["LsDefinition"] = 18] = "LsDefinition";
37241
+ PerfPhase[PerfPhase["LsDefinition"] = 19] = "LsDefinition";
36689
37242
  /**
36690
37243
  * Time spent by the Angular Language Service calculating a "get completions" (AKA autocomplete)
36691
37244
  * operation.
36692
37245
  */
36693
- PerfPhase[PerfPhase["LsCompletions"] = 19] = "LsCompletions";
37246
+ PerfPhase[PerfPhase["LsCompletions"] = 20] = "LsCompletions";
36694
37247
  /**
36695
37248
  * Time spent by the Angular Language Service calculating a "view template typecheck block"
36696
37249
  * operation.
36697
37250
  */
36698
- PerfPhase[PerfPhase["LsTcb"] = 20] = "LsTcb";
37251
+ PerfPhase[PerfPhase["LsTcb"] = 21] = "LsTcb";
36699
37252
  /**
36700
37253
  * Time spent by the Angular Language Service calculating diagnostics.
36701
37254
  */
36702
- PerfPhase[PerfPhase["LsDiagnostics"] = 21] = "LsDiagnostics";
37255
+ PerfPhase[PerfPhase["LsDiagnostics"] = 22] = "LsDiagnostics";
37256
+ /**
37257
+ * Time spent by the Angular Language Service calculating suggestion diagnostics.
37258
+ */
37259
+ PerfPhase[PerfPhase["LsSuggestionDiagnostics"] = 23] = "LsSuggestionDiagnostics";
36703
37260
  /**
36704
37261
  * Time spent by the Angular Language Service calculating a "get component locations for template"
36705
37262
  * operation.
36706
37263
  */
36707
- PerfPhase[PerfPhase["LsComponentLocations"] = 22] = "LsComponentLocations";
37264
+ PerfPhase[PerfPhase["LsComponentLocations"] = 24] = "LsComponentLocations";
36708
37265
  /**
36709
37266
  * Time spent by the Angular Language Service calculating signature help.
36710
37267
  */
36711
- PerfPhase[PerfPhase["LsSignatureHelp"] = 23] = "LsSignatureHelp";
37268
+ PerfPhase[PerfPhase["LsSignatureHelp"] = 25] = "LsSignatureHelp";
36712
37269
  /**
36713
37270
  * Time spent by the Angular Language Service calculating outlining spans.
36714
37271
  */
36715
- PerfPhase[PerfPhase["OutliningSpans"] = 24] = "OutliningSpans";
37272
+ PerfPhase[PerfPhase["OutliningSpans"] = 26] = "OutliningSpans";
36716
37273
  /**
36717
37274
  * Time spent by the Angular Language Service calculating code fixes.
36718
37275
  */
36719
- PerfPhase[PerfPhase["LsCodeFixes"] = 25] = "LsCodeFixes";
37276
+ PerfPhase[PerfPhase["LsCodeFixes"] = 27] = "LsCodeFixes";
36720
37277
  /**
36721
37278
  * Time spent by the Angular Language Service to fix all detected same type errors.
36722
37279
  */
36723
- PerfPhase[PerfPhase["LsCodeFixesAll"] = 26] = "LsCodeFixesAll";
37280
+ PerfPhase[PerfPhase["LsCodeFixesAll"] = 28] = "LsCodeFixesAll";
36724
37281
  /**
36725
37282
  * Time spent computing possible Angular refactorings.
36726
37283
  */
36727
- PerfPhase[PerfPhase["LSComputeApplicableRefactorings"] = 27] = "LSComputeApplicableRefactorings";
37284
+ PerfPhase[PerfPhase["LSComputeApplicableRefactorings"] = 29] = "LSComputeApplicableRefactorings";
36728
37285
  /**
36729
37286
  * Time spent computing changes for applying a given refactoring.
36730
37287
  */
36731
- PerfPhase[PerfPhase["LSApplyRefactoring"] = 28] = "LSApplyRefactoring";
37288
+ PerfPhase[PerfPhase["LSApplyRefactoring"] = 30] = "LSApplyRefactoring";
36732
37289
  /**
36733
37290
  * Time spent by the Angular Language Service calculating semantic classifications.
36734
37291
  */
36735
- PerfPhase[PerfPhase["LSSemanticClassification"] = 29] = "LSSemanticClassification";
37292
+ PerfPhase[PerfPhase["LSSemanticClassification"] = 31] = "LSSemanticClassification";
36736
37293
  /**
36737
37294
  * Tracks the number of `PerfPhase`s, and must appear at the end of the list.
36738
37295
  */
36739
- PerfPhase[PerfPhase["LAST"] = 30] = "LAST";
37296
+ PerfPhase[PerfPhase["LAST"] = 32] = "LAST";
36740
37297
  })(exports.PerfPhase || (exports.PerfPhase = {}));
36741
37298
  /**
36742
37299
  * Represents some occurrence during compilation, and is tracked with a counter.
@@ -40275,6 +40832,314 @@ function extractHostBindingResources(nodes) {
40275
40832
  return result;
40276
40833
  }
40277
40834
 
40835
+ const parseSpanComment = /^(\d+),(\d+)$/;
40836
+ /**
40837
+ * Reads the trailing comments and finds the first match which is a span comment (i.e. 4,10) on a
40838
+ * node and returns it as an `AbsoluteSourceSpan`.
40839
+ *
40840
+ * Will return `null` if no trailing comments on the node match the expected form of a source span.
40841
+ */
40842
+ function readSpanComment(node, sourceFile = node.getSourceFile()) {
40843
+ return (ts.forEachTrailingCommentRange(sourceFile.text, node.getEnd(), (pos, end, kind) => {
40844
+ if (kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
40845
+ return null;
40846
+ }
40847
+ const commentText = sourceFile.text.substring(pos + 2, end - 2);
40848
+ const match = commentText.match(parseSpanComment);
40849
+ if (match === null) {
40850
+ return null;
40851
+ }
40852
+ return new AbsoluteSourceSpan(+match[1], +match[2]);
40853
+ }) || null);
40854
+ }
40855
+ /** Used to identify what type the comment is. */
40856
+ var CommentTriviaType;
40857
+ (function (CommentTriviaType) {
40858
+ CommentTriviaType["DIAGNOSTIC"] = "D";
40859
+ CommentTriviaType["EXPRESSION_TYPE_IDENTIFIER"] = "T";
40860
+ })(CommentTriviaType || (CommentTriviaType = {}));
40861
+ /** Identifies what the TCB expression is for (for example, a directive declaration). */
40862
+ var ExpressionIdentifier;
40863
+ (function (ExpressionIdentifier) {
40864
+ ExpressionIdentifier["DIRECTIVE"] = "DIR";
40865
+ ExpressionIdentifier["COMPONENT_COMPLETION"] = "COMPCOMP";
40866
+ ExpressionIdentifier["EVENT_PARAMETER"] = "EP";
40867
+ ExpressionIdentifier["VARIABLE_AS_EXPRESSION"] = "VAE";
40868
+ })(ExpressionIdentifier || (ExpressionIdentifier = {}));
40869
+ /** Tags the node with the given expression identifier. */
40870
+ function addExpressionIdentifier(node, identifier) {
40871
+ ts.addSyntheticTrailingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, `${CommentTriviaType.EXPRESSION_TYPE_IDENTIFIER}:${identifier}`,
40872
+ /* hasTrailingNewLine */ false);
40873
+ }
40874
+ const IGNORE_FOR_DIAGNOSTICS_MARKER = `${CommentTriviaType.DIAGNOSTIC}:ignore`;
40875
+ /**
40876
+ * Tag the `ts.Node` with an indication that any errors arising from the evaluation of the node
40877
+ * should be ignored.
40878
+ */
40879
+ function markIgnoreDiagnostics(node) {
40880
+ ts.addSyntheticTrailingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, IGNORE_FOR_DIAGNOSTICS_MARKER,
40881
+ /* hasTrailingNewLine */ false);
40882
+ }
40883
+ /** Returns true if the node has a marker that indicates diagnostics errors should be ignored. */
40884
+ function hasIgnoreForDiagnosticsMarker(node, sourceFile) {
40885
+ return (ts.forEachTrailingCommentRange(sourceFile.text, node.getEnd(), (pos, end, kind) => {
40886
+ if (kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
40887
+ return null;
40888
+ }
40889
+ const commentText = sourceFile.text.substring(pos + 2, end - 2);
40890
+ return commentText === IGNORE_FOR_DIAGNOSTICS_MARKER;
40891
+ }) === true);
40892
+ }
40893
+ function makeRecursiveVisitor(visitor) {
40894
+ function recursiveVisitor(node) {
40895
+ const res = visitor(node);
40896
+ return res !== null ? res : node.forEachChild(recursiveVisitor);
40897
+ }
40898
+ return recursiveVisitor;
40899
+ }
40900
+ function getSpanFromOptions(opts) {
40901
+ let withSpan = null;
40902
+ if (opts.withSpan !== undefined) {
40903
+ if (opts.withSpan instanceof AbsoluteSourceSpan) {
40904
+ withSpan = opts.withSpan;
40905
+ }
40906
+ else {
40907
+ withSpan = { start: opts.withSpan.start.offset, end: opts.withSpan.end.offset };
40908
+ }
40909
+ }
40910
+ return withSpan;
40911
+ }
40912
+ /**
40913
+ * Given a `ts.Node` with finds the first node whose matching the criteria specified
40914
+ * by the `FindOptions`.
40915
+ *
40916
+ * Returns `null` when no `ts.Node` matches the given conditions.
40917
+ */
40918
+ function findFirstMatchingNode(tcb, opts) {
40919
+ const withSpan = getSpanFromOptions(opts);
40920
+ const withExpressionIdentifier = opts.withExpressionIdentifier;
40921
+ const sf = tcb.getSourceFile();
40922
+ const visitor = makeRecursiveVisitor((node) => {
40923
+ if (!opts.filter(node)) {
40924
+ return null;
40925
+ }
40926
+ if (withSpan !== null) {
40927
+ const comment = readSpanComment(node, sf);
40928
+ if (comment === null || withSpan.start !== comment.start || withSpan.end !== comment.end) {
40929
+ return null;
40930
+ }
40931
+ }
40932
+ if (withExpressionIdentifier !== undefined &&
40933
+ !hasExpressionIdentifier(sf, node, withExpressionIdentifier)) {
40934
+ return null;
40935
+ }
40936
+ return node;
40937
+ });
40938
+ return tcb.forEachChild(visitor) ?? null;
40939
+ }
40940
+ /**
40941
+ * Given a `ts.Node` with source span comments, finds the first node whose source span comment
40942
+ * matches the given `sourceSpan`. Additionally, the `filter` function allows matching only
40943
+ * `ts.Nodes` of a given type, which provides the ability to select only matches of a given type
40944
+ * when there may be more than one.
40945
+ *
40946
+ * Returns `null` when no `ts.Node` matches the given conditions.
40947
+ */
40948
+ function findAllMatchingNodes(tcb, opts) {
40949
+ const withSpan = getSpanFromOptions(opts);
40950
+ const withExpressionIdentifier = opts.withExpressionIdentifier;
40951
+ const results = [];
40952
+ const stack = [tcb];
40953
+ const sf = tcb.getSourceFile();
40954
+ while (stack.length > 0) {
40955
+ const node = stack.pop();
40956
+ if (!opts.filter(node)) {
40957
+ stack.push(...node.getChildren());
40958
+ continue;
40959
+ }
40960
+ if (withSpan !== null) {
40961
+ const comment = readSpanComment(node, sf);
40962
+ if (comment === null || withSpan.start !== comment.start || withSpan.end !== comment.end) {
40963
+ stack.push(...node.getChildren());
40964
+ continue;
40965
+ }
40966
+ }
40967
+ if (withExpressionIdentifier !== undefined &&
40968
+ !hasExpressionIdentifier(sf, node, withExpressionIdentifier)) {
40969
+ continue;
40970
+ }
40971
+ results.push(node);
40972
+ }
40973
+ return results;
40974
+ }
40975
+ function hasExpressionIdentifier(sourceFile, node, identifier) {
40976
+ return (ts.forEachTrailingCommentRange(sourceFile.text, node.getEnd(), (pos, end, kind) => {
40977
+ if (kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
40978
+ return false;
40979
+ }
40980
+ const commentText = sourceFile.text.substring(pos + 2, end - 2);
40981
+ return commentText === `${CommentTriviaType.EXPRESSION_TYPE_IDENTIFIER}:${identifier}`;
40982
+ }) || false);
40983
+ }
40984
+
40985
+ /**
40986
+ * A `Set` of `ts.SyntaxKind`s of `ts.Expression` which are safe to wrap in a `ts.AsExpression`
40987
+ * without needing to be wrapped in parentheses.
40988
+ *
40989
+ * For example, `foo.bar()` is a `ts.CallExpression`, and can be safely cast to `any` with
40990
+ * `foo.bar() as any`. however, `foo !== bar` is a `ts.BinaryExpression`, and attempting to cast
40991
+ * without the parentheses yields the expression `foo !== bar as any`. This is semantically
40992
+ * equivalent to `foo !== (bar as any)`, which is not what was intended. Thus,
40993
+ * `ts.BinaryExpression`s need to be wrapped in parentheses before casting.
40994
+ */
40995
+ //
40996
+ let SAFE_TO_CAST_WITHOUT_PARENS = null;
40997
+ function tsCastToAny(expr) {
40998
+ if (SAFE_TO_CAST_WITHOUT_PARENS === null) {
40999
+ SAFE_TO_CAST_WITHOUT_PARENS = new Set([
41000
+ // Expressions which are already parenthesized can be cast without further wrapping.
41001
+ ts.SyntaxKind.ParenthesizedExpression,
41002
+ // Expressions which form a single lexical unit leave no room for precedence issues with the cast.
41003
+ ts.SyntaxKind.Identifier,
41004
+ ts.SyntaxKind.CallExpression,
41005
+ ts.SyntaxKind.NonNullExpression,
41006
+ ts.SyntaxKind.ElementAccessExpression,
41007
+ ts.SyntaxKind.PropertyAccessExpression,
41008
+ ts.SyntaxKind.ArrayLiteralExpression,
41009
+ ts.SyntaxKind.ObjectLiteralExpression,
41010
+ // The same goes for various literals.
41011
+ ts.SyntaxKind.StringLiteral,
41012
+ ts.SyntaxKind.NumericLiteral,
41013
+ ts.SyntaxKind.TrueKeyword,
41014
+ ts.SyntaxKind.FalseKeyword,
41015
+ ts.SyntaxKind.NullKeyword,
41016
+ ts.SyntaxKind.UndefinedKeyword,
41017
+ ]);
41018
+ }
41019
+ // Wrap `expr` in parentheses if needed (see `SAFE_TO_CAST_WITHOUT_PARENS` above).
41020
+ if (!SAFE_TO_CAST_WITHOUT_PARENS.has(expr.kind)) {
41021
+ expr = ts.factory.createParenthesizedExpression(expr);
41022
+ }
41023
+ // The outer expression is always wrapped in parentheses.
41024
+ return ts.factory.createParenthesizedExpression(ts.factory.createAsExpression(expr, ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)));
41025
+ }
41026
+ /**
41027
+ * Create an expression which instantiates an element by its HTML tagName.
41028
+ *
41029
+ * Thanks to narrowing of `document.createElement()`, this expression will have its type inferred
41030
+ * based on the tag name, including for custom elements that have appropriate .d.ts definitions.
41031
+ */
41032
+ function tsCreateElement(...tagNames) {
41033
+ const createElement = ts.factory.createPropertyAccessExpression(
41034
+ /* expression */ ts.factory.createIdentifier('document'), 'createElement');
41035
+ let arg;
41036
+ if (tagNames.length === 1) {
41037
+ // If there's only one tag name, we can pass it in directly.
41038
+ arg = ts.factory.createStringLiteral(tagNames[0]);
41039
+ }
41040
+ else {
41041
+ // If there's more than one name, we have to generate a union of all the tag names. To do so,
41042
+ // create an expression in the form of `null! as 'tag-1' | 'tag-2' | 'tag-3'`. This allows
41043
+ // TypeScript to infer the type as a union of the differnet tags.
41044
+ const assertedNullExpression = ts.factory.createNonNullExpression(ts.factory.createNull());
41045
+ const type = ts.factory.createUnionTypeNode(tagNames.map((tag) => ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(tag))));
41046
+ arg = ts.factory.createAsExpression(assertedNullExpression, type);
41047
+ }
41048
+ return ts.factory.createCallExpression(
41049
+ /* expression */ createElement,
41050
+ /* typeArguments */ undefined,
41051
+ /* argumentsArray */ [arg]);
41052
+ }
41053
+ /**
41054
+ * Create a `ts.VariableStatement` which declares a variable without explicit initialization.
41055
+ *
41056
+ * The initializer `null!` is used to bypass strict variable initialization checks.
41057
+ *
41058
+ * Unlike with `tsCreateVariable`, the type of the variable is explicitly specified.
41059
+ */
41060
+ function tsDeclareVariable(id, type) {
41061
+ // When we create a variable like `var _t1: boolean = null!`, TypeScript actually infers `_t1`
41062
+ // to be `never`, instead of a `boolean`. To work around it, we cast the value
41063
+ // in the initializer, e.g. `var _t1 = null! as boolean;`.
41064
+ addExpressionIdentifier(type, ExpressionIdentifier.VARIABLE_AS_EXPRESSION);
41065
+ const initializer = ts.factory.createAsExpression(ts.factory.createNonNullExpression(ts.factory.createNull()), type);
41066
+ const decl = ts.factory.createVariableDeclaration(
41067
+ /* name */ id,
41068
+ /* exclamationToken */ undefined,
41069
+ /* type */ undefined,
41070
+ /* initializer */ initializer);
41071
+ return ts.factory.createVariableStatement(
41072
+ /* modifiers */ undefined,
41073
+ /* declarationList */ [decl]);
41074
+ }
41075
+ /**
41076
+ * Creates a `ts.TypeQueryNode` for a coerced input.
41077
+ *
41078
+ * For example: `typeof MatInput.ngAcceptInputType_value`, where MatInput is `typeName` and `value`
41079
+ * is the `coercedInputName`.
41080
+ *
41081
+ * @param typeName The `EntityName` of the Directive where the static coerced input is defined.
41082
+ * @param coercedInputName The field name of the coerced input.
41083
+ */
41084
+ function tsCreateTypeQueryForCoercedInput(typeName, coercedInputName) {
41085
+ return ts.factory.createTypeQueryNode(ts.factory.createQualifiedName(typeName, `ngAcceptInputType_${coercedInputName}`));
41086
+ }
41087
+ /**
41088
+ * Create a `ts.VariableStatement` that initializes a variable with a given expression.
41089
+ *
41090
+ * Unlike with `tsDeclareVariable`, the type of the variable is inferred from the initializer
41091
+ * expression.
41092
+ */
41093
+ function tsCreateVariable(id, initializer, flags = null) {
41094
+ const decl = ts.factory.createVariableDeclaration(
41095
+ /* name */ id,
41096
+ /* exclamationToken */ undefined,
41097
+ /* type */ undefined,
41098
+ /* initializer */ initializer);
41099
+ return ts.factory.createVariableStatement(
41100
+ /* modifiers */ undefined,
41101
+ /* declarationList */ flags === null
41102
+ ? [decl]
41103
+ : ts.factory.createVariableDeclarationList([decl], flags));
41104
+ }
41105
+ /**
41106
+ * Construct a `ts.CallExpression` that calls a method on a receiver.
41107
+ */
41108
+ function tsCallMethod(receiver, methodName, args = []) {
41109
+ const methodAccess = ts.factory.createPropertyAccessExpression(receiver, methodName);
41110
+ return ts.factory.createCallExpression(
41111
+ /* expression */ methodAccess,
41112
+ /* typeArguments */ undefined,
41113
+ /* argumentsArray */ args);
41114
+ }
41115
+ function isAccessExpression(node) {
41116
+ return ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node);
41117
+ }
41118
+ /**
41119
+ * Creates a TypeScript node representing a numeric value.
41120
+ */
41121
+ function tsNumericExpression(value) {
41122
+ // As of TypeScript 5.3 negative numbers are represented as `prefixUnaryOperator` and passing a
41123
+ // negative number (even as a string) into `createNumericLiteral` will result in an error.
41124
+ if (value < 0) {
41125
+ const operand = ts.factory.createNumericLiteral(Math.abs(value));
41126
+ return ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, operand);
41127
+ }
41128
+ return ts.factory.createNumericLiteral(value);
41129
+ }
41130
+ /**
41131
+ * Check if a node represents a directive declaration in a TypeCheck Block.
41132
+ * Directive declarations can be either:
41133
+ * - var _t1: TestDir /*T:D*\/ = null! as TestDir;
41134
+ * - var _t1 /*T:D*\/ = _ctor1({});
41135
+ */
41136
+ function isDirectiveDeclaration(node) {
41137
+ const sourceFile = node.getSourceFile();
41138
+ return ((ts.isTypeNode(node) || ts.isIdentifier(node)) &&
41139
+ ts.isVariableDeclaration(node.parent) &&
41140
+ hasExpressionIdentifier(sourceFile, node, ExpressionIdentifier.DIRECTIVE));
41141
+ }
41142
+
40278
41143
  const NgOriginalFile = Symbol('NgOriginalFile');
40279
41144
  exports.UpdateMode = void 0;
40280
41145
  (function (UpdateMode) {
@@ -40463,12 +41328,13 @@ exports.SymbolKind = void 0;
40463
41328
 
40464
41329
  /**
40465
41330
  * Constructs a `ts.Diagnostic` for a given `ParseSourceSpan` within a template.
41331
+ *
41332
+ * @param deprecatedDiagInfo Optional information about deprecation and related messages.
40466
41333
  */
40467
- function makeTemplateDiagnostic(id, mapping, span, category, code, messageText, relatedMessages) {
41334
+ function makeTemplateDiagnostic(id, mapping, span, category, code, messageText, relatedMessages, deprecatedDiagInfo) {
40468
41335
  if (mapping.type === 'direct') {
40469
- let relatedInformation = undefined;
41336
+ let relatedInformation = [];
40470
41337
  if (relatedMessages !== undefined) {
40471
- relatedInformation = [];
40472
41338
  for (const relatedMessage of relatedMessages) {
40473
41339
  relatedInformation.push({
40474
41340
  category: ts.DiagnosticCategory.Message,
@@ -40480,6 +41346,9 @@ function makeTemplateDiagnostic(id, mapping, span, category, code, messageText,
40480
41346
  });
40481
41347
  }
40482
41348
  }
41349
+ if (deprecatedDiagInfo !== undefined) {
41350
+ relatedInformation.push(...(deprecatedDiagInfo.relatedMessages ?? []));
41351
+ }
40483
41352
  // For direct mappings, the error is shown inline as ngtsc was able to pinpoint a string
40484
41353
  // constant within the `@Component` decorator for the template. This allows us to map the error
40485
41354
  // directly into the bytes of the source file.
@@ -40494,6 +41363,7 @@ function makeTemplateDiagnostic(id, mapping, span, category, code, messageText,
40494
41363
  start: span.start.offset,
40495
41364
  length: span.end.offset - span.start.offset,
40496
41365
  relatedInformation,
41366
+ reportsDeprecated: deprecatedDiagInfo?.reportsDeprecated,
40497
41367
  };
40498
41368
  }
40499
41369
  else if (mapping.type === 'indirect' || mapping.type === 'external') {
@@ -40538,6 +41408,7 @@ function makeTemplateDiagnostic(id, mapping, span, category, code, messageText,
40538
41408
  start: mapping.node.getStart(),
40539
41409
  length: mapping.node.getEnd() - mapping.node.getStart(),
40540
41410
  relatedInformation,
41411
+ reportsDeprecated: deprecatedDiagInfo?.reportsDeprecated,
40541
41412
  };
40542
41413
  }
40543
41414
  let typeForMessage;
@@ -40553,6 +41424,9 @@ function makeTemplateDiagnostic(id, mapping, span, category, code, messageText,
40553
41424
  else {
40554
41425
  typeForMessage = 'Error';
40555
41426
  }
41427
+ if (deprecatedDiagInfo !== undefined) {
41428
+ relatedInformation.push(...(deprecatedDiagInfo.relatedMessages ?? []));
41429
+ }
40556
41430
  relatedInformation.push({
40557
41431
  category: ts.DiagnosticCategory.Message,
40558
41432
  code: 0,
@@ -40575,6 +41449,7 @@ function makeTemplateDiagnostic(id, mapping, span, category, code, messageText,
40575
41449
  length: span.end.offset - span.start.offset,
40576
41450
  // Show a secondary message indicating the component whose template contains the error.
40577
41451
  relatedInformation,
41452
+ reportsDeprecated: deprecatedDiagInfo?.reportsDeprecated,
40578
41453
  };
40579
41454
  }
40580
41455
  else {
@@ -40607,156 +41482,6 @@ function getTypeCheckId$1(clazz) {
40607
41482
  return sf[TYPE_CHECK_ID_MAP].get(clazz);
40608
41483
  }
40609
41484
 
40610
- const parseSpanComment = /^(\d+),(\d+)$/;
40611
- /**
40612
- * Reads the trailing comments and finds the first match which is a span comment (i.e. 4,10) on a
40613
- * node and returns it as an `AbsoluteSourceSpan`.
40614
- *
40615
- * Will return `null` if no trailing comments on the node match the expected form of a source span.
40616
- */
40617
- function readSpanComment(node, sourceFile = node.getSourceFile()) {
40618
- return (ts.forEachTrailingCommentRange(sourceFile.text, node.getEnd(), (pos, end, kind) => {
40619
- if (kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
40620
- return null;
40621
- }
40622
- const commentText = sourceFile.text.substring(pos + 2, end - 2);
40623
- const match = commentText.match(parseSpanComment);
40624
- if (match === null) {
40625
- return null;
40626
- }
40627
- return new AbsoluteSourceSpan(+match[1], +match[2]);
40628
- }) || null);
40629
- }
40630
- /** Used to identify what type the comment is. */
40631
- var CommentTriviaType;
40632
- (function (CommentTriviaType) {
40633
- CommentTriviaType["DIAGNOSTIC"] = "D";
40634
- CommentTriviaType["EXPRESSION_TYPE_IDENTIFIER"] = "T";
40635
- })(CommentTriviaType || (CommentTriviaType = {}));
40636
- /** Identifies what the TCB expression is for (for example, a directive declaration). */
40637
- var ExpressionIdentifier;
40638
- (function (ExpressionIdentifier) {
40639
- ExpressionIdentifier["DIRECTIVE"] = "DIR";
40640
- ExpressionIdentifier["COMPONENT_COMPLETION"] = "COMPCOMP";
40641
- ExpressionIdentifier["EVENT_PARAMETER"] = "EP";
40642
- ExpressionIdentifier["VARIABLE_AS_EXPRESSION"] = "VAE";
40643
- })(ExpressionIdentifier || (ExpressionIdentifier = {}));
40644
- /** Tags the node with the given expression identifier. */
40645
- function addExpressionIdentifier(node, identifier) {
40646
- ts.addSyntheticTrailingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, `${CommentTriviaType.EXPRESSION_TYPE_IDENTIFIER}:${identifier}`,
40647
- /* hasTrailingNewLine */ false);
40648
- }
40649
- const IGNORE_FOR_DIAGNOSTICS_MARKER = `${CommentTriviaType.DIAGNOSTIC}:ignore`;
40650
- /**
40651
- * Tag the `ts.Node` with an indication that any errors arising from the evaluation of the node
40652
- * should be ignored.
40653
- */
40654
- function markIgnoreDiagnostics(node) {
40655
- ts.addSyntheticTrailingComment(node, ts.SyntaxKind.MultiLineCommentTrivia, IGNORE_FOR_DIAGNOSTICS_MARKER,
40656
- /* hasTrailingNewLine */ false);
40657
- }
40658
- /** Returns true if the node has a marker that indicates diagnostics errors should be ignored. */
40659
- function hasIgnoreForDiagnosticsMarker(node, sourceFile) {
40660
- return (ts.forEachTrailingCommentRange(sourceFile.text, node.getEnd(), (pos, end, kind) => {
40661
- if (kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
40662
- return null;
40663
- }
40664
- const commentText = sourceFile.text.substring(pos + 2, end - 2);
40665
- return commentText === IGNORE_FOR_DIAGNOSTICS_MARKER;
40666
- }) === true);
40667
- }
40668
- function makeRecursiveVisitor(visitor) {
40669
- function recursiveVisitor(node) {
40670
- const res = visitor(node);
40671
- return res !== null ? res : node.forEachChild(recursiveVisitor);
40672
- }
40673
- return recursiveVisitor;
40674
- }
40675
- function getSpanFromOptions(opts) {
40676
- let withSpan = null;
40677
- if (opts.withSpan !== undefined) {
40678
- if (opts.withSpan instanceof AbsoluteSourceSpan) {
40679
- withSpan = opts.withSpan;
40680
- }
40681
- else {
40682
- withSpan = { start: opts.withSpan.start.offset, end: opts.withSpan.end.offset };
40683
- }
40684
- }
40685
- return withSpan;
40686
- }
40687
- /**
40688
- * Given a `ts.Node` with finds the first node whose matching the criteria specified
40689
- * by the `FindOptions`.
40690
- *
40691
- * Returns `null` when no `ts.Node` matches the given conditions.
40692
- */
40693
- function findFirstMatchingNode(tcb, opts) {
40694
- const withSpan = getSpanFromOptions(opts);
40695
- const withExpressionIdentifier = opts.withExpressionIdentifier;
40696
- const sf = tcb.getSourceFile();
40697
- const visitor = makeRecursiveVisitor((node) => {
40698
- if (!opts.filter(node)) {
40699
- return null;
40700
- }
40701
- if (withSpan !== null) {
40702
- const comment = readSpanComment(node, sf);
40703
- if (comment === null || withSpan.start !== comment.start || withSpan.end !== comment.end) {
40704
- return null;
40705
- }
40706
- }
40707
- if (withExpressionIdentifier !== undefined &&
40708
- !hasExpressionIdentifier(sf, node, withExpressionIdentifier)) {
40709
- return null;
40710
- }
40711
- return node;
40712
- });
40713
- return tcb.forEachChild(visitor) ?? null;
40714
- }
40715
- /**
40716
- * Given a `ts.Node` with source span comments, finds the first node whose source span comment
40717
- * matches the given `sourceSpan`. Additionally, the `filter` function allows matching only
40718
- * `ts.Nodes` of a given type, which provides the ability to select only matches of a given type
40719
- * when there may be more than one.
40720
- *
40721
- * Returns `null` when no `ts.Node` matches the given conditions.
40722
- */
40723
- function findAllMatchingNodes(tcb, opts) {
40724
- const withSpan = getSpanFromOptions(opts);
40725
- const withExpressionIdentifier = opts.withExpressionIdentifier;
40726
- const results = [];
40727
- const stack = [tcb];
40728
- const sf = tcb.getSourceFile();
40729
- while (stack.length > 0) {
40730
- const node = stack.pop();
40731
- if (!opts.filter(node)) {
40732
- stack.push(...node.getChildren());
40733
- continue;
40734
- }
40735
- if (withSpan !== null) {
40736
- const comment = readSpanComment(node, sf);
40737
- if (comment === null || withSpan.start !== comment.start || withSpan.end !== comment.end) {
40738
- stack.push(...node.getChildren());
40739
- continue;
40740
- }
40741
- }
40742
- if (withExpressionIdentifier !== undefined &&
40743
- !hasExpressionIdentifier(sf, node, withExpressionIdentifier)) {
40744
- continue;
40745
- }
40746
- results.push(node);
40747
- }
40748
- return results;
40749
- }
40750
- function hasExpressionIdentifier(sourceFile, node, identifier) {
40751
- return (ts.forEachTrailingCommentRange(sourceFile.text, node.getEnd(), (pos, end, kind) => {
40752
- if (kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
40753
- return false;
40754
- }
40755
- const commentText = sourceFile.text.substring(pos + 2, end - 2);
40756
- return commentText === `${CommentTriviaType.EXPRESSION_TYPE_IDENTIFIER}:${identifier}`;
40757
- }) || false);
40758
- }
40759
-
40760
41485
  /**
40761
41486
  * Powers autocompletion for a specific component.
40762
41487
  *
@@ -42473,152 +43198,6 @@ class ReferenceEmitEnvironment {
42473
43198
  }
42474
43199
  }
42475
43200
 
42476
- /**
42477
- * A `Set` of `ts.SyntaxKind`s of `ts.Expression` which are safe to wrap in a `ts.AsExpression`
42478
- * without needing to be wrapped in parentheses.
42479
- *
42480
- * For example, `foo.bar()` is a `ts.CallExpression`, and can be safely cast to `any` with
42481
- * `foo.bar() as any`. however, `foo !== bar` is a `ts.BinaryExpression`, and attempting to cast
42482
- * without the parentheses yields the expression `foo !== bar as any`. This is semantically
42483
- * equivalent to `foo !== (bar as any)`, which is not what was intended. Thus,
42484
- * `ts.BinaryExpression`s need to be wrapped in parentheses before casting.
42485
- */
42486
- //
42487
- let SAFE_TO_CAST_WITHOUT_PARENS = null;
42488
- function tsCastToAny(expr) {
42489
- if (SAFE_TO_CAST_WITHOUT_PARENS === null) {
42490
- SAFE_TO_CAST_WITHOUT_PARENS = new Set([
42491
- // Expressions which are already parenthesized can be cast without further wrapping.
42492
- ts.SyntaxKind.ParenthesizedExpression,
42493
- // Expressions which form a single lexical unit leave no room for precedence issues with the cast.
42494
- ts.SyntaxKind.Identifier,
42495
- ts.SyntaxKind.CallExpression,
42496
- ts.SyntaxKind.NonNullExpression,
42497
- ts.SyntaxKind.ElementAccessExpression,
42498
- ts.SyntaxKind.PropertyAccessExpression,
42499
- ts.SyntaxKind.ArrayLiteralExpression,
42500
- ts.SyntaxKind.ObjectLiteralExpression,
42501
- // The same goes for various literals.
42502
- ts.SyntaxKind.StringLiteral,
42503
- ts.SyntaxKind.NumericLiteral,
42504
- ts.SyntaxKind.TrueKeyword,
42505
- ts.SyntaxKind.FalseKeyword,
42506
- ts.SyntaxKind.NullKeyword,
42507
- ts.SyntaxKind.UndefinedKeyword,
42508
- ]);
42509
- }
42510
- // Wrap `expr` in parentheses if needed (see `SAFE_TO_CAST_WITHOUT_PARENS` above).
42511
- if (!SAFE_TO_CAST_WITHOUT_PARENS.has(expr.kind)) {
42512
- expr = ts.factory.createParenthesizedExpression(expr);
42513
- }
42514
- // The outer expression is always wrapped in parentheses.
42515
- return ts.factory.createParenthesizedExpression(ts.factory.createAsExpression(expr, ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)));
42516
- }
42517
- /**
42518
- * Create an expression which instantiates an element by its HTML tagName.
42519
- *
42520
- * Thanks to narrowing of `document.createElement()`, this expression will have its type inferred
42521
- * based on the tag name, including for custom elements that have appropriate .d.ts definitions.
42522
- */
42523
- function tsCreateElement(...tagNames) {
42524
- const createElement = ts.factory.createPropertyAccessExpression(
42525
- /* expression */ ts.factory.createIdentifier('document'), 'createElement');
42526
- let arg;
42527
- if (tagNames.length === 1) {
42528
- // If there's only one tag name, we can pass it in directly.
42529
- arg = ts.factory.createStringLiteral(tagNames[0]);
42530
- }
42531
- else {
42532
- // If there's more than one name, we have to generate a union of all the tag names. To do so,
42533
- // create an expression in the form of `null! as 'tag-1' | 'tag-2' | 'tag-3'`. This allows
42534
- // TypeScript to infer the type as a union of the differnet tags.
42535
- const assertedNullExpression = ts.factory.createNonNullExpression(ts.factory.createNull());
42536
- const type = ts.factory.createUnionTypeNode(tagNames.map((tag) => ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(tag))));
42537
- arg = ts.factory.createAsExpression(assertedNullExpression, type);
42538
- }
42539
- return ts.factory.createCallExpression(
42540
- /* expression */ createElement,
42541
- /* typeArguments */ undefined,
42542
- /* argumentsArray */ [arg]);
42543
- }
42544
- /**
42545
- * Create a `ts.VariableStatement` which declares a variable without explicit initialization.
42546
- *
42547
- * The initializer `null!` is used to bypass strict variable initialization checks.
42548
- *
42549
- * Unlike with `tsCreateVariable`, the type of the variable is explicitly specified.
42550
- */
42551
- function tsDeclareVariable(id, type) {
42552
- // When we create a variable like `var _t1: boolean = null!`, TypeScript actually infers `_t1`
42553
- // to be `never`, instead of a `boolean`. To work around it, we cast the value
42554
- // in the initializer, e.g. `var _t1 = null! as boolean;`.
42555
- addExpressionIdentifier(type, ExpressionIdentifier.VARIABLE_AS_EXPRESSION);
42556
- const initializer = ts.factory.createAsExpression(ts.factory.createNonNullExpression(ts.factory.createNull()), type);
42557
- const decl = ts.factory.createVariableDeclaration(
42558
- /* name */ id,
42559
- /* exclamationToken */ undefined,
42560
- /* type */ undefined,
42561
- /* initializer */ initializer);
42562
- return ts.factory.createVariableStatement(
42563
- /* modifiers */ undefined,
42564
- /* declarationList */ [decl]);
42565
- }
42566
- /**
42567
- * Creates a `ts.TypeQueryNode` for a coerced input.
42568
- *
42569
- * For example: `typeof MatInput.ngAcceptInputType_value`, where MatInput is `typeName` and `value`
42570
- * is the `coercedInputName`.
42571
- *
42572
- * @param typeName The `EntityName` of the Directive where the static coerced input is defined.
42573
- * @param coercedInputName The field name of the coerced input.
42574
- */
42575
- function tsCreateTypeQueryForCoercedInput(typeName, coercedInputName) {
42576
- return ts.factory.createTypeQueryNode(ts.factory.createQualifiedName(typeName, `ngAcceptInputType_${coercedInputName}`));
42577
- }
42578
- /**
42579
- * Create a `ts.VariableStatement` that initializes a variable with a given expression.
42580
- *
42581
- * Unlike with `tsDeclareVariable`, the type of the variable is inferred from the initializer
42582
- * expression.
42583
- */
42584
- function tsCreateVariable(id, initializer, flags = null) {
42585
- const decl = ts.factory.createVariableDeclaration(
42586
- /* name */ id,
42587
- /* exclamationToken */ undefined,
42588
- /* type */ undefined,
42589
- /* initializer */ initializer);
42590
- return ts.factory.createVariableStatement(
42591
- /* modifiers */ undefined,
42592
- /* declarationList */ flags === null
42593
- ? [decl]
42594
- : ts.factory.createVariableDeclarationList([decl], flags));
42595
- }
42596
- /**
42597
- * Construct a `ts.CallExpression` that calls a method on a receiver.
42598
- */
42599
- function tsCallMethod(receiver, methodName, args = []) {
42600
- const methodAccess = ts.factory.createPropertyAccessExpression(receiver, methodName);
42601
- return ts.factory.createCallExpression(
42602
- /* expression */ methodAccess,
42603
- /* typeArguments */ undefined,
42604
- /* argumentsArray */ args);
42605
- }
42606
- function isAccessExpression(node) {
42607
- return ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node);
42608
- }
42609
- /**
42610
- * Creates a TypeScript node representing a numeric value.
42611
- */
42612
- function tsNumericExpression(value) {
42613
- // As of TypeScript 5.3 negative numbers are represented as `prefixUnaryOperator` and passing a
42614
- // negative number (even as a string) into `createNumericLiteral` will result in an error.
42615
- if (value < 0) {
42616
- const operand = ts.factory.createNumericLiteral(Math.abs(value));
42617
- return ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, operand);
42618
- }
42619
- return ts.factory.createNumericLiteral(value);
42620
- }
42621
-
42622
43201
  /**
42623
43202
  * See `TypeEmitter` for more information on the emitting process.
42624
43203
  */
@@ -42971,7 +43550,8 @@ function inferBoundAttribute(name) {
42971
43550
  const attrPrefix = 'attr.';
42972
43551
  const classPrefix = 'class.';
42973
43552
  const stylePrefix = 'style.';
42974
- const animationPrefix = '@';
43553
+ const animationPrefix = 'animate.';
43554
+ const legacyAnimationPrefix = '@';
42975
43555
  let attrName;
42976
43556
  let type;
42977
43557
  // Infer the binding type based on the prefix.
@@ -42988,7 +43568,11 @@ function inferBoundAttribute(name) {
42988
43568
  type = exports.BindingType.Style;
42989
43569
  }
42990
43570
  else if (name.startsWith(animationPrefix)) {
42991
- attrName = name.slice(animationPrefix.length);
43571
+ attrName = name;
43572
+ type = exports.BindingType.Animation;
43573
+ }
43574
+ else if (name.startsWith(legacyAnimationPrefix)) {
43575
+ attrName = name.slice(legacyAnimationPrefix.length);
42992
43576
  type = exports.BindingType.LegacyAnimation;
42993
43577
  }
42994
43578
  else {
@@ -43993,7 +44577,12 @@ function translateDiagnostic(diagnostic, resolver) {
43993
44577
  return null;
43994
44578
  }
43995
44579
  const { sourceLocation, sourceMapping: templateSourceMapping, span } = fullMapping;
43996
- return makeTemplateDiagnostic(sourceLocation.id, templateSourceMapping, span, diagnostic.category, diagnostic.code, diagnostic.messageText);
44580
+ return makeTemplateDiagnostic(sourceLocation.id, templateSourceMapping, span, diagnostic.category, diagnostic.code, diagnostic.messageText, undefined, diagnostic.reportsDeprecated !== undefined
44581
+ ? {
44582
+ reportsDeprecated: diagnostic.reportsDeprecated,
44583
+ relatedMessages: diagnostic.relatedInformation,
44584
+ }
44585
+ : undefined);
43997
44586
  }
43998
44587
 
43999
44588
  /**
@@ -45351,7 +45940,7 @@ class TcbDomSchemaCheckerOp extends TcbOp {
45351
45940
  }
45352
45941
  if (isPropertyBinding && binding.name !== 'style' && binding.name !== 'class') {
45353
45942
  // A direct binding to a property.
45354
- const propertyName = ATTR_TO_PROP.get(binding.name) ?? binding.name;
45943
+ const propertyName = REGISTRY$1.getMappedPropName(binding.name);
45355
45944
  if (isTemplateElement) {
45356
45945
  this.tcb.domSchemaChecker.checkTemplateElementProperty(this.tcb.id, this.getTagName(element), propertyName, binding.sourceSpan, this.tcb.schemas, this.tcb.hostIsStandalone);
45357
45946
  }
@@ -45523,18 +46112,6 @@ class TcbComponentNodeOp extends TcbOp {
45523
46112
  return id;
45524
46113
  }
45525
46114
  }
45526
- /**
45527
- * Mapping between attributes names that don't correspond to their element property names.
45528
- * Note: this mapping has to be kept in sync with the equally named mapping in the runtime.
45529
- */
45530
- const ATTR_TO_PROP = new Map(Object.entries({
45531
- 'class': 'className',
45532
- 'for': 'htmlFor',
45533
- 'formaction': 'formAction',
45534
- 'innerHtml': 'innerHTML',
45535
- 'readonly': 'readOnly',
45536
- 'tabindex': 'tabIndex',
45537
- }));
45538
46115
  /**
45539
46116
  * A `TcbOp` which generates code to check "unclaimed inputs" - bindings on an element which were
45540
46117
  * not attributed to any directive or component, and are instead processed against the HTML element
@@ -45580,7 +46157,7 @@ class TcbUnclaimedInputsOp extends TcbOp {
45580
46157
  elId = this.scope.resolve(this.target);
45581
46158
  }
45582
46159
  // A direct binding to a property.
45583
- const propertyName = ATTR_TO_PROP.get(binding.name) ?? binding.name;
46160
+ const propertyName = REGISTRY$1.getMappedPropName(binding.name);
45584
46161
  const prop = ts.factory.createElementAccessExpression(elId, ts.factory.createStringLiteral(propertyName));
45585
46162
  const stmt = ts.factory.createBinaryExpression(prop, ts.SyntaxKind.EqualsToken, wrapForDiagnostics(expr));
45586
46163
  addParseSpanInfo(stmt, binding.sourceSpan);
@@ -45718,14 +46295,19 @@ class TcbUnclaimedOutputsOp extends TcbOp {
45718
46295
  const handler = tcbCreateEventHandler(output, this.tcb, this.scope, eventType);
45719
46296
  this.scope.addStatement(ts.factory.createExpressionStatement(handler));
45720
46297
  }
46298
+ else if (output.type === exports.ParsedEventType.Animation) {
46299
+ const eventType = this.tcb.env.referenceExternalType('@angular/core', 'AnimationCallbackEvent');
46300
+ const handler = tcbCreateEventHandler(output, this.tcb, this.scope, eventType);
46301
+ this.scope.addStatement(ts.factory.createExpressionStatement(handler));
46302
+ }
45721
46303
  else if (this.tcb.env.config.checkTypeOfDomEvents) {
45722
46304
  // If strict checking of DOM events is enabled, generate a call to `addEventListener` on
45723
46305
  // the element instance so that TypeScript's type inference for
45724
46306
  // `HTMLElement.addEventListener` using `HTMLElementEventMap` to infer an accurate type for
45725
46307
  // `$event` depending on the event name. For unknown event names, TypeScript resorts to the
45726
46308
  // base `Event` type.
45727
- const handler = tcbCreateEventHandler(output, this.tcb, this.scope, 0 /* EventParamType.Infer */);
45728
46309
  let target;
46310
+ let domEventAssertion;
45729
46311
  // Only check for `window` and `document` since in theory any target can be passed.
45730
46312
  if (output.target === 'window' || output.target === 'document') {
45731
46313
  target = ts.factory.createIdentifier(output.target);
@@ -45736,8 +46318,32 @@ class TcbUnclaimedOutputsOp extends TcbOp {
45736
46318
  else {
45737
46319
  target = elId;
45738
46320
  }
46321
+ // By default the target of an event is `EventTarget | null`, because of bubbling
46322
+ // and custom events. This can be inconvenient in some common cases like `input` elements
46323
+ // since we don't have the ability to type cast in templates. We can improve the type
46324
+ // checking for some of these cases by inferring the target based on the element it was
46325
+ // bound to. We can only do this safely if the element is a void element (e.g. `input` or
46326
+ // `img`), because we know that it couldn't have bubbled from a child. The event handler
46327
+ // with the assertion would look as follows:
46328
+ //
46329
+ // ```
46330
+ // const _t1 = document.createElement('input');
46331
+ //
46332
+ // _t1.addEventListener('input', ($event) => {
46333
+ // ɵassertType<typeof _t1>($event.target);
46334
+ // handler($event.target);
46335
+ // });
46336
+ // ```
46337
+ if (this.target instanceof Element$1 &&
46338
+ this.target.isVoid &&
46339
+ ts.isIdentifier(target)) {
46340
+ domEventAssertion = ts.factory.createCallExpression(this.tcb.env.referenceExternalSymbol('@angular/core', 'ɵassertType'), [ts.factory.createTypeQueryNode(target)], [
46341
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(EVENT_PARAMETER), 'target'),
46342
+ ]);
46343
+ }
45739
46344
  const propertyAccess = ts.factory.createPropertyAccessExpression(target, 'addEventListener');
45740
46345
  addParseSpanInfo(propertyAccess, output.keySpan);
46346
+ const handler = tcbCreateEventHandler(output, this.tcb, this.scope, 0 /* EventParamType.Infer */, domEventAssertion);
45741
46347
  const call = ts.factory.createCallExpression(
45742
46348
  /* expression */ propertyAccess,
45743
46349
  /* typeArguments */ undefined,
@@ -47168,9 +47774,12 @@ const EVENT_PARAMETER = '$event';
47168
47774
  * parameter will have an explicit `any` type, effectively disabling strict type checking of event
47169
47775
  * bindings. Alternatively, an explicit type can be passed for the `$event` parameter.
47170
47776
  */
47171
- function tcbCreateEventHandler(event, tcb, scope, eventType) {
47777
+ function tcbCreateEventHandler(event, tcb, scope, eventType, assertionExpression) {
47172
47778
  const handler = tcbEventHandlerExpression(event.handler, tcb, scope);
47173
47779
  const statements = [];
47780
+ if (assertionExpression !== undefined) {
47781
+ statements.push(ts.factory.createExpressionStatement(assertionExpression));
47782
+ }
47174
47783
  // TODO(crisbeto): remove the `checkTwoWayBoundEvents` check in v20.
47175
47784
  if (event.type === exports.ParsedEventType.TwoWay && tcb.env.config.checkTwoWayBoundEvents) {
47176
47785
  // If we're dealing with a two-way event, we create a variable initialized to the unwrapped
@@ -48016,13 +48625,6 @@ class SymbolBuilder {
48016
48625
  }
48017
48626
  getDirectivesOfNode(templateNode) {
48018
48627
  const elementSourceSpan = templateNode.startSourceSpan ?? templateNode.sourceSpan;
48019
- const tcbSourceFile = this.typeCheckBlock.getSourceFile();
48020
- // directives could be either:
48021
- // - var _t1: TestDir /*T:D*/ = null! as TestDir;
48022
- // - var _t1 /*T:D*/ = _ctor1({});
48023
- const isDirectiveDeclaration = (node) => (ts.isTypeNode(node) || ts.isIdentifier(node)) &&
48024
- ts.isVariableDeclaration(node.parent) &&
48025
- hasExpressionIdentifier(tcbSourceFile, node, ExpressionIdentifier.DIRECTIVE);
48026
48628
  const nodes = findAllMatchingNodes(this.typeCheckBlock, {
48027
48629
  withSpan: elementSourceSpan,
48028
48630
  filter: isDirectiveDeclaration,
@@ -48886,6 +49488,29 @@ class TemplateTypeCheckerImpl {
48886
49488
  return diagnostics.filter((diag) => diag !== null);
48887
49489
  });
48888
49490
  }
49491
+ getSuggestionDiagnosticsForFile(sf, tsLs, optimizeFor) {
49492
+ switch (optimizeFor) {
49493
+ case exports.OptimizeFor.WholeProgram:
49494
+ this.ensureAllShimsForAllFiles();
49495
+ break;
49496
+ case exports.OptimizeFor.SingleFile:
49497
+ this.ensureAllShimsForOneFile(sf);
49498
+ break;
49499
+ }
49500
+ return this.perf.inPhase(exports.PerfPhase.TtcSuggestionDiagnostics, () => {
49501
+ const sfPath = absoluteFromSourceFile(sf);
49502
+ const fileRecord = this.state.get(sfPath);
49503
+ const diagnostics = [];
49504
+ const program = this.programDriver.getProgram();
49505
+ if (fileRecord.hasInlines) {
49506
+ diagnostics.push(...getDeprecatedSuggestionDiagnostics(tsLs, program, sfPath, fileRecord, this));
49507
+ }
49508
+ for (const [shimPath] of fileRecord.shimData) {
49509
+ diagnostics.push(...getDeprecatedSuggestionDiagnostics(tsLs, program, shimPath, fileRecord, this));
49510
+ }
49511
+ return diagnostics.filter((diag) => diag !== null);
49512
+ });
49513
+ }
48889
49514
  getDiagnosticsForComponent(component) {
48890
49515
  this.ensureShimForComponent(component);
48891
49516
  return this.perf.inPhase(exports.PerfPhase.TtcDiagnostics, () => {
@@ -48917,6 +49542,27 @@ class TemplateTypeCheckerImpl {
48917
49542
  return diagnostics.filter((diag) => diag !== null && diag.typeCheckId === id);
48918
49543
  });
48919
49544
  }
49545
+ getSuggestionDiagnosticsForComponent(component, tsLs) {
49546
+ this.ensureShimForComponent(component);
49547
+ return this.perf.inPhase(exports.PerfPhase.TtcSuggestionDiagnostics, () => {
49548
+ const sf = component.getSourceFile();
49549
+ const sfPath = absoluteFromSourceFile(sf);
49550
+ const shimPath = TypeCheckShimGenerator.shimFor(sfPath);
49551
+ const fileRecord = this.getFileData(sfPath);
49552
+ if (!fileRecord.shimData.has(shimPath)) {
49553
+ return [];
49554
+ }
49555
+ const templateId = fileRecord.sourceManager.getTypeCheckId(component);
49556
+ const shimRecord = fileRecord.shimData.get(shimPath);
49557
+ const diagnostics = [];
49558
+ const program = this.programDriver.getProgram();
49559
+ if (shimRecord.hasInlines) {
49560
+ diagnostics.push(...getDeprecatedSuggestionDiagnostics(tsLs, program, sfPath, fileRecord, this));
49561
+ }
49562
+ diagnostics.push(...getDeprecatedSuggestionDiagnostics(tsLs, program, shimPath, fileRecord, this));
49563
+ return diagnostics.filter((diag) => diag !== null && diag.typeCheckId === templateId);
49564
+ });
49565
+ }
48920
49566
  getTypeCheckBlock(component) {
48921
49567
  return this.getLatestComponentState(component).tcb;
48922
49568
  }
@@ -49740,6 +50386,124 @@ function getClassDeclFromSymbol(symbol, checker) {
49740
50386
  }
49741
50387
  return null;
49742
50388
  }
50389
+ /**
50390
+ * Returns the diagnostics that report deprecated symbols in the given TypeScript language service.
50391
+ *
50392
+ * There are two logins here:
50393
+ *
50394
+ * 1. For input properties, function calls, and so on, the diagnostics reported in the TypeScript
50395
+ * Language Service can be directly transformed into template diagnostics.
50396
+ * 2. For the element tag deprecation, we need to manually connect the TCB node to the template node
50397
+ * and generate the template diagnostics.
50398
+ */
50399
+ function getDeprecatedSuggestionDiagnostics(tsLs, program, path, fileRecord, templateTypeChecker) {
50400
+ const sourceFile = program.getSourceFile(path);
50401
+ if (sourceFile === undefined) {
50402
+ return [];
50403
+ }
50404
+ const tsDiags = tsLs.getSuggestionDiagnostics(path).filter(isDeprecatedDiagnostics);
50405
+ const commonTemplateDiags = tsDiags.map((diag) => {
50406
+ return convertDiagnostic(diag, fileRecord.sourceManager);
50407
+ });
50408
+ const elementTagDiags = getTheElementTagDeprecatedSuggestionDiagnostics(path, program, fileRecord, tsDiags, templateTypeChecker);
50409
+ return [...commonTemplateDiags, ...elementTagDiags];
50410
+ }
50411
+ /**
50412
+ * Connect the TCB node to the template node and generate the template diagnostics.
50413
+ *
50414
+ * How to generate the template diagnostics:
50415
+ *
50416
+ * 1. For each diagnostic, find the TCB node that is reported.
50417
+ * 2. Build a map called `nodeToDiag` that the key is the type node and value is the diagnostic.
50418
+ * For example:
50419
+ * ```
50420
+ * var _t1 = null! as TestDir;
50421
+ * ^^^^^^^------ This is diagnostic node that is reported by the ts.
50422
+ * ```
50423
+ * The key is the class component of TestDir.
50424
+ * 3. Find the all directive nodes in the TCB.
50425
+ * For example:
50426
+ * In the above example, the directive node is `_t1`, get the type of `_t1` which is the
50427
+ * class component of `TestDir`. Check if there is a diagnostic in the `nodeToDiag` map
50428
+ * that matches the class component of `TestDir`.
50429
+ * If there is a match, it means that the diagnostic is reported for the directive node
50430
+ * 4. Generate the template diagnostic and return the template diagnostics.
50431
+ */
50432
+ function getTheElementTagDeprecatedSuggestionDiagnostics(shimPath, program, fileRecord, diags, templateTypeChecker) {
50433
+ const sourceFile = program.getSourceFile(shimPath);
50434
+ if (sourceFile === undefined) {
50435
+ return [];
50436
+ }
50437
+ const typeChecker = program.getTypeChecker();
50438
+ const nodeToDiag = new Map();
50439
+ for (const tsDiag of diags) {
50440
+ const diagNode = getTokenAtPosition(sourceFile, tsDiag.start);
50441
+ const nodeType = typeChecker.getTypeAtLocation(diagNode);
50442
+ const nodeSymbolDeclarations = nodeType.symbol.declarations;
50443
+ const decl = nodeSymbolDeclarations !== undefined && nodeSymbolDeclarations.length > 0
50444
+ ? nodeSymbolDeclarations[0]
50445
+ : undefined;
50446
+ if (decl === undefined || !ts.isClassDeclaration(decl)) {
50447
+ continue;
50448
+ }
50449
+ const directiveForDiagnostic = templateTypeChecker.getDirectiveMetadata(decl);
50450
+ // For now, we only report deprecations for components. This is because
50451
+ // directive spans apply to the entire element, so it would cause the deprecation to
50452
+ // appear as a deprecation for the element rather than whatever the selector (likely an attribute)
50453
+ // is for the directive. Technically components have this issue as well but nearly
50454
+ // all component selectors are element selectors.
50455
+ if (directiveForDiagnostic === null || !directiveForDiagnostic.isComponent) {
50456
+ continue;
50457
+ }
50458
+ nodeToDiag.set(decl, tsDiag);
50459
+ }
50460
+ const directiveNodesInTcb = findAllMatchingNodes(sourceFile, {
50461
+ filter: isDirectiveDeclaration,
50462
+ });
50463
+ const templateDiagnostics = [];
50464
+ for (const directive of directiveNodesInTcb) {
50465
+ const directiveType = typeChecker.getTypeAtLocation(directive);
50466
+ const directiveSymbolDeclarations = directiveType.symbol.declarations;
50467
+ const decl = directiveSymbolDeclarations !== undefined && directiveSymbolDeclarations.length > 0
50468
+ ? directiveSymbolDeclarations[0]
50469
+ : undefined;
50470
+ if (decl === undefined) {
50471
+ continue;
50472
+ }
50473
+ if (!ts.isClassDeclaration(decl)) {
50474
+ continue;
50475
+ }
50476
+ const diagnostic = nodeToDiag.get(decl);
50477
+ if (diagnostic === undefined) {
50478
+ continue;
50479
+ }
50480
+ const fullMapping = getSourceMapping(diagnostic.file, directive.getStart(), fileRecord.sourceManager,
50481
+ /**
50482
+ * Don't set to true, the deprecated diagnostics will be ignored if this is a diagnostics request.
50483
+ * Only the deprecated diagnostics will be reported here.
50484
+ */
50485
+ // For example:
50486
+ // var _t2 /*T:DIR*/ /*87,104*/ = _ctor1({ "name": ("") /*96,103*/ }) /*D:ignore*/;
50487
+ // At the end of the statement, there is a comment `/*D:ignore*/` which means that this diagnostic
50488
+ // should be ignored in diagnostics request.
50489
+ /*isDiagnosticsRequest*/ false);
50490
+ if (fullMapping === null) {
50491
+ continue;
50492
+ }
50493
+ const { sourceLocation, sourceMapping: templateSourceMapping, span } = fullMapping;
50494
+ const templateDiagnostic = makeTemplateDiagnostic(sourceLocation.id, templateSourceMapping, span, diagnostic.category, diagnostic.code, diagnostic.messageText, undefined, diagnostic.reportsDeprecated !== undefined
50495
+ ? {
50496
+ reportsDeprecated: diagnostic.reportsDeprecated,
50497
+ relatedMessages: diagnostic.relatedInformation,
50498
+ }
50499
+ : undefined);
50500
+ templateDiagnostics.push(templateDiagnostic);
50501
+ }
50502
+ return templateDiagnostics;
50503
+ }
50504
+ function isDeprecatedDiagnostics(diag) {
50505
+ return diag.reportsDeprecated !== undefined;
50506
+ }
49743
50507
 
49744
50508
  exports.AST = AST;
49745
50509
  exports.ASTWithSource = ASTWithSource;