@angular/compiler 16.2.0 → 17.0.0-next.0

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 (39) hide show
  1. package/esm2022/src/compiler.mjs +3 -3
  2. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  3. package/esm2022/src/render3/partial/component.mjs +4 -1
  4. package/esm2022/src/render3/partial/directive.mjs +1 -1
  5. package/esm2022/src/render3/partial/factory.mjs +1 -1
  6. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  7. package/esm2022/src/render3/partial/injector.mjs +1 -1
  8. package/esm2022/src/render3/partial/ng_module.mjs +1 -1
  9. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  10. package/esm2022/src/render3/r3_ast.mjs +113 -9
  11. package/esm2022/src/render3/r3_class_metadata_compiler.mjs +55 -1
  12. package/esm2022/src/render3/r3_control_flow.mjs +289 -0
  13. package/esm2022/src/render3/r3_deferred_blocks.mjs +16 -9
  14. package/esm2022/src/render3/r3_deferred_triggers.mjs +33 -19
  15. package/esm2022/src/render3/r3_identifiers.mjs +17 -1
  16. package/esm2022/src/render3/r3_template_transform.mjs +28 -7
  17. package/esm2022/src/render3/view/api.mjs +1 -1
  18. package/esm2022/src/render3/view/compiler.mjs +12 -2
  19. package/esm2022/src/render3/view/t2_binder.mjs +66 -5
  20. package/esm2022/src/render3/view/template.mjs +130 -54
  21. package/esm2022/src/template/pipeline/ir/index.mjs +2 -3
  22. package/esm2022/src/template/pipeline/ir/src/enums.mjs +41 -3
  23. package/esm2022/src/template/pipeline/ir/src/expression.mjs +11 -1
  24. package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +16 -4
  25. package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +5 -3
  26. package/esm2022/src/template/pipeline/src/emit.mjs +3 -1
  27. package/esm2022/src/template/pipeline/src/ingest.mjs +10 -10
  28. package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +43 -75
  29. package/esm2022/src/template/pipeline/src/phases/binding_specialization.mjs +2 -2
  30. package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +90 -13
  31. package/esm2022/src/template/pipeline/src/phases/parse_extracted_styles.mjs +38 -0
  32. package/esm2022/src/version.mjs +1 -1
  33. package/fesm2022/compiler.mjs +1110 -425
  34. package/fesm2022/compiler.mjs.map +1 -1
  35. package/fesm2022/testing.mjs +1 -1
  36. package/index.d.ts +141 -5
  37. package/package.json +2 -2
  38. package/testing/index.d.ts +1 -1
  39. package/esm2022/src/template/pipeline/ir/src/element.mjs +0 -108
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v16.2.0
2
+ * @license Angular v17.0.0-next.0
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -2614,6 +2614,20 @@ class Identifiers {
2614
2614
  static { this.resetView = { name: 'ɵɵresetView', moduleName: CORE }; }
2615
2615
  static { this.templateCreate = { name: 'ɵɵtemplate', moduleName: CORE }; }
2616
2616
  static { this.defer = { name: 'ɵɵdefer', moduleName: CORE }; }
2617
+ static { this.deferWhen = { name: 'ɵɵdeferWhen', moduleName: CORE }; }
2618
+ static { this.deferOnIdle = { name: 'ɵɵdeferOnIdle', moduleName: CORE }; }
2619
+ static { this.deferOnImmediate = { name: 'ɵɵdeferOnImmediate', moduleName: CORE }; }
2620
+ static { this.deferOnTimer = { name: 'ɵɵdeferOnTimer', moduleName: CORE }; }
2621
+ static { this.deferOnHover = { name: 'ɵɵdeferOnHover', moduleName: CORE }; }
2622
+ static { this.deferOnInteraction = { name: 'ɵɵdeferOnInteraction', moduleName: CORE }; }
2623
+ static { this.deferOnViewport = { name: 'ɵɵdeferOnViewport', moduleName: CORE }; }
2624
+ static { this.deferPrefetchWhen = { name: 'ɵɵdeferPrefetchWhen', moduleName: CORE }; }
2625
+ static { this.deferPrefetchOnIdle = { name: 'ɵɵdeferPrefetchOnIdle', moduleName: CORE }; }
2626
+ static { this.deferPrefetchOnImmediate = { name: 'ɵɵdeferPrefetchOnImmediate', moduleName: CORE }; }
2627
+ static { this.deferPrefetchOnTimer = { name: 'ɵɵdeferPrefetchOnTimer', moduleName: CORE }; }
2628
+ static { this.deferPrefetchOnHover = { name: 'ɵɵdeferPrefetchOnHover', moduleName: CORE }; }
2629
+ static { this.deferPrefetchOnInteraction = { name: 'ɵɵdeferPrefetchOnInteraction', moduleName: CORE }; }
2630
+ static { this.deferPrefetchOnViewport = { name: 'ɵɵdeferPrefetchOnViewport', moduleName: CORE }; }
2617
2631
  static { this.text = { name: 'ɵɵtext', moduleName: CORE }; }
2618
2632
  static { this.enableBindings = { name: 'ɵɵenableBindings', moduleName: CORE }; }
2619
2633
  static { this.disableBindings = { name: 'ɵɵdisableBindings', moduleName: CORE }; }
@@ -2681,6 +2695,7 @@ class Identifiers {
2681
2695
  static { this.resolveWindow = { name: 'ɵɵresolveWindow', moduleName: CORE }; }
2682
2696
  static { this.resolveDocument = { name: 'ɵɵresolveDocument', moduleName: CORE }; }
2683
2697
  static { this.resolveBody = { name: 'ɵɵresolveBody', moduleName: CORE }; }
2698
+ static { this.getComponentDepsFactory = { name: 'ɵɵgetComponentDepsFactory', moduleName: CORE }; }
2684
2699
  static { this.defineComponent = { name: 'ɵɵdefineComponent', moduleName: CORE }; }
2685
2700
  static { this.declareComponent = { name: 'ɵɵngDeclareComponent', moduleName: CORE }; }
2686
2701
  static { this.setComponentScope = { name: 'ɵɵsetComponentScope', moduleName: CORE }; }
@@ -2729,6 +2744,7 @@ class Identifiers {
2729
2744
  static { this.declarePipe = { name: 'ɵɵngDeclarePipe', moduleName: CORE }; }
2730
2745
  static { this.declareClassMetadata = { name: 'ɵɵngDeclareClassMetadata', moduleName: CORE }; }
2731
2746
  static { this.setClassMetadata = { name: 'ɵsetClassMetadata', moduleName: CORE }; }
2747
+ static { this.setClassMetadataAsync = { name: 'ɵsetClassMetadataAsync', moduleName: CORE }; }
2732
2748
  static { this.queryRefresh = { name: 'ɵɵqueryRefresh', moduleName: CORE }; }
2733
2749
  static { this.viewQuery = { name: 'ɵɵviewQuery', moduleName: CORE }; }
2734
2750
  static { this.loadQuery = { name: 'ɵɵloadQuery', moduleName: CORE }; }
@@ -3983,18 +3999,108 @@ class DeferredBlockError {
3983
3999
  class DeferredBlock {
3984
4000
  constructor(children, triggers, prefetchTriggers, placeholder, loading, error, sourceSpan, startSourceSpan, endSourceSpan) {
3985
4001
  this.children = children;
3986
- this.triggers = triggers;
3987
- this.prefetchTriggers = prefetchTriggers;
3988
4002
  this.placeholder = placeholder;
3989
4003
  this.loading = loading;
3990
4004
  this.error = error;
3991
4005
  this.sourceSpan = sourceSpan;
3992
4006
  this.startSourceSpan = startSourceSpan;
3993
4007
  this.endSourceSpan = endSourceSpan;
4008
+ this.triggers = triggers;
4009
+ this.prefetchTriggers = prefetchTriggers;
4010
+ // We cache the keys since we know that they won't change and we
4011
+ // don't want to enumarate them every time we're traversing the AST.
4012
+ this.definedTriggers = Object.keys(triggers);
4013
+ this.definedPrefetchTriggers = Object.keys(prefetchTriggers);
3994
4014
  }
3995
4015
  visit(visitor) {
3996
4016
  return visitor.visitDeferredBlock(this);
3997
4017
  }
4018
+ visitAll(visitor) {
4019
+ this.visitTriggers(this.definedTriggers, this.triggers, visitor);
4020
+ this.visitTriggers(this.definedPrefetchTriggers, this.prefetchTriggers, visitor);
4021
+ visitAll$1(visitor, this.children);
4022
+ this.placeholder && visitor.visitDeferredBlockPlaceholder(this.placeholder);
4023
+ this.loading && visitor.visitDeferredBlockLoading(this.loading);
4024
+ this.error && visitor.visitDeferredBlockError(this.error);
4025
+ }
4026
+ visitTriggers(keys, triggers, visitor) {
4027
+ for (const key of keys) {
4028
+ visitor.visitDeferredTrigger(triggers[key]);
4029
+ }
4030
+ }
4031
+ }
4032
+ class SwitchBlock {
4033
+ constructor(expression, cases, sourceSpan, startSourceSpan, endSourceSpan) {
4034
+ this.expression = expression;
4035
+ this.cases = cases;
4036
+ this.sourceSpan = sourceSpan;
4037
+ this.startSourceSpan = startSourceSpan;
4038
+ this.endSourceSpan = endSourceSpan;
4039
+ }
4040
+ visit(visitor) {
4041
+ return visitor.visitSwitchBlock(this);
4042
+ }
4043
+ }
4044
+ class SwitchBlockCase {
4045
+ constructor(expression, children, sourceSpan, startSourceSpan) {
4046
+ this.expression = expression;
4047
+ this.children = children;
4048
+ this.sourceSpan = sourceSpan;
4049
+ this.startSourceSpan = startSourceSpan;
4050
+ }
4051
+ visit(visitor) {
4052
+ return visitor.visitSwitchBlockCase(this);
4053
+ }
4054
+ }
4055
+ class ForLoopBlock {
4056
+ constructor(itemName, expression,
4057
+ // TODO(crisbeto): figure out if trackBy should be an AST
4058
+ trackBy, children, empty, sourceSpan, startSourceSpan, endSourceSpan) {
4059
+ this.itemName = itemName;
4060
+ this.expression = expression;
4061
+ this.trackBy = trackBy;
4062
+ this.children = children;
4063
+ this.empty = empty;
4064
+ this.sourceSpan = sourceSpan;
4065
+ this.startSourceSpan = startSourceSpan;
4066
+ this.endSourceSpan = endSourceSpan;
4067
+ }
4068
+ visit(visitor) {
4069
+ return visitor.visitForLoopBlock(this);
4070
+ }
4071
+ }
4072
+ class ForLoopBlockEmpty {
4073
+ constructor(children, sourceSpan, startSourceSpan) {
4074
+ this.children = children;
4075
+ this.sourceSpan = sourceSpan;
4076
+ this.startSourceSpan = startSourceSpan;
4077
+ }
4078
+ visit(visitor) {
4079
+ return visitor.visitForLoopBlockEmpty(this);
4080
+ }
4081
+ }
4082
+ class IfBlock {
4083
+ constructor(branches, sourceSpan, startSourceSpan, endSourceSpan) {
4084
+ this.branches = branches;
4085
+ this.sourceSpan = sourceSpan;
4086
+ this.startSourceSpan = startSourceSpan;
4087
+ this.endSourceSpan = endSourceSpan;
4088
+ }
4089
+ visit(visitor) {
4090
+ return visitor.visitIfBlock(this);
4091
+ }
4092
+ }
4093
+ class IfBlockBranch {
4094
+ constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan) {
4095
+ this.expression = expression;
4096
+ this.children = children;
4097
+ this.expressionAlias = expressionAlias;
4098
+ this.sourceSpan = sourceSpan;
4099
+ this.startSourceSpan = startSourceSpan;
4100
+ }
4101
+ visit(visitor) {
4102
+ return visitor.visitIfBlockBranch(this);
4103
+ }
3998
4104
  }
3999
4105
  class Template {
4000
4106
  constructor(
@@ -4084,12 +4190,7 @@ class RecursiveVisitor$1 {
4084
4190
  visitAll$1(this, template.variables);
4085
4191
  }
4086
4192
  visitDeferredBlock(deferred) {
4087
- visitAll$1(this, deferred.triggers);
4088
- visitAll$1(this, deferred.prefetchTriggers);
4089
- visitAll$1(this, deferred.children);
4090
- deferred.placeholder?.visit(this);
4091
- deferred.loading?.visit(this);
4092
- deferred.error?.visit(this);
4193
+ deferred.visitAll(this);
4093
4194
  }
4094
4195
  visitDeferredBlockPlaceholder(block) {
4095
4196
  visitAll$1(this, block.children);
@@ -4100,6 +4201,25 @@ class RecursiveVisitor$1 {
4100
4201
  visitDeferredBlockLoading(block) {
4101
4202
  visitAll$1(this, block.children);
4102
4203
  }
4204
+ visitSwitchBlock(block) {
4205
+ visitAll$1(this, block.cases);
4206
+ }
4207
+ visitSwitchBlockCase(block) {
4208
+ visitAll$1(this, block.children);
4209
+ }
4210
+ visitForLoopBlock(block) {
4211
+ visitAll$1(this, block.children);
4212
+ block.empty?.visit(this);
4213
+ }
4214
+ visitForLoopBlockEmpty(block) {
4215
+ visitAll$1(this, block.children);
4216
+ }
4217
+ visitIfBlock(block) {
4218
+ visitAll$1(this, block.branches);
4219
+ }
4220
+ visitIfBlockBranch(block) {
4221
+ visitAll$1(this, block.children);
4222
+ }
4103
4223
  visitContent(content) { }
4104
4224
  visitVariable(variable) { }
4105
4225
  visitReference(reference) { }
@@ -8615,140 +8735,6 @@ function repeatGroups(groups, multiples) {
8615
8735
  }
8616
8736
  }
8617
8737
 
8618
- var TagContentType;
8619
- (function (TagContentType) {
8620
- TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
8621
- TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
8622
- TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
8623
- })(TagContentType || (TagContentType = {}));
8624
- function splitNsName(elementName) {
8625
- if (elementName[0] != ':') {
8626
- return [null, elementName];
8627
- }
8628
- const colonIndex = elementName.indexOf(':', 1);
8629
- if (colonIndex === -1) {
8630
- throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
8631
- }
8632
- return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
8633
- }
8634
- // `<ng-container>` tags work the same regardless the namespace
8635
- function isNgContainer(tagName) {
8636
- return splitNsName(tagName)[1] === 'ng-container';
8637
- }
8638
- // `<ng-content>` tags work the same regardless the namespace
8639
- function isNgContent(tagName) {
8640
- return splitNsName(tagName)[1] === 'ng-content';
8641
- }
8642
- // `<ng-template>` tags work the same regardless the namespace
8643
- function isNgTemplate(tagName) {
8644
- return splitNsName(tagName)[1] === 'ng-template';
8645
- }
8646
- function getNsPrefix(fullName) {
8647
- return fullName === null ? null : splitNsName(fullName)[0];
8648
- }
8649
- function mergeNsAndName(prefix, localName) {
8650
- return prefix ? `:${prefix}:${localName}` : localName;
8651
- }
8652
-
8653
- /**
8654
- * Enumeration of the types of attributes which can be applied to an element.
8655
- */
8656
- var BindingKind;
8657
- (function (BindingKind) {
8658
- /**
8659
- * Static attributes.
8660
- */
8661
- BindingKind[BindingKind["Attribute"] = 0] = "Attribute";
8662
- /**
8663
- * Class bindings.
8664
- */
8665
- BindingKind[BindingKind["ClassName"] = 1] = "ClassName";
8666
- /**
8667
- * Style bindings.
8668
- */
8669
- BindingKind[BindingKind["StyleProperty"] = 2] = "StyleProperty";
8670
- /**
8671
- * Dynamic property bindings.
8672
- */
8673
- BindingKind[BindingKind["Property"] = 3] = "Property";
8674
- /**
8675
- * Property or attribute bindings on a template.
8676
- */
8677
- BindingKind[BindingKind["Template"] = 4] = "Template";
8678
- /**
8679
- * Internationalized attributes.
8680
- */
8681
- BindingKind[BindingKind["I18n"] = 5] = "I18n";
8682
- /**
8683
- * TODO: Consider how Animations are handled, and if they should be a distinct BindingKind.
8684
- */
8685
- BindingKind[BindingKind["Animation"] = 6] = "Animation";
8686
- })(BindingKind || (BindingKind = {}));
8687
- const FLYWEIGHT_ARRAY = Object.freeze([]);
8688
- /**
8689
- * Container for all of the various kinds of attributes which are applied on an element.
8690
- */
8691
- class ElementAttributes {
8692
- constructor() {
8693
- this.known = new Set();
8694
- this.byKind = new Map;
8695
- this.projectAs = null;
8696
- }
8697
- get attributes() {
8698
- return this.byKind.get(BindingKind.Attribute) ?? FLYWEIGHT_ARRAY;
8699
- }
8700
- get classes() {
8701
- return this.byKind.get(BindingKind.ClassName) ?? FLYWEIGHT_ARRAY;
8702
- }
8703
- get styles() {
8704
- return this.byKind.get(BindingKind.StyleProperty) ?? FLYWEIGHT_ARRAY;
8705
- }
8706
- get bindings() {
8707
- return this.byKind.get(BindingKind.Property) ?? FLYWEIGHT_ARRAY;
8708
- }
8709
- get template() {
8710
- return this.byKind.get(BindingKind.Template) ?? FLYWEIGHT_ARRAY;
8711
- }
8712
- get i18n() {
8713
- return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
8714
- }
8715
- add(kind, name, value) {
8716
- if (this.known.has(name)) {
8717
- return;
8718
- }
8719
- this.known.add(name);
8720
- const array = this.arrayFor(kind);
8721
- array.push(...getAttributeNameLiterals$1(name));
8722
- if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
8723
- if (value === null) {
8724
- throw Error('Attribute & style element attributes must have a value');
8725
- }
8726
- array.push(value);
8727
- }
8728
- }
8729
- arrayFor(kind) {
8730
- if (!this.byKind.has(kind)) {
8731
- this.byKind.set(kind, []);
8732
- }
8733
- return this.byKind.get(kind);
8734
- }
8735
- }
8736
- function getAttributeNameLiterals$1(name) {
8737
- const [attributeNamespace, attributeName] = splitNsName(name);
8738
- const nameLiteral = literal(attributeName);
8739
- if (attributeNamespace) {
8740
- return [
8741
- literal(0 /* core.AttributeMarker.NamespaceURI */), literal(attributeNamespace), nameLiteral
8742
- ];
8743
- }
8744
- return [nameLiteral];
8745
- }
8746
- function assertIsElementAttributes(attrs) {
8747
- if (!(attrs instanceof ElementAttributes)) {
8748
- throw new Error(`AssertionError: ElementAttributes has already been coalesced into the view constants`);
8749
- }
8750
- }
8751
-
8752
8738
  /**
8753
8739
  * Distinguishes different kinds of IR operations.
8754
8740
  *
@@ -8855,14 +8841,18 @@ var OpKind;
8855
8841
  * An operation to associate an attribute with an element.
8856
8842
  */
8857
8843
  OpKind[OpKind["Attribute"] = 23] = "Attribute";
8844
+ /**
8845
+ * An attribute that has been extracted for inclusion in the consts array.
8846
+ */
8847
+ OpKind[OpKind["ExtractedAttribute"] = 24] = "ExtractedAttribute";
8858
8848
  /**
8859
8849
  * A host binding property.
8860
8850
  */
8861
- OpKind[OpKind["HostProperty"] = 24] = "HostProperty";
8851
+ OpKind[OpKind["HostProperty"] = 25] = "HostProperty";
8862
8852
  /**
8863
8853
  * A namespace change, which causes the subsequent elements to be processed as either HTML or SVG.
8864
8854
  */
8865
- OpKind[OpKind["Namespace"] = 25] = "Namespace";
8855
+ OpKind[OpKind["Namespace"] = 26] = "Namespace";
8866
8856
  // TODO: Add Host Listeners, and possibly other host ops also.
8867
8857
  })(OpKind || (OpKind = {}));
8868
8858
  /**
@@ -8991,6 +8981,40 @@ var SanitizerFn;
8991
8981
  SanitizerFn[SanitizerFn["ResourceUrl"] = 4] = "ResourceUrl";
8992
8982
  SanitizerFn[SanitizerFn["IframeAttribute"] = 5] = "IframeAttribute";
8993
8983
  })(SanitizerFn || (SanitizerFn = {}));
8984
+ /**
8985
+ * Enumeration of the types of attributes which can be applied to an element.
8986
+ */
8987
+ var BindingKind;
8988
+ (function (BindingKind) {
8989
+ /**
8990
+ * Static attributes.
8991
+ */
8992
+ BindingKind[BindingKind["Attribute"] = 0] = "Attribute";
8993
+ /**
8994
+ * Class bindings.
8995
+ */
8996
+ BindingKind[BindingKind["ClassName"] = 1] = "ClassName";
8997
+ /**
8998
+ * Style bindings.
8999
+ */
9000
+ BindingKind[BindingKind["StyleProperty"] = 2] = "StyleProperty";
9001
+ /**
9002
+ * Dynamic property bindings.
9003
+ */
9004
+ BindingKind[BindingKind["Property"] = 3] = "Property";
9005
+ /**
9006
+ * Property or attribute bindings on a template.
9007
+ */
9008
+ BindingKind[BindingKind["Template"] = 4] = "Template";
9009
+ /**
9010
+ * Internationalized attributes.
9011
+ */
9012
+ BindingKind[BindingKind["I18n"] = 5] = "I18n";
9013
+ /**
9014
+ * Animation property bindings.
9015
+ */
9016
+ BindingKind[BindingKind["Animation"] = 6] = "Animation";
9017
+ })(BindingKind || (BindingKind = {}));
8994
9018
 
8995
9019
  /**
8996
9020
  * Marker symbol for `ConsumesSlotOpTrait`.
@@ -9133,7 +9157,7 @@ class Interpolation {
9133
9157
  /**
9134
9158
  * Create a `BindingOp`, not yet transformed into a particular type of binding.
9135
9159
  */
9136
- function createBindingOp(target, kind, name, expression, unit, securityContext, isTemplate, sourceSpan) {
9160
+ function createBindingOp(target, kind, name, expression, unit, securityContext, isTextAttribute, isTemplate, sourceSpan) {
9137
9161
  return {
9138
9162
  kind: OpKind.Binding,
9139
9163
  bindingKind: kind,
@@ -9142,6 +9166,7 @@ function createBindingOp(target, kind, name, expression, unit, securityContext,
9142
9166
  expression,
9143
9167
  unit,
9144
9168
  securityContext,
9169
+ isTextAttribute,
9145
9170
  isTemplate,
9146
9171
  sourceSpan,
9147
9172
  ...NEW_OP,
@@ -9224,7 +9249,7 @@ function createClassMapOp(xref, expression, sourceSpan) {
9224
9249
  /**
9225
9250
  * Create an `AttributeOp`.
9226
9251
  */
9227
- function createAttributeOp(target, name, expression, securityContext, isTemplate, sourceSpan) {
9252
+ function createAttributeOp(target, name, expression, securityContext, isTextAttribute, isTemplate, sourceSpan) {
9228
9253
  return {
9229
9254
  kind: OpKind.Attribute,
9230
9255
  target,
@@ -9232,6 +9257,7 @@ function createAttributeOp(target, name, expression, securityContext, isTemplate
9232
9257
  expression,
9233
9258
  securityContext,
9234
9259
  sanitizer: null,
9260
+ isTextAttribute,
9235
9261
  isTemplate,
9236
9262
  sourceSpan,
9237
9263
  ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
@@ -9861,6 +9887,10 @@ function transformExpressionsInOp(op, transform, flags) {
9861
9887
  transformExpressionsInOp(innerOp, transform, flags | VisitorContextFlag.InChildOperation);
9862
9888
  }
9863
9889
  break;
9890
+ case OpKind.ExtractedAttribute:
9891
+ op.expression =
9892
+ op.expression && transformExpressionsInExpression(op.expression, transform, flags);
9893
+ break;
9864
9894
  case OpKind.Element:
9865
9895
  case OpKind.ElementStart:
9866
9896
  case OpKind.ElementEnd:
@@ -9965,6 +9995,12 @@ function transformExpressionsInStatement(stmt, transform, flags) {
9965
9995
  throw new Error(`Unhandled statement kind: ${stmt.constructor.name}`);
9966
9996
  }
9967
9997
  }
9998
+ /**
9999
+ * Checks whether the given expression is a string literal.
10000
+ */
10001
+ function isStringLiteral(expr) {
10002
+ return expr instanceof LiteralExpr && typeof expr.value === 'string';
10003
+ }
9968
10004
 
9969
10005
  /**
9970
10006
  * A linked list of `Op` nodes of a given subtype.
@@ -10227,7 +10263,7 @@ function createElementStartOp(tag, xref, namespace, sourceSpan) {
10227
10263
  kind: OpKind.ElementStart,
10228
10264
  xref,
10229
10265
  tag,
10230
- attributes: new ElementAttributes(),
10266
+ attributes: null,
10231
10267
  localRefs: [],
10232
10268
  nonBindable: false,
10233
10269
  namespace,
@@ -10243,7 +10279,7 @@ function createTemplateOp(xref, tag, namespace, sourceSpan) {
10243
10279
  return {
10244
10280
  kind: OpKind.Template,
10245
10281
  xref,
10246
- attributes: new ElementAttributes(),
10282
+ attributes: null,
10247
10283
  tag,
10248
10284
  decls: null,
10249
10285
  vars: null,
@@ -10354,6 +10390,19 @@ function createNamespaceOp(namespace) {
10354
10390
  ...NEW_OP,
10355
10391
  };
10356
10392
  }
10393
+ /**
10394
+ * Create an `ExtractedAttributeOp`.
10395
+ */
10396
+ function createExtractedAttributeOp(target, bindingKind, name, expression) {
10397
+ return {
10398
+ kind: OpKind.ExtractedAttribute,
10399
+ target,
10400
+ bindingKind,
10401
+ name,
10402
+ expression,
10403
+ ...NEW_OP,
10404
+ };
10405
+ }
10357
10406
 
10358
10407
  function createHostPropertyOp(name, expression, sourceSpan) {
10359
10408
  return {
@@ -10663,86 +10712,7 @@ function removeAnys(e) {
10663
10712
  }
10664
10713
 
10665
10714
  /**
10666
- * Parses string representation of a style and converts it into object literal.
10667
- *
10668
- * @param value string representation of style as used in the `style` attribute in HTML.
10669
- * Example: `color: red; height: auto`.
10670
- * @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
10671
- * 'auto']`
10672
- */
10673
- function parse(value) {
10674
- // we use a string array here instead of a string map
10675
- // because a string-map is not guaranteed to retain the
10676
- // order of the entries whereas a string array can be
10677
- // constructed in a [key, value, key, value] format.
10678
- const styles = [];
10679
- let i = 0;
10680
- let parenDepth = 0;
10681
- let quote = 0 /* Char.QuoteNone */;
10682
- let valueStart = 0;
10683
- let propStart = 0;
10684
- let currentProp = null;
10685
- while (i < value.length) {
10686
- const token = value.charCodeAt(i++);
10687
- switch (token) {
10688
- case 40 /* Char.OpenParen */:
10689
- parenDepth++;
10690
- break;
10691
- case 41 /* Char.CloseParen */:
10692
- parenDepth--;
10693
- break;
10694
- case 39 /* Char.QuoteSingle */:
10695
- // valueStart needs to be there since prop values don't
10696
- // have quotes in CSS
10697
- if (quote === 0 /* Char.QuoteNone */) {
10698
- quote = 39 /* Char.QuoteSingle */;
10699
- }
10700
- else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
10701
- quote = 0 /* Char.QuoteNone */;
10702
- }
10703
- break;
10704
- case 34 /* Char.QuoteDouble */:
10705
- // same logic as above
10706
- if (quote === 0 /* Char.QuoteNone */) {
10707
- quote = 34 /* Char.QuoteDouble */;
10708
- }
10709
- else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
10710
- quote = 0 /* Char.QuoteNone */;
10711
- }
10712
- break;
10713
- case 58 /* Char.Colon */:
10714
- if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
10715
- currentProp = hyphenate$1(value.substring(propStart, i - 1).trim());
10716
- valueStart = i;
10717
- }
10718
- break;
10719
- case 59 /* Char.Semicolon */:
10720
- if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
10721
- const styleVal = value.substring(valueStart, i - 1).trim();
10722
- styles.push(currentProp, styleVal);
10723
- propStart = i;
10724
- valueStart = 0;
10725
- currentProp = null;
10726
- }
10727
- break;
10728
- }
10729
- }
10730
- if (currentProp && valueStart) {
10731
- const styleVal = value.slice(valueStart).trim();
10732
- styles.push(currentProp, styleVal);
10733
- }
10734
- return styles;
10735
- }
10736
- function hyphenate$1(value) {
10737
- return value
10738
- .replace(/[a-z][A-Z]/g, v => {
10739
- return v.charAt(0) + '-' + v.charAt(1);
10740
- })
10741
- .toLowerCase();
10742
- }
10743
-
10744
- /**
10745
- * Gets a map of all elements in the given view by their xref id.
10715
+ * Gets a map of all elements in the given view by their xref id.
10746
10716
  */
10747
10717
  function getElementsByXrefId(view) {
10748
10718
  const elements = new Map();
@@ -10756,12 +10726,39 @@ function getElementsByXrefId(view) {
10756
10726
  }
10757
10727
 
10758
10728
  /**
10759
- * Find all attribute and binding ops, and collect them into the ElementAttribute structures.
10729
+ * Find all extractable attribute and binding ops, and create ExtractedAttributeOps for them.
10760
10730
  * In cases where no instruction needs to be generated for the attribute or binding, it is removed.
10761
10731
  */
10762
10732
  function phaseAttributeExtraction(cpl) {
10763
10733
  for (const [_, view] of cpl.views) {
10764
- populateElementAttributes(view);
10734
+ const elements = getElementsByXrefId(view);
10735
+ for (const op of view.ops()) {
10736
+ switch (op.kind) {
10737
+ case OpKind.Attribute:
10738
+ extractAttributeOp(view, op, elements);
10739
+ break;
10740
+ case OpKind.Property:
10741
+ if (!op.isAnimationTrigger) {
10742
+ OpList.insertBefore(createExtractedAttributeOp(op.target, op.isTemplate ? BindingKind.Template : BindingKind.Property, op.name, null), lookupElement$2(elements, op.target));
10743
+ }
10744
+ break;
10745
+ case OpKind.StyleProp:
10746
+ case OpKind.ClassProp:
10747
+ // The old compiler treated empty style bindings as regular bindings for the purpose of
10748
+ // directive matching. That behavior is incorrect, but we emulate it in compatibility
10749
+ // mode.
10750
+ if (view.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
10751
+ op.expression instanceof EmptyExpr) {
10752
+ OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null), lookupElement$2(elements, op.target));
10753
+ }
10754
+ break;
10755
+ case OpKind.Listener:
10756
+ if (!op.isAnimationListener) {
10757
+ OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null), lookupElement$2(elements, op.target));
10758
+ }
10759
+ break;
10760
+ }
10761
+ }
10765
10762
  }
10766
10763
  }
10767
10764
  /**
@@ -10775,84 +10772,28 @@ function lookupElement$2(elements, xref) {
10775
10772
  return el;
10776
10773
  }
10777
10774
  /**
10778
- * Populates the ElementAttributes map for the given view, and removes ops for any bindings that do
10779
- * not need further processing.
10775
+ * Extracts an attribute binding.
10780
10776
  */
10781
- function populateElementAttributes(view) {
10782
- const elements = getElementsByXrefId(view);
10783
- for (const op of view.ops()) {
10784
- let ownerOp;
10785
- switch (op.kind) {
10786
- case OpKind.Attribute:
10787
- extractAttributeOp(view, op, elements);
10788
- break;
10789
- case OpKind.Property:
10790
- if (op.isAnimationTrigger) {
10791
- continue; // Don't extract animation properties.
10792
- }
10793
- ownerOp = lookupElement$2(elements, op.target);
10794
- assertIsElementAttributes(ownerOp.attributes);
10795
- ownerOp.attributes.add(op.isTemplate ? BindingKind.Template : BindingKind.Property, op.name, null);
10796
- break;
10797
- case OpKind.StyleProp:
10798
- case OpKind.ClassProp:
10799
- ownerOp = lookupElement$2(elements, op.target);
10800
- assertIsElementAttributes(ownerOp.attributes);
10801
- // Empty StyleProperty and ClassName expressions are treated differently depending on
10802
- // compatibility mode.
10803
- if (view.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
10804
- op.expression instanceof EmptyExpr) {
10805
- // The old compiler treated empty style bindings as regular bindings for the purpose of
10806
- // directive matching. That behavior is incorrect, but we emulate it in compatibility
10807
- // mode.
10808
- ownerOp.attributes.add(BindingKind.Property, op.name, null);
10809
- }
10810
- break;
10811
- case OpKind.Listener:
10812
- if (op.isAnimationListener) {
10813
- continue; // Don't extract animation listeners.
10814
- }
10815
- ownerOp = lookupElement$2(elements, op.target);
10816
- assertIsElementAttributes(ownerOp.attributes);
10817
- ownerOp.attributes.add(BindingKind.Property, op.name, null);
10818
- break;
10819
- }
10820
- }
10821
- }
10822
- function isStringLiteral(expr) {
10823
- return expr instanceof LiteralExpr && typeof expr.value === 'string';
10824
- }
10825
10777
  function extractAttributeOp(view, op, elements) {
10826
10778
  if (op.expression instanceof Interpolation) {
10827
10779
  return;
10828
10780
  }
10829
10781
  const ownerOp = lookupElement$2(elements, op.target);
10830
- assertIsElementAttributes(ownerOp.attributes);
10831
- if (op.name === 'style' && isStringLiteral(op.expression)) {
10832
- // TemplateDefinitionBuilder did not extract style attributes that had a security context.
10833
- if (view.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
10834
- op.securityContext !== SecurityContext.NONE) {
10835
- return;
10836
- }
10837
- // Extract style attributes.
10838
- const parsedStyles = parse(op.expression.value);
10839
- for (let i = 0; i < parsedStyles.length - 1; i += 2) {
10840
- ownerOp.attributes.add(BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1]));
10841
- }
10782
+ let extractable = op.expression.isConstant();
10783
+ if (view.compatibility === CompatibilityMode.TemplateDefinitionBuilder) {
10784
+ // TemplateDefinitionBuilder only extracted attributes that were string literals.
10785
+ extractable = isStringLiteral(op.expression);
10786
+ if (op.name === 'style' || op.name === 'class') {
10787
+ // For style and class attributes, TemplateDefinitionBuilder only extracted them if they were
10788
+ // text attributes. For example, `[attr.class]="'my-class'"` was not extracted despite being a
10789
+ // string literal, because it is not a text attribute.
10790
+ extractable &&= op.isTextAttribute;
10791
+ }
10792
+ }
10793
+ if (extractable) {
10794
+ OpList.insertBefore(createExtractedAttributeOp(op.target, op.isTemplate ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression), ownerOp);
10842
10795
  OpList.remove(op);
10843
10796
  }
10844
- else {
10845
- // The old compiler only extracted string constants, so we emulate that behavior in
10846
- // compaitiblity mode, otherwise we optimize more aggressively.
10847
- let extractable = view.compatibility === CompatibilityMode.TemplateDefinitionBuilder ?
10848
- (op.expression instanceof LiteralExpr && typeof op.expression.value === 'string') :
10849
- op.expression.isConstant();
10850
- // We don't need to generate instructions for attributes that can be extracted as consts.
10851
- if (extractable) {
10852
- ownerOp.attributes.add(op.isTemplate ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression);
10853
- OpList.remove(op);
10854
- }
10855
- }
10856
10797
  }
10857
10798
 
10858
10799
  /**
@@ -10888,7 +10829,7 @@ function phaseBindingSpecialization(job) {
10888
10829
  target.nonBindable = true;
10889
10830
  }
10890
10831
  else {
10891
- OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTemplate, op.sourceSpan));
10832
+ OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTextAttribute, op.isTemplate, op.sourceSpan));
10892
10833
  }
10893
10834
  break;
10894
10835
  case BindingKind.Property:
@@ -10997,30 +10938,142 @@ function chainOperationsInList(opList) {
10997
10938
  }
10998
10939
  }
10999
10940
 
10941
+ var TagContentType;
10942
+ (function (TagContentType) {
10943
+ TagContentType[TagContentType["RAW_TEXT"] = 0] = "RAW_TEXT";
10944
+ TagContentType[TagContentType["ESCAPABLE_RAW_TEXT"] = 1] = "ESCAPABLE_RAW_TEXT";
10945
+ TagContentType[TagContentType["PARSABLE_DATA"] = 2] = "PARSABLE_DATA";
10946
+ })(TagContentType || (TagContentType = {}));
10947
+ function splitNsName(elementName) {
10948
+ if (elementName[0] != ':') {
10949
+ return [null, elementName];
10950
+ }
10951
+ const colonIndex = elementName.indexOf(':', 1);
10952
+ if (colonIndex === -1) {
10953
+ throw new Error(`Unsupported format "${elementName}" expecting ":namespace:name"`);
10954
+ }
10955
+ return [elementName.slice(1, colonIndex), elementName.slice(colonIndex + 1)];
10956
+ }
10957
+ // `<ng-container>` tags work the same regardless the namespace
10958
+ function isNgContainer(tagName) {
10959
+ return splitNsName(tagName)[1] === 'ng-container';
10960
+ }
10961
+ // `<ng-content>` tags work the same regardless the namespace
10962
+ function isNgContent(tagName) {
10963
+ return splitNsName(tagName)[1] === 'ng-content';
10964
+ }
10965
+ // `<ng-template>` tags work the same regardless the namespace
10966
+ function isNgTemplate(tagName) {
10967
+ return splitNsName(tagName)[1] === 'ng-template';
10968
+ }
10969
+ function getNsPrefix(fullName) {
10970
+ return fullName === null ? null : splitNsName(fullName)[0];
10971
+ }
10972
+ function mergeNsAndName(prefix, localName) {
10973
+ return prefix ? `:${prefix}:${localName}` : localName;
10974
+ }
10975
+
11000
10976
  /**
11001
10977
  * Converts the semantic attributes of element-like operations (elements, templates) into constant
11002
10978
  * array expressions, and lifts them into the overall component `consts`.
11003
10979
  */
11004
10980
  function phaseConstCollection(cpl) {
10981
+ // Collect all extracted attributes.
10982
+ const elementAttributes = new Map();
11005
10983
  for (const [_, view] of cpl.views) {
11006
10984
  for (const op of view.create) {
11007
- if (op.kind !== OpKind.ElementStart && op.kind !== OpKind.Element &&
11008
- op.kind !== OpKind.Template) {
11009
- continue;
11010
- }
11011
- else if (!(op.attributes instanceof ElementAttributes)) {
11012
- continue;
10985
+ if (op.kind === OpKind.ExtractedAttribute) {
10986
+ const attributes = elementAttributes.get(op.target) || new ElementAttributes();
10987
+ elementAttributes.set(op.target, attributes);
10988
+ attributes.add(op.bindingKind, op.name, op.expression);
10989
+ OpList.remove(op);
11013
10990
  }
11014
- const attrArray = serializeAttributes(op.attributes);
11015
- if (attrArray.entries.length > 0) {
11016
- op.attributes = cpl.addConst(attrArray);
10991
+ }
10992
+ }
10993
+ // Serialize the extracted attributes into the const array.
10994
+ for (const [_, view] of cpl.views) {
10995
+ for (const op of view.create) {
10996
+ if (op.kind === OpKind.Element || op.kind === OpKind.ElementStart ||
10997
+ op.kind === OpKind.Template) {
10998
+ const attributes = elementAttributes.get(op.xref);
10999
+ if (attributes !== undefined) {
11000
+ const attrArray = serializeAttributes(attributes);
11001
+ if (attrArray.entries.length > 0) {
11002
+ op.attributes = cpl.addConst(attrArray);
11003
+ }
11004
+ }
11017
11005
  }
11018
- else {
11019
- op.attributes = null;
11006
+ }
11007
+ }
11008
+ }
11009
+ /**
11010
+ * Shared instance of an empty array to avoid unnecessary array allocations.
11011
+ */
11012
+ const FLYWEIGHT_ARRAY = Object.freeze([]);
11013
+ /**
11014
+ * Container for all of the various kinds of attributes which are applied on an element.
11015
+ */
11016
+ class ElementAttributes {
11017
+ constructor() {
11018
+ this.known = new Set();
11019
+ this.byKind = new Map;
11020
+ this.projectAs = null;
11021
+ }
11022
+ get attributes() {
11023
+ return this.byKind.get(BindingKind.Attribute) ?? FLYWEIGHT_ARRAY;
11024
+ }
11025
+ get classes() {
11026
+ return this.byKind.get(BindingKind.ClassName) ?? FLYWEIGHT_ARRAY;
11027
+ }
11028
+ get styles() {
11029
+ return this.byKind.get(BindingKind.StyleProperty) ?? FLYWEIGHT_ARRAY;
11030
+ }
11031
+ get bindings() {
11032
+ return this.byKind.get(BindingKind.Property) ?? FLYWEIGHT_ARRAY;
11033
+ }
11034
+ get template() {
11035
+ return this.byKind.get(BindingKind.Template) ?? FLYWEIGHT_ARRAY;
11036
+ }
11037
+ get i18n() {
11038
+ return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
11039
+ }
11040
+ add(kind, name, value) {
11041
+ if (this.known.has(name)) {
11042
+ return;
11043
+ }
11044
+ this.known.add(name);
11045
+ const array = this.arrayFor(kind);
11046
+ array.push(...getAttributeNameLiterals$1(name));
11047
+ if (kind === BindingKind.Attribute || kind === BindingKind.StyleProperty) {
11048
+ if (value === null) {
11049
+ throw Error('Attribute & style element attributes must have a value');
11020
11050
  }
11051
+ array.push(value);
11052
+ }
11053
+ }
11054
+ arrayFor(kind) {
11055
+ if (!this.byKind.has(kind)) {
11056
+ this.byKind.set(kind, []);
11021
11057
  }
11058
+ return this.byKind.get(kind);
11059
+ }
11060
+ }
11061
+ /**
11062
+ * Gets an array of literal expressions representing the attribute's namespaced name.
11063
+ */
11064
+ function getAttributeNameLiterals$1(name) {
11065
+ const [attributeNamespace, attributeName] = splitNsName(name);
11066
+ const nameLiteral = literal(attributeName);
11067
+ if (attributeNamespace) {
11068
+ return [
11069
+ literal(0 /* core.AttributeMarker.NamespaceURI */), literal(attributeNamespace), nameLiteral
11070
+ ];
11022
11071
  }
11072
+ return [nameLiteral];
11023
11073
  }
11074
+ /**
11075
+ * Serializes an ElementAttributes object into an array expression.
11076
+ */
11024
11077
  function serializeAttributes({ attributes, bindings, classes, i18n, projectAs, styles, template }) {
11025
11078
  const attrArray = [...attributes];
11026
11079
  if (projectAs !== null) {
@@ -11426,7 +11479,7 @@ function phaseHostStylePropertyParsing(job) {
11426
11479
  op.bindingKind = BindingKind.StyleProperty;
11427
11480
  op.name = op.name.substring(STYLE_DOT.length);
11428
11481
  if (isCssCustomProperty$1(op.name)) {
11429
- op.name = hyphenate(op.name);
11482
+ op.name = hyphenate$1(op.name);
11430
11483
  }
11431
11484
  const { property, suffix } = parseProperty$1(op.name);
11432
11485
  op.name = property;
@@ -11449,7 +11502,7 @@ function phaseHostStylePropertyParsing(job) {
11449
11502
  function isCssCustomProperty$1(name) {
11450
11503
  return name.startsWith('--');
11451
11504
  }
11452
- function hyphenate(value) {
11505
+ function hyphenate$1(value) {
11453
11506
  return value
11454
11507
  .replace(/[a-z][A-Z]/g, v => {
11455
11508
  return v.charAt(0) + '-' + v.charAt(1);
@@ -11524,6 +11577,85 @@ function phaseNamespace(job) {
11524
11577
  }
11525
11578
  }
11526
11579
 
11580
+ /**
11581
+ * Parses string representation of a style and converts it into object literal.
11582
+ *
11583
+ * @param value string representation of style as used in the `style` attribute in HTML.
11584
+ * Example: `color: red; height: auto`.
11585
+ * @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
11586
+ * 'auto']`
11587
+ */
11588
+ function parse(value) {
11589
+ // we use a string array here instead of a string map
11590
+ // because a string-map is not guaranteed to retain the
11591
+ // order of the entries whereas a string array can be
11592
+ // constructed in a [key, value, key, value] format.
11593
+ const styles = [];
11594
+ let i = 0;
11595
+ let parenDepth = 0;
11596
+ let quote = 0 /* Char.QuoteNone */;
11597
+ let valueStart = 0;
11598
+ let propStart = 0;
11599
+ let currentProp = null;
11600
+ while (i < value.length) {
11601
+ const token = value.charCodeAt(i++);
11602
+ switch (token) {
11603
+ case 40 /* Char.OpenParen */:
11604
+ parenDepth++;
11605
+ break;
11606
+ case 41 /* Char.CloseParen */:
11607
+ parenDepth--;
11608
+ break;
11609
+ case 39 /* Char.QuoteSingle */:
11610
+ // valueStart needs to be there since prop values don't
11611
+ // have quotes in CSS
11612
+ if (quote === 0 /* Char.QuoteNone */) {
11613
+ quote = 39 /* Char.QuoteSingle */;
11614
+ }
11615
+ else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
11616
+ quote = 0 /* Char.QuoteNone */;
11617
+ }
11618
+ break;
11619
+ case 34 /* Char.QuoteDouble */:
11620
+ // same logic as above
11621
+ if (quote === 0 /* Char.QuoteNone */) {
11622
+ quote = 34 /* Char.QuoteDouble */;
11623
+ }
11624
+ else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
11625
+ quote = 0 /* Char.QuoteNone */;
11626
+ }
11627
+ break;
11628
+ case 58 /* Char.Colon */:
11629
+ if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
11630
+ currentProp = hyphenate(value.substring(propStart, i - 1).trim());
11631
+ valueStart = i;
11632
+ }
11633
+ break;
11634
+ case 59 /* Char.Semicolon */:
11635
+ if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
11636
+ const styleVal = value.substring(valueStart, i - 1).trim();
11637
+ styles.push(currentProp, styleVal);
11638
+ propStart = i;
11639
+ valueStart = 0;
11640
+ currentProp = null;
11641
+ }
11642
+ break;
11643
+ }
11644
+ }
11645
+ if (currentProp && valueStart) {
11646
+ const styleVal = value.slice(valueStart).trim();
11647
+ styles.push(currentProp, styleVal);
11648
+ }
11649
+ return styles;
11650
+ }
11651
+ function hyphenate(value) {
11652
+ return value
11653
+ .replace(/[a-z][A-Z]/g, v => {
11654
+ return v.charAt(0) + '-' + v.charAt(1);
11655
+ })
11656
+ .toLowerCase();
11657
+ }
11658
+
11527
11659
  const BINARY_OPERATORS = new Map([
11528
11660
  ['&&', BinaryOperator.And],
11529
11661
  ['>', BinaryOperator.Bigger],
@@ -11664,7 +11796,7 @@ function getVariableName(variable, state) {
11664
11796
  * Normalizes a style prop name by hyphenating it (unless its a CSS variable).
11665
11797
  */
11666
11798
  function normalizeStylePropName(name) {
11667
- return name.startsWith('--') ? name : hyphenate$1(name);
11799
+ return name.startsWith('--') ? name : hyphenate(name);
11668
11800
  }
11669
11801
  /**
11670
11802
  * Strips `!important` out of the given style or class name.
@@ -11846,6 +11978,34 @@ function phaseNullishCoalescing(job) {
11846
11978
  }
11847
11979
  }
11848
11980
 
11981
+ /**
11982
+ * Parses extracted style and class attributes into separate ExtractedAttributeOps per style or
11983
+ * class property.
11984
+ */
11985
+ function phaseParseExtractedStyles(cpl) {
11986
+ for (const [_, view] of cpl.views) {
11987
+ for (const op of view.create) {
11988
+ if (op.kind === OpKind.ExtractedAttribute && op.bindingKind === BindingKind.Attribute &&
11989
+ isStringLiteral(op.expression)) {
11990
+ if (op.name === 'style') {
11991
+ const parsedStyles = parse(op.expression.value);
11992
+ for (let i = 0; i < parsedStyles.length - 1; i += 2) {
11993
+ OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1])), op);
11994
+ }
11995
+ OpList.remove(op);
11996
+ }
11997
+ else if (op.name === 'class') {
11998
+ const parsedClasses = op.expression.value.trim().split(/\s+/g);
11999
+ for (const parsedClass of parsedClasses) {
12000
+ OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null), op);
12001
+ }
12002
+ OpList.remove(op);
12003
+ }
12004
+ }
12005
+ }
12006
+ }
12007
+ }
12008
+
11849
12009
  function phasePipeCreation(cpl) {
11850
12010
  for (const view of cpl.views.values()) {
11851
12011
  processPipeBindingsInView(view);
@@ -13593,6 +13753,7 @@ function transformTemplate(job) {
13593
13753
  phaseStyleBindingSpecialization(job);
13594
13754
  phaseBindingSpecialization(job);
13595
13755
  phaseAttributeExtraction(job);
13756
+ phaseParseExtractedStyles(job);
13596
13757
  phaseRemoveEmptyBindings(job);
13597
13758
  phaseNoListenersOnTemplates(job);
13598
13759
  phasePipeCreation(job);
@@ -13760,7 +13921,7 @@ function ingestComponent(componentName, template, constantPool) {
13760
13921
  function ingestHostBinding(input, bindingParser, constantPool) {
13761
13922
  const job = new HostBindingCompilationJob(input.componentName, constantPool, compatibilityMode);
13762
13923
  for (const property of input.properties ?? []) {
13763
- ingestHostProperty(job, property);
13924
+ ingestHostProperty(job, property, false);
13764
13925
  }
13765
13926
  for (const event of input.events ?? []) {
13766
13927
  ingestHostEvent(job, event);
@@ -13769,7 +13930,7 @@ function ingestHostBinding(input, bindingParser, constantPool) {
13769
13930
  }
13770
13931
  // TODO: We should refactor the parser to use the same types and structures for host bindings as
13771
13932
  // with ordinary components. This would allow us to share a lot more ingestion code.
13772
- function ingestHostProperty(job, property) {
13933
+ function ingestHostProperty(job, property, isTextAttribute) {
13773
13934
  let expression;
13774
13935
  const ast = property.expression.ast;
13775
13936
  if (ast instanceof Interpolation$1) {
@@ -13786,7 +13947,7 @@ function ingestHostProperty(job, property) {
13786
13947
  bindingKind = BindingKind.Attribute;
13787
13948
  }
13788
13949
  job.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, SecurityContext
13789
- .NONE /* TODO: what should we pass as security context? Passing NONE for now. */, false, property.sourceSpan));
13950
+ .NONE /* TODO: what should we pass as security context? Passing NONE for now. */, isTextAttribute, false, property.sourceSpan));
13790
13951
  }
13791
13952
  function ingestHostEvent(job, event) { }
13792
13953
  /**
@@ -13964,10 +14125,10 @@ function ingestBindings(view, op, element) {
13964
14125
  if (element instanceof Template) {
13965
14126
  for (const attr of element.templateAttrs) {
13966
14127
  if (attr instanceof TextAttribute) {
13967
- ingestBinding(view, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, true);
14128
+ ingestBinding(view, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, true, true);
13968
14129
  }
13969
14130
  else {
13970
- ingestBinding(view, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, true);
14131
+ ingestBinding(view, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, false, true);
13971
14132
  }
13972
14133
  }
13973
14134
  }
@@ -13975,10 +14136,10 @@ function ingestBindings(view, op, element) {
13975
14136
  // This is only attribute TextLiteral bindings, such as `attr.foo="bar"`. This can never be
13976
14137
  // `[attr.foo]="bar"` or `attr.foo="{{bar}}"`, both of which will be handled as inputs with
13977
14138
  // `BindingType.Attribute`.
13978
- ingestBinding(view, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, false);
14139
+ ingestBinding(view, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, true, false);
13979
14140
  }
13980
14141
  for (const input of element.inputs) {
13981
- ingestBinding(view, op.xref, input.name, input.value, input.type, input.unit, input.securityContext, input.sourceSpan, false);
14142
+ ingestBinding(view, op.xref, input.name, input.value, input.type, input.unit, input.securityContext, input.sourceSpan, false, false);
13982
14143
  }
13983
14144
  for (const output of element.outputs) {
13984
14145
  let listenerOp;
@@ -14024,7 +14185,7 @@ const BINDING_KINDS = new Map([
14024
14185
  [3 /* e.BindingType.Style */, BindingKind.StyleProperty],
14025
14186
  [4 /* e.BindingType.Animation */, BindingKind.Animation],
14026
14187
  ]);
14027
- function ingestBinding(view, xref, name, value, type, unit, securityContext, sourceSpan, isTemplateBinding) {
14188
+ function ingestBinding(view, xref, name, value, type, unit, securityContext, sourceSpan, isTextAttribute, isTemplateBinding) {
14028
14189
  if (value instanceof ASTWithSource) {
14029
14190
  value = value.ast;
14030
14191
  }
@@ -14039,7 +14200,7 @@ function ingestBinding(view, xref, name, value, type, unit, securityContext, sou
14039
14200
  expression = value;
14040
14201
  }
14041
14202
  const kind = BINDING_KINDS.get(type);
14042
- view.update.push(createBindingOp(xref, kind, name, expression, unit, securityContext, isTemplateBinding, sourceSpan));
14203
+ view.update.push(createBindingOp(xref, kind, name, expression, unit, securityContext, isTextAttribute, isTemplateBinding, sourceSpan));
14043
14204
  }
14044
14205
  /**
14045
14206
  * Process all of the local references on an element-like structure in the template AST and
@@ -14234,7 +14395,7 @@ class StylingBuilder {
14234
14395
  // CSS custom properties are case-sensitive so we shouldn't normalize them.
14235
14396
  // See: https://www.w3.org/TR/css-variables-1/#defining-variables
14236
14397
  if (!isCssCustomProperty(name)) {
14237
- name = hyphenate$1(name);
14398
+ name = hyphenate(name);
14238
14399
  }
14239
14400
  const { property, hasOverrideFlag, suffix: bindingSuffix } = parseProperty(name);
14240
14401
  suffix = typeof suffix === 'string' && suffix.length !== 0 ? suffix : bindingSuffix;
@@ -21301,6 +21462,285 @@ function normalizeNgContentSelect(selectAttr) {
21301
21462
  return selectAttr;
21302
21463
  }
21303
21464
 
21465
+ /** Pattern for the expression in a for loop block. */
21466
+ const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+(.*)/;
21467
+ /** Pattern for the tracking expression in a for loop block. */
21468
+ const FOR_LOOP_TRACK_PATTERN = /^track\s+(.*)/;
21469
+ /** Pattern for the `as` expression in a conditional block. */
21470
+ const CONDITIONAL_ALIAS_PATTERN = /^as\s+(.*)/;
21471
+ /** Pattern used to identify an `else if` block. */
21472
+ const ELSE_IF_PATTERN = /^if\s/;
21473
+ /** Creates an `if` loop block from an HTML AST node. */
21474
+ function createIfBlock(ast, visitor, bindingParser) {
21475
+ const errors = validateIfBlock(ast);
21476
+ const branches = [];
21477
+ if (errors.length > 0) {
21478
+ return { node: null, errors };
21479
+ }
21480
+ // Assumes that the structure is valid since we validated it above.
21481
+ for (const block of ast.blocks) {
21482
+ const children = visitAll(visitor, block.children);
21483
+ // `{:else}` block.
21484
+ if (block.name === 'else' && block.parameters.length === 0) {
21485
+ branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan));
21486
+ continue;
21487
+ }
21488
+ // Expressions for `{:else if}` blocks start at 2 to skip the `if` from the expression.
21489
+ const expressionStart = block.name === 'if' ? 0 : 2;
21490
+ const params = parseConditionalBlockParameters(block, errors, bindingParser, expressionStart);
21491
+ if (params !== null) {
21492
+ branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan));
21493
+ }
21494
+ }
21495
+ return {
21496
+ node: new IfBlock(branches, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
21497
+ errors,
21498
+ };
21499
+ }
21500
+ /** Creates a `for` loop block from an HTML AST node. */
21501
+ function createForLoop(ast, visitor, bindingParser) {
21502
+ const [primaryBlock, ...secondaryBlocks] = ast.blocks;
21503
+ const errors = [];
21504
+ const params = parseForLoopParameters(primaryBlock, errors, bindingParser);
21505
+ let node = null;
21506
+ let empty = null;
21507
+ for (const block of secondaryBlocks) {
21508
+ if (block.name === 'empty') {
21509
+ if (empty !== null) {
21510
+ errors.push(new ParseError(block.sourceSpan, 'For loop can only have one "empty" block'));
21511
+ }
21512
+ else if (block.parameters.length > 0) {
21513
+ errors.push(new ParseError(block.sourceSpan, 'Empty block cannot have parameters'));
21514
+ }
21515
+ else {
21516
+ empty = new ForLoopBlockEmpty(visitAll(visitor, block.children), block.sourceSpan, block.startSourceSpan);
21517
+ }
21518
+ }
21519
+ else {
21520
+ errors.push(new ParseError(block.sourceSpan, `Unrecognized loop block "${block.name}"`));
21521
+ }
21522
+ }
21523
+ if (params !== null) {
21524
+ if (params.trackBy === null) {
21525
+ errors.push(new ParseError(ast.sourceSpan, 'For loop must have a "track" expression'));
21526
+ }
21527
+ else {
21528
+ node = new ForLoopBlock(params.itemName, params.expression, params.trackBy, visitAll(visitor, primaryBlock.children), empty, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
21529
+ }
21530
+ }
21531
+ return { node, errors };
21532
+ }
21533
+ /** Creates a switch block from an HTML AST node. */
21534
+ function createSwitchBlock(ast, visitor, bindingParser) {
21535
+ const [primaryBlock, ...secondaryBlocks] = ast.blocks;
21536
+ const errors = validateSwitchBlock(ast);
21537
+ if (errors.length > 0) {
21538
+ return { node: null, errors };
21539
+ }
21540
+ const primaryExpression = parseBlockParameterToBinding(primaryBlock.parameters[0], bindingParser);
21541
+ const cases = [];
21542
+ let defaultCase = null;
21543
+ // Here we assume that all the blocks are valid given that we validated them above.
21544
+ for (const block of secondaryBlocks) {
21545
+ const expression = block.name === 'case' ?
21546
+ parseBlockParameterToBinding(block.parameters[0], bindingParser) :
21547
+ null;
21548
+ const ast = new SwitchBlockCase(expression, visitAll(visitor, block.children), block.sourceSpan, block.startSourceSpan);
21549
+ if (expression === null) {
21550
+ defaultCase = ast;
21551
+ }
21552
+ else {
21553
+ cases.push(ast);
21554
+ }
21555
+ }
21556
+ // Ensure that the default case is last in the array.
21557
+ if (defaultCase !== null) {
21558
+ cases.push(defaultCase);
21559
+ }
21560
+ return {
21561
+ node: new SwitchBlock(primaryExpression, cases, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
21562
+ errors
21563
+ };
21564
+ }
21565
+ /** Parses the parameters of a `for` loop block. */
21566
+ function parseForLoopParameters(block, errors, bindingParser) {
21567
+ if (block.parameters.length === 0) {
21568
+ errors.push(new ParseError(block.sourceSpan, 'For loop does not have an expression'));
21569
+ return null;
21570
+ }
21571
+ const [expressionParam, ...secondaryParams] = block.parameters;
21572
+ const match = stripOptionalParentheses(expressionParam, errors)?.match(FOR_LOOP_EXPRESSION_PATTERN);
21573
+ if (!match || match[2].trim().length === 0) {
21574
+ errors.push(new ParseError(expressionParam.sourceSpan, 'Cannot parse expression. For loop expression must match the pattern "<identifier> of <expression>"'));
21575
+ return null;
21576
+ }
21577
+ const [, itemName, rawExpression] = match;
21578
+ const result = {
21579
+ itemName,
21580
+ trackBy: null,
21581
+ expression: bindingParser.parseBinding(rawExpression, false, expressionParam.sourceSpan,
21582
+ // Note: `lastIndexOf` here should be enough to know the start index of the expression,
21583
+ // because we know that it'll be the last matching group. Ideally we could use the `d`
21584
+ // flag on the regex and get the index from `match.indices`, but it's unclear if we can
21585
+ // use it yet since it's a relatively new feature. See:
21586
+ // https://github.com/tc39/proposal-regexp-match-indices
21587
+ Math.max(0, expressionParam.expression.lastIndexOf(rawExpression)))
21588
+ };
21589
+ for (const param of secondaryParams) {
21590
+ const trackMatch = param.expression.match(FOR_LOOP_TRACK_PATTERN);
21591
+ // For now loops can only have a `track` parameter.
21592
+ // We may want to rework this later if we add more.
21593
+ if (trackMatch === null) {
21594
+ errors.push(new ParseError(param.sourceSpan, `Unrecognized loop paramater "${param.expression}"`));
21595
+ }
21596
+ else if (result.trackBy !== null) {
21597
+ errors.push(new ParseError(param.sourceSpan, 'For loop can only have one "track" expression'));
21598
+ }
21599
+ else {
21600
+ result.trackBy = trackMatch[1].trim();
21601
+ }
21602
+ }
21603
+ return result;
21604
+ }
21605
+ /** Checks that the shape of a `if` block is valid. Returns an array of errors. */
21606
+ function validateIfBlock(ast) {
21607
+ const errors = [];
21608
+ let hasElse = false;
21609
+ for (let i = 0; i < ast.blocks.length; i++) {
21610
+ const block = ast.blocks[i];
21611
+ // Conditional blocks only allow `if`, `else if` and `else` blocks.
21612
+ if ((block.name !== 'if' || i > 0) && block.name !== 'else') {
21613
+ errors.push(new ParseError(block.sourceSpan, `Unrecognized conditional block "${block.name}"`));
21614
+ continue;
21615
+ }
21616
+ if (block.name === 'if') {
21617
+ continue;
21618
+ }
21619
+ if (block.parameters.length === 0) {
21620
+ if (hasElse) {
21621
+ errors.push(new ParseError(block.sourceSpan, 'Conditional can only have one "else" block'));
21622
+ }
21623
+ else if (ast.blocks.length > 1 && i < ast.blocks.length - 1) {
21624
+ errors.push(new ParseError(block.sourceSpan, 'Else block must be last inside the conditional'));
21625
+ }
21626
+ hasElse = true;
21627
+ // `else if` is an edge case, because it has a space after the block name
21628
+ // which means that the `if` is captured as a part of the parameters.
21629
+ }
21630
+ else if (block.parameters.length > 0 && !ELSE_IF_PATTERN.test(block.parameters[0].expression)) {
21631
+ errors.push(new ParseError(block.sourceSpan, 'Else block cannot have parameters'));
21632
+ }
21633
+ }
21634
+ return errors;
21635
+ }
21636
+ /** Checks that the shape of a `switch` block is valid. Returns an array of errors. */
21637
+ function validateSwitchBlock(ast) {
21638
+ const [primaryBlock, ...secondaryBlocks] = ast.blocks;
21639
+ const errors = [];
21640
+ let hasDefault = false;
21641
+ if (primaryBlock.children.length > 0) {
21642
+ errors.push(new ParseError(primaryBlock.sourceSpan, 'Switch block can only contain "case" and "default" blocks'));
21643
+ }
21644
+ if (primaryBlock.parameters.length !== 1) {
21645
+ errors.push(new ParseError(primaryBlock.sourceSpan, 'Switch block must have exactly one parameter'));
21646
+ }
21647
+ for (const block of secondaryBlocks) {
21648
+ if (block.name === 'case') {
21649
+ if (block.parameters.length !== 1) {
21650
+ errors.push(new ParseError(block.sourceSpan, 'Case block must have exactly one parameter'));
21651
+ }
21652
+ }
21653
+ else if (block.name === 'default') {
21654
+ if (hasDefault) {
21655
+ errors.push(new ParseError(block.sourceSpan, 'Switch block can only have one "default" block'));
21656
+ }
21657
+ else if (block.parameters.length > 0) {
21658
+ errors.push(new ParseError(block.sourceSpan, 'Default block cannot have parameters'));
21659
+ }
21660
+ hasDefault = true;
21661
+ }
21662
+ else {
21663
+ errors.push(new ParseError(block.sourceSpan, 'Switch block can only contain "case" and "default" blocks'));
21664
+ }
21665
+ }
21666
+ return errors;
21667
+ }
21668
+ /** Parses a block parameter into a binding AST. */
21669
+ function parseBlockParameterToBinding(ast, bindingParser, start = 0) {
21670
+ return bindingParser.parseBinding(ast.expression.slice(start), false, ast.sourceSpan, ast.sourceSpan.start.offset + start);
21671
+ }
21672
+ /** Parses the parameter of a conditional block (`if` or `else if`). */
21673
+ function parseConditionalBlockParameters(block, errors, bindingParser, primaryExpressionStart) {
21674
+ if (block.parameters.length === 0) {
21675
+ errors.push(new ParseError(block.sourceSpan, 'Conditional block does not have an expression'));
21676
+ return null;
21677
+ }
21678
+ const expression = parseBlockParameterToBinding(block.parameters[0], bindingParser, primaryExpressionStart);
21679
+ let expressionAlias = null;
21680
+ // Start from 1 since we processed the first parameter already.
21681
+ for (let i = 1; i < block.parameters.length; i++) {
21682
+ const param = block.parameters[i];
21683
+ const aliasMatch = param.expression.match(CONDITIONAL_ALIAS_PATTERN);
21684
+ // For now conditionals can only have an `as` parameter.
21685
+ // We may want to rework this later if we add more.
21686
+ if (aliasMatch === null) {
21687
+ errors.push(new ParseError(param.sourceSpan, `Unrecognized conditional paramater "${param.expression}"`));
21688
+ }
21689
+ else if (expressionAlias !== null) {
21690
+ errors.push(new ParseError(param.sourceSpan, 'Conditional can only have one "as" expression'));
21691
+ }
21692
+ else {
21693
+ expressionAlias = aliasMatch[1].trim();
21694
+ }
21695
+ }
21696
+ return { expression, expressionAlias };
21697
+ }
21698
+ /** Strips optional parentheses around from a control from expression parameter. */
21699
+ function stripOptionalParentheses(param, errors) {
21700
+ const expression = param.expression;
21701
+ const spaceRegex = /^\s$/;
21702
+ let openParens = 0;
21703
+ let start = 0;
21704
+ let end = expression.length - 1;
21705
+ for (let i = 0; i < expression.length; i++) {
21706
+ const char = expression[i];
21707
+ if (char === '(') {
21708
+ start = i + 1;
21709
+ openParens++;
21710
+ }
21711
+ else if (spaceRegex.test(char)) {
21712
+ continue;
21713
+ }
21714
+ else {
21715
+ break;
21716
+ }
21717
+ }
21718
+ if (openParens === 0) {
21719
+ return expression;
21720
+ }
21721
+ for (let i = expression.length - 1; i > -1; i--) {
21722
+ const char = expression[i];
21723
+ if (char === ')') {
21724
+ end = i;
21725
+ openParens--;
21726
+ if (openParens === 0) {
21727
+ break;
21728
+ }
21729
+ }
21730
+ else if (spaceRegex.test(char)) {
21731
+ continue;
21732
+ }
21733
+ else {
21734
+ break;
21735
+ }
21736
+ }
21737
+ if (openParens !== 0) {
21738
+ errors.push(new ParseError(param.sourceSpan, 'Unclosed parentheses in expression'));
21739
+ return null;
21740
+ }
21741
+ return expression.slice(start, end);
21742
+ }
21743
+
21304
21744
  /** Pattern for a timing value in a trigger. */
21305
21745
  const TIME_PATTERN = /^\d+(ms|s)?$/;
21306
21746
  /** Pattern for a separator between keywords in a trigger expression. */
@@ -21322,38 +21762,41 @@ var OnTriggerType;
21322
21762
  OnTriggerType["VIEWPORT"] = "viewport";
21323
21763
  })(OnTriggerType || (OnTriggerType = {}));
21324
21764
  /** Parses a `when` deferred trigger. */
21325
- function parseWhenTrigger({ expression, sourceSpan }, bindingParser, errors) {
21765
+ function parseWhenTrigger({ expression, sourceSpan }, bindingParser, triggers, errors) {
21326
21766
  const whenIndex = expression.indexOf('when');
21327
21767
  // This is here just to be safe, we shouldn't enter this function
21328
21768
  // in the first place if a block doesn't have the "when" keyword.
21329
21769
  if (whenIndex === -1) {
21330
21770
  errors.push(new ParseError(sourceSpan, `Could not find "when" keyword in expression`));
21331
- return null;
21332
21771
  }
21333
- const start = getTriggerParametersStart(expression, whenIndex + 1);
21334
- const parsed = bindingParser.parseBinding(expression.slice(start), false, sourceSpan, sourceSpan.start.offset + start);
21335
- return new BoundDeferredTrigger(parsed, sourceSpan);
21772
+ else {
21773
+ const start = getTriggerParametersStart(expression, whenIndex + 1);
21774
+ const parsed = bindingParser.parseBinding(expression.slice(start), false, sourceSpan, sourceSpan.start.offset + start);
21775
+ trackTrigger('when', triggers, errors, new BoundDeferredTrigger(parsed, sourceSpan));
21776
+ }
21336
21777
  }
21337
21778
  /** Parses an `on` trigger */
21338
- function parseOnTrigger({ expression, sourceSpan }, errors) {
21779
+ function parseOnTrigger({ expression, sourceSpan }, triggers, errors) {
21339
21780
  const onIndex = expression.indexOf('on');
21340
21781
  // This is here just to be safe, we shouldn't enter this function
21341
21782
  // in the first place if a block doesn't have the "on" keyword.
21342
21783
  if (onIndex === -1) {
21343
21784
  errors.push(new ParseError(sourceSpan, `Could not find "on" keyword in expression`));
21344
- return [];
21345
21785
  }
21346
- const start = getTriggerParametersStart(expression, onIndex + 1);
21347
- return new OnTriggerParser(expression, start, sourceSpan, errors).parse();
21786
+ else {
21787
+ const start = getTriggerParametersStart(expression, onIndex + 1);
21788
+ const parser = new OnTriggerParser(expression, start, sourceSpan, triggers, errors);
21789
+ parser.parse();
21790
+ }
21348
21791
  }
21349
21792
  class OnTriggerParser {
21350
- constructor(expression, start, span, errors) {
21793
+ constructor(expression, start, span, triggers, errors) {
21351
21794
  this.expression = expression;
21352
21795
  this.start = start;
21353
21796
  this.span = span;
21797
+ this.triggers = triggers;
21354
21798
  this.errors = errors;
21355
21799
  this.index = 0;
21356
- this.triggers = [];
21357
21800
  this.tokens = new Lexer().tokenize(expression.slice(start));
21358
21801
  }
21359
21802
  parse() {
@@ -21384,7 +21827,6 @@ class OnTriggerParser {
21384
21827
  }
21385
21828
  this.advance();
21386
21829
  }
21387
- return this.triggers;
21388
21830
  }
21389
21831
  advance() {
21390
21832
  this.index++;
@@ -21405,22 +21847,22 @@ class OnTriggerParser {
21405
21847
  try {
21406
21848
  switch (identifier.toString()) {
21407
21849
  case OnTriggerType.IDLE:
21408
- this.triggers.push(createIdleTrigger(parameters, sourceSpan));
21850
+ this.trackTrigger('idle', createIdleTrigger(parameters, sourceSpan));
21409
21851
  break;
21410
21852
  case OnTriggerType.TIMER:
21411
- this.triggers.push(createTimerTrigger(parameters, sourceSpan));
21853
+ this.trackTrigger('timer', createTimerTrigger(parameters, sourceSpan));
21412
21854
  break;
21413
21855
  case OnTriggerType.INTERACTION:
21414
- this.triggers.push(createInteractionTrigger(parameters, sourceSpan));
21856
+ this.trackTrigger('interaction', createInteractionTrigger(parameters, sourceSpan));
21415
21857
  break;
21416
21858
  case OnTriggerType.IMMEDIATE:
21417
- this.triggers.push(createImmediateTrigger(parameters, sourceSpan));
21859
+ this.trackTrigger('immediate', createImmediateTrigger(parameters, sourceSpan));
21418
21860
  break;
21419
21861
  case OnTriggerType.HOVER:
21420
- this.triggers.push(createHoverTrigger(parameters, sourceSpan));
21862
+ this.trackTrigger('hover', createHoverTrigger(parameters, sourceSpan));
21421
21863
  break;
21422
21864
  case OnTriggerType.VIEWPORT:
21423
- this.triggers.push(createViewportTrigger(parameters, sourceSpan));
21865
+ this.trackTrigger('viewport', createViewportTrigger(parameters, sourceSpan));
21424
21866
  break;
21425
21867
  default:
21426
21868
  throw new Error(`Unrecognized trigger type "${identifier}"`);
@@ -21489,6 +21931,9 @@ class OnTriggerParser {
21489
21931
  // Eventually we could expose this information on the token directly.
21490
21932
  return this.expression.slice(this.start + this.token().index, this.start + this.token().end);
21491
21933
  }
21934
+ trackTrigger(name, trigger) {
21935
+ trackTrigger(name, this.triggers, this.errors, trigger);
21936
+ }
21492
21937
  error(token, message) {
21493
21938
  const newStart = this.span.start.moveBy(this.start + token.index);
21494
21939
  const newEnd = newStart.moveBy(token.end - token.index);
@@ -21498,6 +21943,15 @@ class OnTriggerParser {
21498
21943
  this.error(token, `Unexpected token "${token}"`);
21499
21944
  }
21500
21945
  }
21946
+ /** Adds a trigger to a map of triggers. */
21947
+ function trackTrigger(name, allTriggers, errors, trigger) {
21948
+ if (allTriggers[name]) {
21949
+ errors.push(new ParseError(trigger.sourceSpan, `Duplicate "${name}" trigger is not allowed`));
21950
+ }
21951
+ else {
21952
+ allTriggers[name] = trigger;
21953
+ }
21954
+ }
21501
21955
  function createIdleTrigger(parameters, sourceSpan) {
21502
21956
  if (parameters.length > 0) {
21503
21957
  throw new Error(`"${OnTriggerType.IDLE}" trigger cannot have parameters`);
@@ -21641,6 +22095,9 @@ function parsePlaceholderBlock(ast, visitor) {
21641
22095
  let minimumTime = null;
21642
22096
  for (const param of ast.parameters) {
21643
22097
  if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
22098
+ if (minimumTime != null) {
22099
+ throw new Error(`Placeholder block can only have one "minimum" parameter`);
22100
+ }
21644
22101
  const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
21645
22102
  if (parsedTime === null) {
21646
22103
  throw new Error(`Could not parse time value of parameter "minimum"`);
@@ -21658,6 +22115,9 @@ function parseLoadingBlock(ast, visitor) {
21658
22115
  let minimumTime = null;
21659
22116
  for (const param of ast.parameters) {
21660
22117
  if (AFTER_PARAMETER_PATTERN.test(param.expression)) {
22118
+ if (afterTime != null) {
22119
+ throw new Error(`Loading block can only have one "after" parameter`);
22120
+ }
21661
22121
  const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
21662
22122
  if (parsedTime === null) {
21663
22123
  throw new Error(`Could not parse time value of parameter "after"`);
@@ -21665,6 +22125,9 @@ function parseLoadingBlock(ast, visitor) {
21665
22125
  afterTime = parsedTime;
21666
22126
  }
21667
22127
  else if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
22128
+ if (minimumTime != null) {
22129
+ throw new Error(`Loading block can only have one "minimum" parameter`);
22130
+ }
21668
22131
  const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
21669
22132
  if (parsedTime === null) {
21670
22133
  throw new Error(`Could not parse time value of parameter "minimum"`);
@@ -21684,24 +22147,22 @@ function parseErrorBlock(ast, visitor) {
21684
22147
  return new DeferredBlockError(visitAll(visitor, ast.children), ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
21685
22148
  }
21686
22149
  function parsePrimaryTriggers(params, bindingParser, errors) {
21687
- const triggers = [];
21688
- const prefetchTriggers = [];
22150
+ const triggers = {};
22151
+ const prefetchTriggers = {};
21689
22152
  for (const param of params) {
21690
22153
  // The lexer ignores the leading spaces so we can assume
21691
22154
  // that the expression starts with a keyword.
21692
22155
  if (WHEN_PARAMETER_PATTERN.test(param.expression)) {
21693
- const result = parseWhenTrigger(param, bindingParser, errors);
21694
- result !== null && triggers.push(result);
22156
+ parseWhenTrigger(param, bindingParser, triggers, errors);
21695
22157
  }
21696
22158
  else if (ON_PARAMETER_PATTERN.test(param.expression)) {
21697
- triggers.push(...parseOnTrigger(param, errors));
22159
+ parseOnTrigger(param, triggers, errors);
21698
22160
  }
21699
22161
  else if (PREFETCH_WHEN_PATTERN.test(param.expression)) {
21700
- const result = parseWhenTrigger(param, bindingParser, errors);
21701
- result !== null && prefetchTriggers.push(result);
22162
+ parseWhenTrigger(param, bindingParser, prefetchTriggers, errors);
21702
22163
  }
21703
22164
  else if (PREFETCH_ON_PATTERN.test(param.expression)) {
21704
- prefetchTriggers.push(...parseOnTrigger(param, errors));
22165
+ parseOnTrigger(param, prefetchTriggers, errors);
21705
22166
  }
21706
22167
  else {
21707
22168
  errors.push(new ParseError(param.sourceSpan, 'Unrecognized trigger'));
@@ -21947,13 +22408,33 @@ class HtmlAstToIvyAst {
21947
22408
  this.reportError('Block group must have at least one block.', group.sourceSpan);
21948
22409
  return null;
21949
22410
  }
21950
- if (primaryBlock.name === 'defer' && this.options.enabledBlockTypes.has(primaryBlock.name)) {
21951
- const { node, errors } = createDeferredBlock(group, this, this.bindingParser);
21952
- this.errors.push(...errors);
21953
- return node;
22411
+ if (!this.options.enabledBlockTypes.has(primaryBlock.name)) {
22412
+ this.reportError(`Unrecognized block "${primaryBlock.name}".`, primaryBlock.sourceSpan);
22413
+ return null;
21954
22414
  }
21955
- this.reportError(`Unrecognized block "${primaryBlock.name}".`, primaryBlock.sourceSpan);
21956
- return null;
22415
+ let result = null;
22416
+ switch (primaryBlock.name) {
22417
+ case 'defer':
22418
+ result = createDeferredBlock(group, this, this.bindingParser);
22419
+ break;
22420
+ case 'switch':
22421
+ result = createSwitchBlock(group, this, this.bindingParser);
22422
+ break;
22423
+ case 'for':
22424
+ result = createForLoop(group, this, this.bindingParser);
22425
+ break;
22426
+ case 'if':
22427
+ result = createIfBlock(group, this, this.bindingParser);
22428
+ break;
22429
+ default:
22430
+ result = {
22431
+ node: null,
22432
+ errors: [new ParseError(primaryBlock.sourceSpan, `Unrecognized block "${primaryBlock.name}".`)]
22433
+ };
22434
+ break;
22435
+ }
22436
+ this.errors.push(...result.errors);
22437
+ return result.node;
21957
22438
  }
21958
22439
  visitBlock(block, context) { }
21959
22440
  visitBlockParameter(parameter, context) { }
@@ -23308,6 +23789,10 @@ class TemplateDefinitionBuilder {
23308
23789
  this.visitTextAttribute = invalid;
23309
23790
  this.visitBoundAttribute = invalid;
23310
23791
  this.visitBoundEvent = invalid;
23792
+ this.visitDeferredTrigger = invalid;
23793
+ this.visitDeferredBlockError = invalid;
23794
+ this.visitDeferredBlockLoading = invalid;
23795
+ this.visitDeferredBlockPlaceholder = invalid;
23311
23796
  this._bindingScope = parentBindingScope.nestedScope(level);
23312
23797
  // Turn the relative context file path into an identifier by replacing non-alphanumeric
23313
23798
  // characters with underscores.
@@ -23864,28 +24349,22 @@ class TemplateDefinitionBuilder {
23864
24349
  this.creationInstruction(span, isNgContainer$1 ? Identifiers.elementContainerEnd : Identifiers.elementEnd);
23865
24350
  }
23866
24351
  }
23867
- visitTemplate(template) {
23868
- const NG_TEMPLATE_TAG_NAME = 'ng-template';
24352
+ createEmbeddedTemplateFn(tagName, children, contextNameSuffix, sourceSpan, variables = [], attrsExprs, references, i18n) {
23869
24353
  const templateIndex = this.allocateDataSlot();
23870
- if (this.i18n) {
23871
- this.i18n.appendTemplate(template.i18n, templateIndex);
24354
+ if (this.i18n && i18n) {
24355
+ this.i18n.appendTemplate(i18n, templateIndex);
23872
24356
  }
23873
- const tagNameWithoutNamespace = template.tagName ? splitNsName(template.tagName)[1] : template.tagName;
23874
- const contextName = `${this.contextName}${template.tagName ? '_' + sanitizeIdentifier(template.tagName) : ''}_${templateIndex}`;
24357
+ const contextName = `${this.contextName}${contextNameSuffix}_${templateIndex}`;
23875
24358
  const templateName = `${contextName}_Template`;
23876
24359
  const parameters = [
23877
24360
  literal(templateIndex),
23878
24361
  variable(templateName),
23879
- // We don't care about the tag's namespace here, because we infer
23880
- // it based on the parent nodes inside the template instruction.
23881
- literal(tagNameWithoutNamespace),
24362
+ literal(tagName),
24363
+ this.addAttrsToConsts(attrsExprs || null),
23882
24364
  ];
23883
- // prepare attributes parameter (including attributes used for directive matching)
23884
- const attrsExprs = this.getAttributeExpressions(NG_TEMPLATE_TAG_NAME, template.attributes, template.inputs, template.outputs, undefined /* styles */, template.templateAttrs);
23885
- parameters.push(this.addAttrsToConsts(attrsExprs));
23886
24365
  // local refs (ex.: <ng-template #foo>)
23887
- if (template.references && template.references.length) {
23888
- const refs = this.prepareRefsArray(template.references);
24366
+ if (references && references.length > 0) {
24367
+ const refs = this.prepareRefsArray(references);
23889
24368
  parameters.push(this.addToConsts(refs));
23890
24369
  parameters.push(importExpr(Identifiers.templateRefExtractor));
23891
24370
  }
@@ -23896,17 +24375,28 @@ class TemplateDefinitionBuilder {
23896
24375
  // be able to support bindings in nested templates to local refs that occur after the
23897
24376
  // template definition. e.g. <div *ngIf="showing">{{ foo }}</div> <div #foo></div>
23898
24377
  this._nestedTemplateFns.push(() => {
23899
- const templateFunctionExpr = templateVisitor.buildTemplateFunction(template.children, template.variables, this._ngContentReservedSlots.length + this._ngContentSelectorsOffset, template.i18n);
24378
+ const templateFunctionExpr = templateVisitor.buildTemplateFunction(children, variables, this._ngContentReservedSlots.length + this._ngContentSelectorsOffset, i18n);
23900
24379
  this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(templateName));
23901
24380
  if (templateVisitor._ngContentReservedSlots.length) {
23902
24381
  this._ngContentReservedSlots.push(...templateVisitor._ngContentReservedSlots);
23903
24382
  }
23904
24383
  });
23905
24384
  // e.g. template(1, MyComp_Template_1)
23906
- this.creationInstruction(template.sourceSpan, Identifiers.templateCreate, () => {
24385
+ this.creationInstruction(sourceSpan, Identifiers.templateCreate, () => {
23907
24386
  parameters.splice(2, 0, literal(templateVisitor.getConstCount()), literal(templateVisitor.getVarCount()));
23908
24387
  return trimTrailingNulls(parameters);
23909
24388
  });
24389
+ return templateIndex;
24390
+ }
24391
+ visitTemplate(template) {
24392
+ // We don't care about the tag's namespace here, because we infer
24393
+ // it based on the parent nodes inside the template instruction.
24394
+ const tagNameWithoutNamespace = template.tagName ? splitNsName(template.tagName)[1] : template.tagName;
24395
+ const contextNameSuffix = template.tagName ? '_' + sanitizeIdentifier(template.tagName) : '';
24396
+ const NG_TEMPLATE_TAG_NAME = 'ng-template';
24397
+ // prepare attributes parameter (including attributes used for directive matching)
24398
+ const attrsExprs = this.getAttributeExpressions(NG_TEMPLATE_TAG_NAME, template.attributes, template.inputs, template.outputs, undefined /* styles */, template.templateAttrs);
24399
+ const templateIndex = this.createEmbeddedTemplateFn(tagNameWithoutNamespace, template.children, contextNameSuffix, template.sourceSpan, template.variables, attrsExprs, template.references, template.i18n);
23910
24400
  // handle property bindings e.g. ɵɵproperty('ngForOf', ctx.items), et al;
23911
24401
  this.templatePropertyBindings(templateIndex, template.templateAttrs);
23912
24402
  // Only add normal input/output binding instructions on explicit <ng-template> elements.
@@ -24001,49 +24491,115 @@ class TemplateDefinitionBuilder {
24001
24491
  return null;
24002
24492
  }
24003
24493
  visitDeferredBlock(deferred) {
24004
- const templateIndex = this.allocateDataSlot();
24494
+ const { loading, placeholder, error, triggers, prefetchTriggers } = deferred;
24495
+ const primaryTemplateIndex = this.createEmbeddedTemplateFn(null, deferred.children, '_Defer', deferred.sourceSpan);
24496
+ const loadingIndex = loading ?
24497
+ this.createEmbeddedTemplateFn(null, loading.children, '_DeferLoading', loading.sourceSpan) :
24498
+ null;
24499
+ const loadingConsts = loading ?
24500
+ trimTrailingNulls([literal(loading.minimumTime), literal(loading.afterTime)]) :
24501
+ null;
24502
+ const placeholderIndex = placeholder ?
24503
+ this.createEmbeddedTemplateFn(null, placeholder.children, '_DeferPlaceholder', placeholder.sourceSpan) :
24504
+ null;
24505
+ const placeholderConsts = placeholder && placeholder.minimumTime !== null ?
24506
+ // TODO(crisbeto): potentially pass the time directly instead of storing it in the `consts`
24507
+ // since `{:placeholder}` can only have one parameter?
24508
+ literalArr([literal(placeholder.minimumTime)]) :
24509
+ null;
24510
+ const errorIndex = error ?
24511
+ this.createEmbeddedTemplateFn(null, error.children, '_DeferError', error.sourceSpan) :
24512
+ null;
24513
+ // Note: we generate this last so the index matches the instruction order.
24514
+ const deferredIndex = this.allocateDataSlot();
24515
+ const depsFnName = `${this.contextName}_Defer_${deferredIndex}_DepsFn`;
24516
+ // e.g. `defer(1, 0, MyComp_Defer_1_DepsFn, ...)`
24517
+ this.creationInstruction(deferred.sourceSpan, Identifiers.defer, trimTrailingNulls([
24518
+ literal(deferredIndex),
24519
+ literal(primaryTemplateIndex),
24520
+ this.createDeferredDepsFunction(depsFnName, deferred),
24521
+ literal(loadingIndex),
24522
+ literal(placeholderIndex),
24523
+ literal(errorIndex),
24524
+ loadingConsts?.length ? this.addToConsts(literalArr(loadingConsts)) : TYPED_NULL_EXPR,
24525
+ placeholderConsts ? this.addToConsts(placeholderConsts) : TYPED_NULL_EXPR,
24526
+ ]));
24527
+ this.createDeferTriggerInstructions(deferredIndex, triggers, false);
24528
+ this.createDeferTriggerInstructions(deferredIndex, prefetchTriggers, true);
24529
+ }
24530
+ createDeferredDepsFunction(name, deferred) {
24005
24531
  const deferredDeps = this.deferBlocks.get(deferred);
24006
- const contextName = `${this.contextName}_Defer_${templateIndex}`;
24007
- const depsFnName = `${contextName}_DepsFn`;
24008
- const parameters = [
24009
- literal(templateIndex),
24010
- deferredDeps ? variable(depsFnName) : TYPED_NULL_EXPR,
24011
- ];
24012
- if (deferredDeps) {
24013
- // This defer block has deps for which we need to generate dynamic imports.
24014
- const dependencyExp = [];
24015
- for (const deferredDep of deferredDeps) {
24016
- if (deferredDep.isDeferrable) {
24017
- // Callback function, e.g. `function(m) { return m.MyCmp; }`.
24018
- const innerFn = fn([new FnParam('m', DYNAMIC_TYPE)], [new ReturnStatement(variable('m').prop(deferredDep.symbolName))]);
24019
- const fileName = deferredDep.importPath;
24020
- // Dynamic import, e.g. `import('./a').then(...)`.
24021
- const importExpr = (new DynamicImportExpr(fileName)).prop('then').callFn([innerFn]);
24022
- dependencyExp.push(importExpr);
24023
- }
24024
- else {
24025
- // Non-deferrable symbol, just use a reference to the type.
24026
- dependencyExp.push(deferredDep.type);
24027
- }
24532
+ if (!deferredDeps || deferredDeps.length === 0) {
24533
+ return TYPED_NULL_EXPR;
24534
+ }
24535
+ // This defer block has deps for which we need to generate dynamic imports.
24536
+ const dependencyExp = [];
24537
+ for (const deferredDep of deferredDeps) {
24538
+ if (deferredDep.isDeferrable) {
24539
+ // Callback function, e.g. `function(m) { return m.MyCmp; }`.
24540
+ const innerFn = fn([new FnParam('m', DYNAMIC_TYPE)], [new ReturnStatement(variable('m').prop(deferredDep.symbolName))]);
24541
+ // Dynamic import, e.g. `import('./a').then(...)`.
24542
+ const importExpr = (new DynamicImportExpr(deferredDep.importPath)).prop('then').callFn([innerFn]);
24543
+ dependencyExp.push(importExpr);
24544
+ }
24545
+ else {
24546
+ // Non-deferrable symbol, just use a reference to the type.
24547
+ dependencyExp.push(deferredDep.type);
24028
24548
  }
24029
- const depsFnBody = [];
24030
- depsFnBody.push(new ReturnStatement(literalArr(dependencyExp)));
24031
- const depsFnExpr = fn([] /* args */, depsFnBody, INFERRED_TYPE, null, depsFnName);
24032
- this.constantPool.statements.push(depsFnExpr.toDeclStmt(depsFnName));
24033
24549
  }
24034
- // e.g. `defer(1, MyComp_Defer_1_DepsFn, ...)`
24035
- this.creationInstruction(deferred.sourceSpan, Identifiers.defer, () => {
24036
- return trimTrailingNulls(parameters);
24037
- });
24550
+ const depsFnExpr = fn([], [new ReturnStatement(literalArr(dependencyExp))], INFERRED_TYPE, null, name);
24551
+ this.constantPool.statements.push(depsFnExpr.toDeclStmt(name));
24552
+ return variable(name);
24553
+ }
24554
+ createDeferTriggerInstructions(deferredIndex, triggers, prefetch) {
24555
+ const { when, idle, immediate, timer, hover, interaction, viewport } = triggers;
24556
+ // `deferWhen(ctx.someValue)`
24557
+ if (when) {
24558
+ const value = when.value.visit(this._valueConverter);
24559
+ this.allocateBindingSlots(value);
24560
+ this.updateInstructionWithAdvance(deferredIndex, when.sourceSpan, prefetch ? Identifiers.deferPrefetchWhen : Identifiers.deferWhen, () => this.convertPropertyBinding(value));
24561
+ }
24562
+ // Note that we generate an implicit `on idle` if the `deferred` block has no triggers.
24563
+ // TODO(crisbeto): decide if this should be baked into the `defer` instruction.
24564
+ // `deferOnIdle()`
24565
+ if (idle || (!prefetch && Object.keys(triggers).length === 0)) {
24566
+ this.creationInstruction(idle?.sourceSpan || null, prefetch ? Identifiers.deferPrefetchOnIdle : Identifiers.deferOnIdle);
24567
+ }
24568
+ // `deferOnImmediate()`
24569
+ if (immediate) {
24570
+ this.creationInstruction(immediate.sourceSpan, prefetch ? Identifiers.deferPrefetchOnImmediate : Identifiers.deferOnImmediate);
24571
+ }
24572
+ // `deferOnTimer(1337)`
24573
+ if (timer) {
24574
+ this.creationInstruction(timer.sourceSpan, prefetch ? Identifiers.deferPrefetchOnTimer : Identifiers.deferOnTimer, [literal(timer.delay)]);
24575
+ }
24576
+ // `deferOnHover()`
24577
+ if (hover) {
24578
+ this.creationInstruction(hover.sourceSpan, prefetch ? Identifiers.deferPrefetchOnHover : Identifiers.deferOnHover);
24579
+ }
24580
+ // TODO(crisbeto): currently the reference is passed as a string.
24581
+ // Update this once we figure out how we should refer to the target.
24582
+ // `deferOnInteraction(target)`
24583
+ if (interaction) {
24584
+ this.creationInstruction(interaction.sourceSpan, prefetch ? Identifiers.deferPrefetchOnInteraction : Identifiers.deferOnInteraction, [literal(interaction.reference)]);
24585
+ }
24586
+ // TODO(crisbeto): currently the reference is passed as a string.
24587
+ // Update this once we figure out how we should refer to the target.
24588
+ // `deferOnViewport(target)`
24589
+ if (viewport) {
24590
+ this.creationInstruction(viewport.sourceSpan, prefetch ? Identifiers.deferPrefetchOnViewport : Identifiers.deferOnViewport, [literal(viewport.reference)]);
24591
+ }
24038
24592
  }
24039
- // TODO: implement nested deferred block instructions.
24040
- visitDeferredTrigger(trigger) { }
24041
- visitDeferredBlockPlaceholder(block) { }
24042
- visitDeferredBlockError(block) { }
24043
- visitDeferredBlockLoading(block) { }
24044
24593
  allocateDataSlot() {
24045
24594
  return this._dataIndex++;
24046
24595
  }
24596
+ // TODO: implement control flow instructions
24597
+ visitSwitchBlock(block) { }
24598
+ visitSwitchBlockCase(block) { }
24599
+ visitForLoopBlock(block) { }
24600
+ visitForLoopBlockEmpty(block) { }
24601
+ visitIfBlock(block) { }
24602
+ visitIfBlockBranch(block) { }
24047
24603
  getConstCount() {
24048
24604
  return this._dataIndex;
24049
24605
  }
@@ -24293,7 +24849,8 @@ class TemplateDefinitionBuilder {
24293
24849
  return literal(consts.push(expression) - 1);
24294
24850
  }
24295
24851
  addAttrsToConsts(attrs) {
24296
- return attrs.length > 0 ? this.addToConsts(literalArr(attrs)) : TYPED_NULL_EXPR;
24852
+ return attrs !== null && attrs.length > 0 ? this.addToConsts(literalArr(attrs)) :
24853
+ TYPED_NULL_EXPR;
24297
24854
  }
24298
24855
  prepareRefsArray(references) {
24299
24856
  if (!references || references.length === 0) {
@@ -25137,9 +25694,17 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
25137
25694
  }
25138
25695
  definitionMap.set('template', templateFn);
25139
25696
  }
25140
- if (meta.declarations.length > 0) {
25697
+ if (meta.declarationListEmitMode !== 3 /* DeclarationListEmitMode.RuntimeResolved */ &&
25698
+ meta.declarations.length > 0) {
25141
25699
  definitionMap.set('dependencies', compileDeclarationList(literalArr(meta.declarations.map(decl => decl.type)), meta.declarationListEmitMode));
25142
25700
  }
25701
+ else if (meta.declarationListEmitMode === 3 /* DeclarationListEmitMode.RuntimeResolved */) {
25702
+ const args = [meta.type.value];
25703
+ if (meta.rawImports) {
25704
+ args.push(meta.rawImports);
25705
+ }
25706
+ definitionMap.set('dependencies', importExpr(Identifiers.getComponentDepsFactory).callFn(args));
25707
+ }
25143
25708
  if (meta.encapsulation === null) {
25144
25709
  meta.encapsulation = ViewEncapsulation.Emulated;
25145
25710
  }
@@ -25211,6 +25776,8 @@ function compileDeclarationList(list, mode) {
25211
25776
  // directives: function () { return [MyDir].map(ng.resolveForwardRef); }
25212
25777
  const resolvedList = list.prop('map').callFn([importExpr(Identifiers.resolveForwardRef)]);
25213
25778
  return fn([], [new ReturnStatement(resolvedList)]);
25779
+ case 3 /* DeclarationListEmitMode.RuntimeResolved */:
25780
+ throw new Error(`Unsupported with an array of pre-resolved dependencies`);
25214
25781
  }
25215
25782
  }
25216
25783
  function prepareQueryParams(query, constantPool) {
@@ -26331,7 +26898,7 @@ function publishFacade(global) {
26331
26898
  * @description
26332
26899
  * Entry point for all public APIs of the compiler package.
26333
26900
  */
26334
- const VERSION = new Version('16.2.0');
26901
+ const VERSION = new Version('17.0.0-next.0');
26335
26902
 
26336
26903
  class CompilerConfig {
26337
26904
  constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
@@ -27891,6 +28458,25 @@ class Scope {
27891
28458
  visitDeferredBlockLoading(block) {
27892
28459
  block.children.forEach(node => node.visit(this));
27893
28460
  }
28461
+ visitSwitchBlock(block) {
28462
+ block.cases.forEach(node => node.visit(this));
28463
+ }
28464
+ visitSwitchBlockCase(block) {
28465
+ block.children.forEach(node => node.visit(this));
28466
+ }
28467
+ visitForLoopBlock(block) {
28468
+ block.children.forEach(node => node.visit(this));
28469
+ block.empty?.visit(this);
28470
+ }
28471
+ visitForLoopBlockEmpty(block) {
28472
+ block.children.forEach(node => node.visit(this));
28473
+ }
28474
+ visitIfBlock(block) {
28475
+ block.branches.forEach(node => node.visit(this));
28476
+ }
28477
+ visitIfBlockBranch(block) {
28478
+ block.children.forEach(node => node.visit(this));
28479
+ }
27894
28480
  // Unused visitors.
27895
28481
  visitContent(content) { }
27896
28482
  visitBoundAttribute(attr) { }
@@ -28045,9 +28631,10 @@ class DirectiveBinder {
28045
28631
  node.children.forEach(child => child.visit(this));
28046
28632
  }
28047
28633
  visitDeferredBlock(deferred) {
28634
+ const wasInDeferBlock = this.isInDeferBlock;
28048
28635
  this.isInDeferBlock = true;
28049
28636
  deferred.children.forEach(child => child.visit(this));
28050
- this.isInDeferBlock = false;
28637
+ this.isInDeferBlock = wasInDeferBlock;
28051
28638
  deferred.placeholder?.visit(this);
28052
28639
  deferred.loading?.visit(this);
28053
28640
  deferred.error?.visit(this);
@@ -28061,6 +28648,25 @@ class DirectiveBinder {
28061
28648
  visitDeferredBlockLoading(block) {
28062
28649
  block.children.forEach(child => child.visit(this));
28063
28650
  }
28651
+ visitSwitchBlock(block) {
28652
+ block.cases.forEach(node => node.visit(this));
28653
+ }
28654
+ visitSwitchBlockCase(block) {
28655
+ block.children.forEach(node => node.visit(this));
28656
+ }
28657
+ visitForLoopBlock(block) {
28658
+ block.children.forEach(node => node.visit(this));
28659
+ block.empty?.visit(this);
28660
+ }
28661
+ visitForLoopBlockEmpty(block) {
28662
+ block.children.forEach(node => node.visit(this));
28663
+ }
28664
+ visitIfBlock(block) {
28665
+ block.branches.forEach(node => node.visit(this));
28666
+ }
28667
+ visitIfBlockBranch(block) {
28668
+ block.children.forEach(node => node.visit(this));
28669
+ }
28064
28670
  // Unused visitors.
28065
28671
  visitContent(content) { }
28066
28672
  visitVariable(variable) { }
@@ -28197,11 +28803,10 @@ class TemplateBinder extends RecursiveAstVisitor {
28197
28803
  }
28198
28804
  visitDeferredBlock(deferred) {
28199
28805
  this.deferBlocks.add(deferred);
28806
+ const wasInDeferBlock = this.isInDeferBlock;
28200
28807
  this.isInDeferBlock = true;
28201
28808
  deferred.children.forEach(this.visitNode);
28202
- this.isInDeferBlock = false;
28203
- deferred.triggers.forEach(this.visitNode);
28204
- deferred.prefetchTriggers.forEach(this.visitNode);
28809
+ this.isInDeferBlock = wasInDeferBlock;
28205
28810
  deferred.placeholder && this.visitNode(deferred.placeholder);
28206
28811
  deferred.loading && this.visitNode(deferred.loading);
28207
28812
  deferred.error && this.visitNode(deferred.error);
@@ -28220,6 +28825,29 @@ class TemplateBinder extends RecursiveAstVisitor {
28220
28825
  visitDeferredBlockLoading(block) {
28221
28826
  block.children.forEach(this.visitNode);
28222
28827
  }
28828
+ visitSwitchBlock(block) {
28829
+ block.expression.visit(this);
28830
+ block.cases.forEach(this.visitNode);
28831
+ }
28832
+ visitSwitchBlockCase(block) {
28833
+ block.expression?.visit(this);
28834
+ block.children.forEach(this.visitNode);
28835
+ }
28836
+ visitForLoopBlock(block) {
28837
+ block.expression.visit(this);
28838
+ block.children.forEach(this.visitNode);
28839
+ block.empty?.visit(this);
28840
+ }
28841
+ visitForLoopBlockEmpty(block) {
28842
+ block.children.forEach(this.visitNode);
28843
+ }
28844
+ visitIfBlock(block) {
28845
+ block.branches.forEach(node => node.visit(this));
28846
+ }
28847
+ visitIfBlockBranch(block) {
28848
+ block.expression?.visit(this);
28849
+ block.children.forEach(node => node.visit(this));
28850
+ }
28223
28851
  visitBoundText(text) {
28224
28852
  text.value.visit(this);
28225
28853
  }
@@ -28362,6 +28990,60 @@ function compileClassMetadata(metadata) {
28362
28990
  const iife = fn([], [devOnlyGuardedExpression(fnCall).toStmt()]);
28363
28991
  return iife.callFn([]);
28364
28992
  }
28993
+ /**
28994
+ * Wraps the `setClassMetadata` function with extra logic that dynamically
28995
+ * loads dependencies from `{#defer}` blocks.
28996
+ *
28997
+ * Generates a call like this:
28998
+ * ```
28999
+ * setClassMetadataAsync(type, () => {
29000
+ * return [
29001
+ * import('./cmp-a').then(m => m.CmpA);
29002
+ * import('./cmp-b').then(m => m.CmpB);
29003
+ * ];
29004
+ * }, (CmpA, CmpB) => {
29005
+ * setClassMetadata(type, decorators, ctorParameters, propParameters);
29006
+ * });
29007
+ * ```
29008
+ *
29009
+ * Similar to the `setClassMetadata` call, it's wrapped into the `ngDevMode`
29010
+ * check to tree-shake away this code in production mode.
29011
+ */
29012
+ function compileComponentClassMetadata(metadata, deferrableTypes) {
29013
+ if (deferrableTypes.size === 0) {
29014
+ // If there are no deferrable symbols - just generate a regular `setClassMetadata` call.
29015
+ return compileClassMetadata(metadata);
29016
+ }
29017
+ const dynamicImports = [];
29018
+ const importedSymbols = [];
29019
+ for (const [symbolName, importPath] of deferrableTypes) {
29020
+ // e.g. `function(m) { return m.CmpA; }`
29021
+ const innerFn = fn([new FnParam('m', DYNAMIC_TYPE)], [new ReturnStatement(variable('m').prop(symbolName))]);
29022
+ // e.g. `import('./cmp-a').then(...)`
29023
+ const importExpr = (new DynamicImportExpr(importPath)).prop('then').callFn([innerFn]);
29024
+ dynamicImports.push(importExpr);
29025
+ importedSymbols.push(new FnParam(symbolName, DYNAMIC_TYPE));
29026
+ }
29027
+ // e.g. `function() { return [ ... ]; }`
29028
+ const dependencyLoadingFn = fn([], [new ReturnStatement(literalArr(dynamicImports))]);
29029
+ // e.g. `setClassMetadata(...)`
29030
+ const setClassMetadataCall = importExpr(Identifiers.setClassMetadata).callFn([
29031
+ metadata.type,
29032
+ metadata.decorators,
29033
+ metadata.ctorParameters ?? literal(null),
29034
+ metadata.propDecorators ?? literal(null),
29035
+ ]);
29036
+ // e.g. `function(CmpA) { setClassMetadata(...); }`
29037
+ const setClassMetaWrapper = fn(importedSymbols, [setClassMetadataCall.toStmt()]);
29038
+ // Final `setClassMetadataAsync()` call with all arguments
29039
+ const setClassMetaAsync = importExpr(Identifiers.setClassMetadataAsync).callFn([
29040
+ metadata.type, dependencyLoadingFn, setClassMetaWrapper
29041
+ ]);
29042
+ // Generate an ngDevMode guarded call to `setClassMetadataAsync` with
29043
+ // the class identifier and its metadata, so that this call can be tree-shaken.
29044
+ const iife = fn([], [devOnlyGuardedExpression(setClassMetaAsync).toStmt()]);
29045
+ return iife.callFn([]);
29046
+ }
28365
29047
 
28366
29048
  /**
28367
29049
  * Every time we make a breaking change to the declaration interface or partial-linker behavior, we
@@ -28374,7 +29056,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
28374
29056
  function compileDeclareClassMetadata(metadata) {
28375
29057
  const definitionMap = new DefinitionMap();
28376
29058
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
28377
- definitionMap.set('version', literal('16.2.0'));
29059
+ definitionMap.set('version', literal('17.0.0-next.0'));
28378
29060
  definitionMap.set('ngImport', importExpr(Identifiers.core));
28379
29061
  definitionMap.set('type', metadata.type);
28380
29062
  definitionMap.set('decorators', metadata.decorators);
@@ -28477,7 +29159,7 @@ function compileDeclareDirectiveFromMetadata(meta) {
28477
29159
  function createDirectiveDefinitionMap(meta) {
28478
29160
  const definitionMap = new DefinitionMap();
28479
29161
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
28480
- definitionMap.set('version', literal('16.2.0'));
29162
+ definitionMap.set('version', literal('17.0.0-next.0'));
28481
29163
  // e.g. `type: MyDirective`
28482
29164
  definitionMap.set('type', meta.type.value);
28483
29165
  if (meta.isStandalone) {
@@ -28668,6 +29350,9 @@ function compileUsedDependenciesMetadata(meta) {
28668
29350
  const wrapType = meta.declarationListEmitMode !== 0 /* DeclarationListEmitMode.Direct */ ?
28669
29351
  generateForwardRef :
28670
29352
  (expr) => expr;
29353
+ if (meta.declarationListEmitMode === 3 /* DeclarationListEmitMode.RuntimeResolved */) {
29354
+ throw new Error(`Unsupported emit mode`);
29355
+ }
28671
29356
  return toOptionalLiteralArray(meta.declarations, decl => {
28672
29357
  switch (decl.kind) {
28673
29358
  case R3TemplateDependencyKind.Directive:
@@ -28705,7 +29390,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
28705
29390
  function compileDeclareFactoryFunction(meta) {
28706
29391
  const definitionMap = new DefinitionMap();
28707
29392
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
28708
- definitionMap.set('version', literal('16.2.0'));
29393
+ definitionMap.set('version', literal('17.0.0-next.0'));
28709
29394
  definitionMap.set('ngImport', importExpr(Identifiers.core));
28710
29395
  definitionMap.set('type', meta.type.value);
28711
29396
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -28740,7 +29425,7 @@ function compileDeclareInjectableFromMetadata(meta) {
28740
29425
  function createInjectableDefinitionMap(meta) {
28741
29426
  const definitionMap = new DefinitionMap();
28742
29427
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
28743
- definitionMap.set('version', literal('16.2.0'));
29428
+ definitionMap.set('version', literal('17.0.0-next.0'));
28744
29429
  definitionMap.set('ngImport', importExpr(Identifiers.core));
28745
29430
  definitionMap.set('type', meta.type.value);
28746
29431
  // Only generate providedIn property if it has a non-null value
@@ -28791,7 +29476,7 @@ function compileDeclareInjectorFromMetadata(meta) {
28791
29476
  function createInjectorDefinitionMap(meta) {
28792
29477
  const definitionMap = new DefinitionMap();
28793
29478
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
28794
- definitionMap.set('version', literal('16.2.0'));
29479
+ definitionMap.set('version', literal('17.0.0-next.0'));
28795
29480
  definitionMap.set('ngImport', importExpr(Identifiers.core));
28796
29481
  definitionMap.set('type', meta.type.value);
28797
29482
  definitionMap.set('providers', meta.providers);
@@ -28824,7 +29509,7 @@ function createNgModuleDefinitionMap(meta) {
28824
29509
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
28825
29510
  }
28826
29511
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
28827
- definitionMap.set('version', literal('16.2.0'));
29512
+ definitionMap.set('version', literal('17.0.0-next.0'));
28828
29513
  definitionMap.set('ngImport', importExpr(Identifiers.core));
28829
29514
  definitionMap.set('type', meta.type.value);
28830
29515
  // We only generate the keys in the metadata if the arrays contain values.
@@ -28875,7 +29560,7 @@ function compileDeclarePipeFromMetadata(meta) {
28875
29560
  function createPipeDefinitionMap(meta) {
28876
29561
  const definitionMap = new DefinitionMap();
28877
29562
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
28878
- definitionMap.set('version', literal('16.2.0'));
29563
+ definitionMap.set('version', literal('17.0.0-next.0'));
28879
29564
  definitionMap.set('ngImport', importExpr(Identifiers.core));
28880
29565
  // e.g. `type: MyPipe`
28881
29566
  definitionMap.set('type', meta.type.value);
@@ -28908,5 +29593,5 @@ publishFacade(_global);
28908
29593
 
28909
29594
  // This file is not used to build this module. It is only used during editing
28910
29595
 
28911
- export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockGroup, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation$1 as Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
29596
+ export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockGroup, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation$1 as Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, ForLoopBlock as TmplAstForLoopBlock, ForLoopBlockEmpty as TmplAstForLoopBlockEmpty, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, IfBlock as TmplAstIfBlock, IfBlockBranch as TmplAstIfBlockBranch, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, SwitchBlock as TmplAstSwitchBlock, SwitchBlockCase as TmplAstSwitchBlockCase, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassMetadata, compileComponentClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
28912
29597
  //# sourceMappingURL=compiler.mjs.map