@angular/core 20.0.0-next.2 → 20.0.0-next.4

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 (56) hide show
  1. package/event_dispatcher.d-pVP0-wST.d.ts +345 -0
  2. package/fesm2022/core.mjs +614 -428
  3. package/fesm2022/core.mjs.map +1 -1
  4. package/fesm2022/injector-BlLwZ2sr.mjs +24 -0
  5. package/fesm2022/injector-BlLwZ2sr.mjs.map +1 -0
  6. package/fesm2022/primitives/di.mjs +5 -18
  7. package/fesm2022/primitives/di.mjs.map +1 -1
  8. package/fesm2022/primitives/event-dispatch.mjs +1 -1
  9. package/fesm2022/primitives/signals.mjs +4 -589
  10. package/fesm2022/primitives/signals.mjs.map +1 -1
  11. package/fesm2022/rxjs-interop.mjs +1 -8
  12. package/fesm2022/rxjs-interop.mjs.map +1 -1
  13. package/fesm2022/testing.mjs +2 -10
  14. package/fesm2022/testing.mjs.map +1 -1
  15. package/fesm2022/untracked-DkcXpNb_.mjs +620 -0
  16. package/fesm2022/untracked-DkcXpNb_.mjs.map +1 -0
  17. package/index.d.ts +7589 -7510
  18. package/{navigation_types.d-u4EOrrdZ.d.ts → navigation_types.d-DgDrF5rp.d.ts} +2 -2
  19. package/package.json +2 -2
  20. package/primitives/di/index.d.ts +25 -10
  21. package/primitives/event-dispatch/index.d.ts +5 -340
  22. package/primitives/signals/index.d.ts +5 -208
  23. package/rxjs-interop/index.d.ts +1 -10
  24. package/schematics/bundles/{apply_import_manager-CyRT0UvU.js → apply_import_manager-CeNv8GIG.js} +6 -6
  25. package/schematics/bundles/{checker-DF8ZaFW5.js → checker-k591b6WQ.js} +856 -180
  26. package/schematics/bundles/cleanup-unused-imports.js +42 -69
  27. package/schematics/bundles/{compiler_host-Da636uJ8.js → compiler_host-DwM3ugW3.js} +2 -2
  28. package/schematics/bundles/control-flow-migration.js +34 -13
  29. package/schematics/bundles/imports-CIX-JgAN.js +1 -1
  30. package/schematics/bundles/{program-BZk27Ndu.js → index-B4OAlHh8.js} +2234 -2097
  31. package/schematics/bundles/{index-DnkWgagp.js → index-BhELUmYx.js} +11 -11
  32. package/schematics/bundles/inject-flags.js +18 -52
  33. package/schematics/bundles/inject-migration.js +3 -3
  34. package/schematics/bundles/leading_space-D9nQ8UQC.js +1 -1
  35. package/schematics/bundles/{migrate_ts_type_references-DtkOnnv0.js → migrate_ts_type_references-Be0TNYen.js} +20 -20
  36. package/schematics/bundles/ng_decorators-DznZ5jMl.js +1 -1
  37. package/schematics/bundles/nodes-B16H9JUd.js +1 -1
  38. package/schematics/bundles/output-migration.js +62 -90
  39. package/schematics/bundles/project_tsconfig_paths-CDVxT6Ov.js +1 -1
  40. package/schematics/bundles/property_name-BBwFuqMe.js +1 -1
  41. package/schematics/bundles/route-lazy-loading.js +3 -3
  42. package/schematics/bundles/{project_paths-Jtbi76Bs.js → run_in_devkit-CkvEksWP.js} +262 -197
  43. package/schematics/bundles/self-closing-tags-migration.js +41 -71
  44. package/schematics/bundles/signal-input-migration.js +69 -97
  45. package/schematics/bundles/signal-queries-migration.js +80 -108
  46. package/schematics/bundles/signals.js +11 -11
  47. package/schematics/bundles/standalone-migration.js +8 -22
  48. package/schematics/bundles/symbol-VPWguRxr.js +25 -0
  49. package/schematics/bundles/test-bed-get.js +98 -0
  50. package/schematics/migrations.json +5 -0
  51. package/testing/index.d.ts +2 -4
  52. package/weak_ref.d-BZ7gyRag.d.ts +216 -0
  53. package/fesm2022/weak_ref-DrMdAIDh.mjs +0 -12
  54. package/fesm2022/weak_ref-DrMdAIDh.mjs.map +0 -1
  55. package/schematics/bundles/index-vGJcp5M7.js +0 -30
  56. package/weak_ref.d-ttyj86RV.d.ts +0 -9
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v20.0.0-next.2
3
+ * @license Angular v20.0.0-next.4
4
4
  * (c) 2010-2025 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
@@ -2773,6 +2773,11 @@ class Identifiers {
2773
2773
  name: 'ɵɵdeferEnableTimerScheduling',
2774
2774
  moduleName: CORE,
2775
2775
  };
2776
+ static conditionalCreate = { name: 'ɵɵconditionalCreate', moduleName: CORE };
2777
+ static conditionalBranchCreate = {
2778
+ name: 'ɵɵconditionalBranchCreate',
2779
+ moduleName: CORE,
2780
+ };
2776
2781
  static conditional = { name: 'ɵɵconditional', moduleName: CORE };
2777
2782
  static repeater = { name: 'ɵɵrepeater', moduleName: CORE };
2778
2783
  static repeaterCreate = { name: 'ɵɵrepeaterCreate', moduleName: CORE };
@@ -5350,6 +5355,28 @@ let Icu$1 = class Icu {
5350
5355
  return visitor.visitIcu(this);
5351
5356
  }
5352
5357
  };
5358
+ /**
5359
+ * AST node that represents the host element of a directive.
5360
+ * This node is used only for type checking purposes and cannot be produced from a user's template.
5361
+ */
5362
+ class HostElement {
5363
+ tagNames;
5364
+ bindings;
5365
+ listeners;
5366
+ sourceSpan;
5367
+ constructor(tagNames, bindings, listeners, sourceSpan) {
5368
+ this.tagNames = tagNames;
5369
+ this.bindings = bindings;
5370
+ this.listeners = listeners;
5371
+ this.sourceSpan = sourceSpan;
5372
+ if (tagNames.length === 0) {
5373
+ throw new Error('HostElement must have at least one tag name.');
5374
+ }
5375
+ }
5376
+ visit() {
5377
+ throw new Error(`HostElement cannot be visited`);
5378
+ }
5379
+ }
5353
5380
  let RecursiveVisitor$1 = class RecursiveVisitor {
5354
5381
  visitElement(element) {
5355
5382
  visitAll$1(this, element.attributes);
@@ -8581,167 +8608,175 @@ var OpKind;
8581
8608
  * node.
8582
8609
  */
8583
8610
  OpKind[OpKind["DisableBindings"] = 10] = "DisableBindings";
8611
+ /**
8612
+ * Create a conditional creation instruction op.
8613
+ */
8614
+ OpKind[OpKind["ConditionalCreate"] = 11] = "ConditionalCreate";
8615
+ /**
8616
+ * Create a conditional branch creation instruction op.
8617
+ */
8618
+ OpKind[OpKind["ConditionalBranchCreate"] = 12] = "ConditionalBranchCreate";
8584
8619
  /**
8585
8620
  * An op to conditionally render a template.
8586
8621
  */
8587
- OpKind[OpKind["Conditional"] = 11] = "Conditional";
8622
+ OpKind[OpKind["Conditional"] = 13] = "Conditional";
8588
8623
  /**
8589
8624
  * An operation to re-enable binding, after it was previously disabled.
8590
8625
  */
8591
- OpKind[OpKind["EnableBindings"] = 12] = "EnableBindings";
8626
+ OpKind[OpKind["EnableBindings"] = 14] = "EnableBindings";
8592
8627
  /**
8593
8628
  * An operation to render a text node.
8594
8629
  */
8595
- OpKind[OpKind["Text"] = 13] = "Text";
8630
+ OpKind[OpKind["Text"] = 15] = "Text";
8596
8631
  /**
8597
8632
  * An operation declaring an event listener for an element.
8598
8633
  */
8599
- OpKind[OpKind["Listener"] = 14] = "Listener";
8634
+ OpKind[OpKind["Listener"] = 16] = "Listener";
8600
8635
  /**
8601
8636
  * An operation to interpolate text into a text node.
8602
8637
  */
8603
- OpKind[OpKind["InterpolateText"] = 15] = "InterpolateText";
8638
+ OpKind[OpKind["InterpolateText"] = 17] = "InterpolateText";
8604
8639
  /**
8605
8640
  * An intermediate binding op, that has not yet been processed into an individual property,
8606
8641
  * attribute, style, etc.
8607
8642
  */
8608
- OpKind[OpKind["Binding"] = 16] = "Binding";
8643
+ OpKind[OpKind["Binding"] = 18] = "Binding";
8609
8644
  /**
8610
8645
  * An operation to bind an expression to a property of an element.
8611
8646
  */
8612
- OpKind[OpKind["Property"] = 17] = "Property";
8647
+ OpKind[OpKind["Property"] = 19] = "Property";
8613
8648
  /**
8614
8649
  * An operation to bind an expression to a style property of an element.
8615
8650
  */
8616
- OpKind[OpKind["StyleProp"] = 18] = "StyleProp";
8651
+ OpKind[OpKind["StyleProp"] = 20] = "StyleProp";
8617
8652
  /**
8618
8653
  * An operation to bind an expression to a class property of an element.
8619
8654
  */
8620
- OpKind[OpKind["ClassProp"] = 19] = "ClassProp";
8655
+ OpKind[OpKind["ClassProp"] = 21] = "ClassProp";
8621
8656
  /**
8622
8657
  * An operation to bind an expression to the styles of an element.
8623
8658
  */
8624
- OpKind[OpKind["StyleMap"] = 20] = "StyleMap";
8659
+ OpKind[OpKind["StyleMap"] = 22] = "StyleMap";
8625
8660
  /**
8626
8661
  * An operation to bind an expression to the classes of an element.
8627
8662
  */
8628
- OpKind[OpKind["ClassMap"] = 21] = "ClassMap";
8663
+ OpKind[OpKind["ClassMap"] = 23] = "ClassMap";
8629
8664
  /**
8630
8665
  * An operation to advance the runtime's implicit slot context during the update phase of a view.
8631
8666
  */
8632
- OpKind[OpKind["Advance"] = 22] = "Advance";
8667
+ OpKind[OpKind["Advance"] = 24] = "Advance";
8633
8668
  /**
8634
8669
  * An operation to instantiate a pipe.
8635
8670
  */
8636
- OpKind[OpKind["Pipe"] = 23] = "Pipe";
8671
+ OpKind[OpKind["Pipe"] = 25] = "Pipe";
8637
8672
  /**
8638
8673
  * An operation to associate an attribute with an element.
8639
8674
  */
8640
- OpKind[OpKind["Attribute"] = 24] = "Attribute";
8675
+ OpKind[OpKind["Attribute"] = 26] = "Attribute";
8641
8676
  /**
8642
8677
  * An attribute that has been extracted for inclusion in the consts array.
8643
8678
  */
8644
- OpKind[OpKind["ExtractedAttribute"] = 25] = "ExtractedAttribute";
8679
+ OpKind[OpKind["ExtractedAttribute"] = 27] = "ExtractedAttribute";
8645
8680
  /**
8646
8681
  * An operation that configures a `@defer` block.
8647
8682
  */
8648
- OpKind[OpKind["Defer"] = 26] = "Defer";
8683
+ OpKind[OpKind["Defer"] = 28] = "Defer";
8649
8684
  /**
8650
8685
  * An operation that controls when a `@defer` loads.
8651
8686
  */
8652
- OpKind[OpKind["DeferOn"] = 27] = "DeferOn";
8687
+ OpKind[OpKind["DeferOn"] = 29] = "DeferOn";
8653
8688
  /**
8654
8689
  * An operation that controls when a `@defer` loads, using a custom expression as the condition.
8655
8690
  */
8656
- OpKind[OpKind["DeferWhen"] = 28] = "DeferWhen";
8691
+ OpKind[OpKind["DeferWhen"] = 30] = "DeferWhen";
8657
8692
  /**
8658
8693
  * An i18n message that has been extracted for inclusion in the consts array.
8659
8694
  */
8660
- OpKind[OpKind["I18nMessage"] = 29] = "I18nMessage";
8695
+ OpKind[OpKind["I18nMessage"] = 31] = "I18nMessage";
8661
8696
  /**
8662
8697
  * A host binding property.
8663
8698
  */
8664
- OpKind[OpKind["HostProperty"] = 30] = "HostProperty";
8699
+ OpKind[OpKind["HostProperty"] = 32] = "HostProperty";
8665
8700
  /**
8666
8701
  * A namespace change, which causes the subsequent elements to be processed as either HTML or SVG.
8667
8702
  */
8668
- OpKind[OpKind["Namespace"] = 31] = "Namespace";
8703
+ OpKind[OpKind["Namespace"] = 33] = "Namespace";
8669
8704
  /**
8670
8705
  * Configure a content projeciton definition for the view.
8671
8706
  */
8672
- OpKind[OpKind["ProjectionDef"] = 32] = "ProjectionDef";
8707
+ OpKind[OpKind["ProjectionDef"] = 34] = "ProjectionDef";
8673
8708
  /**
8674
8709
  * Create a content projection slot.
8675
8710
  */
8676
- OpKind[OpKind["Projection"] = 33] = "Projection";
8711
+ OpKind[OpKind["Projection"] = 35] = "Projection";
8677
8712
  /**
8678
8713
  * Create a repeater creation instruction op.
8679
8714
  */
8680
- OpKind[OpKind["RepeaterCreate"] = 34] = "RepeaterCreate";
8715
+ OpKind[OpKind["RepeaterCreate"] = 36] = "RepeaterCreate";
8681
8716
  /**
8682
8717
  * An update up for a repeater.
8683
8718
  */
8684
- OpKind[OpKind["Repeater"] = 35] = "Repeater";
8719
+ OpKind[OpKind["Repeater"] = 37] = "Repeater";
8685
8720
  /**
8686
8721
  * An operation to bind an expression to the property side of a two-way binding.
8687
8722
  */
8688
- OpKind[OpKind["TwoWayProperty"] = 36] = "TwoWayProperty";
8723
+ OpKind[OpKind["TwoWayProperty"] = 38] = "TwoWayProperty";
8689
8724
  /**
8690
8725
  * An operation declaring the event side of a two-way binding.
8691
8726
  */
8692
- OpKind[OpKind["TwoWayListener"] = 37] = "TwoWayListener";
8727
+ OpKind[OpKind["TwoWayListener"] = 39] = "TwoWayListener";
8693
8728
  /**
8694
8729
  * A creation-time operation that initializes the slot for a `@let` declaration.
8695
8730
  */
8696
- OpKind[OpKind["DeclareLet"] = 38] = "DeclareLet";
8731
+ OpKind[OpKind["DeclareLet"] = 40] = "DeclareLet";
8697
8732
  /**
8698
8733
  * An update-time operation that stores the current value of a `@let` declaration.
8699
8734
  */
8700
- OpKind[OpKind["StoreLet"] = 39] = "StoreLet";
8735
+ OpKind[OpKind["StoreLet"] = 41] = "StoreLet";
8701
8736
  /**
8702
8737
  * The start of an i18n block.
8703
8738
  */
8704
- OpKind[OpKind["I18nStart"] = 40] = "I18nStart";
8739
+ OpKind[OpKind["I18nStart"] = 42] = "I18nStart";
8705
8740
  /**
8706
8741
  * A self-closing i18n on a single element.
8707
8742
  */
8708
- OpKind[OpKind["I18n"] = 41] = "I18n";
8743
+ OpKind[OpKind["I18n"] = 43] = "I18n";
8709
8744
  /**
8710
8745
  * The end of an i18n block.
8711
8746
  */
8712
- OpKind[OpKind["I18nEnd"] = 42] = "I18nEnd";
8747
+ OpKind[OpKind["I18nEnd"] = 44] = "I18nEnd";
8713
8748
  /**
8714
8749
  * An expression in an i18n message.
8715
8750
  */
8716
- OpKind[OpKind["I18nExpression"] = 43] = "I18nExpression";
8751
+ OpKind[OpKind["I18nExpression"] = 45] = "I18nExpression";
8717
8752
  /**
8718
8753
  * An instruction that applies a set of i18n expressions.
8719
8754
  */
8720
- OpKind[OpKind["I18nApply"] = 44] = "I18nApply";
8755
+ OpKind[OpKind["I18nApply"] = 46] = "I18nApply";
8721
8756
  /**
8722
8757
  * An instruction to create an ICU expression.
8723
8758
  */
8724
- OpKind[OpKind["IcuStart"] = 45] = "IcuStart";
8759
+ OpKind[OpKind["IcuStart"] = 47] = "IcuStart";
8725
8760
  /**
8726
8761
  * An instruction to update an ICU expression.
8727
8762
  */
8728
- OpKind[OpKind["IcuEnd"] = 46] = "IcuEnd";
8763
+ OpKind[OpKind["IcuEnd"] = 48] = "IcuEnd";
8729
8764
  /**
8730
8765
  * An instruction representing a placeholder in an ICU expression.
8731
8766
  */
8732
- OpKind[OpKind["IcuPlaceholder"] = 47] = "IcuPlaceholder";
8767
+ OpKind[OpKind["IcuPlaceholder"] = 49] = "IcuPlaceholder";
8733
8768
  /**
8734
8769
  * An i18n context containing information needed to generate an i18n message.
8735
8770
  */
8736
- OpKind[OpKind["I18nContext"] = 48] = "I18nContext";
8771
+ OpKind[OpKind["I18nContext"] = 50] = "I18nContext";
8737
8772
  /**
8738
8773
  * A creation op that corresponds to i18n attributes on an element.
8739
8774
  */
8740
- OpKind[OpKind["I18nAttributes"] = 49] = "I18nAttributes";
8775
+ OpKind[OpKind["I18nAttributes"] = 51] = "I18nAttributes";
8741
8776
  /**
8742
8777
  * Creation op that attaches the location at which an element was defined in a template to it.
8743
8778
  */
8744
- OpKind[OpKind["SourceLocation"] = 50] = "SourceLocation";
8779
+ OpKind[OpKind["SourceLocation"] = 52] = "SourceLocation";
8745
8780
  })(OpKind || (OpKind = {}));
8746
8781
  /**
8747
8782
  * Distinguishes different kinds of IR expressions.
@@ -10291,6 +10326,8 @@ function transformExpressionsInOp(op, transform, flags) {
10291
10326
  case OpKind.IcuPlaceholder:
10292
10327
  case OpKind.DeclareLet:
10293
10328
  case OpKind.SourceLocation:
10329
+ case OpKind.ConditionalCreate:
10330
+ case OpKind.ConditionalBranchCreate:
10294
10331
  // These operations contain no expressions.
10295
10332
  break;
10296
10333
  default:
@@ -10706,6 +10743,8 @@ const elementContainerOpKinds = new Set([
10706
10743
  OpKind.ContainerStart,
10707
10744
  OpKind.Template,
10708
10745
  OpKind.RepeaterCreate,
10746
+ OpKind.ConditionalCreate,
10747
+ OpKind.ConditionalBranchCreate,
10709
10748
  ]);
10710
10749
  /**
10711
10750
  * Checks whether the given operation represents the creation of an element or container.
@@ -10757,6 +10796,48 @@ function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace
10757
10796
  ...NEW_OP,
10758
10797
  };
10759
10798
  }
10799
+ function createConditionalCreateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
10800
+ return {
10801
+ kind: OpKind.ConditionalCreate,
10802
+ xref,
10803
+ templateKind,
10804
+ attributes: null,
10805
+ tag,
10806
+ handle: new SlotHandle(),
10807
+ functionNameSuffix,
10808
+ decls: null,
10809
+ vars: null,
10810
+ localRefs: [],
10811
+ nonBindable: false,
10812
+ namespace,
10813
+ i18nPlaceholder,
10814
+ startSourceSpan,
10815
+ wholeSourceSpan,
10816
+ ...TRAIT_CONSUMES_SLOT,
10817
+ ...NEW_OP,
10818
+ };
10819
+ }
10820
+ function createConditionalBranchCreateOp(xref, templateKind, tag, functionNameSuffix, namespace, i18nPlaceholder, startSourceSpan, wholeSourceSpan) {
10821
+ return {
10822
+ kind: OpKind.ConditionalBranchCreate,
10823
+ xref,
10824
+ templateKind,
10825
+ attributes: null,
10826
+ tag,
10827
+ handle: new SlotHandle(),
10828
+ functionNameSuffix,
10829
+ decls: null,
10830
+ vars: null,
10831
+ localRefs: [],
10832
+ nonBindable: false,
10833
+ namespace,
10834
+ i18nPlaceholder,
10835
+ startSourceSpan,
10836
+ wholeSourceSpan,
10837
+ ...TRAIT_CONSUMES_SLOT,
10838
+ ...NEW_OP,
10839
+ };
10840
+ }
10760
10841
  function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, emptyTag, i18nPlaceholder, emptyI18nPlaceholder, startSourceSpan, wholeSourceSpan) {
10761
10842
  return {
10762
10843
  kind: OpKind.RepeaterCreate,
@@ -11704,36 +11785,38 @@ function specializeBindings(job) {
11704
11785
  }
11705
11786
  }
11706
11787
 
11707
- const CHAINABLE = new Set([
11708
- Identifiers.attribute,
11709
- Identifiers.classProp,
11710
- Identifiers.element,
11711
- Identifiers.elementContainer,
11712
- Identifiers.elementContainerEnd,
11713
- Identifiers.elementContainerStart,
11714
- Identifiers.elementEnd,
11715
- Identifiers.elementStart,
11716
- Identifiers.hostProperty,
11717
- Identifiers.i18nExp,
11718
- Identifiers.listener,
11719
- Identifiers.listener,
11720
- Identifiers.property,
11721
- Identifiers.styleProp,
11722
- Identifiers.stylePropInterpolate1,
11723
- Identifiers.stylePropInterpolate2,
11724
- Identifiers.stylePropInterpolate3,
11725
- Identifiers.stylePropInterpolate4,
11726
- Identifiers.stylePropInterpolate5,
11727
- Identifiers.stylePropInterpolate6,
11728
- Identifiers.stylePropInterpolate7,
11729
- Identifiers.stylePropInterpolate8,
11730
- Identifiers.stylePropInterpolateV,
11731
- Identifiers.syntheticHostListener,
11732
- Identifiers.syntheticHostProperty,
11733
- Identifiers.templateCreate,
11734
- Identifiers.twoWayProperty,
11735
- Identifiers.twoWayListener,
11736
- Identifiers.declareLet,
11788
+ const CHAIN_COMPATIBILITY = new Map([
11789
+ [Identifiers.attribute, Identifiers.attribute],
11790
+ [Identifiers.classProp, Identifiers.classProp],
11791
+ [Identifiers.element, Identifiers.element],
11792
+ [Identifiers.elementContainer, Identifiers.elementContainer],
11793
+ [Identifiers.elementContainerEnd, Identifiers.elementContainerEnd],
11794
+ [Identifiers.elementContainerStart, Identifiers.elementContainerStart],
11795
+ [Identifiers.elementEnd, Identifiers.elementEnd],
11796
+ [Identifiers.elementStart, Identifiers.elementStart],
11797
+ [Identifiers.hostProperty, Identifiers.hostProperty],
11798
+ [Identifiers.i18nExp, Identifiers.i18nExp],
11799
+ [Identifiers.listener, Identifiers.listener],
11800
+ [Identifiers.listener, Identifiers.listener],
11801
+ [Identifiers.property, Identifiers.property],
11802
+ [Identifiers.styleProp, Identifiers.styleProp],
11803
+ [Identifiers.stylePropInterpolate1, Identifiers.stylePropInterpolate1],
11804
+ [Identifiers.stylePropInterpolate2, Identifiers.stylePropInterpolate2],
11805
+ [Identifiers.stylePropInterpolate3, Identifiers.stylePropInterpolate3],
11806
+ [Identifiers.stylePropInterpolate4, Identifiers.stylePropInterpolate4],
11807
+ [Identifiers.stylePropInterpolate5, Identifiers.stylePropInterpolate5],
11808
+ [Identifiers.stylePropInterpolate6, Identifiers.stylePropInterpolate6],
11809
+ [Identifiers.stylePropInterpolate7, Identifiers.stylePropInterpolate7],
11810
+ [Identifiers.stylePropInterpolate8, Identifiers.stylePropInterpolate8],
11811
+ [Identifiers.stylePropInterpolateV, Identifiers.stylePropInterpolateV],
11812
+ [Identifiers.syntheticHostListener, Identifiers.syntheticHostListener],
11813
+ [Identifiers.syntheticHostProperty, Identifiers.syntheticHostProperty],
11814
+ [Identifiers.templateCreate, Identifiers.templateCreate],
11815
+ [Identifiers.twoWayProperty, Identifiers.twoWayProperty],
11816
+ [Identifiers.twoWayListener, Identifiers.twoWayListener],
11817
+ [Identifiers.declareLet, Identifiers.declareLet],
11818
+ [Identifiers.conditionalCreate, Identifiers.conditionalBranchCreate],
11819
+ [Identifiers.conditionalBranchCreate, Identifiers.conditionalBranchCreate],
11737
11820
  ]);
11738
11821
  /**
11739
11822
  * Chaining results in repeated call expressions, causing a deep AST of receiver expressions. To prevent running out of
@@ -11779,14 +11862,16 @@ function chainOperationsInList(opList) {
11779
11862
  continue;
11780
11863
  }
11781
11864
  const instruction = op.statement.expr.fn.value;
11782
- if (!CHAINABLE.has(instruction)) {
11865
+ if (!CHAIN_COMPATIBILITY.has(instruction)) {
11783
11866
  // This instruction isn't chainable.
11784
11867
  chain = null;
11785
11868
  continue;
11786
11869
  }
11787
11870
  // This instruction can be chained. It can either be added on to the previous chain (if
11788
11871
  // compatible) or it can be the start of a new chain.
11789
- if (chain !== null && chain.instruction === instruction && chain.length < MAX_CHAIN_LENGTH) {
11872
+ if (chain !== null &&
11873
+ CHAIN_COMPATIBILITY.get(chain.instruction) === instruction &&
11874
+ chain.length < MAX_CHAIN_LENGTH) {
11790
11875
  // This instruction can be added onto the previous chain.
11791
11876
  const expression = chain.expression.callFn(op.statement.expr.args, op.statement.expr.sourceSpan, op.statement.expr.pure);
11792
11877
  chain.expression = expression;
@@ -13014,6 +13099,8 @@ function recursivelyProcessView(view, parentScope) {
13014
13099
  const scope = getScopeForView(view, parentScope);
13015
13100
  for (const op of view.create) {
13016
13101
  switch (op.kind) {
13102
+ case OpKind.ConditionalCreate:
13103
+ case OpKind.ConditionalBranchCreate:
13017
13104
  case OpKind.Template:
13018
13105
  // Descend into child embedded views.
13019
13106
  recursivelyProcessView(view.job.views.get(op.xref), scope);
@@ -13071,6 +13158,8 @@ function getScopeForView(view, parent) {
13071
13158
  for (const op of view.create) {
13072
13159
  switch (op.kind) {
13073
13160
  case OpKind.ElementStart:
13161
+ case OpKind.ConditionalCreate:
13162
+ case OpKind.ConditionalBranchCreate:
13074
13163
  case OpKind.Template:
13075
13164
  if (!Array.isArray(op.localRefs)) {
13076
13165
  throw new Error(`AssertionError: expected localRefs to be an array`);
@@ -21601,6 +21690,8 @@ function liftLocalRefs(job) {
21601
21690
  for (const op of unit.create) {
21602
21691
  switch (op.kind) {
21603
21692
  case OpKind.ElementStart:
21693
+ case OpKind.ConditionalCreate:
21694
+ case OpKind.ConditionalBranchCreate:
21604
21695
  case OpKind.Template:
21605
21696
  if (!Array.isArray(op.localRefs)) {
21606
21697
  throw new Error(`AssertionError: expected localRefs to be an array still`);
@@ -21743,7 +21834,9 @@ function parseExtractedStyles(job) {
21743
21834
  isStringLiteral(op.expression)) {
21744
21835
  const target = elements.get(op.target);
21745
21836
  if (target !== undefined &&
21746
- target.kind === OpKind.Template &&
21837
+ (target.kind === OpKind.Template ||
21838
+ target.kind === OpKind.ConditionalCreate ||
21839
+ target.kind === OpKind.ConditionalBranchCreate) &&
21747
21840
  target.templateKind === TemplateKind.Structural) {
21748
21841
  // TemplateDefinitionBuilder will not apply class and style bindings to structural
21749
21842
  // directives; instead, it will leave them as attributes.
@@ -21858,6 +21951,8 @@ function addNamesToView(unit, baseName, state, compatibility) {
21858
21951
  addNamesToView(fallbackView, `${baseName}_ProjectionFallback_${op.handle.slot}`, state, compatibility);
21859
21952
  }
21860
21953
  break;
21954
+ case OpKind.ConditionalCreate:
21955
+ case OpKind.ConditionalBranchCreate:
21861
21956
  case OpKind.Template:
21862
21957
  if (!(unit instanceof ViewCompilationUnit)) {
21863
21958
  throw new Error(`AssertionError: must be compiling a component`);
@@ -22343,6 +22438,8 @@ function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
22343
22438
  }
22344
22439
  i18nBlock = null;
22345
22440
  break;
22441
+ case OpKind.ConditionalCreate:
22442
+ case OpKind.ConditionalBranchCreate:
22346
22443
  case OpKind.Template:
22347
22444
  subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.xref), i18nBlock, op.i18nPlaceholder, subTemplateIndex);
22348
22445
  break;
@@ -22548,7 +22645,6 @@ function enableBindings() {
22548
22645
  function listener(name, handlerFn, eventTargetResolver, syntheticHost, sourceSpan) {
22549
22646
  const args = [literal$1(name), handlerFn];
22550
22647
  if (eventTargetResolver !== null) {
22551
- args.push(literal$1(false)); // `useCapture` flag, defaults to `false`
22552
22648
  args.push(importExpr(eventTargetResolver));
22553
22649
  }
22554
22650
  return call(syntheticHost ? Identifiers.syntheticHostListener : Identifiers.listener, args, sourceSpan);
@@ -22708,6 +22804,42 @@ function i18nStart(slot, constIndex, subTemplateIndex, sourceSpan) {
22708
22804
  }
22709
22805
  return call(Identifiers.i18nStart, args, sourceSpan);
22710
22806
  }
22807
+ function conditionalCreate(slot, templateFnRef, decls, vars, tag, constIndex, localRefs, sourceSpan) {
22808
+ const args = [
22809
+ literal$1(slot),
22810
+ templateFnRef,
22811
+ literal$1(decls),
22812
+ literal$1(vars),
22813
+ literal$1(tag),
22814
+ literal$1(constIndex),
22815
+ ];
22816
+ if (localRefs !== null) {
22817
+ args.push(literal$1(localRefs));
22818
+ args.push(importExpr(Identifiers.templateRefExtractor));
22819
+ }
22820
+ while (args[args.length - 1].isEquivalent(NULL_EXPR)) {
22821
+ args.pop();
22822
+ }
22823
+ return call(Identifiers.conditionalCreate, args, sourceSpan);
22824
+ }
22825
+ function conditionalBranchCreate(slot, templateFnRef, decls, vars, tag, constIndex, localRefs, sourceSpan) {
22826
+ const args = [
22827
+ literal$1(slot),
22828
+ templateFnRef,
22829
+ literal$1(decls),
22830
+ literal$1(vars),
22831
+ literal$1(tag),
22832
+ literal$1(constIndex),
22833
+ ];
22834
+ if (localRefs !== null) {
22835
+ args.push(literal$1(localRefs));
22836
+ args.push(importExpr(Identifiers.templateRefExtractor));
22837
+ }
22838
+ while (args[args.length - 1].isEquivalent(NULL_EXPR)) {
22839
+ args.pop();
22840
+ }
22841
+ return call(Identifiers.conditionalBranchCreate, args, sourceSpan);
22842
+ }
22711
22843
  function repeaterCreate(slot, viewFnName, decls, vars, tag, constIndex, trackByFn, trackByUsesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, emptyTag, emptyConstIndex, sourceSpan) {
22712
22844
  const args = [
22713
22845
  literal$1(slot),
@@ -23277,6 +23409,26 @@ function reifyCreateOperations(unit, ops) {
23277
23409
  }
23278
23410
  OpList.replace(op, projection(op.handle.slot, op.projectionSlotIndex, op.attributes, fallbackViewFnName, fallbackDecls, fallbackVars, op.sourceSpan));
23279
23411
  break;
23412
+ case OpKind.ConditionalCreate:
23413
+ if (!(unit instanceof ViewCompilationUnit)) {
23414
+ throw new Error(`AssertionError: must be compiling a component`);
23415
+ }
23416
+ if (Array.isArray(op.localRefs)) {
23417
+ throw new Error(`AssertionError: local refs array should have been extracted into a constant`);
23418
+ }
23419
+ const conditionalCreateChildView = unit.job.views.get(op.xref);
23420
+ OpList.replace(op, conditionalCreate(op.handle.slot, variable(conditionalCreateChildView.fnName), conditionalCreateChildView.decls, conditionalCreateChildView.vars, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
23421
+ break;
23422
+ case OpKind.ConditionalBranchCreate:
23423
+ if (!(unit instanceof ViewCompilationUnit)) {
23424
+ throw new Error(`AssertionError: must be compiling a component`);
23425
+ }
23426
+ if (Array.isArray(op.localRefs)) {
23427
+ throw new Error(`AssertionError: local refs array should have been extracted into a constant`);
23428
+ }
23429
+ const conditionalBranchCreateChildView = unit.job.views.get(op.xref);
23430
+ OpList.replace(op, conditionalBranchCreate(op.handle.slot, variable(conditionalBranchCreateChildView.fnName), conditionalBranchCreateChildView.decls, conditionalBranchCreateChildView.vars, op.tag, op.attributes, op.localRefs, op.startSourceSpan));
23431
+ break;
23280
23432
  case OpKind.RepeaterCreate:
23281
23433
  if (op.handle.slot === null) {
23282
23434
  throw new Error('No slot was assigned for repeater instruction');
@@ -23834,6 +23986,8 @@ function resolvePlaceholdersForView(job, unit, i18nContexts, elements, pendingSt
23834
23986
  pendingStructuralDirective = undefined;
23835
23987
  }
23836
23988
  break;
23989
+ case OpKind.ConditionalCreate:
23990
+ case OpKind.ConditionalBranchCreate:
23837
23991
  case OpKind.Template:
23838
23992
  const view = job.views.get(op.xref);
23839
23993
  if (op.i18nPlaceholder === undefined) {
@@ -24397,7 +24551,10 @@ function allocateSlots(job) {
24397
24551
  // propagate the number of slots used for each view into the operation which declares it.
24398
24552
  for (const unit of job.units) {
24399
24553
  for (const op of unit.ops()) {
24400
- if (op.kind === OpKind.Template || op.kind === OpKind.RepeaterCreate) {
24554
+ if (op.kind === OpKind.Template ||
24555
+ op.kind === OpKind.ConditionalCreate ||
24556
+ op.kind === OpKind.ConditionalBranchCreate ||
24557
+ op.kind === OpKind.RepeaterCreate) {
24401
24558
  // Record the number of slots used by the view this `ir.TemplateOp` declares in the
24402
24559
  // operation itself, so it can be emitted later.
24403
24560
  const childView = job.views.get(op.xref);
@@ -24458,6 +24615,8 @@ function optimizeStoreLet(job) {
24458
24615
  * typescript AST, the parentheses node is removed, and then the remaining AST is printed, it
24459
24616
  * incorrectly prints `a ? b : c ?? d`. This is different from how it handles the same situation
24460
24617
  * with `||` and `&&` where it prints the parentheses even if they are not present in the AST.
24618
+ * Note: We may be able to remove this case if Typescript resolves the following issue:
24619
+ * https://github.com/microsoft/TypeScript/issues/61369
24461
24620
  */
24462
24621
  function stripNonrequiredParentheses(job) {
24463
24622
  // Check which parentheses are required.
@@ -24832,7 +24991,10 @@ function countVariables(job) {
24832
24991
  // an embedded view).
24833
24992
  for (const unit of job.units) {
24834
24993
  for (const op of unit.create) {
24835
- if (op.kind !== OpKind.Template && op.kind !== OpKind.RepeaterCreate) {
24994
+ if (op.kind !== OpKind.Template &&
24995
+ op.kind !== OpKind.RepeaterCreate &&
24996
+ op.kind !== OpKind.ConditionalCreate &&
24997
+ op.kind !== OpKind.ConditionalBranchCreate) {
24836
24998
  continue;
24837
24999
  }
24838
25000
  const childView = job.views.get(op.xref);
@@ -25816,13 +25978,14 @@ function ingestIfBlock(unit, ifBlock) {
25816
25978
  }
25817
25979
  ifCaseI18nMeta = ifCase.i18n;
25818
25980
  }
25819
- const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, tagName, 'Conditional', Namespace.HTML, ifCaseI18nMeta, ifCase.startSourceSpan, ifCase.sourceSpan);
25820
- unit.create.push(templateOp);
25981
+ const createOp = i === 0 ? createConditionalCreateOp : createConditionalBranchCreateOp;
25982
+ const conditionalCreateOp = createOp(cView.xref, TemplateKind.Block, tagName, 'Conditional', Namespace.HTML, ifCaseI18nMeta, ifCase.startSourceSpan, ifCase.sourceSpan);
25983
+ unit.create.push(conditionalCreateOp);
25821
25984
  if (firstXref === null) {
25822
25985
  firstXref = cView.xref;
25823
25986
  }
25824
25987
  const caseExpr = ifCase.expression ? convertAst(ifCase.expression, unit.job, null) : null;
25825
- const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, templateOp.xref, templateOp.handle, ifCase.expressionAlias);
25988
+ const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, conditionalCreateOp.xref, conditionalCreateOp.handle, ifCase.expressionAlias);
25826
25989
  conditions.push(conditionalCaseExpr);
25827
25990
  ingestNodes(cView, ifCase.children);
25828
25991
  }
@@ -25838,7 +26001,8 @@ function ingestSwitchBlock(unit, switchBlock) {
25838
26001
  }
25839
26002
  let firstXref = null;
25840
26003
  let conditions = [];
25841
- for (const switchCase of switchBlock.cases) {
26004
+ for (let i = 0; i < switchBlock.cases.length; i++) {
26005
+ const switchCase = switchBlock.cases[i];
25842
26006
  const cView = unit.job.allocateView(unit.xref);
25843
26007
  const tagName = ingestControlFlowInsertionPoint(unit, cView.xref, switchCase);
25844
26008
  let switchCaseI18nMeta = undefined;
@@ -25848,15 +26012,16 @@ function ingestSwitchBlock(unit, switchBlock) {
25848
26012
  }
25849
26013
  switchCaseI18nMeta = switchCase.i18n;
25850
26014
  }
25851
- const templateOp = createTemplateOp(cView.xref, TemplateKind.Block, tagName, 'Case', Namespace.HTML, switchCaseI18nMeta, switchCase.startSourceSpan, switchCase.sourceSpan);
25852
- unit.create.push(templateOp);
26015
+ const createOp = i === 0 ? createConditionalCreateOp : createConditionalBranchCreateOp;
26016
+ const conditionalCreateOp = createOp(cView.xref, TemplateKind.Block, tagName, 'Case', Namespace.HTML, switchCaseI18nMeta, switchCase.startSourceSpan, switchCase.sourceSpan);
26017
+ unit.create.push(conditionalCreateOp);
25853
26018
  if (firstXref === null) {
25854
26019
  firstXref = cView.xref;
25855
26020
  }
25856
26021
  const caseExpr = switchCase.expression
25857
26022
  ? convertAst(switchCase.expression, unit.job, switchBlock.startSourceSpan)
25858
26023
  : null;
25859
- const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, templateOp.xref, templateOp.handle);
26024
+ const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, conditionalCreateOp.xref, conditionalCreateOp.handle);
25860
26025
  conditions.push(conditionalCaseExpr);
25861
26026
  ingestNodes(cView, switchCase.children);
25862
26027
  }
@@ -29463,7 +29628,7 @@ class R3TargetBinder {
29463
29628
  * metadata about the types referenced in the template.
29464
29629
  */
29465
29630
  bind(target) {
29466
- if (!target.template) {
29631
+ if (!target.template && !target.host) {
29467
29632
  throw new Error('Empty bound targets are not supported');
29468
29633
  }
29469
29634
  const directives = new Map();
@@ -29493,6 +29658,11 @@ class R3TargetBinder {
29493
29658
  // template. This extracts all the metadata that doesn't depend on directive matching.
29494
29659
  TemplateBinder.applyWithScope(target.template, scope, expressions, symbols, nestingLevel, usedPipes, eagerPipes, deferBlocks);
29495
29660
  }
29661
+ // Bind the host element in a separate scope. Note that it only uses the
29662
+ // `TemplateBinder` since directives don't apply inside a host context.
29663
+ if (target.host) {
29664
+ TemplateBinder.applyWithScope(target.host, Scope$1.apply(target.host), expressions, symbols, nestingLevel, usedPipes, eagerPipes, deferBlocks);
29665
+ }
29496
29666
  return new R3BoundTarget(target, directives, eagerDirectives, bindings, references, expressions, symbols, nestingLevel, scopedNodeEntities, usedPipes, eagerPipes, deferBlocks);
29497
29667
  }
29498
29668
  }
@@ -29568,7 +29738,7 @@ let Scope$1 = class Scope {
29568
29738
  nodeOrNodes instanceof Content) {
29569
29739
  nodeOrNodes.children.forEach((node) => node.visit(this));
29570
29740
  }
29571
- else {
29741
+ else if (!(nodeOrNodes instanceof HostElement)) {
29572
29742
  // No overarching `Template` instance, so process the nodes directly.
29573
29743
  nodeOrNodes.forEach((node) => node.visit(this));
29574
29744
  }
@@ -29897,7 +30067,7 @@ class TemplateBinder extends RecursiveAstVisitor {
29897
30067
  /**
29898
30068
  * Process a template and extract metadata about expressions and symbols within.
29899
30069
  *
29900
- * @param nodes the nodes of the template to process
30070
+ * @param nodeOrNodes the nodes of the template to process
29901
30071
  * @param scope the `Scope` of the template being processed.
29902
30072
  * @returns three maps which contain metadata about the template: `expressions` which interprets
29903
30073
  * special `AST` nodes in expressions as pointing to references or variables declared within the
@@ -29906,11 +30076,11 @@ class TemplateBinder extends RecursiveAstVisitor {
29906
30076
  * nesting level (how many levels deep within the template structure the `Template` is), starting
29907
30077
  * at 1.
29908
30078
  */
29909
- static applyWithScope(nodes, scope, expressions, symbols, nestingLevel, usedPipes, eagerPipes, deferBlocks) {
29910
- const template = nodes instanceof Template ? nodes : null;
30079
+ static applyWithScope(nodeOrNodes, scope, expressions, symbols, nestingLevel, usedPipes, eagerPipes, deferBlocks) {
30080
+ const template = nodeOrNodes instanceof Template ? nodeOrNodes : null;
29911
30081
  // The top-level template has nesting level 0.
29912
30082
  const binder = new TemplateBinder(expressions, symbols, usedPipes, eagerPipes, deferBlocks, nestingLevel, scope, template, 0);
29913
- binder.ingest(nodes);
30083
+ binder.ingest(nodeOrNodes);
29914
30084
  }
29915
30085
  ingest(nodeOrNodes) {
29916
30086
  if (nodeOrNodes instanceof Template) {
@@ -29952,6 +30122,10 @@ class TemplateBinder extends RecursiveAstVisitor {
29952
30122
  nodeOrNodes.children.forEach((node) => node.visit(this));
29953
30123
  this.nestingLevel.set(nodeOrNodes, this.level);
29954
30124
  }
30125
+ else if (nodeOrNodes instanceof HostElement) {
30126
+ // Host elements are always at the top level.
30127
+ this.nestingLevel.set(nodeOrNodes, 0);
30128
+ }
29955
30129
  else {
29956
30130
  // Visit each node from the top-level template.
29957
30131
  nodeOrNodes.forEach(this.visitNode);
@@ -31437,7 +31611,7 @@ var FactoryTarget;
31437
31611
  * @description
31438
31612
  * Entry point for all public APIs of the compiler package.
31439
31613
  */
31440
- new Version('20.0.0-next.2');
31614
+ new Version('20.0.0-next.4');
31441
31615
 
31442
31616
  //////////////////////////////////////
31443
31617
  // THIS FILE HAS GLOBAL SIDE EFFECT //
@@ -31903,6 +32077,10 @@ exports.ErrorCode = void 0;
31903
32077
  * A symbol referenced in `@Component.imports` isn't being used within the template.
31904
32078
  */
31905
32079
  ErrorCode[ErrorCode["UNUSED_STANDALONE_IMPORTS"] = 8113] = "UNUSED_STANDALONE_IMPORTS";
32080
+ /**
32081
+ * An expression mixes nullish coalescing and logical and/or without parentheses.
32082
+ */
32083
+ ErrorCode[ErrorCode["UNPARENTHESIZED_NULLISH_COALESCING"] = 8114] = "UNPARENTHESIZED_NULLISH_COALESCING";
31906
32084
  /**
31907
32085
  * The template type-checking engine would need to generate an inline type check block for a
31908
32086
  * component, but the current type-checking environment doesn't support it.
@@ -32061,6 +32239,7 @@ exports.ExtendedTemplateDiagnosticName = void 0;
32061
32239
  ExtendedTemplateDiagnosticName["CONTROL_FLOW_PREVENTING_CONTENT_PROJECTION"] = "controlFlowPreventingContentProjection";
32062
32240
  ExtendedTemplateDiagnosticName["UNUSED_LET_DECLARATION"] = "unusedLetDeclaration";
32063
32241
  ExtendedTemplateDiagnosticName["UNUSED_STANDALONE_IMPORTS"] = "unusedStandaloneImports";
32242
+ ExtendedTemplateDiagnosticName["UNPARENTHESIZED_NULLISH_COALESCING"] = "unparenthesizedNullishCoalescing";
32064
32243
  })(exports.ExtendedTemplateDiagnosticName || (exports.ExtendedTemplateDiagnosticName = {}));
32065
32244
 
32066
32245
  /**
@@ -32387,7 +32566,7 @@ class NodeJSPathManipulation {
32387
32566
  // G3-ESM-MARKER: G3 uses CommonJS, but externally everything in ESM.
32388
32567
  // CommonJS/ESM interop for determining the current file name and containing dir.
32389
32568
  const isCommonJS = typeof __filename !== 'undefined';
32390
- const currentFileUrl = isCommonJS ? null : (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('checker-DF8ZaFW5.js', document.baseURI).href));
32569
+ const currentFileUrl = isCommonJS ? null : (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('checker-k591b6WQ.js', document.baseURI).href));
32391
32570
  const currentFileName = isCommonJS ? __filename : url.fileURLToPath(currentFileUrl);
32392
32571
  /**
32393
32572
  * A wrapper around the Node.js file-system that supports readonly operations and path manipulation.
@@ -37638,33 +37817,7 @@ class ExpressionTranslatorVisitor {
37638
37817
  }
37639
37818
  }
37640
37819
  visitConditionalExpr(ast, context) {
37641
- let cond = ast.condition.visitExpression(this, context);
37642
- // Ordinarily the ternary operator is right-associative. The following are equivalent:
37643
- // `a ? b : c ? d : e` => `a ? b : (c ? d : e)`
37644
- //
37645
- // However, occasionally Angular needs to produce a left-associative conditional, such as in
37646
- // the case of a null-safe navigation production: `{{a?.b ? c : d}}`. This template produces
37647
- // a ternary of the form:
37648
- // `a == null ? null : rest of expression`
37649
- // If the rest of the expression is also a ternary though, this would produce the form:
37650
- // `a == null ? null : a.b ? c : d`
37651
- // which, if left as right-associative, would be incorrectly associated as:
37652
- // `a == null ? null : (a.b ? c : d)`
37653
- //
37654
- // In such cases, the left-associativity needs to be enforced with parentheses:
37655
- // `(a == null ? null : a.b) ? c : d`
37656
- //
37657
- // Such parentheses could always be included in the condition (guaranteeing correct behavior) in
37658
- // all cases, but this has a code size cost. Instead, parentheses are added only when a
37659
- // conditional expression is directly used as the condition of another.
37660
- //
37661
- // TODO(alxhub): investigate better logic for precendence of conditional operators
37662
- if (ast.condition instanceof ConditionalExpr) {
37663
- // The condition of this ternary needs to be wrapped in parentheses to maintain
37664
- // left-associativity.
37665
- cond = this.factory.createParenthesizedExpression(cond);
37666
- }
37667
- return this.factory.createConditional(cond, ast.trueCase.visitExpression(this, context), ast.falseCase.visitExpression(this, context));
37820
+ return this.factory.createConditional(ast.condition.visitExpression(this, context), ast.trueCase.visitExpression(this, context), ast.falseCase.visitExpression(this, context));
37668
37821
  }
37669
37822
  visitDynamicImportExpr(ast, context) {
37670
37823
  const urlExpression = typeof ast.url === 'string'
@@ -39209,7 +39362,12 @@ function extractDirectiveMetadata(clazz, decorator, reflector, importTracker, ev
39209
39362
  throw new FatalDiagnosticError(exports.ErrorCode.DIRECTIVE_MISSING_SELECTOR, expr, `Directive ${clazz.name.text} has no selector, please add it!`);
39210
39363
  }
39211
39364
  }
39212
- const host = extractHostBindings(decoratedElements, evaluator, coreModule, compilationMode, directive);
39365
+ const hostBindingNodes = {
39366
+ literal: null,
39367
+ bindingDecorators: new Set(),
39368
+ listenerDecorators: new Set(),
39369
+ };
39370
+ const host = extractHostBindings(decoratedElements, evaluator, coreModule, compilationMode, hostBindingNodes, directive);
39213
39371
  const providers = directive.has('providers')
39214
39372
  ? new WrappedNodeExpr(annotateForClosureCompiler
39215
39373
  ? wrapFunctionExpressionsInParens(directive.get('providers'))
@@ -39321,6 +39479,7 @@ function extractDirectiveMetadata(clazz, decorator, reflector, importTracker, ev
39321
39479
  isStructural,
39322
39480
  hostDirectives,
39323
39481
  rawHostDirectives,
39482
+ hostBindingNodes,
39324
39483
  // Track inputs from class metadata. This is useful for migration efforts.
39325
39484
  inputFieldNamesFromMetadataArray: new Set(Object.values(inputsFromMeta).map((i) => i.classPropertyName)),
39326
39485
  };
@@ -39403,10 +39562,14 @@ function extractDecoratorQueryMetadata(exprNode, name, args, propertyName, refle
39403
39562
  emitDistinctChangesOnly,
39404
39563
  };
39405
39564
  }
39406
- function extractHostBindings(members, evaluator, coreModule, compilationMode, metadata) {
39565
+ function extractHostBindings(members, evaluator, coreModule, compilationMode, hostBindingNodes, metadata) {
39407
39566
  let bindings;
39408
39567
  if (metadata && metadata.has('host')) {
39409
- bindings = evaluateHostExpressionBindings(metadata.get('host'), evaluator);
39568
+ const hostExpression = metadata.get('host');
39569
+ bindings = evaluateHostExpressionBindings(hostExpression, evaluator);
39570
+ if (ts.isObjectLiteralExpression(hostExpression)) {
39571
+ hostBindingNodes.literal = hostExpression;
39572
+ }
39410
39573
  }
39411
39574
  else {
39412
39575
  bindings = parseHostBindings({});
@@ -39430,6 +39593,9 @@ function extractHostBindings(members, evaluator, coreModule, compilationMode, me
39430
39593
  }
39431
39594
  hostPropertyName = resolved;
39432
39595
  }
39596
+ if (ts.isDecorator(decorator.node)) {
39597
+ hostBindingNodes.bindingDecorators.add(decorator.node);
39598
+ }
39433
39599
  // Since this is a decorator, we know that the value is a class member. Always access it
39434
39600
  // through `this` so that further down the line it can't be confused for a literal value
39435
39601
  // (e.g. if there's a property called `true`). There is no size penalty, because all
@@ -39465,6 +39631,9 @@ function extractHostBindings(members, evaluator, coreModule, compilationMode, me
39465
39631
  args = resolvedArgs;
39466
39632
  }
39467
39633
  }
39634
+ if (ts.isDecorator(decorator.node)) {
39635
+ hostBindingNodes.listenerDecorators.add(decorator.node);
39636
+ }
39468
39637
  bindings.listeners[eventName] = `${member.name}(${args.join(',')})`;
39469
39638
  });
39470
39639
  });
@@ -40134,6 +40303,19 @@ function toR3InputMetadata(mapping) {
40134
40303
  isSignal: mapping.isSignal,
40135
40304
  };
40136
40305
  }
40306
+ function extractHostBindingResources(nodes) {
40307
+ const result = new Set();
40308
+ if (nodes.literal !== null) {
40309
+ result.add({ path: null, node: nodes.literal });
40310
+ }
40311
+ for (const current of nodes.bindingDecorators) {
40312
+ result.add({ path: null, node: current.expression });
40313
+ }
40314
+ for (const current of nodes.listenerDecorators) {
40315
+ result.add({ path: null, node: current.expression });
40316
+ }
40317
+ return result;
40318
+ }
40137
40319
 
40138
40320
  const NgOriginalFile = Symbol('NgOriginalFile');
40139
40321
  exports.UpdateMode = void 0;
@@ -40441,7 +40623,7 @@ function parseTemplateAsSourceFile(fileName, template) {
40441
40623
  }
40442
40624
 
40443
40625
  const TYPE_CHECK_ID_MAP = Symbol('TypeCheckId');
40444
- function getTypeCheckId(clazz) {
40626
+ function getTypeCheckId$1(clazz) {
40445
40627
  const sf = clazz.getSourceFile();
40446
40628
  if (sf[TYPE_CHECK_ID_MAP] === undefined) {
40447
40629
  sf[TYPE_CHECK_ID_MAP] = new Map();
@@ -42212,7 +42394,7 @@ class RegistryDomSchemaChecker {
42212
42394
  this._diagnostics.push(diag);
42213
42395
  }
42214
42396
  }
42215
- checkProperty(id, element, name, span, schemas, hostIsStandalone) {
42397
+ checkTemplateElementProperty(id, element, name, span, schemas, hostIsStandalone) {
42216
42398
  if (!REGISTRY$1.hasProperty(element.name, name, schemas)) {
42217
42399
  const mapping = this.resolver.getTemplateSourceMapping(id);
42218
42400
  const decorator = hostIsStandalone ? '@Component' : '@NgModule';
@@ -42235,6 +42417,18 @@ class RegistryDomSchemaChecker {
42235
42417
  this._diagnostics.push(diag);
42236
42418
  }
42237
42419
  }
42420
+ checkHostElementProperty(id, element, name, span, schemas) {
42421
+ for (const tagName of element.tagNames) {
42422
+ if (REGISTRY$1.hasProperty(tagName, name, schemas)) {
42423
+ continue;
42424
+ }
42425
+ const errorMessage = `Can't bind to '${name}' since it isn't a known property of '${tagName}'.`;
42426
+ const mapping = this.resolver.getHostBindingsMapping(id);
42427
+ const diag = makeTemplateDiagnostic(id, mapping, span, ts.DiagnosticCategory.Error, ngErrorCode(exports.ErrorCode.SCHEMA_INVALID_ATTRIBUTE), errorMessage);
42428
+ this._diagnostics.push(diag);
42429
+ break;
42430
+ }
42431
+ }
42238
42432
  }
42239
42433
 
42240
42434
  /**
@@ -42346,13 +42540,26 @@ function tsCastToAny(expr) {
42346
42540
  * Thanks to narrowing of `document.createElement()`, this expression will have its type inferred
42347
42541
  * based on the tag name, including for custom elements that have appropriate .d.ts definitions.
42348
42542
  */
42349
- function tsCreateElement(tagName) {
42543
+ function tsCreateElement(...tagNames) {
42350
42544
  const createElement = ts.factory.createPropertyAccessExpression(
42351
42545
  /* expression */ ts.factory.createIdentifier('document'), 'createElement');
42546
+ let arg;
42547
+ if (tagNames.length === 1) {
42548
+ // If there's only one tag name, we can pass it in directly.
42549
+ arg = ts.factory.createStringLiteral(tagNames[0]);
42550
+ }
42551
+ else {
42552
+ // If there's more than one name, we have to generate a union of all the tag names. To do so,
42553
+ // create an expression in the form of `null! as 'tag-1' | 'tag-2' | 'tag-3'`. This allows
42554
+ // TypeScript to infer the type as a union of the differnet tags.
42555
+ const assertedNullExpression = ts.factory.createNonNullExpression(ts.factory.createNull());
42556
+ const type = ts.factory.createUnionTypeNode(tagNames.map((tag) => ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(tag))));
42557
+ arg = ts.factory.createAsExpression(assertedNullExpression, type);
42558
+ }
42352
42559
  return ts.factory.createCallExpression(
42353
42560
  /* expression */ createElement,
42354
42561
  /* typeArguments */ undefined,
42355
- /* argumentsArray */ [ts.factory.createStringLiteral(tagName)]);
42562
+ /* argumentsArray */ [arg]);
42356
42563
  }
42357
42564
  /**
42358
42565
  * Create a `ts.VariableStatement` which declares a variable without explicit initialization.
@@ -42528,6 +42735,353 @@ class TypeParameterEmitter {
42528
42735
  }
42529
42736
  }
42530
42737
 
42738
+ /*!
42739
+ * @license
42740
+ * Copyright Google LLC All Rights Reserved.
42741
+ *
42742
+ * Use of this source code is governed by an MIT-style license that can be
42743
+ * found in the LICENSE file at https://angular.dev/license
42744
+ */
42745
+ /**
42746
+ * Comment attached to an AST node that serves as a guard to distinguish nodes
42747
+ * used for type checking host bindings from ones used for templates.
42748
+ */
42749
+ const GUARD_COMMENT_TEXT = 'hostBindingsBlockGuard';
42750
+ /**
42751
+ * Creates an AST node that represents the host element of a directive.
42752
+ * Can return null if there are no valid bindings to be checked.
42753
+ * @param type Whether the host element is for a directive or a component.
42754
+ * @param selector Selector of the directive.
42755
+ * @param sourceNode Class declaration for the directive.
42756
+ * @param literal `host` object literal from the decorator.
42757
+ * @param bindingDecorators `HostBinding` decorators discovered on the node.
42758
+ * @param listenerDecorators `HostListener` decorators discovered on the node.
42759
+ */
42760
+ function createHostElement(type, selector, sourceNode, literal, bindingDecorators, listenerDecorators) {
42761
+ const bindings = [];
42762
+ const listeners = [];
42763
+ let parser = null;
42764
+ if (literal !== null) {
42765
+ for (const prop of literal.properties) {
42766
+ // We only support type checking of static bindings.
42767
+ if (ts.isPropertyAssignment(prop) &&
42768
+ ts.isStringLiteralLike(prop.initializer) &&
42769
+ isStaticName(prop.name)) {
42770
+ parser ??= makeBindingParser();
42771
+ createNodeFromHostLiteralProperty(prop, parser, bindings, listeners);
42772
+ }
42773
+ }
42774
+ }
42775
+ for (const decorator of bindingDecorators) {
42776
+ createNodeFromBindingDecorator(decorator, bindings);
42777
+ }
42778
+ for (const decorator of listenerDecorators) {
42779
+ parser ??= makeBindingParser();
42780
+ createNodeFromListenerDecorator(decorator, parser, listeners);
42781
+ }
42782
+ // The element will be a no-op if there are no bindings.
42783
+ if (bindings.length === 0 && listeners.length === 0) {
42784
+ return null;
42785
+ }
42786
+ const tagNames = [];
42787
+ if (selector !== null) {
42788
+ const parts = CssSelector.parse(selector);
42789
+ for (const part of parts) {
42790
+ if (part.element !== null) {
42791
+ tagNames.push(part.element);
42792
+ }
42793
+ }
42794
+ }
42795
+ // If none of the selectors have a tag name, fall back to `ng-component`/`ng-directive`.
42796
+ // This is how the runtime handles components without tag names as well.
42797
+ if (tagNames.length === 0) {
42798
+ tagNames.push(`ng-${type}`);
42799
+ }
42800
+ return new HostElement(tagNames, bindings, listeners, createSourceSpan(sourceNode.name));
42801
+ }
42802
+ /**
42803
+ * Creates an AST node that can be used as a guard in `if` statements to distinguish TypeScript
42804
+ * nodes used for checking host bindings from ones used for checking templates.
42805
+ */
42806
+ function createHostBindingsBlockGuard() {
42807
+ // Note that the comment text is quite generic. This doesn't really matter, because it is
42808
+ // used only inside a TCB and there's no way for users to produce a comment there.
42809
+ // `true /*hostBindings*/`.
42810
+ const trueExpr = ts.addSyntheticTrailingComment(ts.factory.createTrue(), ts.SyntaxKind.MultiLineCommentTrivia, GUARD_COMMENT_TEXT);
42811
+ // Wrap the expression in parentheses to ensure that the comment is attached to the correct node.
42812
+ return ts.factory.createParenthesizedExpression(trueExpr);
42813
+ }
42814
+ /**
42815
+ * Determines if a given node is a guard that indicates that descendant nodes are used to check
42816
+ * host bindings.
42817
+ */
42818
+ function isHostBindingsBlockGuard(node) {
42819
+ if (!ts.isIfStatement(node)) {
42820
+ return false;
42821
+ }
42822
+ // Needs to be kept in sync with `createHostBindingsMarker`.
42823
+ const expr = node.expression;
42824
+ if (!ts.isParenthesizedExpression(expr) || expr.expression.kind !== ts.SyntaxKind.TrueKeyword) {
42825
+ return false;
42826
+ }
42827
+ const text = expr.getSourceFile().text;
42828
+ return (ts.forEachTrailingCommentRange(text, expr.expression.getEnd(), (pos, end, kind) => kind === ts.SyntaxKind.MultiLineCommentTrivia &&
42829
+ text.substring(pos + 2, end - 2) === GUARD_COMMENT_TEXT) || false);
42830
+ }
42831
+ /**
42832
+ * If possible, creates and tracks the relevant AST node for a binding declared
42833
+ * through a property on the `host` literal.
42834
+ * @param prop Property to parse.
42835
+ * @param parser Binding parser used to parse the expressions.
42836
+ * @param bindings Array tracking the bound attributes of the host element.
42837
+ * @param listeners Array tracking the event listeners of the host element.
42838
+ */
42839
+ function createNodeFromHostLiteralProperty(property, parser, bindings, listeners) {
42840
+ // TODO(crisbeto): surface parsing errors here, because currently they just get ignored.
42841
+ // They'll still get reported when the handler tries to parse the bindings, but here we
42842
+ // can highlight the nodes more accurately.
42843
+ const { name, initializer } = property;
42844
+ if (name.text.startsWith('[') && name.text.endsWith(']')) {
42845
+ const { attrName, type } = inferBoundAttribute(name.text.slice(1, -1));
42846
+ const valueSpan = createStaticExpressionSpan(initializer);
42847
+ const ast = parser.parseBinding(initializer.text, true, valueSpan, valueSpan.start.offset);
42848
+ if (ast.errors.length > 0) {
42849
+ return; // See TODO above.
42850
+ }
42851
+ fixupSpans(ast, initializer);
42852
+ bindings.push(new BoundAttribute(attrName, type, 0, ast, null, createSourceSpan(property), createStaticExpressionSpan(name), valueSpan, undefined));
42853
+ }
42854
+ else if (name.text.startsWith('(') && name.text.endsWith(')')) {
42855
+ const events = [];
42856
+ parser.parseEvent(name.text.slice(1, -1), initializer.text, false, createSourceSpan(property), createStaticExpressionSpan(initializer), [], events, createStaticExpressionSpan(name));
42857
+ if (events.length === 0 || events[0].handler.errors.length > 0) {
42858
+ return; // See TODO above.
42859
+ }
42860
+ fixupSpans(events[0].handler, initializer);
42861
+ listeners.push(BoundEvent.fromParsedEvent(events[0]));
42862
+ }
42863
+ }
42864
+ /**
42865
+ * If possible, creates and tracks a bound attribute node from a `HostBinding` decorator.
42866
+ * @param decorator Decorator from which to create the node.
42867
+ * @param bindings Array tracking the bound attributes of the host element.
42868
+ */
42869
+ function createNodeFromBindingDecorator(decorator, bindings) {
42870
+ // We only support decorators that are being called.
42871
+ if (!ts.isCallExpression(decorator.expression)) {
42872
+ return;
42873
+ }
42874
+ const args = decorator.expression.arguments;
42875
+ const property = decorator.parent;
42876
+ let nameNode = null;
42877
+ let propertyName = null;
42878
+ if (property && ts.isPropertyDeclaration(property) && isStaticName(property.name)) {
42879
+ propertyName = property.name;
42880
+ }
42881
+ // The first parameter is optional. If omitted, the name
42882
+ // of the class member is used as the property.
42883
+ if (args.length === 0) {
42884
+ nameNode = propertyName;
42885
+ }
42886
+ else if (ts.isStringLiteralLike(args[0])) {
42887
+ nameNode = args[0];
42888
+ }
42889
+ else {
42890
+ return;
42891
+ }
42892
+ if (nameNode === null || propertyName === null) {
42893
+ return;
42894
+ }
42895
+ // We can't synthesize a fake expression here and pass it through the binding parser, because
42896
+ // it constructs all the spans based on the source code origin and they aren't easily mappable
42897
+ // back to the source. E.g. `@HostBinding('foo') id = '123'` in source code would look
42898
+ // something like `[foo]="this.id"` in the AST. Instead we construct the expressions
42899
+ // manually here. Note that we use a dummy span with -1/-1 as offsets, because it isn't
42900
+ // used for type checking and constructing it accurately would take some effort.
42901
+ const span = new ParseSpan(-1, -1);
42902
+ const propertyStart = property.getStart();
42903
+ const receiver = new ThisReceiver(span, new AbsoluteSourceSpan(propertyStart, propertyStart));
42904
+ const nameSpan = new AbsoluteSourceSpan(propertyName.getStart(), propertyName.getEnd());
42905
+ const read = ts.isIdentifier(propertyName)
42906
+ ? new PropertyRead(span, nameSpan, nameSpan, receiver, propertyName.text)
42907
+ : new KeyedRead(span, nameSpan, receiver, new LiteralPrimitive(span, nameSpan, propertyName.text));
42908
+ const { attrName, type } = inferBoundAttribute(nameNode.text);
42909
+ bindings.push(new BoundAttribute(attrName, type, 0, read, null, createSourceSpan(decorator), createStaticExpressionSpan(nameNode), createSourceSpan(decorator), undefined));
42910
+ }
42911
+ /**
42912
+ * If possible, creates and tracks a bound event node from a `HostBinding` decorator.
42913
+ * @param decorator Decorator from which to create the node.
42914
+ * @param parser Binding parser used to parse the expressions.
42915
+ * @param bindings Array tracking the bound events of the host element.
42916
+ */
42917
+ function createNodeFromListenerDecorator(decorator, parser, listeners) {
42918
+ // We only support decorators that are being called with at least one argument.
42919
+ if (!ts.isCallExpression(decorator.expression) || decorator.expression.arguments.length === 0) {
42920
+ return;
42921
+ }
42922
+ const args = decorator.expression.arguments;
42923
+ const method = decorator.parent;
42924
+ // Only handle decorators that are statically analyzable.
42925
+ if (!method ||
42926
+ !ts.isMethodDeclaration(method) ||
42927
+ !isStaticName(method.name) ||
42928
+ !ts.isStringLiteralLike(args[0])) {
42929
+ return;
42930
+ }
42931
+ // We can't synthesize a fake expression here and pass it through the binding parser, because
42932
+ // it constructs all the spans based on the source code origin and they aren't easily mappable
42933
+ // back to the source. E.g. `@HostListener('foo') handleFoo() {}` in source code would look
42934
+ // something like `(foo)="handleFoo()"` in the AST. Instead we construct the expressions
42935
+ // manually here. Note that we use a dummy span with -1/-1 as offsets, because it isn't
42936
+ // used for type checking and constructing it accurately would take some effort.
42937
+ const span = new ParseSpan(-1, -1);
42938
+ const argNodes = [];
42939
+ const methodStart = method.getStart();
42940
+ const methodReceiver = new ThisReceiver(span, new AbsoluteSourceSpan(methodStart, methodStart));
42941
+ const nameSpan = new AbsoluteSourceSpan(method.name.getStart(), method.name.getEnd());
42942
+ const receiver = ts.isIdentifier(method.name)
42943
+ ? new PropertyRead(span, nameSpan, nameSpan, methodReceiver, method.name.text)
42944
+ : new KeyedRead(span, nameSpan, methodReceiver, new LiteralPrimitive(span, nameSpan, method.name.text));
42945
+ if (args.length > 1 && ts.isArrayLiteralExpression(args[1])) {
42946
+ for (const expr of args[1].elements) {
42947
+ // If the parameter is a static string, parse it using the binding parser since it can be any
42948
+ // expression, otherwise treat it as `any` so the rest of the parameters can be checked.
42949
+ if (ts.isStringLiteralLike(expr)) {
42950
+ const span = createStaticExpressionSpan(expr);
42951
+ const ast = parser.parseBinding(expr.text, true, span, span.start.offset);
42952
+ fixupSpans(ast, expr);
42953
+ argNodes.push(ast);
42954
+ }
42955
+ else {
42956
+ // Represents `$any(0)`. We need to construct it manually in order to set the right spans.
42957
+ const expressionSpan = new AbsoluteSourceSpan(expr.getStart(), expr.getEnd());
42958
+ const anyRead = new PropertyRead(span, expressionSpan, expressionSpan, new ImplicitReceiver(span, expressionSpan), '$any');
42959
+ const anyCall = new Call(span, expressionSpan, anyRead, [new LiteralPrimitive(span, expressionSpan, 0)], expressionSpan);
42960
+ argNodes.push(anyCall);
42961
+ }
42962
+ }
42963
+ }
42964
+ const callNode = new Call(span, nameSpan, receiver, argNodes, span);
42965
+ const eventNameNode = args[0];
42966
+ const [eventName, phase] = eventNameNode.text.split('.');
42967
+ listeners.push(new BoundEvent(eventName, eventName.startsWith('@') ? exports.ParsedEventType.Animation : exports.ParsedEventType.Regular, callNode, null, phase, createSourceSpan(decorator), createSourceSpan(decorator), createStaticExpressionSpan(eventNameNode)));
42968
+ }
42969
+ /**
42970
+ * Infers the attribute name and binding type of a bound attribute based on its raw name.
42971
+ * @param name Name from which to infer the information.
42972
+ */
42973
+ function inferBoundAttribute(name) {
42974
+ const attrPrefix = 'attr.';
42975
+ const classPrefix = 'class.';
42976
+ const stylePrefix = 'style.';
42977
+ const animationPrefix = '@';
42978
+ let attrName;
42979
+ let type;
42980
+ // Infer the binding type based on the prefix.
42981
+ if (name.startsWith(attrPrefix)) {
42982
+ attrName = name.slice(attrPrefix.length);
42983
+ type = exports.BindingType.Attribute;
42984
+ }
42985
+ else if (name.startsWith(classPrefix)) {
42986
+ attrName = name.slice(classPrefix.length);
42987
+ type = exports.BindingType.Class;
42988
+ }
42989
+ else if (name.startsWith(stylePrefix)) {
42990
+ attrName = name.slice(stylePrefix.length);
42991
+ type = exports.BindingType.Style;
42992
+ }
42993
+ else if (name.startsWith(animationPrefix)) {
42994
+ attrName = name.slice(animationPrefix.length);
42995
+ type = exports.BindingType.Animation;
42996
+ }
42997
+ else {
42998
+ attrName = name;
42999
+ type = exports.BindingType.Property;
43000
+ }
43001
+ return { attrName, type };
43002
+ }
43003
+ /** Checks whether the specified node is a static name node. */
43004
+ function isStaticName(node) {
43005
+ return ts.isIdentifier(node) || ts.isStringLiteralLike(node);
43006
+ }
43007
+ /** Creates a `ParseSourceSpan` pointing to a static expression AST node's source. */
43008
+ function createStaticExpressionSpan(node) {
43009
+ const span = createSourceSpan(node);
43010
+ // Offset by one on both sides to skip over the quotes.
43011
+ if (ts.isStringLiteralLike(node)) {
43012
+ span.fullStart = span.fullStart.moveBy(1);
43013
+ span.start = span.start.moveBy(1);
43014
+ span.end = span.end.moveBy(-1);
43015
+ }
43016
+ return span;
43017
+ }
43018
+ /**
43019
+ * Adjusts the spans of a parsed AST so that they're appropriate for a host bindings context.
43020
+ * @param ast The parsed AST that may need to be adjusted.
43021
+ * @param initializer TypeScript node from which the source of the AST was extracted.
43022
+ */
43023
+ function fixupSpans(ast, initializer) {
43024
+ // When parsing the initializer as a property/event binding, we use `.text` which excludes escaped
43025
+ // quotes and is generally what we want, because preserving them would result in a parser error,
43026
+ // however it has the downside in that the spans of the expressions following the escaped
43027
+ // characters are no longer accurate relative to the source code. The more escaped characters
43028
+ // there are before a node, the more inaccurate its span will be. If we detect cases like that,
43029
+ // we override the spans of all nodes following the escaped string to point to the entire
43030
+ // initializer string so that we don't surface diagnostics with mangled spans. This isn't ideal,
43031
+ // but is likely rare in user code. Some workarounds that were attempted and ultimately discarded:
43032
+ // 1. Counting the number of escaped strings before a node and adjusting its span accordingly -
43033
+ // There's a prototype of this approach in https://github.com/crisbeto/angular/commit/1eb92353784a609f6be7e6653ae5a9faef549e6a
43034
+ // It works for the most part, but is complex and somewhat brittle, because it's not just the
43035
+ // escaped literals that need to be updated, but also any nodes _after_ them and any nodes
43036
+ // _containing_ them which gets increasingly complex with more complicated ASTs.
43037
+ // 2. Replacing escape characters with whitespaces, for example `\'foo\' + 123` would become
43038
+ // ` 'foo ' + 123` - this appears to produce accurate ASTs for some simpler use cases, but has
43039
+ // the potential of either changing the user's code into something that's no longer parseable or
43040
+ // causing type checking errors (e.g. the typings might require the exact string 'foo').
43041
+ // 3. Passing the raw text (e.g. `initializer.getText().slice(1, -1)`) into the binding parser -
43042
+ // This will preserve the right mappings, but can lead to parsing errors, because some of the
43043
+ // strings won't have to be escaped anymore. We could add a mode to the parser that allows it to
43044
+ // recover from such cases, but it'll introduce more complexity that we may not want to take on.
43045
+ // 4. Constructing some sort of string like `<host ${name.getText()}=${initializer.getText()}/>`,
43046
+ // passing it through the HTML parser and extracting the first attribute from it - wasn't explored
43047
+ // much, but likely has the same issues as approach #3.
43048
+ const escapeIndex = initializer.getText().indexOf('\\', 1);
43049
+ if (escapeIndex > -1) {
43050
+ const newSpan = new ParseSpan(0, initializer.getWidth());
43051
+ const newSourceSpan = new AbsoluteSourceSpan(initializer.getStart(), initializer.getEnd());
43052
+ ast.visit(new ReplaceSpanVisitor(escapeIndex, newSpan, newSourceSpan));
43053
+ }
43054
+ }
43055
+ /**
43056
+ * Visitor that replaces the spans of all nodes with new ones,
43057
+ * if they're defined after a specific index.
43058
+ */
43059
+ class ReplaceSpanVisitor extends RecursiveAstVisitor {
43060
+ afterIndex;
43061
+ overrideSpan;
43062
+ overrideSourceSpan;
43063
+ constructor(afterIndex, overrideSpan, overrideSourceSpan) {
43064
+ super();
43065
+ this.afterIndex = afterIndex;
43066
+ this.overrideSpan = overrideSpan;
43067
+ this.overrideSourceSpan = overrideSourceSpan;
43068
+ }
43069
+ visit(ast) {
43070
+ // Only nodes after the index need to be adjusted, but all nodes should be visited.
43071
+ if (ast.span.start >= this.afterIndex || ast.span.end >= this.afterIndex) {
43072
+ ast.span = this.overrideSpan;
43073
+ ast.sourceSpan = this.overrideSourceSpan;
43074
+ if (ast instanceof ASTWithName) {
43075
+ ast.nameSpan = this.overrideSourceSpan;
43076
+ }
43077
+ if (ast instanceof Call || ast instanceof SafeCall) {
43078
+ ast.argumentSpan = this.overrideSourceSpan;
43079
+ }
43080
+ }
43081
+ super.visit(ast);
43082
+ }
43083
+ }
43084
+
42531
43085
  /**
42532
43086
  * External modules/identifiers that always should exist for type check
42533
43087
  * block files.
@@ -42596,18 +43150,39 @@ function getSourceMapping(shimSf, position, resolver, isDiagnosticRequest) {
42596
43150
  if (sourceLocation === null) {
42597
43151
  return null;
42598
43152
  }
42599
- const mapping = resolver.getTemplateSourceMapping(sourceLocation.id);
43153
+ if (isInHostBindingTcb(node)) {
43154
+ const hostSourceMapping = resolver.getHostBindingsMapping(sourceLocation.id);
43155
+ const span = resolver.toHostParseSourceSpan(sourceLocation.id, sourceLocation.span);
43156
+ if (span === null) {
43157
+ return null;
43158
+ }
43159
+ return { sourceLocation, sourceMapping: hostSourceMapping, span };
43160
+ }
42600
43161
  const span = resolver.toTemplateParseSourceSpan(sourceLocation.id, sourceLocation.span);
42601
43162
  if (span === null) {
42602
43163
  return null;
42603
43164
  }
42604
43165
  // TODO(atscott): Consider adding a context span by walking up from `node` until we get a
42605
43166
  // different span.
42606
- return { sourceLocation, sourceMapping: mapping, span };
43167
+ return {
43168
+ sourceLocation,
43169
+ sourceMapping: resolver.getTemplateSourceMapping(sourceLocation.id),
43170
+ span,
43171
+ };
43172
+ }
43173
+ function isInHostBindingTcb(node) {
43174
+ let current = node;
43175
+ while (current && !ts.isFunctionDeclaration(current)) {
43176
+ if (isHostBindingsBlockGuard(current)) {
43177
+ return true;
43178
+ }
43179
+ current = current.parent;
43180
+ }
43181
+ return false;
42607
43182
  }
42608
43183
  function findTypeCheckBlock(file, id, isDiagnosticRequest) {
42609
43184
  for (const stmt of file.statements) {
42610
- if (ts.isFunctionDeclaration(stmt) && getTemplateId(stmt, file, isDiagnosticRequest) === id) {
43185
+ if (ts.isFunctionDeclaration(stmt) && getTypeCheckId(stmt, file, isDiagnosticRequest) === id) {
42611
43186
  return stmt;
42612
43187
  }
42613
43188
  }
@@ -42630,7 +43205,7 @@ function findSourceLocation(node, sourceFile, isDiagnosticsRequest) {
42630
43205
  if (span !== null) {
42631
43206
  // Once the positional information has been extracted, search further up the TCB to extract
42632
43207
  // the unique id that is attached with the TCB's function declaration.
42633
- const id = getTemplateId(node, sourceFile, isDiagnosticsRequest);
43208
+ const id = getTypeCheckId(node, sourceFile, isDiagnosticsRequest);
42634
43209
  if (id === null) {
42635
43210
  return null;
42636
43211
  }
@@ -42640,7 +43215,7 @@ function findSourceLocation(node, sourceFile, isDiagnosticsRequest) {
42640
43215
  }
42641
43216
  return null;
42642
43217
  }
42643
- function getTemplateId(node, sourceFile, isDiagnosticRequest) {
43218
+ function getTypeCheckId(node, sourceFile, isDiagnosticRequest) {
42644
43219
  // Walk up to the function declaration of the TCB, the file information is attached there.
42645
43220
  while (!ts.isFunctionDeclaration(node)) {
42646
43221
  if (hasIgnoreForDiagnosticsMarker(node, sourceFile) && isDiagnosticRequest) {
@@ -43896,7 +44471,6 @@ var TcbGenericContextBehavior;
43896
44471
  */
43897
44472
  function generateTypeCheckBlock(env, ref, name, meta, domSchemaChecker, oobRecorder, genericContextBehavior) {
43898
44473
  const tcb = new Context(env, domSchemaChecker, oobRecorder, meta.id, meta.boundTarget, meta.pipes, meta.schemas, meta.isStandalone, meta.preserveWhitespaces);
43899
- const scope = Scope.forNodes(tcb, null, null, tcb.boundTarget.target.template, /* guard */ null);
43900
44474
  const ctxRawType = env.referenceType(ref);
43901
44475
  if (!ts.isTypeReferenceNode(ctxRawType)) {
43902
44476
  throw new Error(`Expected TypeReferenceNode when referencing the ctx param for ${ref.debugName}`);
@@ -43923,13 +44497,19 @@ function generateTypeCheckBlock(env, ref, name, meta, domSchemaChecker, oobRecor
43923
44497
  }
43924
44498
  }
43925
44499
  const paramList = [tcbThisParam(ctxRawType.typeName, typeArguments)];
43926
- const scopeStatements = scope.render();
43927
- const innerBody = ts.factory.createBlock([...env.getPreludeStatements(), ...scopeStatements]);
43928
- // Wrap the body in an "if (true)" expression. This is unnecessary but has the effect of causing
43929
- // the `ts.Printer` to format the type-check block nicely.
43930
- const body = ts.factory.createBlock([
43931
- ts.factory.createIfStatement(ts.factory.createTrue(), innerBody, undefined),
43932
- ]);
44500
+ const statements = [];
44501
+ // Add the template type checking code.
44502
+ if (tcb.boundTarget.target.template !== undefined) {
44503
+ const templateScope = Scope.forNodes(tcb, null, null, tcb.boundTarget.target.template,
44504
+ /* guard */ null);
44505
+ statements.push(renderBlockStatements(env, templateScope, ts.factory.createTrue()));
44506
+ }
44507
+ // Add the host bindings type checking code.
44508
+ if (tcb.boundTarget.target.host !== undefined) {
44509
+ const hostScope = Scope.forNodes(tcb, null, tcb.boundTarget.target.host, null, null);
44510
+ statements.push(renderBlockStatements(env, hostScope, createHostBindingsBlockGuard()));
44511
+ }
44512
+ const body = ts.factory.createBlock(statements);
43933
44513
  const fnDecl = ts.factory.createFunctionDeclaration(
43934
44514
  /* modifiers */ undefined,
43935
44515
  /* asteriskToken */ undefined,
@@ -43941,6 +44521,14 @@ function generateTypeCheckBlock(env, ref, name, meta, domSchemaChecker, oobRecor
43941
44521
  addTypeCheckId(fnDecl, meta.id);
43942
44522
  return fnDecl;
43943
44523
  }
44524
+ function renderBlockStatements(env, scope, wrapperExpression) {
44525
+ const scopeStatements = scope.render();
44526
+ const innerBody = ts.factory.createBlock([...env.getPreludeStatements(), ...scopeStatements]);
44527
+ // Wrap the body in an if statement. This serves two purposes:
44528
+ // 1. It allows us to distinguish between the sections of the block (e.g. host or template).
44529
+ // 2. It allows the `ts.Printer` to produce better-looking output.
44530
+ return ts.factory.createIfStatement(wrapperExpression, innerBody);
44531
+ }
43944
44532
  /**
43945
44533
  * A code generation operation that's involved in the construction of a Type Check Block.
43946
44534
  *
@@ -44693,20 +45281,28 @@ class TcbDomSchemaCheckerOp extends TcbOp {
44693
45281
  return false;
44694
45282
  }
44695
45283
  execute() {
44696
- if (this.checkElement) {
44697
- this.tcb.domSchemaChecker.checkElement(this.tcb.id, this.element, this.tcb.schemas, this.tcb.hostIsStandalone);
45284
+ const element = this.element;
45285
+ const isTemplateElement = element instanceof Element$1;
45286
+ const bindings = isTemplateElement ? element.inputs : element.bindings;
45287
+ if (this.checkElement && isTemplateElement) {
45288
+ this.tcb.domSchemaChecker.checkElement(this.tcb.id, element, this.tcb.schemas, this.tcb.hostIsStandalone);
44698
45289
  }
44699
45290
  // TODO(alxhub): this could be more efficient.
44700
- for (const binding of this.element.inputs) {
45291
+ for (const binding of bindings) {
44701
45292
  const isPropertyBinding = binding.type === exports.BindingType.Property || binding.type === exports.BindingType.TwoWay;
44702
- if (isPropertyBinding && this.claimedInputs.has(binding.name)) {
45293
+ if (isPropertyBinding && this.claimedInputs?.has(binding.name)) {
44703
45294
  // Skip this binding as it was claimed by a directive.
44704
45295
  continue;
44705
45296
  }
44706
45297
  if (isPropertyBinding && binding.name !== 'style' && binding.name !== 'class') {
44707
45298
  // A direct binding to a property.
44708
45299
  const propertyName = ATTR_TO_PROP.get(binding.name) ?? binding.name;
44709
- this.tcb.domSchemaChecker.checkProperty(this.tcb.id, this.element, propertyName, binding.sourceSpan, this.tcb.schemas, this.tcb.hostIsStandalone);
45300
+ if (isTemplateElement) {
45301
+ this.tcb.domSchemaChecker.checkTemplateElementProperty(this.tcb.id, element, propertyName, binding.sourceSpan, this.tcb.schemas, this.tcb.hostIsStandalone);
45302
+ }
45303
+ else {
45304
+ this.tcb.domSchemaChecker.checkHostElementProperty(this.tcb.id, element, propertyName, binding.keySpan, this.tcb.schemas);
45305
+ }
44710
45306
  }
44711
45307
  }
44712
45308
  return null;
@@ -44821,6 +45417,30 @@ class TcbControlFlowContentProjectionOp extends TcbOp {
44821
45417
  return false;
44822
45418
  }
44823
45419
  }
45420
+ /**
45421
+ * A `TcbOp` which creates an expression for a the host element of a directive.
45422
+ *
45423
+ * Executing this operation returns a reference to the element variable.
45424
+ */
45425
+ class TcbHostElementOp extends TcbOp {
45426
+ tcb;
45427
+ scope;
45428
+ element;
45429
+ optional = true;
45430
+ constructor(tcb, scope, element) {
45431
+ super();
45432
+ this.tcb = tcb;
45433
+ this.scope = scope;
45434
+ this.element = element;
45435
+ }
45436
+ execute() {
45437
+ const id = this.tcb.allocateId();
45438
+ const initializer = tsCreateElement(...this.element.tagNames);
45439
+ addParseSpanInfo(initializer, this.element.sourceSpan);
45440
+ this.scope.addStatement(tsCreateVariable(id, initializer));
45441
+ return id;
45442
+ }
45443
+ }
44824
45444
  /**
44825
45445
  * Mapping between attributes names that don't correspond to their element property names.
44826
45446
  * Note: this mapping has to be kept in sync with the equally named mapping in the runtime.
@@ -44846,13 +45466,15 @@ const ATTR_TO_PROP = new Map(Object.entries({
44846
45466
  class TcbUnclaimedInputsOp extends TcbOp {
44847
45467
  tcb;
44848
45468
  scope;
44849
- element;
45469
+ inputs;
45470
+ target;
44850
45471
  claimedInputs;
44851
- constructor(tcb, scope, element, claimedInputs) {
45472
+ constructor(tcb, scope, inputs, target, claimedInputs) {
44852
45473
  super();
44853
45474
  this.tcb = tcb;
44854
45475
  this.scope = scope;
44855
- this.element = element;
45476
+ this.inputs = inputs;
45477
+ this.target = target;
44856
45478
  this.claimedInputs = claimedInputs;
44857
45479
  }
44858
45480
  get optional() {
@@ -44863,9 +45485,9 @@ class TcbUnclaimedInputsOp extends TcbOp {
44863
45485
  // the element itself.
44864
45486
  let elId = null;
44865
45487
  // TODO(alxhub): this could be more efficient.
44866
- for (const binding of this.element.inputs) {
45488
+ for (const binding of this.inputs) {
44867
45489
  const isPropertyBinding = binding.type === exports.BindingType.Property || binding.type === exports.BindingType.TwoWay;
44868
- if (isPropertyBinding && this.claimedInputs.has(binding.name)) {
45490
+ if (isPropertyBinding && this.claimedInputs?.has(binding.name)) {
44869
45491
  // Skip this binding as it was claimed by a directive.
44870
45492
  continue;
44871
45493
  }
@@ -44873,7 +45495,7 @@ class TcbUnclaimedInputsOp extends TcbOp {
44873
45495
  if (this.tcb.env.config.checkTypeOfDomBindings && isPropertyBinding) {
44874
45496
  if (binding.name !== 'style' && binding.name !== 'class') {
44875
45497
  if (elId === null) {
44876
- elId = this.scope.resolve(this.element);
45498
+ elId = this.scope.resolve(this.target);
44877
45499
  }
44878
45500
  // A direct binding to a property.
44879
45501
  const propertyName = ATTR_TO_PROP.get(binding.name) ?? binding.name;
@@ -44973,13 +45595,17 @@ class TcbDirectiveOutputsOp extends TcbOp {
44973
45595
  class TcbUnclaimedOutputsOp extends TcbOp {
44974
45596
  tcb;
44975
45597
  scope;
44976
- element;
45598
+ target;
45599
+ outputs;
45600
+ inputs;
44977
45601
  claimedOutputs;
44978
- constructor(tcb, scope, element, claimedOutputs) {
45602
+ constructor(tcb, scope, target, outputs, inputs, claimedOutputs) {
44979
45603
  super();
44980
45604
  this.tcb = tcb;
44981
45605
  this.scope = scope;
44982
- this.element = element;
45606
+ this.target = target;
45607
+ this.outputs = outputs;
45608
+ this.inputs = inputs;
44983
45609
  this.claimedOutputs = claimedOutputs;
44984
45610
  }
44985
45611
  get optional() {
@@ -44988,14 +45614,16 @@ class TcbUnclaimedOutputsOp extends TcbOp {
44988
45614
  execute() {
44989
45615
  let elId = null;
44990
45616
  // TODO(alxhub): this could be more efficient.
44991
- for (const output of this.element.outputs) {
44992
- if (this.claimedOutputs.has(output.name)) {
45617
+ for (const output of this.outputs) {
45618
+ if (this.claimedOutputs?.has(output.name)) {
44993
45619
  // Skip this event handler as it was claimed by a directive.
44994
45620
  continue;
44995
45621
  }
44996
- if (this.tcb.env.config.checkTypeOfOutputEvents && output.name.endsWith('Change')) {
45622
+ if (this.tcb.env.config.checkTypeOfOutputEvents &&
45623
+ this.inputs !== null &&
45624
+ output.name.endsWith('Change')) {
44997
45625
  const inputName = output.name.slice(0, -6);
44998
- if (checkSplitTwoWayBinding(inputName, output, this.element.inputs, this.tcb)) {
45626
+ if (checkSplitTwoWayBinding(inputName, output, this.inputs, this.tcb)) {
44999
45627
  // Skip this event handler as the error was already handled.
45000
45628
  continue;
45001
45629
  }
@@ -45016,7 +45644,7 @@ class TcbUnclaimedOutputsOp extends TcbOp {
45016
45644
  // base `Event` type.
45017
45645
  const handler = tcbCreateEventHandler(output, this.tcb, this.scope, 0 /* EventParamType.Infer */);
45018
45646
  if (elId === null) {
45019
- elId = this.scope.resolve(this.element);
45647
+ elId = this.scope.resolve(this.target);
45020
45648
  }
45021
45649
  const propertyAccess = ts.factory.createPropertyAccessExpression(elId, 'addEventListener');
45022
45650
  addParseSpanInfo(propertyAccess, output.keySpan);
@@ -45406,6 +46034,10 @@ class Scope {
45406
46034
  * A map of `TmplAstElement`s to the index of their `TcbElementOp` in the `opQueue`
45407
46035
  */
45408
46036
  elementOpMap = new Map();
46037
+ /**
46038
+ * A map of `TmplAstHostElement`s to the index of their `TcbHostElementOp` in the `opQueue`
46039
+ */
46040
+ hostElementOpMap = new Map();
45409
46041
  /**
45410
46042
  * A map of maps which tracks the index of `TcbDirectiveCtorOp`s in the `opQueue` for each
45411
46043
  * directive on a `TmplAstElement` or `TmplAstTemplate` node.
@@ -45508,8 +46140,13 @@ class Scope {
45508
46140
  this.registerVariable(scope, variable, new TcbBlockImplicitVariableOp(tcb, scope, type, variable));
45509
46141
  }
45510
46142
  }
45511
- for (const node of children) {
45512
- scope.appendNode(node);
46143
+ else if (scopedNode instanceof HostElement) {
46144
+ scope.appendNode(scopedNode);
46145
+ }
46146
+ if (children !== null) {
46147
+ for (const node of children) {
46148
+ scope.appendNode(node);
46149
+ }
45513
46150
  }
45514
46151
  // Once everything is registered, we need to check if there are `@let`
45515
46152
  // declarations that conflict with other local symbols defined after them.
@@ -45669,6 +46306,9 @@ class Scope {
45669
46306
  // Resolving the DOM node of an element in this template.
45670
46307
  return this.resolveOp(this.elementOpMap.get(ref));
45671
46308
  }
46309
+ else if (ref instanceof HostElement && this.hostElementOpMap.has(ref)) {
46310
+ return this.resolveOp(this.hostElementOpMap.get(ref));
46311
+ }
45672
46312
  else {
45673
46313
  return null;
45674
46314
  }
@@ -45764,6 +46404,11 @@ class Scope {
45764
46404
  this.letDeclOpMap.set(node.name, { opIndex, node });
45765
46405
  }
45766
46406
  }
46407
+ else if (node instanceof HostElement) {
46408
+ const opIndex = this.opQueue.push(new TcbHostElementOp(this.tcb, this, node)) - 1;
46409
+ this.hostElementOpMap.set(node, opIndex);
46410
+ this.opQueue.push(new TcbUnclaimedInputsOp(this.tcb, this, node.bindings, node, null), new TcbUnclaimedOutputsOp(this.tcb, this, node, node.listeners, null, null), new TcbDomSchemaCheckerOp(this.tcb, node, false, null));
46411
+ }
45767
46412
  }
45768
46413
  appendChildren(node) {
45769
46414
  for (const child of node.children) {
@@ -45798,8 +46443,7 @@ class Scope {
45798
46443
  // If there are no directives, then all inputs are unclaimed inputs, so queue an operation
45799
46444
  // to add them if needed.
45800
46445
  if (node instanceof Element$1) {
45801
- this.opQueue.push(new TcbUnclaimedInputsOp(this.tcb, this, node, claimedInputs));
45802
- this.opQueue.push(new TcbDomSchemaCheckerOp(this.tcb, node, /* checkElement */ true, claimedInputs));
46446
+ this.opQueue.push(new TcbUnclaimedInputsOp(this.tcb, this, node.inputs, node, claimedInputs), new TcbDomSchemaCheckerOp(this.tcb, node, /* checkElement */ true, claimedInputs));
45803
46447
  }
45804
46448
  return;
45805
46449
  }
@@ -45850,7 +46494,7 @@ class Scope {
45850
46494
  claimedInputs.add(propertyName);
45851
46495
  }
45852
46496
  }
45853
- this.opQueue.push(new TcbUnclaimedInputsOp(this.tcb, this, node, claimedInputs));
46497
+ this.opQueue.push(new TcbUnclaimedInputsOp(this.tcb, this, node.inputs, node, claimedInputs));
45854
46498
  // If there are no directives which match this element, then it's a "plain" DOM element (or a
45855
46499
  // web component), and should be checked against the DOM schema. If any directives match,
45856
46500
  // we must assume that the element could be custom (either a component, or a directive like
@@ -45867,7 +46511,7 @@ class Scope {
45867
46511
  // If there are no directives, then all outputs are unclaimed outputs, so queue an operation
45868
46512
  // to add them if needed.
45869
46513
  if (node instanceof Element$1) {
45870
- this.opQueue.push(new TcbUnclaimedOutputsOp(this.tcb, this, node, claimedOutputs));
46514
+ this.opQueue.push(new TcbUnclaimedOutputsOp(this.tcb, this, node, node.outputs, node.inputs, claimedOutputs));
45871
46515
  }
45872
46516
  return;
45873
46517
  }
@@ -45884,7 +46528,7 @@ class Scope {
45884
46528
  claimedOutputs.add(outputProperty);
45885
46529
  }
45886
46530
  }
45887
- this.opQueue.push(new TcbUnclaimedOutputsOp(this.tcb, this, node, claimedOutputs));
46531
+ this.opQueue.push(new TcbUnclaimedOutputsOp(this.tcb, this, node, node.outputs, node.inputs, claimedOutputs));
45888
46532
  }
45889
46533
  }
45890
46534
  appendDeepSchemaChecks(nodes) {
@@ -46535,18 +47179,22 @@ class TypeCheckContextImpl {
46535
47179
  *
46536
47180
  * Implements `TypeCheckContext.addTemplate`.
46537
47181
  */
46538
- addDirective(ref, binder, schemas, templateContext, isStandalone) {
47182
+ addDirective(ref, binder, schemas, templateContext, hostBindingContext, isStandalone) {
46539
47183
  if (!this.host.shouldCheckClass(ref.node)) {
46540
47184
  return;
46541
47185
  }
46542
- const fileData = this.dataForFile(ref.node.getSourceFile());
47186
+ const sourceFile = ref.node.getSourceFile();
47187
+ const fileData = this.dataForFile(sourceFile);
46543
47188
  const shimData = this.pendingShimForClass(ref.node);
46544
47189
  const id = fileData.sourceManager.getTypeCheckId(ref.node);
46545
47190
  const templateParsingDiagnostics = [];
46546
47191
  if (templateContext !== null && templateContext.parseErrors !== null) {
46547
47192
  templateParsingDiagnostics.push(...getTemplateDiagnostics(templateContext.parseErrors, id, templateContext.sourceMapping));
46548
47193
  }
46549
- const boundTarget = binder.bind({ template: templateContext?.nodes });
47194
+ const boundTarget = binder.bind({
47195
+ template: templateContext?.nodes,
47196
+ host: hostBindingContext?.node,
47197
+ });
46550
47198
  if (this.inlining === InliningMode.InlineOps) {
46551
47199
  // Get all of the directives used in the template and record inline type constructors when
46552
47200
  // required.
@@ -46576,6 +47224,7 @@ class TypeCheckContextImpl {
46576
47224
  template: templateContext?.nodes || null,
46577
47225
  boundTarget,
46578
47226
  templateParsingDiagnostics,
47227
+ hostElement: hostBindingContext?.node ?? null,
46579
47228
  });
46580
47229
  const usedPipes = [];
46581
47230
  if (templateContext !== null) {
@@ -46601,6 +47250,12 @@ class TypeCheckContextImpl {
46601
47250
  if (templateContext !== null) {
46602
47251
  fileData.sourceManager.captureTemplateSource(id, templateContext.sourceMapping, templateContext.file);
46603
47252
  }
47253
+ if (hostBindingContext !== null) {
47254
+ fileData.sourceManager.captureHostBindingsMapping(id, hostBindingContext.sourceMapping,
47255
+ // We only support host bindings in the same file as the directive
47256
+ // so we can get the source file from here.
47257
+ new ParseSourceFile(sourceFile.text, sourceFile.fileName));
47258
+ }
46604
47259
  const meta = {
46605
47260
  id,
46606
47261
  boundTarget,
@@ -46904,10 +47559,10 @@ function findClosestLineStartPosition(linesMap, position, low = 0, high = linesM
46904
47559
  }
46905
47560
 
46906
47561
  /**
46907
- * Represents the source of a template that was processed during type-checking. This information is
46908
- * used when translating parse offsets in diagnostics back to their original line/column location.
47562
+ * Represents the source of code processed during type-checking. This information is used when
47563
+ * translating parse offsets in diagnostics back to their original line/column location.
46909
47564
  */
46910
- class TemplateSource {
47565
+ class Source {
46911
47566
  mapping;
46912
47567
  file;
46913
47568
  lineStarts = null;
@@ -46944,11 +47599,16 @@ class DirectiveSourceManager {
46944
47599
  * diagnostics produced for TCB code to their source location in the template.
46945
47600
  */
46946
47601
  templateSources = new Map();
47602
+ /** Keeps track of type check IDs and the source location of their host bindings. */
47603
+ hostBindingSources = new Map();
46947
47604
  getTypeCheckId(node) {
46948
- return getTypeCheckId(node);
47605
+ return getTypeCheckId$1(node);
46949
47606
  }
46950
47607
  captureTemplateSource(id, mapping, file) {
46951
- this.templateSources.set(id, new TemplateSource(mapping, file));
47608
+ this.templateSources.set(id, new Source(mapping, file));
47609
+ }
47610
+ captureHostBindingsMapping(id, mapping, file) {
47611
+ this.hostBindingSources.set(id, new Source(mapping, file));
46952
47612
  }
46953
47613
  getTemplateSourceMapping(id) {
46954
47614
  if (!this.templateSources.has(id)) {
@@ -46956,6 +47616,12 @@ class DirectiveSourceManager {
46956
47616
  }
46957
47617
  return this.templateSources.get(id).mapping;
46958
47618
  }
47619
+ getHostBindingsMapping(id) {
47620
+ if (!this.hostBindingSources.has(id)) {
47621
+ throw new Error(`Unexpected unknown type check ID: ${id}`);
47622
+ }
47623
+ return this.hostBindingSources.get(id).mapping;
47624
+ }
46959
47625
  toTemplateParseSourceSpan(id, span) {
46960
47626
  if (!this.templateSources.has(id)) {
46961
47627
  return null;
@@ -46963,6 +47629,13 @@ class DirectiveSourceManager {
46963
47629
  const templateSource = this.templateSources.get(id);
46964
47630
  return templateSource.toParseSourceSpan(span.start, span.end);
46965
47631
  }
47632
+ toHostParseSourceSpan(id, span) {
47633
+ if (!this.hostBindingSources.has(id)) {
47634
+ return null;
47635
+ }
47636
+ const source = this.hostBindingSources.get(id);
47637
+ return source.toParseSourceSpan(span.start, span.end);
47638
+ }
46966
47639
  }
46967
47640
 
46968
47641
  /**
@@ -47727,16 +48400,17 @@ class TemplateTypeCheckerImpl {
47727
48400
  }
47728
48401
  getTemplate(component, optimizeFor) {
47729
48402
  const { data } = this.getLatestComponentState(component, optimizeFor);
47730
- if (data === null) {
47731
- return null;
47732
- }
47733
- return data.template;
48403
+ return data?.template ?? null;
48404
+ }
48405
+ getHostElement(directive, optimizeFor) {
48406
+ const { data } = this.getLatestComponentState(directive, optimizeFor);
48407
+ return data?.hostElement ?? null;
47734
48408
  }
47735
48409
  getUsedDirectives(component) {
47736
- return this.getLatestComponentState(component).data?.boundTarget.getUsedDirectives() || null;
48410
+ return this.getLatestComponentState(component).data?.boundTarget.getUsedDirectives() ?? null;
47737
48411
  }
47738
48412
  getUsedPipes(component) {
47739
- return this.getLatestComponentState(component).data?.boundTarget.getUsedPipes() || null;
48413
+ return this.getLatestComponentState(component).data?.boundTarget.getUsedPipes() ?? null;
47740
48414
  }
47741
48415
  getLatestComponentState(component, optimizeFor = exports.OptimizeFor.SingleFile) {
47742
48416
  switch (optimizeFor) {
@@ -47931,7 +48605,7 @@ class TemplateTypeCheckerImpl {
47931
48605
  this.isComplete = false;
47932
48606
  }
47933
48607
  getExpressionTarget(expression, clazz) {
47934
- return (this.getLatestComponentState(clazz).data?.boundTarget.getExpressionTarget(expression) || null);
48608
+ return (this.getLatestComponentState(clazz).data?.boundTarget.getExpressionTarget(expression) ?? null);
47935
48609
  }
47936
48610
  makeTemplateDiagnostic(clazz, sourceSpan, category, errorCode, message, relatedInformation) {
47937
48611
  const sfPath = absoluteFromSourceFile(clazz.getSourceFile());
@@ -48607,6 +49281,7 @@ exports.createDirectiveType = createDirectiveType;
48607
49281
  exports.createFactoryType = createFactoryType;
48608
49282
  exports.createForwardRefResolver = createForwardRefResolver;
48609
49283
  exports.createHostDirectivesMappingArray = createHostDirectivesMappingArray;
49284
+ exports.createHostElement = createHostElement;
48610
49285
  exports.createInjectableType = createInjectableType;
48611
49286
  exports.createInjectorType = createInjectorType;
48612
49287
  exports.createMayBeForwardRefExpression = createMayBeForwardRefExpression;
@@ -48622,6 +49297,7 @@ exports.extraReferenceFromTypeQuery = extraReferenceFromTypeQuery;
48622
49297
  exports.extractDecoratorQueryMetadata = extractDecoratorQueryMetadata;
48623
49298
  exports.extractDirectiveMetadata = extractDirectiveMetadata;
48624
49299
  exports.extractDirectiveTypeCheckMeta = extractDirectiveTypeCheckMeta;
49300
+ exports.extractHostBindingResources = extractHostBindingResources;
48625
49301
  exports.extractMessages = extractMessages;
48626
49302
  exports.extractReferencesFromType = extractReferencesFromType;
48627
49303
  exports.findAngularDecorator = findAngularDecorator;