@angular/compiler 17.0.0-next.6 → 17.0.0-next.8

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 (75) hide show
  1. package/esm2022/src/compiler.mjs +4 -3
  2. package/esm2022/src/config.mjs +2 -4
  3. package/esm2022/src/injectable_compiler_2.mjs +3 -6
  4. package/esm2022/src/jit_compiler_facade.mjs +2 -7
  5. package/esm2022/src/ml_parser/lexer.mjs +19 -11
  6. package/esm2022/src/ml_parser/parser.mjs +28 -10
  7. package/esm2022/src/ml_parser/tokens.mjs +1 -1
  8. package/esm2022/src/output/abstract_emitter.mjs +8 -1
  9. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  10. package/esm2022/src/render3/partial/component.mjs +45 -1
  11. package/esm2022/src/render3/partial/directive.mjs +1 -1
  12. package/esm2022/src/render3/partial/factory.mjs +1 -1
  13. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  14. package/esm2022/src/render3/partial/injector.mjs +1 -1
  15. package/esm2022/src/render3/partial/ng_module.mjs +1 -1
  16. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  17. package/esm2022/src/render3/r3_ast.mjs +37 -19
  18. package/esm2022/src/render3/r3_class_debug_info_compiler.mjs +36 -0
  19. package/esm2022/src/render3/r3_control_flow.mjs +40 -23
  20. package/esm2022/src/render3/r3_deferred_blocks.mjs +13 -3
  21. package/esm2022/src/render3/r3_factory.mjs +2 -2
  22. package/esm2022/src/render3/r3_identifiers.mjs +3 -1
  23. package/esm2022/src/render3/r3_template_transform.mjs +19 -23
  24. package/esm2022/src/render3/util.mjs +3 -3
  25. package/esm2022/src/render3/view/compiler.mjs +8 -6
  26. package/esm2022/src/render3/view/t2_binder.mjs +8 -7
  27. package/esm2022/src/render3/view/template.mjs +36 -27
  28. package/esm2022/src/render3/view/util.mjs +8 -2
  29. package/esm2022/src/template/pipeline/ir/src/enums.mjs +42 -9
  30. package/esm2022/src/template/pipeline/ir/src/expression.mjs +61 -16
  31. package/esm2022/src/template/pipeline/ir/src/operations.mjs +2 -2
  32. package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +55 -12
  33. package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +35 -4
  34. package/esm2022/src/template/pipeline/ir/src/traits.mjs +17 -2
  35. package/esm2022/src/template/pipeline/ir/src/variable.mjs +6 -2
  36. package/esm2022/src/template/pipeline/src/conversion.mjs +3 -2
  37. package/esm2022/src/template/pipeline/src/emit.mjs +16 -10
  38. package/esm2022/src/template/pipeline/src/ingest.mjs +159 -18
  39. package/esm2022/src/template/pipeline/src/instruction.mjs +44 -7
  40. package/esm2022/src/template/pipeline/src/phases/apply_i18n_expressions.mjs +37 -0
  41. package/esm2022/src/template/pipeline/src/phases/assign_i18n_slot_dependencies.mjs +33 -0
  42. package/esm2022/src/template/pipeline/src/phases/chaining.mjs +13 -12
  43. package/esm2022/src/template/pipeline/src/phases/conditionals.mjs +22 -9
  44. package/esm2022/src/template/pipeline/src/phases/empty_elements.mjs +14 -3
  45. package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +6 -2
  46. package/esm2022/src/template/pipeline/src/phases/has_const_trait_collection.mjs +34 -0
  47. package/esm2022/src/template/pipeline/src/phases/host_style_property_parsing.mjs +6 -1
  48. package/esm2022/src/template/pipeline/src/phases/i18n_const_collection.mjs +3 -3
  49. package/esm2022/src/template/pipeline/src/phases/i18n_message_extraction.mjs +18 -15
  50. package/esm2022/src/template/pipeline/src/phases/i18n_text_extraction.mjs +31 -5
  51. package/esm2022/src/template/pipeline/src/phases/naming.mjs +3 -3
  52. package/esm2022/src/template/pipeline/src/phases/ng_container.mjs +6 -1
  53. package/esm2022/src/template/pipeline/src/phases/propagate_i18n_blocks.mjs +57 -0
  54. package/esm2022/src/template/pipeline/src/phases/propagate_i18n_placeholders.mjs +39 -0
  55. package/esm2022/src/template/pipeline/src/phases/pure_function_extraction.mjs +4 -4
  56. package/esm2022/src/template/pipeline/src/phases/reify.mjs +25 -10
  57. package/esm2022/src/template/pipeline/src/phases/resolve_i18n_placeholders.mjs +163 -36
  58. package/esm2022/src/template/pipeline/src/phases/slot_allocation.mjs +5 -5
  59. package/esm2022/src/template/pipeline/src/phases/temporary_variables.mjs +53 -38
  60. package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +10 -1
  61. package/esm2022/src/template/pipeline/src/phases/variable_optimization.mjs +9 -1
  62. package/esm2022/src/version.mjs +1 -1
  63. package/fesm2022/compiler.mjs +1406 -550
  64. package/fesm2022/compiler.mjs.map +1 -1
  65. package/index.d.ts +81 -18
  66. package/package.json +2 -8
  67. package/esm2022/src/template/pipeline/src/phases/generate_i18n_blocks.mjs +0 -38
  68. package/esm2022/src/template/pipeline/src/phases/no_listeners_on_templates.mjs +0 -32
  69. package/esm2022/testing/index.mjs +0 -13
  70. package/esm2022/testing/public_api.mjs +0 -16
  71. package/esm2022/testing/src/testing.mjs +0 -29
  72. package/esm2022/testing/testing.mjs +0 -5
  73. package/fesm2022/testing.mjs +0 -39
  74. package/fesm2022/testing.mjs.map +0 -1
  75. package/testing/index.d.ts +0 -25
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v17.0.0-next.6
2
+ * @license Angular v17.0.0-next.8
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -2482,6 +2482,7 @@ class Identifiers {
2482
2482
  static { this.deferPrefetchOnHover = { name: 'ɵɵdeferPrefetchOnHover', moduleName: CORE }; }
2483
2483
  static { this.deferPrefetchOnInteraction = { name: 'ɵɵdeferPrefetchOnInteraction', moduleName: CORE }; }
2484
2484
  static { this.deferPrefetchOnViewport = { name: 'ɵɵdeferPrefetchOnViewport', moduleName: CORE }; }
2485
+ static { this.deferEnableTimerScheduling = { name: 'ɵɵdeferEnableTimerScheduling', moduleName: CORE }; }
2485
2486
  static { this.conditional = { name: 'ɵɵconditional', moduleName: CORE }; }
2486
2487
  static { this.repeater = { name: 'ɵɵrepeater', moduleName: CORE }; }
2487
2488
  static { this.repeaterCreate = { name: 'ɵɵrepeaterCreate', moduleName: CORE }; }
@@ -2605,6 +2606,7 @@ class Identifiers {
2605
2606
  static { this.declareClassMetadata = { name: 'ɵɵngDeclareClassMetadata', moduleName: CORE }; }
2606
2607
  static { this.setClassMetadata = { name: 'ɵsetClassMetadata', moduleName: CORE }; }
2607
2608
  static { this.setClassMetadataAsync = { name: 'ɵsetClassMetadataAsync', moduleName: CORE }; }
2609
+ static { this.setClassDebugInfo = { name: 'ɵsetClassDebugInfo', moduleName: CORE }; }
2608
2610
  static { this.queryRefresh = { name: 'ɵɵqueryRefresh', moduleName: CORE }; }
2609
2611
  static { this.viewQuery = { name: 'ɵɵviewQuery', moduleName: CORE }; }
2610
2612
  static { this.loadQuery = { name: 'ɵɵloadQuery', moduleName: CORE }; }
@@ -3139,7 +3141,14 @@ class AbstractEmitterVisitor {
3139
3141
  return null;
3140
3142
  }
3141
3143
  visitInvokeFunctionExpr(expr, ctx) {
3144
+ const shouldParenthesize = expr.fn instanceof ArrowFunctionExpr;
3145
+ if (shouldParenthesize) {
3146
+ ctx.print(expr.fn, '(');
3147
+ }
3142
3148
  expr.fn.visitExpression(this, ctx);
3149
+ if (shouldParenthesize) {
3150
+ ctx.print(expr.fn, ')');
3151
+ }
3143
3152
  ctx.print(expr, `(`);
3144
3153
  this.visitAllExpressions(expr.args, ctx, ',');
3145
3154
  ctx.print(expr, `)`);
@@ -3438,7 +3447,7 @@ function wrapReference(value) {
3438
3447
  }
3439
3448
  function refsToArray(refs, shouldForwardDeclare) {
3440
3449
  const values = literalArr(refs.map(ref => ref.value));
3441
- return shouldForwardDeclare ? fn([], [new ReturnStatement(values)]) : values;
3450
+ return shouldForwardDeclare ? arrowFn([], values) : values;
3442
3451
  }
3443
3452
  function createMayBeForwardRefExpression(expression, forwardRef) {
3444
3453
  return { expression, forwardRef };
@@ -3471,7 +3480,7 @@ function convertFromMaybeForwardRefExpression({ expression, forwardRef }) {
3471
3480
  * ```
3472
3481
  */
3473
3482
  function generateForwardRef(expr) {
3474
- return importExpr(Identifiers.forwardRef).callFn([fn([], [new ReturnStatement(expr)])]);
3483
+ return importExpr(Identifiers.forwardRef).callFn([arrowFn([], expr)]);
3475
3484
  }
3476
3485
 
3477
3486
  var R3FactoryDelegateType;
@@ -3559,7 +3568,7 @@ function compileFactoryFunction(meta) {
3559
3568
  if (baseFactoryVar !== null) {
3560
3569
  // There is a base factory variable so wrap its declaration along with the factory function into
3561
3570
  // an IIFE.
3562
- factoryFn = fn([], [
3571
+ factoryFn = arrowFn([], [
3563
3572
  new DeclareVarStmt(baseFactoryVar.name), new ReturnStatement(factoryFn)
3564
3573
  ]).callFn([], /* sourceSpan */ undefined, /* pure */ true);
3565
3574
  }
@@ -3861,12 +3870,13 @@ class DeferredBlockError {
3861
3870
  }
3862
3871
  }
3863
3872
  class DeferredBlock {
3864
- constructor(children, triggers, prefetchTriggers, placeholder, loading, error, sourceSpan, startSourceSpan, endSourceSpan) {
3873
+ constructor(children, triggers, prefetchTriggers, placeholder, loading, error, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan) {
3865
3874
  this.children = children;
3866
3875
  this.placeholder = placeholder;
3867
3876
  this.loading = loading;
3868
3877
  this.error = error;
3869
3878
  this.sourceSpan = sourceSpan;
3879
+ this.mainBlockSpan = mainBlockSpan;
3870
3880
  this.startSourceSpan = startSourceSpan;
3871
3881
  this.endSourceSpan = endSourceSpan;
3872
3882
  this.triggers = triggers;
@@ -3883,20 +3893,23 @@ class DeferredBlock {
3883
3893
  this.visitTriggers(this.definedTriggers, this.triggers, visitor);
3884
3894
  this.visitTriggers(this.definedPrefetchTriggers, this.prefetchTriggers, visitor);
3885
3895
  visitAll$1(visitor, this.children);
3886
- this.placeholder && visitor.visitDeferredBlockPlaceholder(this.placeholder);
3887
- this.loading && visitor.visitDeferredBlockLoading(this.loading);
3888
- this.error && visitor.visitDeferredBlockError(this.error);
3896
+ const remainingBlocks = [this.placeholder, this.loading, this.error].filter(x => x !== null);
3897
+ visitAll$1(visitor, remainingBlocks);
3889
3898
  }
3890
3899
  visitTriggers(keys, triggers, visitor) {
3891
- for (const key of keys) {
3892
- visitor.visitDeferredTrigger(triggers[key]);
3893
- }
3900
+ visitAll$1(visitor, keys.map(k => triggers[k]));
3894
3901
  }
3895
3902
  }
3896
3903
  class SwitchBlock {
3897
- constructor(expression, cases, sourceSpan, startSourceSpan, endSourceSpan) {
3904
+ constructor(expression, cases,
3905
+ /**
3906
+ * These blocks are only captured to allow for autocompletion in the language service. They
3907
+ * aren't meant to be processed in any other way.
3908
+ */
3909
+ unknownBlocks, sourceSpan, startSourceSpan, endSourceSpan) {
3898
3910
  this.expression = expression;
3899
3911
  this.cases = cases;
3912
+ this.unknownBlocks = unknownBlocks;
3900
3913
  this.sourceSpan = sourceSpan;
3901
3914
  this.startSourceSpan = startSourceSpan;
3902
3915
  this.endSourceSpan = endSourceSpan;
@@ -3906,18 +3919,19 @@ class SwitchBlock {
3906
3919
  }
3907
3920
  }
3908
3921
  class SwitchBlockCase {
3909
- constructor(expression, children, sourceSpan, startSourceSpan) {
3922
+ constructor(expression, children, sourceSpan, startSourceSpan, endSourceSpan) {
3910
3923
  this.expression = expression;
3911
3924
  this.children = children;
3912
3925
  this.sourceSpan = sourceSpan;
3913
3926
  this.startSourceSpan = startSourceSpan;
3927
+ this.endSourceSpan = endSourceSpan;
3914
3928
  }
3915
3929
  visit(visitor) {
3916
3930
  return visitor.visitSwitchBlockCase(this);
3917
3931
  }
3918
3932
  }
3919
3933
  class ForLoopBlock {
3920
- constructor(item, expression, trackBy, contextVariables, children, empty, sourceSpan, startSourceSpan, endSourceSpan) {
3934
+ constructor(item, expression, trackBy, contextVariables, children, empty, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan) {
3921
3935
  this.item = item;
3922
3936
  this.expression = expression;
3923
3937
  this.trackBy = trackBy;
@@ -3925,6 +3939,7 @@ class ForLoopBlock {
3925
3939
  this.children = children;
3926
3940
  this.empty = empty;
3927
3941
  this.sourceSpan = sourceSpan;
3942
+ this.mainBlockSpan = mainBlockSpan;
3928
3943
  this.startSourceSpan = startSourceSpan;
3929
3944
  this.endSourceSpan = endSourceSpan;
3930
3945
  }
@@ -3933,10 +3948,11 @@ class ForLoopBlock {
3933
3948
  }
3934
3949
  }
3935
3950
  class ForLoopBlockEmpty {
3936
- constructor(children, sourceSpan, startSourceSpan) {
3951
+ constructor(children, sourceSpan, startSourceSpan, endSourceSpan) {
3937
3952
  this.children = children;
3938
3953
  this.sourceSpan = sourceSpan;
3939
3954
  this.startSourceSpan = startSourceSpan;
3955
+ this.endSourceSpan = endSourceSpan;
3940
3956
  }
3941
3957
  visit(visitor) {
3942
3958
  return visitor.visitForLoopBlockEmpty(this);
@@ -3954,17 +3970,27 @@ class IfBlock {
3954
3970
  }
3955
3971
  }
3956
3972
  class IfBlockBranch {
3957
- constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan) {
3973
+ constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan, endSourceSpan) {
3958
3974
  this.expression = expression;
3959
3975
  this.children = children;
3960
3976
  this.expressionAlias = expressionAlias;
3961
3977
  this.sourceSpan = sourceSpan;
3962
3978
  this.startSourceSpan = startSourceSpan;
3979
+ this.endSourceSpan = endSourceSpan;
3963
3980
  }
3964
3981
  visit(visitor) {
3965
3982
  return visitor.visitIfBlockBranch(this);
3966
3983
  }
3967
3984
  }
3985
+ class UnknownBlock {
3986
+ constructor(name, sourceSpan) {
3987
+ this.name = name;
3988
+ this.sourceSpan = sourceSpan;
3989
+ }
3990
+ visit(visitor) {
3991
+ return visitor.visitUnknownBlock(this);
3992
+ }
3993
+ }
3968
3994
  class Template {
3969
3995
  constructor(
3970
3996
  // tagName is the name of the container element, if applicable.
@@ -4071,10 +4097,9 @@ class RecursiveVisitor$1 {
4071
4097
  visitAll$1(this, block.children);
4072
4098
  }
4073
4099
  visitForLoopBlock(block) {
4074
- block.item.visit(this);
4075
- visitAll$1(this, Object.values(block.contextVariables));
4076
- visitAll$1(this, block.children);
4077
- block.empty?.visit(this);
4100
+ const blockItems = [block.item, ...Object.values(block.contextVariables), ...block.children];
4101
+ block.empty && blockItems.push(block.empty);
4102
+ visitAll$1(this, blockItems);
4078
4103
  }
4079
4104
  visitForLoopBlockEmpty(block) {
4080
4105
  visitAll$1(this, block.children);
@@ -4083,8 +4108,9 @@ class RecursiveVisitor$1 {
4083
4108
  visitAll$1(this, block.branches);
4084
4109
  }
4085
4110
  visitIfBlockBranch(block) {
4086
- visitAll$1(this, block.children);
4087
- block.expressionAlias?.visit(this);
4111
+ const blockItems = block.children;
4112
+ block.expressionAlias && blockItems.push(block.expressionAlias);
4113
+ visitAll$1(this, blockItems);
4088
4114
  }
4089
4115
  visitContent(content) { }
4090
4116
  visitVariable(variable) { }
@@ -4096,6 +4122,7 @@ class RecursiveVisitor$1 {
4096
4122
  visitBoundText(text) { }
4097
4123
  visitIcu(icu) { }
4098
4124
  visitDeferredTrigger(trigger) { }
4125
+ visitUnknownBlock(block) { }
4099
4126
  }
4100
4127
  function visitAll$1(visitor, nodes) {
4101
4128
  const result = [];
@@ -4931,7 +4958,13 @@ class DefinitionMap {
4931
4958
  }
4932
4959
  set(key, value) {
4933
4960
  if (value) {
4934
- this.values.push({ key: key, value, quoted: false });
4961
+ const existing = this.values.find(value => value.key === key);
4962
+ if (existing) {
4963
+ existing.value = value;
4964
+ }
4965
+ else {
4966
+ this.values.push({ key: key, value, quoted: false });
4967
+ }
4935
4968
  }
4936
4969
  }
4937
4970
  toLiteralMap() {
@@ -5074,10 +5107,7 @@ function compileInjectable(meta, resolveForwardRefs) {
5074
5107
  });
5075
5108
  }
5076
5109
  else {
5077
- result = {
5078
- statements: [],
5079
- expression: fn([], [new ReturnStatement(meta.useFactory.callFn([]))])
5080
- };
5110
+ result = { statements: [], expression: arrowFn([], meta.useFactory.callFn([])) };
5081
5111
  }
5082
5112
  }
5083
5113
  else if (meta.useValue !== undefined) {
@@ -5146,7 +5176,7 @@ function delegateToFactory(type, useType, unwrapForwardRefs) {
5146
5176
  return createFactoryFunction(unwrappedType);
5147
5177
  }
5148
5178
  function createFactoryFunction(type) {
5149
- return fn([new FnParam('t', DYNAMIC_TYPE)], [new ReturnStatement(type.prop('ɵfac').callFn([variable('t')]))]);
5179
+ return arrowFn([new FnParam('t', DYNAMIC_TYPE)], type.prop('ɵfac').callFn([variable('t')]));
5150
5180
  }
5151
5181
 
5152
5182
  const UNUSABLE_INTERPOLATION_REGEXPS = [
@@ -8759,38 +8789,58 @@ var OpKind;
8759
8789
  * An attribute that has been extracted for inclusion in the consts array.
8760
8790
  */
8761
8791
  OpKind[OpKind["ExtractedAttribute"] = 25] = "ExtractedAttribute";
8792
+ /**
8793
+ * An operation that configures a `@defer` block.
8794
+ */
8795
+ OpKind[OpKind["Defer"] = 26] = "Defer";
8796
+ /**
8797
+ * An IR operation that provides secondary templates of a `@defer` block.
8798
+ */
8799
+ OpKind[OpKind["DeferSecondaryBlock"] = 27] = "DeferSecondaryBlock";
8800
+ /**
8801
+ * An operation that controls when a `@defer` loads.
8802
+ */
8803
+ OpKind[OpKind["DeferOn"] = 28] = "DeferOn";
8762
8804
  /**
8763
8805
  * An i18n message that has been extracted for inclusion in the consts array.
8764
8806
  */
8765
- OpKind[OpKind["ExtractedMessage"] = 26] = "ExtractedMessage";
8807
+ OpKind[OpKind["ExtractedMessage"] = 29] = "ExtractedMessage";
8766
8808
  /**
8767
8809
  * A host binding property.
8768
8810
  */
8769
- OpKind[OpKind["HostProperty"] = 27] = "HostProperty";
8811
+ OpKind[OpKind["HostProperty"] = 30] = "HostProperty";
8770
8812
  /**
8771
8813
  * A namespace change, which causes the subsequent elements to be processed as either HTML or SVG.
8772
8814
  */
8773
- OpKind[OpKind["Namespace"] = 28] = "Namespace";
8815
+ OpKind[OpKind["Namespace"] = 31] = "Namespace";
8774
8816
  /**
8775
8817
  * Configure a content projeciton definition for the view.
8776
8818
  */
8777
- OpKind[OpKind["ProjectionDef"] = 29] = "ProjectionDef";
8819
+ OpKind[OpKind["ProjectionDef"] = 32] = "ProjectionDef";
8778
8820
  /**
8779
8821
  * Create a content projection slot.
8780
8822
  */
8781
- OpKind[OpKind["Projection"] = 30] = "Projection";
8823
+ OpKind[OpKind["Projection"] = 33] = "Projection";
8782
8824
  /**
8783
8825
  * The start of an i18n block.
8784
8826
  */
8785
- OpKind[OpKind["I18nStart"] = 31] = "I18nStart";
8827
+ OpKind[OpKind["I18nStart"] = 34] = "I18nStart";
8786
8828
  /**
8787
8829
  * A self-closing i18n on a single element.
8788
8830
  */
8789
- OpKind[OpKind["I18n"] = 32] = "I18n";
8831
+ OpKind[OpKind["I18n"] = 35] = "I18n";
8790
8832
  /**
8791
8833
  * The end of an i18n block.
8792
8834
  */
8793
- OpKind[OpKind["I18nEnd"] = 33] = "I18nEnd";
8835
+ OpKind[OpKind["I18nEnd"] = 36] = "I18nEnd";
8836
+ /**
8837
+ * An expression in an i18n message.
8838
+ */
8839
+ OpKind[OpKind["I18nExpression"] = 37] = "I18nExpression";
8840
+ /**
8841
+ * An instruction that applies a set of i18n expressions.
8842
+ */
8843
+ OpKind[OpKind["I18nApply"] = 38] = "I18nApply";
8794
8844
  })(OpKind || (OpKind = {}));
8795
8845
  /**
8796
8846
  * Distinguishes different kinds of IR expressions.
@@ -8881,6 +8931,10 @@ var ExpressionKind;
8881
8931
  * An expression that will cause a literal slot index to be emitted.
8882
8932
  */
8883
8933
  ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 20] = "SlotLiteralExpr";
8934
+ /**
8935
+ * A test expression for a conditional op.
8936
+ */
8937
+ ExpressionKind[ExpressionKind["ConditionalCase"] = 21] = "ConditionalCase";
8884
8938
  })(ExpressionKind || (ExpressionKind = {}));
8885
8939
  /**
8886
8940
  * Distinguishes between different kinds of `SemanticVariable`s.
@@ -8922,6 +8976,15 @@ var SanitizerFn;
8922
8976
  SanitizerFn[SanitizerFn["ResourceUrl"] = 4] = "ResourceUrl";
8923
8977
  SanitizerFn[SanitizerFn["IframeAttribute"] = 5] = "IframeAttribute";
8924
8978
  })(SanitizerFn || (SanitizerFn = {}));
8979
+ /**
8980
+ * Enumeration of the different kinds of `@defer` secondary blocks.
8981
+ */
8982
+ var DeferSecondaryKind;
8983
+ (function (DeferSecondaryKind) {
8984
+ DeferSecondaryKind[DeferSecondaryKind["Loading"] = 0] = "Loading";
8985
+ DeferSecondaryKind[DeferSecondaryKind["Placeholder"] = 1] = "Placeholder";
8986
+ DeferSecondaryKind[DeferSecondaryKind["Error"] = 2] = "Error";
8987
+ })(DeferSecondaryKind || (DeferSecondaryKind = {}));
8925
8988
  /**
8926
8989
  * Enumeration of the types of attributes which can be applied to an element.
8927
8990
  */
@@ -8977,6 +9040,10 @@ const ConsumesVarsTrait = Symbol('ConsumesVars');
8977
9040
  * Marker symbol for `UsesVarOffset` trait.
8978
9041
  */
8979
9042
  const UsesVarOffset = Symbol('UsesVarOffset');
9043
+ /**
9044
+ * Marker symbol for `HasConst` trait.
9045
+ */
9046
+ const HasConst = Symbol('HasConst');
8980
9047
  /**
8981
9048
  * Default values for most `ConsumesSlotOpTrait` fields (used with the spread operator to initialize
8982
9049
  * implementors of the trait).
@@ -8992,7 +9059,7 @@ const TRAIT_CONSUMES_SLOT = {
8992
9059
  */
8993
9060
  const TRAIT_USES_SLOT_INDEX = {
8994
9061
  [UsesSlotIndex]: true,
8995
- slot: null,
9062
+ targetSlot: null,
8996
9063
  };
8997
9064
  /**
8998
9065
  * Default values for most `DependsOnSlotContextOpTrait` fields (used with the spread operator to
@@ -9016,6 +9083,14 @@ const TRAIT_USES_VAR_OFFSET = {
9016
9083
  [UsesVarOffset]: true,
9017
9084
  varOffset: null,
9018
9085
  };
9086
+ /**
9087
+ * Default values for `HasConst` fields (used with the spread operator to initialize
9088
+ * implementors of this trait).
9089
+ */
9090
+ const TRAIT_HAS_CONST = {
9091
+ [HasConst]: true,
9092
+ constIndex: null,
9093
+ };
9019
9094
  /**
9020
9095
  * Test whether an operation implements `ConsumesSlotOpTrait`.
9021
9096
  */
@@ -9040,6 +9115,9 @@ function hasUsesVarOffsetTrait(expr) {
9040
9115
  function hasUsesSlotIndexTrait(value) {
9041
9116
  return value[UsesSlotIndex] === true;
9042
9117
  }
9118
+ function hasConstTrait(value) {
9119
+ return value[HasConst] === true;
9120
+ }
9043
9121
 
9044
9122
  /**
9045
9123
  * Create a `StatementOp`.
@@ -9078,11 +9156,12 @@ const NEW_OP = {
9078
9156
  /**
9079
9157
  * Create an `InterpolationTextOp`.
9080
9158
  */
9081
- function createInterpolateTextOp(xref, interpolation, sourceSpan) {
9159
+ function createInterpolateTextOp(xref, interpolation, i18nPlaceholders, sourceSpan) {
9082
9160
  return {
9083
9161
  kind: OpKind.InterpolateText,
9084
9162
  target: xref,
9085
9163
  interpolation,
9164
+ i18nPlaceholders,
9086
9165
  sourceSpan,
9087
9166
  ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
9088
9167
  ...TRAIT_CONSUMES_VARS,
@@ -9220,17 +9299,47 @@ function createAdvanceOp(delta, sourceSpan) {
9220
9299
  /**
9221
9300
  * Create a conditional op, which will display an embedded view according to a condtion.
9222
9301
  */
9223
- function createConditionalOp(target, test, sourceSpan) {
9302
+ function createConditionalOp(target, test, conditions, sourceSpan) {
9224
9303
  return {
9225
9304
  kind: OpKind.Conditional,
9226
9305
  target,
9227
9306
  test,
9228
- conditions: [],
9307
+ conditions,
9229
9308
  processed: null,
9230
9309
  sourceSpan,
9310
+ contextValue: null,
9231
9311
  ...NEW_OP,
9232
9312
  ...TRAIT_USES_SLOT_INDEX,
9233
9313
  ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
9314
+ ...TRAIT_CONSUMES_VARS,
9315
+ };
9316
+ }
9317
+ /**
9318
+ * Create an i18n expression op.
9319
+ */
9320
+ function createI18nExpressionOp(owner, expression, i18nPlaceholder, sourceSpan) {
9321
+ return {
9322
+ kind: OpKind.I18nExpression,
9323
+ owner,
9324
+ target: owner,
9325
+ expression,
9326
+ i18nPlaceholder,
9327
+ sourceSpan,
9328
+ ...NEW_OP,
9329
+ ...TRAIT_CONSUMES_VARS,
9330
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
9331
+ };
9332
+ }
9333
+ /**
9334
+ * Creates an op to apply i18n expression ops.
9335
+ */
9336
+ function createI18nApplyOp(target, sourceSpan) {
9337
+ return {
9338
+ kind: OpKind.I18nApply,
9339
+ target,
9340
+ sourceSpan,
9341
+ ...NEW_OP,
9342
+ ...TRAIT_USES_SLOT_INDEX,
9234
9343
  };
9235
9344
  }
9236
9345
 
@@ -9281,7 +9390,7 @@ class ReferenceExpr extends ExpressionBase {
9281
9390
  this.offset = offset;
9282
9391
  this.kind = ExpressionKind.Reference;
9283
9392
  this[_a] = true;
9284
- this.slot = null;
9393
+ this.targetSlot = null;
9285
9394
  }
9286
9395
  visitExpression() { }
9287
9396
  isEquivalent(e) {
@@ -9293,7 +9402,7 @@ class ReferenceExpr extends ExpressionBase {
9293
9402
  transformInternalExpressions() { }
9294
9403
  clone() {
9295
9404
  const expr = new ReferenceExpr(this.target, this.offset);
9296
- expr.slot = this.slot;
9405
+ expr.targetSlot = this.targetSlot;
9297
9406
  return expr;
9298
9407
  }
9299
9408
  }
@@ -9530,7 +9639,7 @@ class PipeBindingExpr extends ExpressionBase {
9530
9639
  this[_d] = true;
9531
9640
  this[_e] = true;
9532
9641
  this[_f] = true;
9533
- this.slot = null;
9642
+ this.targetSlot = null;
9534
9643
  this.varOffset = null;
9535
9644
  }
9536
9645
  visitExpression(visitor, context) {
@@ -9551,7 +9660,7 @@ class PipeBindingExpr extends ExpressionBase {
9551
9660
  }
9552
9661
  clone() {
9553
9662
  const r = new PipeBindingExpr(this.target, this.name, this.args.map(a => a.clone()));
9554
- r.slot = this.slot;
9663
+ r.targetSlot = this.targetSlot;
9555
9664
  r.varOffset = this.varOffset;
9556
9665
  return r;
9557
9666
  }
@@ -9568,7 +9677,7 @@ class PipeBindingVariadicExpr extends ExpressionBase {
9568
9677
  this[_g] = true;
9569
9678
  this[_h] = true;
9570
9679
  this[_j] = true;
9571
- this.slot = null;
9680
+ this.targetSlot = null;
9572
9681
  this.varOffset = null;
9573
9682
  }
9574
9683
  visitExpression(visitor, context) {
@@ -9585,7 +9694,7 @@ class PipeBindingVariadicExpr extends ExpressionBase {
9585
9694
  }
9586
9695
  clone() {
9587
9696
  const r = new PipeBindingVariadicExpr(this.target, this.name, this.args.clone(), this.numArgs);
9588
- r.slot = this.slot;
9697
+ r.targetSlot = this.targetSlot;
9589
9698
  r.varOffset = this.varOffset;
9590
9699
  return r;
9591
9700
  }
@@ -9785,20 +9894,56 @@ class SlotLiteralExpr extends ExpressionBase {
9785
9894
  this.target = target;
9786
9895
  this.kind = ExpressionKind.SlotLiteralExpr;
9787
9896
  this[_k] = true;
9788
- this.slot = null;
9897
+ this.targetSlot = null;
9789
9898
  }
9790
9899
  visitExpression(visitor, context) { }
9791
9900
  isEquivalent(e) {
9792
- return e instanceof SlotLiteralExpr && e.target === this.target && e.slot === this.slot;
9901
+ return e instanceof SlotLiteralExpr && e.target === this.target &&
9902
+ e.targetSlot === this.targetSlot;
9793
9903
  }
9794
9904
  isConstant() {
9795
9905
  return true;
9796
9906
  }
9797
9907
  clone() {
9798
- return new SlotLiteralExpr(this.target);
9908
+ const copy = new SlotLiteralExpr(this.target);
9909
+ copy.targetSlot = this.targetSlot;
9910
+ return copy;
9799
9911
  }
9800
9912
  transformInternalExpressions() { }
9801
9913
  }
9914
+ class ConditionalCaseExpr extends ExpressionBase {
9915
+ /**
9916
+ * Create an expression for one branch of a conditional.
9917
+ * @param expr The expression to be tested for this case. Might be null, as in an `else` case.
9918
+ * @param target The Xref of the view to be displayed if this condition is true.
9919
+ */
9920
+ constructor(expr, target, alias = null) {
9921
+ super();
9922
+ this.expr = expr;
9923
+ this.target = target;
9924
+ this.alias = alias;
9925
+ this.kind = ExpressionKind.ConditionalCase;
9926
+ }
9927
+ visitExpression(visitor, context) {
9928
+ if (this.expr !== null) {
9929
+ this.expr.visitExpression(visitor, context);
9930
+ }
9931
+ }
9932
+ isEquivalent(e) {
9933
+ return e instanceof ConditionalCaseExpr && e.expr === this.expr;
9934
+ }
9935
+ isConstant() {
9936
+ return true;
9937
+ }
9938
+ clone() {
9939
+ return new ConditionalCaseExpr(this.expr, this.target);
9940
+ }
9941
+ transformInternalExpressions(transform, flags) {
9942
+ if (this.expr !== null) {
9943
+ this.expr = transformExpressionsInExpression(this.expr, transform, flags);
9944
+ }
9945
+ }
9946
+ }
9802
9947
  /**
9803
9948
  * Visits all `Expression`s in the AST of `op` with the `visitor` function.
9804
9949
  */
@@ -9851,6 +9996,9 @@ function transformExpressionsInOp(op, transform, flags) {
9851
9996
  op.sanitizer =
9852
9997
  op.sanitizer && transformExpressionsInExpression(op.sanitizer, transform, flags);
9853
9998
  break;
9999
+ case OpKind.I18nExpression:
10000
+ op.expression = transformExpressionsInExpression(op.expression, transform, flags);
10001
+ break;
9854
10002
  case OpKind.InterpolateText:
9855
10003
  transformExpressionsInInterpolation(op.interpolation, transform, flags);
9856
10004
  break;
@@ -9862,15 +10010,18 @@ function transformExpressionsInOp(op, transform, flags) {
9862
10010
  break;
9863
10011
  case OpKind.Conditional:
9864
10012
  for (const condition of op.conditions) {
9865
- if (condition[1] === null) {
10013
+ if (condition.expr === null) {
9866
10014
  // This is a default case.
9867
10015
  continue;
9868
10016
  }
9869
- condition[1] = transformExpressionsInExpression(condition[1], transform, flags);
10017
+ condition.expr = transformExpressionsInExpression(condition.expr, transform, flags);
9870
10018
  }
9871
10019
  if (op.processed !== null) {
9872
10020
  op.processed = transformExpressionsInExpression(op.processed, transform, flags);
9873
10021
  }
10022
+ if (op.contextValue !== null) {
10023
+ op.contextValue = transformExpressionsInExpression(op.contextValue, transform, flags);
10024
+ }
9874
10025
  break;
9875
10026
  case OpKind.Listener:
9876
10027
  for (const innerOp of op.handlerOps) {
@@ -9887,18 +10038,20 @@ function transformExpressionsInOp(op, transform, flags) {
9887
10038
  transformExpressionsInStatement(statement, transform, flags);
9888
10039
  }
9889
10040
  break;
10041
+ case OpKind.I18n:
9890
10042
  case OpKind.I18nStart:
9891
- for (const placeholder in op.tagNameParams) {
9892
- op.tagNameParams[placeholder] =
9893
- transformExpressionsInExpression(op.tagNameParams[placeholder], transform, flags);
10043
+ for (const [placeholder, expression] of op.params) {
10044
+ op.params.set(placeholder, transformExpressionsInExpression(expression, transform, flags));
9894
10045
  }
9895
10046
  break;
10047
+ case OpKind.Defer:
10048
+ case OpKind.DeferSecondaryBlock:
10049
+ case OpKind.DeferOn:
9896
10050
  case OpKind.Projection:
9897
10051
  case OpKind.ProjectionDef:
9898
10052
  case OpKind.Element:
9899
10053
  case OpKind.ElementStart:
9900
10054
  case OpKind.ElementEnd:
9901
- case OpKind.I18n:
9902
10055
  case OpKind.I18nEnd:
9903
10056
  case OpKind.Container:
9904
10057
  case OpKind.ContainerStart:
@@ -9910,6 +10063,7 @@ function transformExpressionsInOp(op, transform, flags) {
9910
10063
  case OpKind.Pipe:
9911
10064
  case OpKind.Advance:
9912
10065
  case OpKind.Namespace:
10066
+ case OpKind.I18nApply:
9913
10067
  // These operations contain no expressions.
9914
10068
  break;
9915
10069
  default:
@@ -10190,7 +10344,7 @@ class OpList {
10190
10344
  // Replace `oldOp` with the chain `first` -> `last`.
10191
10345
  if (oldPrev !== null) {
10192
10346
  oldPrev.next = first;
10193
- first.prev = oldOp.prev;
10347
+ first.prev = oldPrev;
10194
10348
  }
10195
10349
  if (oldNext !== null) {
10196
10350
  oldNext.prev = last;
@@ -10297,7 +10451,7 @@ function isElementOrContainerOp(op) {
10297
10451
  /**
10298
10452
  * Create an `ElementStartOp`.
10299
10453
  */
10300
- function createElementStartOp(tag, xref, namespace, i18n, sourceSpan) {
10454
+ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan) {
10301
10455
  return {
10302
10456
  kind: OpKind.ElementStart,
10303
10457
  xref,
@@ -10306,7 +10460,7 @@ function createElementStartOp(tag, xref, namespace, i18n, sourceSpan) {
10306
10460
  localRefs: [],
10307
10461
  nonBindable: false,
10308
10462
  namespace,
10309
- i18n,
10463
+ i18nPlaceholder,
10310
10464
  sourceSpan,
10311
10465
  ...TRAIT_CONSUMES_SLOT,
10312
10466
  ...NEW_OP,
@@ -10315,19 +10469,19 @@ function createElementStartOp(tag, xref, namespace, i18n, sourceSpan) {
10315
10469
  /**
10316
10470
  * Create a `TemplateOp`.
10317
10471
  */
10318
- function createTemplateOp(xref, tag, namespace, controlFlow, i18n, sourceSpan) {
10472
+ function createTemplateOp(xref, tag, namespace, generatedInBlock, i18nPlaceholder, sourceSpan) {
10319
10473
  return {
10320
10474
  kind: OpKind.Template,
10321
10475
  xref,
10322
10476
  attributes: null,
10323
10477
  tag,
10324
- controlFlow,
10478
+ block: generatedInBlock,
10325
10479
  decls: null,
10326
10480
  vars: null,
10327
10481
  localRefs: [],
10328
10482
  nonBindable: false,
10329
10483
  namespace,
10330
- i18n,
10484
+ i18nPlaceholder,
10331
10485
  sourceSpan,
10332
10486
  ...TRAIT_CONSUMES_SLOT,
10333
10487
  ...NEW_OP,
@@ -10432,11 +10586,9 @@ function createProjectionOp(xref, selector) {
10432
10586
  attributes: null,
10433
10587
  localRefs: [],
10434
10588
  nonBindable: false,
10435
- i18n: undefined,
10436
10589
  sourceSpan: null,
10437
10590
  ...NEW_OP,
10438
10591
  ...TRAIT_CONSUMES_SLOT,
10439
- ...TRAIT_USES_SLOT_INDEX,
10440
10592
  };
10441
10593
  }
10442
10594
  /**
@@ -10452,6 +10604,42 @@ function createExtractedAttributeOp(target, bindingKind, name, expression) {
10452
10604
  ...NEW_OP,
10453
10605
  };
10454
10606
  }
10607
+ function createDeferOp(xref, main, sourceSpan) {
10608
+ return {
10609
+ kind: OpKind.Defer,
10610
+ xref,
10611
+ target: main,
10612
+ loading: null,
10613
+ placeholder: null,
10614
+ error: null,
10615
+ sourceSpan,
10616
+ ...NEW_OP,
10617
+ ...TRAIT_CONSUMES_SLOT,
10618
+ ...TRAIT_USES_SLOT_INDEX,
10619
+ };
10620
+ }
10621
+ function createDeferSecondaryOp(deferOp, secondaryView, secondaryBlockKind) {
10622
+ return {
10623
+ kind: OpKind.DeferSecondaryBlock,
10624
+ deferOp,
10625
+ target: secondaryView,
10626
+ secondaryBlockKind,
10627
+ constValue: null,
10628
+ makeExpression: literalOrArrayLiteral$1,
10629
+ ...NEW_OP,
10630
+ ...TRAIT_USES_SLOT_INDEX,
10631
+ ...TRAIT_HAS_CONST,
10632
+ };
10633
+ }
10634
+ function createDeferOnOp(xref, sourceSpan) {
10635
+ return {
10636
+ kind: OpKind.DeferOn,
10637
+ xref,
10638
+ sourceSpan,
10639
+ ...NEW_OP,
10640
+ ...TRAIT_CONSUMES_SLOT,
10641
+ };
10642
+ }
10455
10643
  /**
10456
10644
  * Create an `ExtractedMessageOp`.
10457
10645
  */
@@ -10467,13 +10655,15 @@ function createExtractedMessageOp(owner, expression, statements) {
10467
10655
  /**
10468
10656
  * Create an `I18nStartOp`.
10469
10657
  */
10470
- function createI18nStartOp(xref, i18n) {
10658
+ function createI18nStartOp(xref, message, root) {
10471
10659
  return {
10472
10660
  kind: OpKind.I18nStart,
10473
10661
  xref,
10474
- i18n,
10475
- tagNameParams: {},
10662
+ root: root ?? xref,
10663
+ message,
10664
+ params: new Map(),
10476
10665
  messageIndex: null,
10666
+ subTemplateIndex: null,
10477
10667
  ...NEW_OP,
10478
10668
  ...TRAIT_CONSUMES_SLOT,
10479
10669
  };
@@ -10488,6 +10678,12 @@ function createI18nEndOp(xref) {
10488
10678
  ...NEW_OP,
10489
10679
  };
10490
10680
  }
10681
+ function literalOrArrayLiteral$1(value) {
10682
+ if (Array.isArray(value)) {
10683
+ return literalArr(value.map(literalOrArrayLiteral$1));
10684
+ }
10685
+ return literal(value, INFERRED_TYPE);
10686
+ }
10491
10687
 
10492
10688
  function createHostPropertyOp(name, expression, isAnimationTrigger, sourceSpan) {
10493
10689
  return {
@@ -10501,6 +10697,12 @@ function createHostPropertyOp(name, expression, isAnimationTrigger, sourceSpan)
10501
10697
  };
10502
10698
  }
10503
10699
 
10700
+ /**
10701
+ * When referenced in the template's context parameters, this indicates a reference to the entire
10702
+ * context object, rather than a specific parameter.
10703
+ */
10704
+ const CTX_REF = 'CTX_REF_MARKER';
10705
+
10504
10706
  var CompilationJobKind;
10505
10707
  (function (CompilationJobKind) {
10506
10708
  CompilationJobKind[CompilationJobKind["Tmpl"] = 0] = "Tmpl";
@@ -10688,10 +10890,16 @@ function phaseVarCounting(job) {
10688
10890
  // First, count the vars used in each view, and update the view-level counter.
10689
10891
  for (const unit of job.units) {
10690
10892
  let varCount = 0;
10893
+ // Count variables on top-level ops first. Don't explore nested expressions just yet.
10691
10894
  for (const op of unit.ops()) {
10692
10895
  if (hasConsumesVarsTrait(op)) {
10693
10896
  varCount += varsUsedByOp(op);
10694
10897
  }
10898
+ }
10899
+ // Count variables on expressions inside ops. We do this later because some of these expressions
10900
+ // might be conditional (e.g. `pipeBinding` inside of a ternary), and we don't want to interfere
10901
+ // with indices for top-level binding slots (e.g. `property`).
10902
+ for (const op of unit.ops()) {
10695
10903
  visitExpressionsInOp(op, expr => {
10696
10904
  if (!isIrExpression(expr)) {
10697
10905
  return;
@@ -10752,6 +10960,9 @@ function varsUsedByOp(op) {
10752
10960
  case OpKind.InterpolateText:
10753
10961
  // `ir.InterpolateTextOp`s use a variable slot for each dynamic expression.
10754
10962
  return op.interpolation.expressions.length;
10963
+ case OpKind.I18nExpression:
10964
+ case OpKind.Conditional:
10965
+ return 1;
10755
10966
  default:
10756
10967
  throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
10757
10968
  }
@@ -10823,6 +11034,60 @@ function removeAnys(e) {
10823
11034
  return e;
10824
11035
  }
10825
11036
 
11037
+ /**
11038
+ * Adds apply operations after i18n expressions.
11039
+ */
11040
+ function phaseApplyI18nExpressions(job) {
11041
+ for (const unit of job.units) {
11042
+ for (const op of unit.update) {
11043
+ // Only add apply after expressions that are not followed by more expressions.
11044
+ if (op.kind === OpKind.I18nExpression && needsApplication(op)) {
11045
+ // TODO: what should be the source span for the apply op?
11046
+ OpList.insertAfter(createI18nApplyOp(op.owner, null), op);
11047
+ }
11048
+ }
11049
+ }
11050
+ }
11051
+ /**
11052
+ * Checks whether the given expression op needs to be followed with an apply op.
11053
+ */
11054
+ function needsApplication(op) {
11055
+ // If the next op is not another expression, we need to apply.
11056
+ if (op.next?.kind !== OpKind.I18nExpression) {
11057
+ return true;
11058
+ }
11059
+ // If the next op is an expression targeting a different i18n block, we need to apply.
11060
+ if (op.next.owner !== op.owner) {
11061
+ return true;
11062
+ }
11063
+ return false;
11064
+ }
11065
+
11066
+ /**
11067
+ * Updates i18n expression ops to depend on the last slot in their owning i18n block.
11068
+ */
11069
+ function phaseAssignI18nSlotDependencies(job) {
11070
+ const i18nLastSlotConsumers = new Map();
11071
+ let lastSlotConsumer = null;
11072
+ for (const unit of job.units) {
11073
+ // Record the last consumed slot before each i18n end instruction.
11074
+ for (const op of unit.create) {
11075
+ if (op.kind === OpKind.I18nEnd) {
11076
+ i18nLastSlotConsumers.set(op.xref, lastSlotConsumer);
11077
+ }
11078
+ if (hasConsumesSlotTrait(op)) {
11079
+ lastSlotConsumer = op.xref;
11080
+ }
11081
+ }
11082
+ // Assign i18n expressions to target the last slot in its owning block.
11083
+ for (const op of unit.update) {
11084
+ if (op.kind === OpKind.I18nExpression) {
11085
+ op.target = i18nLastSlotConsumers.get(op.owner);
11086
+ }
11087
+ }
11088
+ }
11089
+ }
11090
+
10826
11091
  /**
10827
11092
  * Gets a map of all elements in the given view by their xref id.
10828
11093
  */
@@ -10984,14 +11249,20 @@ function phaseBindingSpecialization(job) {
10984
11249
  }
10985
11250
 
10986
11251
  const CHAINABLE = new Set([
10987
- Identifiers.elementStart,
10988
- Identifiers.elementEnd,
11252
+ Identifiers.attribute,
11253
+ Identifiers.classProp,
10989
11254
  Identifiers.element,
10990
- Identifiers.property,
11255
+ Identifiers.elementContainer,
11256
+ Identifiers.elementContainerEnd,
11257
+ Identifiers.elementContainerStart,
11258
+ Identifiers.elementEnd,
11259
+ Identifiers.elementStart,
10991
11260
  Identifiers.hostProperty,
10992
- Identifiers.syntheticHostProperty,
11261
+ Identifiers.i18nExp,
11262
+ Identifiers.listener,
11263
+ Identifiers.listener,
11264
+ Identifiers.property,
10993
11265
  Identifiers.styleProp,
10994
- Identifiers.attribute,
10995
11266
  Identifiers.stylePropInterpolate1,
10996
11267
  Identifiers.stylePropInterpolate2,
10997
11268
  Identifiers.stylePropInterpolate3,
@@ -11001,13 +11272,8 @@ const CHAINABLE = new Set([
11001
11272
  Identifiers.stylePropInterpolate7,
11002
11273
  Identifiers.stylePropInterpolate8,
11003
11274
  Identifiers.stylePropInterpolateV,
11004
- Identifiers.classProp,
11005
- Identifiers.listener,
11006
- Identifiers.elementContainerStart,
11007
- Identifiers.elementContainerEnd,
11008
- Identifiers.elementContainer,
11009
- Identifiers.listener,
11010
11275
  Identifiers.syntheticHostListener,
11276
+ Identifiers.syntheticHostProperty,
11011
11277
  Identifiers.templateCreate,
11012
11278
  ]);
11013
11279
  /**
@@ -11084,9 +11350,9 @@ function phaseConditionals(job) {
11084
11350
  }
11085
11351
  let test;
11086
11352
  // Any case with a `null` condition is `default`. If one exists, default to it instead.
11087
- const defaultCase = op.conditions.findIndex(([xref, cond]) => cond === null);
11353
+ const defaultCase = op.conditions.findIndex((cond) => cond.expr === null);
11088
11354
  if (defaultCase >= 0) {
11089
- const [xref, cond] = op.conditions.splice(defaultCase, 1)[0];
11355
+ const xref = op.conditions.splice(defaultCase, 1)[0].target;
11090
11356
  test = new SlotLiteralExpr(xref);
11091
11357
  }
11092
11358
  else {
@@ -11094,13 +11360,26 @@ function phaseConditionals(job) {
11094
11360
  test = literal(-1);
11095
11361
  }
11096
11362
  // Switch expressions assign their main test to a temporary, to avoid re-executing it.
11097
- let tmp = new AssignTemporaryExpr(op.test, job.allocateXrefId());
11098
- // For each remaining condition, test whether the temporary satifies the check.
11363
+ let tmp = op.test == null ? null : new AssignTemporaryExpr(op.test, job.allocateXrefId());
11364
+ // For each remaining condition, test whether the temporary satifies the check. (If no temp is
11365
+ // present, just check each expression directly.)
11099
11366
  for (let i = op.conditions.length - 1; i >= 0; i--) {
11100
- const useTmp = i === 0 ? tmp : new ReadTemporaryExpr(tmp.xref);
11101
- const [xref, check] = op.conditions[i];
11102
- const comparison = new BinaryOperatorExpr(BinaryOperator.Identical, useTmp, check);
11103
- test = new ConditionalExpr(comparison, new SlotLiteralExpr(xref), test);
11367
+ let conditionalCase = op.conditions[i];
11368
+ if (conditionalCase.expr === null) {
11369
+ continue;
11370
+ }
11371
+ if (tmp !== null) {
11372
+ const useTmp = i === 0 ? tmp : new ReadTemporaryExpr(tmp.xref);
11373
+ conditionalCase.expr =
11374
+ new BinaryOperatorExpr(BinaryOperator.Identical, useTmp, conditionalCase.expr);
11375
+ }
11376
+ else if (conditionalCase.alias !== null) {
11377
+ const caseExpressionTemporaryXref = job.allocateXrefId();
11378
+ conditionalCase.expr =
11379
+ new AssignTemporaryExpr(conditionalCase.expr, caseExpressionTemporaryXref);
11380
+ op.contextValue = new ReadTemporaryExpr(caseExpressionTemporaryXref);
11381
+ }
11382
+ test = new ConditionalExpr(conditionalCase.expr, new SlotLiteralExpr(conditionalCase.target), test);
11104
11383
  }
11105
11384
  // Save the resulting aggregate Joost-expression.
11106
11385
  op.processed = test;
@@ -11162,14 +11441,15 @@ const BINARY_OPERATORS = new Map([
11162
11441
  ['||', BinaryOperator.Or],
11163
11442
  ['+', BinaryOperator.Plus],
11164
11443
  ]);
11165
- const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
11166
11444
  function namespaceForKey(namespacePrefixKey) {
11445
+ const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
11167
11446
  if (namespacePrefixKey === null) {
11168
11447
  return Namespace.HTML;
11169
11448
  }
11170
11449
  return NAMESPACES.get(namespacePrefixKey) ?? Namespace.HTML;
11171
11450
  }
11172
11451
  function keyForNamespace(namespace) {
11452
+ const NAMESPACES = new Map([['svg', Namespace.SVG], ['math', Namespace.Math]]);
11173
11453
  for (const [k, n] of NAMESPACES.entries()) {
11174
11454
  if (n === namespace) {
11175
11455
  return k;
@@ -11345,6 +11625,10 @@ const REPLACEMENTS = new Map([
11345
11625
  [OpKind.ContainerEnd, [OpKind.ContainerStart, OpKind.Container]],
11346
11626
  [OpKind.I18nEnd, [OpKind.I18nStart, OpKind.I18n]],
11347
11627
  ]);
11628
+ /**
11629
+ * Op kinds that should not prevent merging of start/end ops.
11630
+ */
11631
+ const IGNORED_OP_KINDS = new Set([OpKind.Pipe]);
11348
11632
  /**
11349
11633
  * Replace sequences of mergable elements (e.g. `ElementStart` and `ElementEnd`) with a consolidated
11350
11634
  * element (e.g. `Element`).
@@ -11352,15 +11636,22 @@ const REPLACEMENTS = new Map([
11352
11636
  function phaseEmptyElements(job) {
11353
11637
  for (const unit of job.units) {
11354
11638
  for (const op of unit.create) {
11639
+ // Find end ops that may be able to be merged.
11355
11640
  const opReplacements = REPLACEMENTS.get(op.kind);
11356
11641
  if (opReplacements === undefined) {
11357
11642
  continue;
11358
11643
  }
11359
11644
  const [startKind, mergedKind] = opReplacements;
11360
- if (op.prev !== null && op.prev.kind === startKind) {
11645
+ // Locate the previous (non-ignored) op.
11646
+ let prevOp = op.prev;
11647
+ while (prevOp !== null && IGNORED_OP_KINDS.has(prevOp.kind)) {
11648
+ prevOp = prevOp.prev;
11649
+ }
11650
+ // If the previous op is the corresponding start op, we can megre.
11651
+ if (prevOp !== null && prevOp.kind === startKind) {
11361
11652
  // Transmute the start instruction to the merged version. This is safe as they're designed
11362
11653
  // to be identical apart from the `kind`.
11363
- op.prev.kind = mergedKind;
11654
+ prevOp.kind = mergedKind;
11364
11655
  // Remove the end instruction.
11365
11656
  OpList.remove(op);
11366
11657
  }
@@ -11592,31 +11883,39 @@ function phaseGenerateAdvance(job) {
11592
11883
  }
11593
11884
 
11594
11885
  /**
11595
- * Generate i18n start and end isntructions to mark i18n blocks.
11886
+ * Locate projection slots, populate the each component's `ngContentSelectors` literal field,
11887
+ * populate `project` arguments, and generate the required `projectionDef` instruction for the job's
11888
+ * root view.
11596
11889
  */
11597
- function phaseGenerateI18nBlocks(job) {
11890
+ function phaseGenerateProjectionDef(job) {
11891
+ // TODO: Why does TemplateDefinitionBuilder force a shared constant?
11892
+ const share = job.compatibility === CompatibilityMode.TemplateDefinitionBuilder;
11893
+ // Collect all selectors from this component, and its nested views. Also, assign each projection a
11894
+ // unique ascending projection slot index.
11895
+ const selectors = [];
11896
+ let projectionSlotIndex = 0;
11598
11897
  for (const unit of job.units) {
11599
- const elements = getElementsByXrefId(unit);
11600
11898
  for (const op of unit.create) {
11601
- switch (op.kind) {
11602
- case OpKind.ElementEnd:
11603
- const start = elements.get(op.xref);
11604
- if (start.i18n instanceof Message) {
11605
- const id = job.allocateXrefId();
11606
- OpList.insertAfter(createI18nStartOp(id, start.i18n), start);
11607
- OpList.insertBefore(createI18nEndOp(id), op);
11608
- }
11609
- break;
11610
- case OpKind.Template:
11611
- if (op.i18n !== undefined) {
11612
- const id = job.allocateXrefId();
11613
- OpList.insertBefore(createI18nStartOp(id, op.i18n), op);
11614
- OpList.insertAfter(createI18nEndOp(id), op);
11615
- }
11616
- break;
11899
+ if (op.kind === OpKind.Projection) {
11900
+ selectors.push(op.selector);
11901
+ op.projectionSlotIndex = projectionSlotIndex++;
11617
11902
  }
11618
11903
  }
11619
11904
  }
11905
+ if (selectors.length > 0) {
11906
+ // Create the projectionDef array. If we only found a single wildcard selector, then we use the
11907
+ // default behavior with no arguments instead.
11908
+ let defExpr = null;
11909
+ if (selectors.length > 1 || selectors[0] !== '*') {
11910
+ const def = selectors.map(s => s === '*' ? s : parseSelectorToR3Selector(s));
11911
+ defExpr = job.pool.getConstLiteral(literalOrArrayLiteral(def), share);
11912
+ }
11913
+ // Create the ngContentSelectors constant.
11914
+ job.contentSelectors = job.pool.getConstLiteral(literalOrArrayLiteral(selectors), share);
11915
+ // The projection def instruction goes at the beginning of the root view, before any
11916
+ // `projection` instructions.
11917
+ job.root.create.prepend([createProjectionDefOp(defExpr)]);
11918
+ }
11620
11919
  }
11621
11920
 
11622
11921
  /**
@@ -11727,7 +12026,11 @@ function generateVariablesInScopeForView(view, scope) {
11727
12026
  }
11728
12027
  // Add variables for all context variables available in this scope's view.
11729
12028
  for (const [name, value] of view.job.views.get(scope.view).contextVariables) {
11730
- newOps.push(createVariableOp(view.job.allocateXrefId(), scope.contextVariables.get(name), new ReadPropExpr(new ContextExpr(scope.view), value)));
12029
+ const context = new ContextExpr(scope.view);
12030
+ // We either read the context, or, if the variable is CTX_REF, use the context directly.
12031
+ const variable = value === CTX_REF ? context : new ReadPropExpr(context, value);
12032
+ // Add the variable declaration.
12033
+ newOps.push(createVariableOp(view.job.allocateXrefId(), scope.contextVariables.get(name), variable));
11731
12034
  }
11732
12035
  // Add variables for all local references declared for elements in this scope.
11733
12036
  for (const ref of scope.references) {
@@ -11740,15 +12043,46 @@ function generateVariablesInScopeForView(view, scope) {
11740
12043
  return newOps;
11741
12044
  }
11742
12045
 
12046
+ /**
12047
+ * Looks for the HasConst trait, indicating that an op or expression has some data which
12048
+ * should be collected into the constant array. Capable of collecting either a single literal value,
12049
+ * or an array literal.
12050
+ */
12051
+ function phaseConstTraitCollection(job) {
12052
+ const collectGlobalConsts = (e) => {
12053
+ if (e instanceof ExpressionBase && hasConstTrait(e)) {
12054
+ // TODO: Figure out how to make this type narrowing work.
12055
+ const ea = e;
12056
+ if (ea.constValue !== null) {
12057
+ ea.constIndex = job.addConst(ea.constValue);
12058
+ }
12059
+ }
12060
+ return e;
12061
+ };
12062
+ for (const unit of job.units) {
12063
+ for (const op of unit.ops()) {
12064
+ if (hasConstTrait(op) && op.constValue !== null) {
12065
+ op.constIndex = job.addConst(op.makeExpression(op.constValue));
12066
+ }
12067
+ transformExpressionsInOp(op, collectGlobalConsts, VisitorContextFlag.None);
12068
+ }
12069
+ }
12070
+ }
12071
+
11743
12072
  const STYLE_DOT = 'style.';
11744
12073
  const CLASS_DOT = 'class.';
11745
12074
  const STYLE_BANG = 'style!';
11746
12075
  const CLASS_BANG = 'class!';
12076
+ const BANG_IMPORTANT = '!important';
11747
12077
  function phaseHostStylePropertyParsing(job) {
11748
12078
  for (const op of job.root.update) {
11749
12079
  if (op.kind !== OpKind.Binding) {
11750
12080
  continue;
11751
12081
  }
12082
+ if (op.name.endsWith(BANG_IMPORTANT)) {
12083
+ // Delete any `!important` suffixes from the binding name.
12084
+ op.name = op.name.substring(0, op.name.length - BANG_IMPORTANT.length);
12085
+ }
11752
12086
  if (op.name.startsWith(STYLE_DOT)) {
11753
12087
  op.bindingKind = BindingKind.StyleProperty;
11754
12088
  op.name = op.name.substring(STYLE_DOT.length);
@@ -11802,6 +12136,31 @@ function parseProperty$1(name) {
11802
12136
  return { property, suffix };
11803
12137
  }
11804
12138
 
12139
+ /**
12140
+ * Lifts i18n properties into the consts array.
12141
+ */
12142
+ function phaseI18nConstCollection(job) {
12143
+ // Serialize the extracted messages into the const array.
12144
+ // TODO: Use `Map` instead of object.
12145
+ const messageConstIndices = {};
12146
+ for (const unit of job.units) {
12147
+ for (const op of unit.create) {
12148
+ if (op.kind === OpKind.ExtractedMessage) {
12149
+ messageConstIndices[op.owner] = job.addConst(op.expression, op.statements);
12150
+ OpList.remove(op);
12151
+ }
12152
+ }
12153
+ }
12154
+ // Assign const index to i18n ops that messages were extracted from.
12155
+ for (const unit of job.units) {
12156
+ for (const op of unit.create) {
12157
+ if (op.kind === OpKind.I18nStart || op.kind === OpKind.I18n) {
12158
+ op.messageIndex = messageConstIndices[op.root];
12159
+ }
12160
+ }
12161
+ }
12162
+ }
12163
+
11805
12164
  function mapEntry(key, value) {
11806
12165
  return { key, value, quoted: false };
11807
12166
  }
@@ -16691,7 +17050,7 @@ class _Tokenizer {
16691
17050
  new PlainCharacterCursor(_file, range);
16692
17051
  this._preserveLineEndings = options.preserveLineEndings || false;
16693
17052
  this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false;
16694
- this._tokenizeBlocks = options.tokenizeBlocks || false;
17053
+ this._tokenizeBlocks = options.tokenizeBlocks ?? true;
16695
17054
  try {
16696
17055
  this._cursor.init();
16697
17056
  }
@@ -16749,7 +17108,7 @@ class _Tokenizer {
16749
17108
  this.handleError(e);
16750
17109
  }
16751
17110
  }
16752
- this._beginToken(28 /* TokenType.EOF */);
17111
+ this._beginToken(29 /* TokenType.EOF */);
16753
17112
  this._endToken([]);
16754
17113
  }
16755
17114
  _getBlockName() {
@@ -16770,7 +17129,7 @@ class _Tokenizer {
16770
17129
  }
16771
17130
  _consumeBlockStart(start) {
16772
17131
  this._beginToken(24 /* TokenType.BLOCK_OPEN_START */, start);
16773
- this._endToken([this._getBlockName()]);
17132
+ const startToken = this._endToken([this._getBlockName()]);
16774
17133
  if (this._cursor.peek() === $LPAREN) {
16775
17134
  // Advance past the opening paren.
16776
17135
  this._cursor.advance();
@@ -16778,14 +17137,22 @@ class _Tokenizer {
16778
17137
  this._consumeBlockParameters();
16779
17138
  // Allow spaces before the closing paren.
16780
17139
  this._attemptCharCodeUntilFn(isNotWhitespace);
16781
- // Skip over the closing paren.
16782
- this._requireCharCode($RPAREN);
16783
- // Allow spaces after the paren.
16784
- this._attemptCharCodeUntilFn(isNotWhitespace);
17140
+ if (this._attemptCharCode($RPAREN)) {
17141
+ // Allow spaces after the paren.
17142
+ this._attemptCharCodeUntilFn(isNotWhitespace);
17143
+ }
17144
+ else {
17145
+ startToken.type = 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */;
17146
+ return;
17147
+ }
17148
+ }
17149
+ if (this._attemptCharCode($LBRACE)) {
17150
+ this._beginToken(25 /* TokenType.BLOCK_OPEN_END */);
17151
+ this._endToken([]);
17152
+ }
17153
+ else {
17154
+ startToken.type = 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */;
16785
17155
  }
16786
- this._beginToken(25 /* TokenType.BLOCK_OPEN_END */);
16787
- this._requireCharCode($LBRACE);
16788
- this._endToken([]);
16789
17156
  }
16790
17157
  _consumeBlockEnd(start) {
16791
17158
  this._beginToken(26 /* TokenType.BLOCK_CLOSE */, start);
@@ -17758,7 +18125,7 @@ class _TreeBuilder {
17758
18125
  this._advance();
17759
18126
  }
17760
18127
  build() {
17761
- while (this._peek.type !== 28 /* TokenType.EOF */) {
18128
+ while (this._peek.type !== 29 /* TokenType.EOF */) {
17762
18129
  if (this._peek.type === 0 /* TokenType.TAG_OPEN_START */ ||
17763
18130
  this._peek.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) {
17764
18131
  this._consumeStartTag(this._advance());
@@ -17790,6 +18157,10 @@ class _TreeBuilder {
17790
18157
  this._closeVoidElement();
17791
18158
  this._consumeBlockClose(this._advance());
17792
18159
  }
18160
+ else if (this._peek.type === 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */) {
18161
+ this._closeVoidElement();
18162
+ this._consumeIncompleteBlock(this._advance());
18163
+ }
17793
18164
  else {
17794
18165
  // Skip all other tokens...
17795
18166
  this._advance();
@@ -17863,7 +18234,7 @@ class _TreeBuilder {
17863
18234
  if (!exp)
17864
18235
  return null;
17865
18236
  const end = this._advance();
17866
- exp.push({ type: 28 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan });
18237
+ exp.push({ type: 29 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan });
17867
18238
  // parse everything in between { and }
17868
18239
  const expansionCaseParser = new _TreeBuilder(exp, this.getTagDefinition);
17869
18240
  expansionCaseParser.build();
@@ -17903,7 +18274,7 @@ class _TreeBuilder {
17903
18274
  return null;
17904
18275
  }
17905
18276
  }
17906
- if (this._peek.type === 28 /* TokenType.EOF */) {
18277
+ if (this._peek.type === 29 /* TokenType.EOF */) {
17907
18278
  this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
17908
18279
  return null;
17909
18280
  }
@@ -18105,16 +18476,30 @@ class _TreeBuilder {
18105
18476
  const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
18106
18477
  const block = new Block(token.parts[0], parameters, [], span, startSpan);
18107
18478
  this._pushContainer(block, false);
18108
- return block;
18109
18479
  }
18110
18480
  _consumeBlockClose(token) {
18111
- const previousContainer = this._getContainer();
18112
18481
  if (!this._popContainer(null, Block, token.sourceSpan)) {
18113
- const context = previousContainer instanceof Element ?
18114
- `There is an unclosed "${previousContainer.name}" HTML tag that may have to be closed first.` :
18115
- `The block may have been closed earlier.`;
18116
- this.errors.push(TreeError.create(null, token.sourceSpan, `Unexpected closing block. ${context}`));
18482
+ this.errors.push(TreeError.create(null, token.sourceSpan, `Unexpected closing block. The block may have been closed earlier. ` +
18483
+ `If you meant to write the } character, you should use the "}" ` +
18484
+ `HTML entity instead.`));
18485
+ }
18486
+ }
18487
+ _consumeIncompleteBlock(token) {
18488
+ const parameters = [];
18489
+ while (this._peek.type === 27 /* TokenType.BLOCK_PARAMETER */) {
18490
+ const paramToken = this._advance();
18491
+ parameters.push(new BlockParameter(paramToken.parts[0], paramToken.sourceSpan));
18117
18492
  }
18493
+ const end = this._peek.sourceSpan.fullStart;
18494
+ const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
18495
+ // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
18496
+ const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
18497
+ const block = new Block(token.parts[0], parameters, [], span, startSpan);
18498
+ this._pushContainer(block, false);
18499
+ // Incomplete blocks don't have children so we close them immediately and report an error.
18500
+ this._popContainer(null, Block, null);
18501
+ this.errors.push(TreeError.create(token.parts[0], span, `Incomplete block "${token.parts[0]}". If you meant to write the @ character, ` +
18502
+ `you should use the "@" HTML entity instead.`));
18118
18503
  }
18119
18504
  _getContainer() {
18120
18505
  return this._containerStack.length > 0 ? this._containerStack[this._containerStack.length - 1] :
@@ -18668,17 +19053,20 @@ function phaseI18nMessageExtraction(job) {
18668
19053
  const fileBasedI18nSuffix = job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
18669
19054
  for (const unit of job.units) {
18670
19055
  for (const op of unit.create) {
18671
- if (op.kind === OpKind.I18nStart && op.i18n instanceof Message) {
18672
- // Sort the params map to match the ordering in TemplateDefinitionBuilder.
18673
- const params = Object.fromEntries(Object.entries(op.tagNameParams).sort());
18674
- const mainVar = variable(job.pool.uniqueName(TRANSLATION_VAR_PREFIX));
18675
- // Closure Compiler requires const names to start with `MSG_` but disallows any other const
18676
- // to start with `MSG_`. We define a variable starting with `MSG_` just for the
18677
- // `goog.getMsg` call
18678
- const closureVar = i18nGenerateClosureVar(job.pool, op.i18n.id, fileBasedI18nSuffix, job.i18nUseExternalIds);
18679
- // TODO: figure out transformFn.
18680
- const statements = getTranslationDeclStmts$1(op.i18n, mainVar, closureVar, params, undefined /*transformFn*/);
18681
- unit.create.push(createExtractedMessageOp(op.xref, mainVar, statements));
19056
+ if ((op.kind === OpKind.I18nStart || op.kind === OpKind.I18n)) {
19057
+ // Only extract messages from root i18n ops, not sub-template ones.
19058
+ if (op.xref === op.root) {
19059
+ // Sort the params map to match the ordering in TemplateDefinitionBuilder.
19060
+ const params = new Map([...op.params.entries()].sort());
19061
+ const mainVar = variable(job.pool.uniqueName(TRANSLATION_VAR_PREFIX));
19062
+ // Closure Compiler requires const names to start with `MSG_` but disallows any other
19063
+ // const to start with `MSG_`. We define a variable starting with `MSG_` just for the
19064
+ // `goog.getMsg` call
19065
+ const closureVar = i18nGenerateClosureVar(job.pool, op.message.id, fileBasedI18nSuffix, job.i18nUseExternalIds);
19066
+ // TODO: figure out transformFn.
19067
+ const statements = getTranslationDeclStmts$1(op.message, mainVar, closureVar, params, undefined /*transformFn*/);
19068
+ unit.create.push(createExtractedMessageOp(op.xref, mainVar, statements));
19069
+ }
18682
19070
  }
18683
19071
  }
18684
19072
  }
@@ -18709,10 +19097,11 @@ function phaseI18nMessageExtraction(job) {
18709
19097
  * post-processing).
18710
19098
  * @returns An array of statements that defined a given translation.
18711
19099
  */
18712
- function getTranslationDeclStmts$1(message, variable, closureVar, params = {}, transformFn) {
19100
+ function getTranslationDeclStmts$1(message, variable, closureVar, params, transformFn) {
19101
+ const paramsObject = Object.fromEntries(params);
18713
19102
  const statements = [
18714
19103
  declareI18nVariable(variable),
18715
- ifStmt(createClosureModeGuard$1(), createGoogleGetMsgStatements(variable, message, closureVar, params), createLocalizeStatements(variable, message, formatI18nPlaceholderNamesInMap(params, /* useCamelCase */ false))),
19104
+ ifStmt(createClosureModeGuard$1(), createGoogleGetMsgStatements(variable, message, closureVar, paramsObject), createLocalizeStatements(variable, message, formatI18nPlaceholderNamesInMap(paramsObject, /* useCamelCase */ false))),
18716
19105
  ];
18717
19106
  if (transformFn) {
18718
19107
  statements.push(new ExpressionStatement(variable.set(transformFn(variable))));
@@ -18755,22 +19144,48 @@ function i18nGenerateClosureVar(pool, messageId, fileBasedI18nSuffix, useExterna
18755
19144
  */
18756
19145
  function phaseI18nTextExtraction(job) {
18757
19146
  for (const unit of job.units) {
18758
- let inI18nBlock = false;
19147
+ // Remove all text nodes within i18n blocks, their content is already captured in the i18n
19148
+ // message.
19149
+ let currentI18nId = null;
19150
+ const textNodes = new Map();
18759
19151
  for (const op of unit.create) {
18760
19152
  switch (op.kind) {
18761
19153
  case OpKind.I18nStart:
18762
- inI18nBlock = true;
19154
+ currentI18nId = op.xref;
18763
19155
  break;
18764
19156
  case OpKind.I18nEnd:
18765
- inI18nBlock = false;
19157
+ currentI18nId = null;
18766
19158
  break;
18767
19159
  case OpKind.Text:
18768
- if (inI18nBlock) {
19160
+ if (currentI18nId !== null) {
19161
+ textNodes.set(op.xref, currentI18nId);
18769
19162
  OpList.remove(op);
18770
19163
  }
18771
19164
  break;
18772
19165
  }
18773
19166
  }
19167
+ // Update any interpolations to the removed text, and instead represent them as a series of i18n
19168
+ // expressions that we then apply.
19169
+ for (const op of unit.update) {
19170
+ switch (op.kind) {
19171
+ case OpKind.InterpolateText:
19172
+ if (!textNodes.has(op.target)) {
19173
+ continue;
19174
+ }
19175
+ const i18nBlockId = textNodes.get(op.target);
19176
+ const ops = [];
19177
+ for (let i = 0; i < op.interpolation.expressions.length; i++) {
19178
+ const expr = op.interpolation.expressions[i];
19179
+ const placeholder = op.i18nPlaceholders[i];
19180
+ ops.push(createI18nExpressionOp(i18nBlockId, expr, placeholder, expr.sourceSpan ?? op.sourceSpan));
19181
+ }
19182
+ if (ops.length > 0) {
19183
+ // ops.push(ir.createI18nApplyOp(i18nBlockId, op.i18nPlaceholders, op.sourceSpan));
19184
+ }
19185
+ OpList.replaceWithMany(op, ops);
19186
+ break;
19187
+ }
19188
+ }
18774
19189
  }
18775
19190
  }
18776
19191
 
@@ -18934,7 +19349,7 @@ function addNamesToView(unit, baseName, state, compatibility) {
18934
19349
  if (op.handlerFnName !== null) {
18935
19350
  break;
18936
19351
  }
18937
- if (!op.hostListener && op.slot === null) {
19352
+ if (!op.hostListener && op.targetSlot === null) {
18938
19353
  throw new Error(`Expected a slot to be assigned`);
18939
19354
  }
18940
19355
  let animation = '';
@@ -18946,7 +19361,7 @@ function addNamesToView(unit, baseName, state, compatibility) {
18946
19361
  op.handlerFnName = `${baseName}_${animation}${op.name}_HostBindingHandler`;
18947
19362
  }
18948
19363
  else {
18949
- op.handlerFnName = `${unit.fnName}_${op.tag.replace('-', '_')}_${animation}${op.name}_${op.slot}_listener`;
19364
+ op.handlerFnName = `${unit.fnName}_${op.tag.replace('-', '_')}_${animation}${op.name}_${op.targetSlot}_listener`;
18950
19365
  }
18951
19366
  op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
18952
19367
  break;
@@ -19095,6 +19510,11 @@ function phaseNgContainer(job) {
19095
19510
  for (const unit of job.units) {
19096
19511
  const updatedElementXrefs = new Set();
19097
19512
  for (const op of unit.create) {
19513
+ if (op.kind === OpKind.Element && op.tag === CONTAINER_TAG) {
19514
+ // Transmute the `Element` instruction to `Container`.
19515
+ op.kind = OpKind.Container;
19516
+ updatedElementXrefs.add(op.xref);
19517
+ }
19098
19518
  if (op.kind === OpKind.ElementStart && op.tag === CONTAINER_TAG) {
19099
19519
  // Transmute the `ElementStart` instruction to `ContainerStart`.
19100
19520
  op.kind = OpKind.ContainerStart;
@@ -19108,30 +19528,6 @@ function phaseNgContainer(job) {
19108
19528
  }
19109
19529
  }
19110
19530
 
19111
- function phaseNoListenersOnTemplates(job) {
19112
- for (const unit of job.units) {
19113
- let inTemplate = false;
19114
- for (const op of unit.create) {
19115
- switch (op.kind) {
19116
- case OpKind.Template:
19117
- inTemplate = true;
19118
- break;
19119
- case OpKind.ElementStart:
19120
- case OpKind.Element:
19121
- case OpKind.ContainerStart:
19122
- case OpKind.Container:
19123
- inTemplate = false;
19124
- break;
19125
- case OpKind.Listener:
19126
- if (inTemplate) {
19127
- OpList.remove(op);
19128
- }
19129
- break;
19130
- }
19131
- }
19132
- }
19133
- }
19134
-
19135
19531
  /**
19136
19532
  * Looks up an element in the given map by xref ID.
19137
19533
  */
@@ -19189,6 +19585,95 @@ function phaseNullishCoalescing(job) {
19189
19585
  }
19190
19586
  }
19191
19587
 
19588
+ function kindTest(kind) {
19589
+ return (op) => op.kind === kind;
19590
+ }
19591
+ /**
19592
+ * Defines the groups based on `OpKind` that ops will be divided into, for the various create
19593
+ * binding kinds. Ops will be collected into groups, then optionally transformed, before recombining
19594
+ * the groups in the order defined here.
19595
+ */
19596
+ const CREATE_ORDERING = [
19597
+ { test: op => op.kind === OpKind.Listener && op.hostListener && op.isAnimationListener },
19598
+ { test: op => op.kind === OpKind.Listener && !(op.hostListener && op.isAnimationListener) },
19599
+ ];
19600
+ /**
19601
+ * As above, but for update ops.
19602
+ */
19603
+ const UPDATE_ORDERING = [
19604
+ { test: op => op.kind === OpKind.HostProperty && op.expression instanceof Interpolation },
19605
+ { test: op => op.kind === OpKind.HostProperty && !(op.expression instanceof Interpolation) },
19606
+ { test: kindTest(OpKind.StyleMap), transform: keepLast },
19607
+ { test: kindTest(OpKind.ClassMap), transform: keepLast },
19608
+ { test: kindTest(OpKind.StyleProp) },
19609
+ { test: kindTest(OpKind.ClassProp) },
19610
+ { test: op => op.kind === OpKind.Property && op.expression instanceof Interpolation },
19611
+ { test: op => op.kind === OpKind.Property && !(op.expression instanceof Interpolation) },
19612
+ { test: kindTest(OpKind.Attribute) },
19613
+ ];
19614
+ /**
19615
+ * The set of all op kinds we handle in the reordering phase.
19616
+ */
19617
+ const handledOpKinds = new Set([
19618
+ OpKind.Listener, OpKind.StyleMap, OpKind.ClassMap, OpKind.StyleProp,
19619
+ OpKind.ClassProp, OpKind.Property, OpKind.HostProperty, OpKind.Attribute
19620
+ ]);
19621
+ function phaseOrdering(job) {
19622
+ for (const unit of job.units) {
19623
+ // First, we pull out ops that need to be ordered. Then, when we encounter an op that shouldn't
19624
+ // be reordered, put the ones we've pulled so far back in the correct order. Finally, if we
19625
+ // still have ops pulled at the end, put them back in the correct order.
19626
+ // Create mode:
19627
+ let opsToOrder = [];
19628
+ for (const op of unit.create) {
19629
+ if (handledOpKinds.has(op.kind)) {
19630
+ opsToOrder.push(op);
19631
+ OpList.remove(op);
19632
+ }
19633
+ else {
19634
+ OpList.insertBefore(reorder(opsToOrder, CREATE_ORDERING), op);
19635
+ opsToOrder = [];
19636
+ }
19637
+ }
19638
+ unit.create.push(reorder(opsToOrder, CREATE_ORDERING));
19639
+ // Update mode:
19640
+ opsToOrder = [];
19641
+ for (const op of unit.update) {
19642
+ if (handledOpKinds.has(op.kind)) {
19643
+ opsToOrder.push(op);
19644
+ OpList.remove(op);
19645
+ }
19646
+ else {
19647
+ OpList.insertBefore(reorder(opsToOrder, UPDATE_ORDERING), op);
19648
+ opsToOrder = [];
19649
+ }
19650
+ }
19651
+ unit.update.push(reorder(opsToOrder, UPDATE_ORDERING));
19652
+ }
19653
+ }
19654
+ /**
19655
+ * Reorders the given list of ops according to the ordering defined by `ORDERING`.
19656
+ */
19657
+ function reorder(ops, ordering) {
19658
+ // Break the ops list into groups based on OpKind.
19659
+ const groups = Array.from(ordering, () => new Array());
19660
+ for (const op of ops) {
19661
+ const groupIndex = ordering.findIndex(o => o.test(op));
19662
+ groups[groupIndex].push(op);
19663
+ }
19664
+ // Reassemble the groups into a single list, in the correct order.
19665
+ return groups.flatMap((group, i) => {
19666
+ const transform = ordering[i].transform;
19667
+ return transform ? transform(group) : group;
19668
+ });
19669
+ }
19670
+ /**
19671
+ * Keeps only the last op in a list of ops.
19672
+ */
19673
+ function keepLast(ops) {
19674
+ return ops.slice(ops.length - 1);
19675
+ }
19676
+
19192
19677
  /**
19193
19678
  * Parses extracted style and class attributes into separate ExtractedAttributeOps per style or
19194
19679
  * class property.
@@ -19217,6 +19702,36 @@ function phaseParseExtractedStyles(cpl) {
19217
19702
  }
19218
19703
  }
19219
19704
 
19705
+ /**
19706
+ * Attributes of `ng-content` named 'select' are specifically removed, because they control which
19707
+ * content matches as a property of the `projection`, and are not a plain attribute.
19708
+ */
19709
+ function phaseRemoveContentSelectors(job) {
19710
+ for (const unit of job.units) {
19711
+ const elements = getElementsByXrefId(unit);
19712
+ for (const op of unit.update) {
19713
+ switch (op.kind) {
19714
+ case OpKind.Binding:
19715
+ const target = lookupElement(elements, op.target);
19716
+ if (op.name.toLowerCase() === 'select' && target.kind === OpKind.Projection) {
19717
+ OpList.remove(op);
19718
+ }
19719
+ continue;
19720
+ }
19721
+ }
19722
+ }
19723
+ }
19724
+ /**
19725
+ * Looks up an element in the given map by xref ID.
19726
+ */
19727
+ function lookupElement(elements, xref) {
19728
+ const el = elements.get(xref);
19729
+ if (el === undefined) {
19730
+ throw new Error('All attributes should have an element-like target.');
19731
+ }
19732
+ return el;
19733
+ }
19734
+
19220
19735
  function phasePipeCreation(job) {
19221
19736
  for (const unit of job.units) {
19222
19737
  processPipeBindingsInView(unit);
@@ -19283,93 +19798,84 @@ function phasePipeVariadic(job) {
19283
19798
  }
19284
19799
  }
19285
19800
 
19286
- function kindTest(kind) {
19287
- return (op) => op.kind === kind;
19288
- }
19289
19801
  /**
19290
- * Defines the groups based on `OpKind` that ops will be divided into, for the various create
19291
- * binding kinds. Ops will be collected into groups, then optionally transformed, before recombining
19292
- * the groups in the order defined here.
19802
+ * Propagate i18n blocks down through child templates that act as placeholders in the root i18n
19803
+ * message.
19293
19804
  */
19294
- const CREATE_ORDERING = [
19295
- { test: op => op.kind === OpKind.Listener && op.hostListener && op.isAnimationListener },
19296
- { test: op => op.kind === OpKind.Listener && !(op.hostListener && op.isAnimationListener) },
19297
- ];
19805
+ function phasePropagateI18nBlocks(job) {
19806
+ propagateI18nBlocksToTemplates(job.root, 0);
19807
+ }
19298
19808
  /**
19299
- * As above, but for update ops.
19809
+ * Propagates i18n ops in the given view through to any child views recursively.
19300
19810
  */
19301
- const UPDATE_ORDERING = [
19302
- { test: op => op.kind === OpKind.HostProperty && op.expression instanceof Interpolation },
19303
- { test: op => op.kind === OpKind.HostProperty && !(op.expression instanceof Interpolation) },
19304
- { test: kindTest(OpKind.StyleMap), transform: keepLast },
19305
- { test: kindTest(OpKind.ClassMap), transform: keepLast },
19306
- { test: kindTest(OpKind.StyleProp) },
19307
- { test: kindTest(OpKind.ClassProp) },
19308
- { test: op => op.kind === OpKind.Property && op.expression instanceof Interpolation },
19309
- { test: op => op.kind === OpKind.Property && !(op.expression instanceof Interpolation) },
19310
- { test: kindTest(OpKind.Attribute) },
19311
- ];
19811
+ function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
19812
+ let i18nBlock = null;
19813
+ for (const op of unit.create) {
19814
+ switch (op.kind) {
19815
+ case OpKind.I18nStart:
19816
+ op.subTemplateIndex = subTemplateIndex === 0 ? null : subTemplateIndex;
19817
+ i18nBlock = op;
19818
+ break;
19819
+ case OpKind.I18nEnd:
19820
+ i18nBlock = null;
19821
+ break;
19822
+ case OpKind.Template:
19823
+ const templateView = unit.job.views.get(op.xref);
19824
+ // We found an <ng-template> inside an i18n block; increment the sub-template counter and
19825
+ // wrap the template's view in a child i18n block.
19826
+ if (op.i18nPlaceholder !== undefined) {
19827
+ if (i18nBlock === null) {
19828
+ throw Error('Expected template with i18n placeholder to be in an i18n block.');
19829
+ }
19830
+ subTemplateIndex++;
19831
+ wrapTemplateWithI18n(templateView, i18nBlock);
19832
+ }
19833
+ // Continue traversing inside the template's view.
19834
+ propagateI18nBlocksToTemplates(templateView, subTemplateIndex);
19835
+ }
19836
+ }
19837
+ }
19312
19838
  /**
19313
- * The set of all op kinds we handle in the reordering phase.
19839
+ * Wraps a template view with i18n start and end ops.
19314
19840
  */
19315
- const handledOpKinds = new Set([
19316
- OpKind.Listener, OpKind.StyleMap, OpKind.ClassMap, OpKind.StyleProp,
19317
- OpKind.ClassProp, OpKind.Property, OpKind.HostProperty, OpKind.Attribute
19318
- ]);
19319
- function phaseOrdering(job) {
19841
+ function wrapTemplateWithI18n(unit, parentI18n) {
19842
+ // Only add i18n ops if they have not already been propagated to this template.
19843
+ if (unit.create.head.next?.kind !== OpKind.I18nStart) {
19844
+ const id = unit.job.allocateXrefId();
19845
+ OpList.insertAfter(createI18nStartOp(id, parentI18n.message, parentI18n.root), unit.create.head);
19846
+ OpList.insertBefore(createI18nEndOp(id), unit.create.tail);
19847
+ }
19848
+ }
19849
+
19850
+ function phasePropagateI18nPlaceholders(job) {
19851
+ // Get all of the i18n ops.
19852
+ const i18nOps = new Map();
19320
19853
  for (const unit of job.units) {
19321
- // First, we pull out ops that need to be ordered. Then, when we encounter an op that shouldn't
19322
- // be reordered, put the ones we've pulled so far back in the correct order. Finally, if we
19323
- // still have ops pulled at the end, put them back in the correct order.
19324
- // Create mode:
19325
- let opsToOrder = [];
19326
19854
  for (const op of unit.create) {
19327
- if (handledOpKinds.has(op.kind)) {
19328
- opsToOrder.push(op);
19329
- OpList.remove(op);
19330
- }
19331
- else {
19332
- OpList.insertBefore(reorder(opsToOrder, CREATE_ORDERING), op);
19333
- opsToOrder = [];
19855
+ if (op.kind === OpKind.I18nStart) {
19856
+ i18nOps.set(op.xref, op);
19334
19857
  }
19335
19858
  }
19336
- unit.create.push(reorder(opsToOrder, CREATE_ORDERING));
19337
- // Update mode:
19338
- opsToOrder = [];
19339
- for (const op of unit.update) {
19340
- if (handledOpKinds.has(op.kind)) {
19341
- opsToOrder.push(op);
19342
- OpList.remove(op);
19343
- }
19344
- else {
19345
- OpList.insertBefore(reorder(opsToOrder, UPDATE_ORDERING), op);
19346
- opsToOrder = [];
19859
+ }
19860
+ // Propagate i18n params from sub-templates up to the root i18n op.
19861
+ for (const op of i18nOps.values()) {
19862
+ if (op.xref !== op.root) {
19863
+ const rootOp = i18nOps.get(op.root);
19864
+ for (const [placeholder, value] of op.params) {
19865
+ rootOp.params.set(placeholder, value);
19347
19866
  }
19348
19867
  }
19349
- unit.update.push(reorder(opsToOrder, UPDATE_ORDERING));
19350
19868
  }
19351
- }
19352
- /**
19353
- * Reorders the given list of ops according to the ordering defined by `ORDERING`.
19354
- */
19355
- function reorder(ops, ordering) {
19356
- // Break the ops list into groups based on OpKind.
19357
- const groups = Array.from(ordering, () => new Array());
19358
- for (const op of ops) {
19359
- const groupIndex = ordering.findIndex(o => o.test(op));
19360
- groups[groupIndex].push(op);
19869
+ // Validate the root i18n ops have all placeholders filled in.
19870
+ for (const op of i18nOps.values()) {
19871
+ if (op.xref === op.root) {
19872
+ for (const placeholder in op.message.placeholders) {
19873
+ if (!op.params.has(placeholder)) {
19874
+ throw Error(`Failed to resolve i18n placeholder: ${placeholder}`);
19875
+ }
19876
+ }
19877
+ }
19361
19878
  }
19362
- // Reassemble the groups into a single list, in the correct order.
19363
- return groups.flatMap((group, i) => {
19364
- const transform = ordering[i].transform;
19365
- return transform ? transform(group) : group;
19366
- });
19367
- }
19368
- /**
19369
- * Keeps only the last op in a list of ops.
19370
- */
19371
- function keepLast(ops) {
19372
- return ops.slice(ops.length - 1);
19373
19879
  }
19374
19880
 
19375
19881
  function phasePureFunctionExtraction(job) {
@@ -19402,7 +19908,7 @@ class PureFunctionConstant extends GenericKeyFn {
19402
19908
  toSharedConstantDeclaration(declName, keyExpr) {
19403
19909
  const fnParams = [];
19404
19910
  for (let idx = 0; idx < this.numArgs; idx++) {
19405
- fnParams.push(new FnParam('_p' + idx));
19911
+ fnParams.push(new FnParam('a' + idx));
19406
19912
  }
19407
19913
  // We will never visit `ir.PureFunctionParameterExpr`s that don't belong to us, because this
19408
19914
  // transform runs inside another visitor which will visit nested pure functions before this one.
@@ -19410,9 +19916,9 @@ class PureFunctionConstant extends GenericKeyFn {
19410
19916
  if (!(expr instanceof PureFunctionParameterExpr)) {
19411
19917
  return expr;
19412
19918
  }
19413
- return variable('_p' + expr.index);
19919
+ return variable('a' + expr.index);
19414
19920
  }, VisitorContextFlag.None);
19415
- return new DeclareFunctionStmt(declName, fnParams, [new ReturnStatement(returnExpr)]);
19921
+ return new DeclareVarStmt(declName, new ArrowFunctionExpr(fnParams, returnExpr), undefined, StmtModifier.Final);
19416
19922
  }
19417
19923
  }
19418
19924
 
@@ -19576,6 +20082,25 @@ function text(slot, initialValue, sourceSpan) {
19576
20082
  }
19577
20083
  return call(Identifiers.text, args, sourceSpan);
19578
20084
  }
20085
+ function defer(selfSlot, primarySlot, dependencyResolverFn, loadingSlot, placeholderSlot, errorSlot, loadingConfigIndex, placeholderConfigIndex, sourceSpan) {
20086
+ const args = [
20087
+ literal(selfSlot),
20088
+ literal(primarySlot),
20089
+ literal(dependencyResolverFn),
20090
+ literal(loadingSlot),
20091
+ literal(placeholderSlot),
20092
+ literal(errorSlot),
20093
+ literal(loadingConfigIndex),
20094
+ literal(placeholderConfigIndex),
20095
+ ];
20096
+ while (args[args.length - 1].value === null) {
20097
+ args.pop();
20098
+ }
20099
+ return call(Identifiers.defer, args, sourceSpan);
20100
+ }
20101
+ function deferOn(sourceSpan) {
20102
+ return call(Identifiers.deferOnIdle, [], sourceSpan);
20103
+ }
19579
20104
  function projectionDef(def) {
19580
20105
  return call(Identifiers.projectionDef, def ? [def] : [], null);
19581
20106
  }
@@ -19589,11 +20114,19 @@ function projection(slot, projectionSlotIndex, attributes) {
19589
20114
  }
19590
20115
  return call(Identifiers.projection, args, null);
19591
20116
  }
19592
- function i18nStart(slot, constIndex) {
19593
- return call(Identifiers.i18nStart, [literal(slot), literal(constIndex)], null);
20117
+ function i18nStart(slot, constIndex, subTemplateIndex) {
20118
+ const args = [literal(slot), literal(constIndex)];
20119
+ if (subTemplateIndex !== null) {
20120
+ args.push(literal(subTemplateIndex));
20121
+ }
20122
+ return call(Identifiers.i18nStart, args, null);
19594
20123
  }
19595
- function i18n(slot) {
19596
- return call(Identifiers.i18n, [literal(slot)], null);
20124
+ function i18n(slot, constIndex, subTemplateIndex) {
20125
+ const args = [literal(slot), literal(constIndex)];
20126
+ if (subTemplateIndex) {
20127
+ args.push(literal(subTemplateIndex));
20128
+ }
20129
+ return call(Identifiers.i18n, args, null);
19597
20130
  }
19598
20131
  function i18nEnd() {
19599
20132
  return call(Identifiers.i18nEnd, [], null);
@@ -19670,6 +20203,12 @@ function textInterpolate(strings, expressions, sourceSpan) {
19670
20203
  }
19671
20204
  return callVariadicInstruction(TEXT_INTERPOLATE_CONFIG, [], interpolationArgs, [], sourceSpan);
19672
20205
  }
20206
+ function i18nExp(expr, sourceSpan) {
20207
+ return call(Identifiers.i18nExp, [expr], sourceSpan);
20208
+ }
20209
+ function i18nApply(slot, sourceSpan) {
20210
+ return call(Identifiers.i18nApply, [literal(slot)], sourceSpan);
20211
+ }
19673
20212
  function propertyInterpolate(name, strings, expressions, sanitizer, sourceSpan) {
19674
20213
  const interpolationArgs = collateInterpolationArgs(strings, expressions);
19675
20214
  const extraArgs = [];
@@ -19739,8 +20278,12 @@ function call(instruction, args, sourceSpan) {
19739
20278
  const expr = importExpr(instruction).callFn(args, sourceSpan);
19740
20279
  return createStatementOp(new ExpressionStatement(expr, sourceSpan));
19741
20280
  }
19742
- function conditional(slot, condition) {
19743
- return call(Identifiers.conditional, [literal(slot), condition], null);
20281
+ function conditional(slot, condition, contextValue, sourceSpan) {
20282
+ const args = [literal(slot), condition];
20283
+ if (contextValue !== null) {
20284
+ args.push(contextValue);
20285
+ }
20286
+ return call(Identifiers.conditional, args, sourceSpan);
19744
20287
  }
19745
20288
  /**
19746
20289
  * `InterpolationConfig` for the `textInterpolate` instruction.
@@ -19966,20 +20509,20 @@ function reifyCreateOperations(unit, ops) {
19966
20509
  OpList.replace(op, elementContainerEnd());
19967
20510
  break;
19968
20511
  case OpKind.I18nStart:
19969
- OpList.replace(op, i18nStart(op.slot, op.messageIndex));
20512
+ OpList.replace(op, i18nStart(op.slot, op.messageIndex, op.subTemplateIndex));
19970
20513
  break;
19971
20514
  case OpKind.I18nEnd:
19972
20515
  OpList.replace(op, i18nEnd());
19973
20516
  break;
19974
20517
  case OpKind.I18n:
19975
- OpList.replace(op, i18n(op.slot));
20518
+ OpList.replace(op, i18n(op.slot, op.messageIndex, op.subTemplateIndex));
19976
20519
  break;
19977
20520
  case OpKind.Template:
19978
20521
  if (!(unit instanceof ViewCompilationUnit)) {
19979
20522
  throw new Error(`AssertionError: must be compiling a component`);
19980
20523
  }
19981
20524
  const childView = unit.job.views.get(op.xref);
19982
- OpList.replace(op, template(op.slot, variable(childView.fnName), childView.decls, childView.vars, op.controlFlow ? null : op.tag, op.attributes, op.sourceSpan));
20525
+ OpList.replace(op, template(op.slot, variable(childView.fnName), childView.decls, childView.vars, op.block ? null : op.tag, op.attributes, op.sourceSpan));
19983
20526
  break;
19984
20527
  case OpKind.DisableBindings:
19985
20528
  OpList.replace(op, disableBindings());
@@ -20016,6 +20559,15 @@ function reifyCreateOperations(unit, ops) {
20016
20559
  break;
20017
20560
  }
20018
20561
  break;
20562
+ case OpKind.Defer:
20563
+ OpList.replace(op, defer(op.slot, op.targetSlot, null, op.loading && op.loading.targetSlot, op.placeholder && op.placeholder.targetSlot, op.error && op.error.targetSlot, op.loading?.constIndex ?? null, op.placeholder?.constIndex ?? null, op.sourceSpan));
20564
+ break;
20565
+ case OpKind.DeferSecondaryBlock:
20566
+ OpList.remove(op);
20567
+ break;
20568
+ case OpKind.DeferOn:
20569
+ OpList.replace(op, deferOn(op.sourceSpan));
20570
+ break;
20019
20571
  case OpKind.ProjectionDef:
20020
20572
  OpList.replace(op, projectionDef(op.def));
20021
20573
  break;
@@ -20075,6 +20627,12 @@ function reifyUpdateOperations(_unit, ops) {
20075
20627
  OpList.replace(op, classMap(op.expression, op.sourceSpan));
20076
20628
  }
20077
20629
  break;
20630
+ case OpKind.I18nExpression:
20631
+ OpList.replace(op, i18nExp(op.expression, op.sourceSpan));
20632
+ break;
20633
+ case OpKind.I18nApply:
20634
+ OpList.replace(op, i18nApply(op.targetSlot, op.sourceSpan));
20635
+ break;
20078
20636
  case OpKind.InterpolateText:
20079
20637
  OpList.replace(op, textInterpolate(op.interpolation.strings, op.interpolation.expressions, op.sourceSpan));
20080
20638
  break;
@@ -20109,10 +20667,10 @@ function reifyUpdateOperations(_unit, ops) {
20109
20667
  if (op.processed === null) {
20110
20668
  throw new Error(`Conditional test was not set.`);
20111
20669
  }
20112
- if (op.slot === null) {
20670
+ if (op.targetSlot === null) {
20113
20671
  throw new Error(`Conditional slot was not set.`);
20114
20672
  }
20115
- OpList.replace(op, conditional(op.slot, op.processed));
20673
+ OpList.replace(op, conditional(op.targetSlot, op.processed, op.contextValue, op.sourceSpan));
20116
20674
  break;
20117
20675
  case OpKind.Statement:
20118
20676
  // Pass statement operations directly through.
@@ -20130,7 +20688,7 @@ function reifyIrExpression(expr) {
20130
20688
  case ExpressionKind.NextContext:
20131
20689
  return nextContext(expr.steps);
20132
20690
  case ExpressionKind.Reference:
20133
- return reference(expr.slot + 1 + expr.offset);
20691
+ return reference(expr.targetSlot + 1 + expr.offset);
20134
20692
  case ExpressionKind.LexicalRead:
20135
20693
  throw new Error(`AssertionError: unresolved LexicalRead of ${expr.name}`);
20136
20694
  case ExpressionKind.RestoreView:
@@ -20165,13 +20723,13 @@ function reifyIrExpression(expr) {
20165
20723
  case ExpressionKind.PureFunctionParameterExpr:
20166
20724
  throw new Error(`AssertionError: expected PureFunctionParameterExpr to have been extracted`);
20167
20725
  case ExpressionKind.PipeBinding:
20168
- return pipeBind(expr.slot, expr.varOffset, expr.args);
20726
+ return pipeBind(expr.targetSlot, expr.varOffset, expr.args);
20169
20727
  case ExpressionKind.PipeBindingVariadic:
20170
- return pipeBindV(expr.slot, expr.varOffset, expr.args);
20728
+ return pipeBindV(expr.targetSlot, expr.varOffset, expr.args);
20171
20729
  case ExpressionKind.SanitizerExpr:
20172
20730
  return importExpr(sanitizerIdentifierMap.get(expr.fn));
20173
20731
  case ExpressionKind.SlotLiteralExpr:
20174
- return literal(expr.slot);
20732
+ return literal(expr.targetSlot);
20175
20733
  default:
20176
20734
  throw new Error(`AssertionError: Unsupported reification of ir.Expression kind: ${ExpressionKind[expr.kind]}`);
20177
20735
  }
@@ -20290,58 +20848,186 @@ function resolveDollarEvent(unit, ops) {
20290
20848
  }
20291
20849
  }
20292
20850
  }
20293
-
20294
- /**
20295
- * The escape sequence used indicate message param values.
20296
- */
20297
- const ESCAPE = '\uFFFD';
20851
+
20852
+ /**
20853
+ * The escape sequence used indicate message param values.
20854
+ */
20855
+ const ESCAPE = '\uFFFD';
20856
+ /**
20857
+ * Marker used to indicate an element tag.
20858
+ */
20859
+ const ELEMENT_MARKER = '#';
20860
+ /**
20861
+ * Marker used to indicate a template tag.
20862
+ */
20863
+ const TEMPLATE_MARKER = '*';
20864
+ /**
20865
+ * Marker used to indicate closing of an element or template tag.
20866
+ */
20867
+ const TAG_CLOSE_MARKER = '/';
20868
+ /**
20869
+ * Marker used to indicate the sub-template context.
20870
+ */
20871
+ const CONTEXT_MARKER = ':';
20872
+ /**
20873
+ * Marker used to indicate the start of a list of values.
20874
+ */
20875
+ const LIST_START_MARKER = '[';
20876
+ /**
20877
+ * Marker used to indicate the end of a list of values.
20878
+ */
20879
+ const LIST_END_MARKER = ']';
20880
+ /**
20881
+ * Delimiter used to separate multiple values in a list.
20882
+ */
20883
+ const LIST_DELIMITER = '|';
20884
+ var I18nParamValueFlags;
20885
+ (function (I18nParamValueFlags) {
20886
+ I18nParamValueFlags[I18nParamValueFlags["None"] = 0] = "None";
20887
+ /**
20888
+ * This value represtents an element tag.
20889
+ */
20890
+ I18nParamValueFlags[I18nParamValueFlags["ElementTag"] = 1] = "ElementTag";
20891
+ /**
20892
+ * This value represents a template tag.
20893
+ */
20894
+ I18nParamValueFlags[I18nParamValueFlags["TemplateTag"] = 2] = "TemplateTag";
20895
+ /**
20896
+ * This value represents the closing of a tag. (Can only be used together with ElementTag or
20897
+ * TemplateTag)
20898
+ */
20899
+ I18nParamValueFlags[I18nParamValueFlags["CloseTag"] = 4] = "CloseTag";
20900
+ })(I18nParamValueFlags || (I18nParamValueFlags = {}));
20901
+ /**
20902
+ * Represents the complete i18n params map for an i18n op.
20903
+ */
20904
+ class I18nPlaceholderParams {
20905
+ constructor() {
20906
+ this.values = new Map();
20907
+ }
20908
+ /**
20909
+ * Adds a new value to the params map.
20910
+ */
20911
+ addValue(placeholder, value, subTemplateIndex, flags) {
20912
+ const placeholderValues = this.values.get(placeholder) ?? [];
20913
+ placeholderValues.push({ value, subTemplateIndex, flags });
20914
+ this.values.set(placeholder, placeholderValues);
20915
+ }
20916
+ /**
20917
+ * Saves the params map, in serialized form, into the given i18n op.
20918
+ */
20919
+ saveToOp(op) {
20920
+ for (const [placeholder, placeholderValues] of this.values) {
20921
+ op.params.set(placeholder, literal(this.serializeValues(placeholderValues)));
20922
+ }
20923
+ }
20924
+ /**
20925
+ * Serializes a list of i18n placeholder values.
20926
+ */
20927
+ serializeValues(values) {
20928
+ const serializedValues = values.map(value => this.serializeValue(value));
20929
+ return serializedValues.length === 1 ?
20930
+ serializedValues[0] :
20931
+ `${LIST_START_MARKER}${serializedValues.join(LIST_DELIMITER)}${LIST_END_MARKER}`;
20932
+ }
20933
+ /**
20934
+ * Serializes a single i18n placeholder value.
20935
+ */
20936
+ serializeValue(value) {
20937
+ let tagMarker = '';
20938
+ let closeMarker = '';
20939
+ if (value.flags & I18nParamValueFlags.ElementTag) {
20940
+ tagMarker = ELEMENT_MARKER;
20941
+ }
20942
+ else if (value.flags & I18nParamValueFlags.TemplateTag) {
20943
+ tagMarker = TEMPLATE_MARKER;
20944
+ }
20945
+ if (tagMarker !== '') {
20946
+ closeMarker = value.flags & I18nParamValueFlags.CloseTag ? TAG_CLOSE_MARKER : '';
20947
+ }
20948
+ const context = value.subTemplateIndex === null ? '' : `${CONTEXT_MARKER}${value.subTemplateIndex}`;
20949
+ return `${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
20950
+ }
20951
+ }
20298
20952
  /**
20299
20953
  * Resolve the placeholders in i18n messages.
20300
20954
  */
20301
20955
  function phaseResolveI18nPlaceholders(job) {
20302
20956
  for (const unit of job.units) {
20303
- let i18nOp = null;
20304
- let startTags = [];
20305
- let closeTags = [];
20957
+ const i18nOps = new Map();
20958
+ const params = new Map();
20959
+ let currentI18nOp = null;
20960
+ // Record slots for tag name placeholders.
20306
20961
  for (const op of unit.create) {
20307
- if (op.kind === OpKind.I18nStart && op.i18n instanceof Message) {
20308
- i18nOp = op;
20309
- }
20310
- else if (op.kind === OpKind.I18nEnd) {
20311
- i18nOp = null;
20962
+ switch (op.kind) {
20963
+ case OpKind.I18nStart:
20964
+ case OpKind.I18n:
20965
+ i18nOps.set(op.xref, op);
20966
+ currentI18nOp = op.kind === OpKind.I18nStart ? op : null;
20967
+ break;
20968
+ case OpKind.I18nEnd:
20969
+ currentI18nOp = null;
20970
+ break;
20971
+ case OpKind.Element:
20972
+ case OpKind.ElementStart:
20973
+ case OpKind.Template:
20974
+ // For elements with i18n placeholders, record its slot value in the params map under both
20975
+ // the start and close placeholders.
20976
+ if (op.i18nPlaceholder !== undefined) {
20977
+ if (currentI18nOp === null) {
20978
+ throw Error('i18n tag placeholder should only occur inside an i18n block');
20979
+ }
20980
+ const { startName, closeName } = op.i18nPlaceholder;
20981
+ const subTemplateIndex = getSubTemplateIndexForTag(job, currentI18nOp, op);
20982
+ const flags = op.kind === OpKind.Template ? I18nParamValueFlags.TemplateTag :
20983
+ I18nParamValueFlags.ElementTag;
20984
+ addParam(params, currentI18nOp, startName, op.slot, subTemplateIndex, flags);
20985
+ addParam(params, currentI18nOp, closeName, op.slot, subTemplateIndex, flags | I18nParamValueFlags.CloseTag);
20986
+ }
20987
+ break;
20312
20988
  }
20313
- else if ((op.kind === OpKind.Element || op.kind === OpKind.ElementStart) &&
20314
- op.i18n instanceof TagPlaceholder) {
20315
- if (i18nOp === null) {
20316
- throw Error('i18n tag placeholder should only occur inside an i18n block');
20989
+ }
20990
+ // Fill in values for each of the i18n expression placeholders.
20991
+ const i18nBlockPlaceholderIndices = new Map();
20992
+ for (const op of unit.update) {
20993
+ if (op.kind === OpKind.I18nExpression) {
20994
+ const i18nOp = i18nOps.get(op.owner);
20995
+ let index = i18nBlockPlaceholderIndices.get(op.owner) || 0;
20996
+ if (!i18nOp) {
20997
+ throw Error('Cannot find corresponding i18nStart for i18nExpr');
20317
20998
  }
20318
- // In order to add the keys in the same order as TemplateDefinitionBuilder, we separately
20319
- // track the start and close tag placeholders.
20320
- // TODO: when TemplateDefinitionBuilder compatibility is not required, we can just add both
20321
- // keys directly to the map here.
20322
- startTags.push({
20323
- i18nOp,
20324
- placeholder: op.i18n.startName,
20325
- value: literal(`${ESCAPE}#${op.slot}${ESCAPE}`)
20326
- });
20327
- closeTags.push({
20328
- i18nOp,
20329
- placeholder: op.i18n.closeName,
20330
- value: literal(`${ESCAPE}/#${op.slot}${ESCAPE}`)
20331
- });
20999
+ addParam(params, i18nOp, op.i18nPlaceholder.name, index++, i18nOp.subTemplateIndex);
21000
+ i18nBlockPlaceholderIndices.set(op.owner, index);
20332
21001
  }
20333
21002
  }
20334
- // Add the start tags in the order we encountered them, to match TemplateDefinitionBuilder.
20335
- for (const { i18nOp, placeholder, value } of startTags) {
20336
- i18nOp.tagNameParams[placeholder] = value;
21003
+ // After colleccting all params, save them to the i18n ops.
21004
+ for (const [xref, i18nOpParams] of params) {
21005
+ i18nOpParams.saveToOp(i18nOps.get(xref));
20337
21006
  }
20338
- // Add the close tags in reverse order that we encountered the start tags, to match
20339
- // TemplateDefinitionBuilder.
20340
- for (let i = closeTags.length - 1; i >= 0; i--) {
20341
- const { i18nOp, placeholder, value } = closeTags[i];
20342
- i18nOp.tagNameParams[placeholder] = value;
21007
+ }
21008
+ }
21009
+ /**
21010
+ * Add a param to the params map for the given i18n op.
21011
+ */
21012
+ function addParam(params, i18nOp, placeholder, value, subTemplateIndex, flags = I18nParamValueFlags.None) {
21013
+ const i18nOpParams = params.get(i18nOp.xref) ?? new I18nPlaceholderParams();
21014
+ i18nOpParams.addValue(placeholder, value, subTemplateIndex, flags);
21015
+ params.set(i18nOp.xref, i18nOpParams);
21016
+ }
21017
+ /**
21018
+ * Get the subTemplateIndex for the given op. For template ops, use the subTemplateIndex of the
21019
+ * child i18n block inside the template. For all other ops, use the subTemplateIndex of the i18n
21020
+ * block the op belongs to.
21021
+ */
21022
+ function getSubTemplateIndexForTag(job, i18nOp, op) {
21023
+ if (op.kind === OpKind.Template) {
21024
+ for (const childOp of job.views.get(op.xref).create) {
21025
+ if (childOp.kind === OpKind.I18nStart) {
21026
+ return childOp.subTemplateIndex;
21027
+ }
20343
21028
  }
20344
21029
  }
21030
+ return i18nOp.subTemplateIndex;
20345
21031
  }
20346
21032
 
20347
21033
  /**
@@ -20586,19 +21272,19 @@ function phaseSlotAllocation(job) {
20586
21272
  const childView = job.views.get(op.xref);
20587
21273
  op.decls = childView.decls;
20588
21274
  }
20589
- if (hasUsesSlotIndexTrait(op) && op.slot === null) {
21275
+ if (hasUsesSlotIndexTrait(op) && op.targetSlot === null) {
20590
21276
  if (!slotMap.has(op.target)) {
20591
21277
  // We do expect to find a slot allocated for everything which might be referenced.
20592
21278
  throw new Error(`AssertionError: no slot allocated for ${OpKind[op.kind]} target ${op.target}`);
20593
21279
  }
20594
- op.slot = slotMap.get(op.target);
21280
+ op.targetSlot = slotMap.get(op.target);
20595
21281
  }
20596
21282
  // Process all `ir.Expression`s within this view, and look for `usesSlotIndexExprTrait`.
20597
21283
  visitExpressionsInOp(op, expr => {
20598
21284
  if (!isIrExpression(expr)) {
20599
21285
  return;
20600
21286
  }
20601
- if (!hasUsesSlotIndexTrait(expr) || expr.slot !== null) {
21287
+ if (!hasUsesSlotIndexTrait(expr) || expr.targetSlot !== null) {
20602
21288
  return;
20603
21289
  }
20604
21290
  // The `UsesSlotIndexExprTrait` indicates that this expression references something declared
@@ -20609,7 +21295,7 @@ function phaseSlotAllocation(job) {
20609
21295
  throw new Error(`AssertionError: no slot allocated for ${expr.constructor.name} target ${expr.target}`);
20610
21296
  }
20611
21297
  // Record the allocated slot on the expression.
20612
- expr.slot = slotMap.get(expr.target);
21298
+ expr.targetSlot = slotMap.get(expr.target);
20613
21299
  });
20614
21300
  }
20615
21301
  }
@@ -20660,47 +21346,62 @@ function phaseStyleBindingSpecialization(cpl) {
20660
21346
  */
20661
21347
  function phaseTemporaryVariables(cpl) {
20662
21348
  for (const unit of cpl.units) {
20663
- let opCount = 0;
20664
- let generatedStatements = [];
20665
- for (const op of unit.ops()) {
20666
- // Identify the final time each temp var is read.
20667
- const finalReads = new Map();
20668
- visitExpressionsInOp(op, expr => {
20669
- if (expr instanceof ReadTemporaryExpr) {
20670
- finalReads.set(expr.xref, expr);
20671
- }
20672
- });
20673
- // Name the temp vars, accounting for the fact that a name can be reused after it has been
20674
- // read for the final time.
20675
- let count = 0;
20676
- const assigned = new Set();
20677
- const released = new Set();
20678
- const defs = new Map();
20679
- visitExpressionsInOp(op, expr => {
20680
- if (expr instanceof AssignTemporaryExpr) {
20681
- if (!assigned.has(expr.xref)) {
20682
- assigned.add(expr.xref);
20683
- // TODO: Exactly replicate the naming scheme used by `TemplateDefinitionBuilder`.
20684
- // It seems to rely on an expression index instead of an op index.
20685
- defs.set(expr.xref, `tmp_${opCount}_${count++}`);
20686
- }
20687
- assignName(defs, expr);
21349
+ unit.create.prepend(generateTemporaries(unit.create));
21350
+ unit.update.prepend(generateTemporaries(unit.update));
21351
+ }
21352
+ }
21353
+ function generateTemporaries(ops) {
21354
+ let opCount = 0;
21355
+ let generatedStatements = [];
21356
+ // For each op, search for any variables that are assigned or read. For each variable, generate a
21357
+ // name and produce a `DeclareVarStmt` to the beginning of the block.
21358
+ for (const op of ops) {
21359
+ // Identify the final time each temp var is read.
21360
+ const finalReads = new Map();
21361
+ visitExpressionsInOp(op, (expr, flag) => {
21362
+ if (flag & VisitorContextFlag.InChildOperation) {
21363
+ return;
21364
+ }
21365
+ if (expr instanceof ReadTemporaryExpr) {
21366
+ finalReads.set(expr.xref, expr);
21367
+ }
21368
+ });
21369
+ // Name the temp vars, accounting for the fact that a name can be reused after it has been
21370
+ // read for the final time.
21371
+ let count = 0;
21372
+ const assigned = new Set();
21373
+ const released = new Set();
21374
+ const defs = new Map();
21375
+ visitExpressionsInOp(op, (expr, flag) => {
21376
+ if (flag & VisitorContextFlag.InChildOperation) {
21377
+ return;
21378
+ }
21379
+ if (expr instanceof AssignTemporaryExpr) {
21380
+ if (!assigned.has(expr.xref)) {
21381
+ assigned.add(expr.xref);
21382
+ // TODO: Exactly replicate the naming scheme used by `TemplateDefinitionBuilder`.
21383
+ // It seems to rely on an expression index instead of an op index.
21384
+ defs.set(expr.xref, `tmp_${opCount}_${count++}`);
20688
21385
  }
20689
- else if (expr instanceof ReadTemporaryExpr) {
20690
- if (finalReads.get(expr.xref) === expr) {
20691
- released.add(expr.xref);
20692
- count--;
20693
- }
20694
- assignName(defs, expr);
21386
+ assignName(defs, expr);
21387
+ }
21388
+ else if (expr instanceof ReadTemporaryExpr) {
21389
+ if (finalReads.get(expr.xref) === expr) {
21390
+ released.add(expr.xref);
21391
+ count--;
20695
21392
  }
20696
- });
20697
- // Add declarations for the temp vars.
20698
- generatedStatements.push(...Array.from(new Set(defs.values()))
20699
- .map(name => createStatementOp(new DeclareVarStmt(name))));
20700
- opCount++;
21393
+ assignName(defs, expr);
21394
+ }
21395
+ });
21396
+ // Add declarations for the temp vars.
21397
+ generatedStatements.push(...Array.from(new Set(defs.values()))
21398
+ .map(name => createStatementOp(new DeclareVarStmt(name))));
21399
+ opCount++;
21400
+ if (op.kind === OpKind.Listener) {
21401
+ op.handlerOps.prepend(generateTemporaries(op.handlerOps));
20701
21402
  }
20702
- unit.update.prepend(generatedStatements);
20703
21403
  }
21404
+ return generatedStatements;
20704
21405
  }
20705
21406
  /**
20706
21407
  * Assigns a name to the temporary variable in the given temporary variable expression.
@@ -21068,6 +21769,13 @@ function allowConservativeInlining(decl, target) {
21068
21769
  // that behavior here.
21069
21770
  switch (decl.variable.kind) {
21070
21771
  case SemanticVariableKind.Identifier:
21772
+ if (decl.initializer instanceof ReadVarExpr && decl.initializer.name === 'ctx') {
21773
+ // Although TemplateDefinitionBuilder is cautious about inlining, we still want to do so
21774
+ // when the variable is the context, to imitate its behavior with aliases in control flow
21775
+ // blocks. This quirky behavior will become dead code once compatibility mode is no longer
21776
+ // supported.
21777
+ return true;
21778
+ }
21071
21779
  return false;
21072
21780
  case SemanticVariableKind.Context:
21073
21781
  // Context can only be inlined into other variables.
@@ -21077,111 +21785,20 @@ function allowConservativeInlining(decl, target) {
21077
21785
  }
21078
21786
  }
21079
21787
 
21080
- /**
21081
- * Locate projection slots, populate the each component's `ngContentSelectors` literal field,
21082
- * populate `project` arguments, and generate the required `projectionDef` instruction for the job's
21083
- * root view.
21084
- */
21085
- function phaseGenerateProjectionDef(job) {
21086
- // TODO: Why does TemplateDefinitionBuilder force a shared constant?
21087
- const share = job.compatibility === CompatibilityMode.TemplateDefinitionBuilder;
21088
- // Collect all selectors from this component, and its nested views. Also, assign each projection a
21089
- // unique ascending projection slot index.
21090
- const selectors = [];
21091
- let projectionSlotIndex = 0;
21092
- for (const unit of job.units) {
21093
- for (const op of unit.create) {
21094
- if (op.kind === OpKind.Projection) {
21095
- selectors.push(op.selector);
21096
- op.projectionSlotIndex = projectionSlotIndex++;
21097
- }
21098
- }
21099
- }
21100
- if (selectors.length > 0) {
21101
- // Create the projectionDef array. If we only found a single wildcard selector, then we use the
21102
- // default behavior with no arguments instead.
21103
- let defExpr = null;
21104
- if (selectors.length > 1 || selectors[0] !== '*') {
21105
- const def = selectors.map(s => s === '*' ? s : parseSelectorToR3Selector(s));
21106
- defExpr = job.pool.getConstLiteral(literalOrArrayLiteral(def), share);
21107
- }
21108
- // Create the ngContentSelectors constant.
21109
- job.contentSelectors = job.pool.getConstLiteral(literalOrArrayLiteral(selectors), share);
21110
- // The projection def instruction goes at the beginning of the root view, before any
21111
- // `projection` instructions.
21112
- job.root.create.prepend([createProjectionDefOp(defExpr)]);
21113
- }
21114
- }
21115
-
21116
- /**
21117
- * Lifts i18n properties into the consts array.
21118
- */
21119
- function phaseI18nConstCollection(job) {
21120
- // Serialize the extracted messages into the const array.
21121
- // TODO: Use `Map` instead of object.
21122
- const messageConstIndices = {};
21123
- for (const unit of job.units) {
21124
- for (const op of unit.create) {
21125
- if (op.kind === OpKind.ExtractedMessage) {
21126
- messageConstIndices[op.owner] = job.addConst(op.expression, op.statements);
21127
- OpList.remove(op);
21128
- }
21129
- }
21130
- }
21131
- // Assign const index to i18n ops that messages were extracted from.
21132
- for (const unit of job.units) {
21133
- for (const op of unit.create) {
21134
- if (op.kind === OpKind.I18nStart && messageConstIndices[op.xref] !== undefined) {
21135
- op.messageIndex = messageConstIndices[op.xref];
21136
- }
21137
- }
21138
- }
21139
- }
21140
-
21141
- /**
21142
- * Attributes of `ng-content` named 'select' are specifically removed, because they control which
21143
- * content matches as a property of the `projection`, and are not a plain attribute.
21144
- */
21145
- function phaseRemoveContentSelectors(job) {
21146
- for (const unit of job.units) {
21147
- const elements = getElementsByXrefId(unit);
21148
- for (const op of unit.update) {
21149
- switch (op.kind) {
21150
- case OpKind.Binding:
21151
- const target = lookupElement(elements, op.target);
21152
- if (op.name.toLowerCase() === 'select' && target.kind === OpKind.Projection) {
21153
- OpList.remove(op);
21154
- }
21155
- continue;
21156
- }
21157
- }
21158
- }
21159
- }
21160
- /**
21161
- * Looks up an element in the given map by xref ID.
21162
- */
21163
- function lookupElement(elements, xref) {
21164
- const el = elements.get(xref);
21165
- if (el === undefined) {
21166
- throw new Error('All attributes should have an element-like target.');
21167
- }
21168
- return el;
21169
- }
21170
-
21171
21788
  const phases = [
21172
21789
  { kind: CompilationJobKind.Tmpl, fn: phaseRemoveContentSelectors },
21173
- { kind: CompilationJobKind.Tmpl, fn: phaseGenerateI18nBlocks },
21174
- { kind: CompilationJobKind.Tmpl, fn: phaseI18nTextExtraction },
21175
21790
  { kind: CompilationJobKind.Host, fn: phaseHostStylePropertyParsing },
21176
21791
  { kind: CompilationJobKind.Tmpl, fn: phaseNamespace },
21177
21792
  { kind: CompilationJobKind.Both, fn: phaseStyleBindingSpecialization },
21178
21793
  { kind: CompilationJobKind.Both, fn: phaseBindingSpecialization },
21794
+ { kind: CompilationJobKind.Tmpl, fn: phasePropagateI18nBlocks },
21179
21795
  { kind: CompilationJobKind.Both, fn: phaseAttributeExtraction },
21180
21796
  { kind: CompilationJobKind.Both, fn: phaseParseExtractedStyles },
21181
21797
  { kind: CompilationJobKind.Tmpl, fn: phaseRemoveEmptyBindings },
21182
21798
  { kind: CompilationJobKind.Tmpl, fn: phaseConditionals },
21183
- { kind: CompilationJobKind.Tmpl, fn: phaseNoListenersOnTemplates },
21184
21799
  { kind: CompilationJobKind.Tmpl, fn: phasePipeCreation },
21800
+ { kind: CompilationJobKind.Tmpl, fn: phaseI18nTextExtraction },
21801
+ { kind: CompilationJobKind.Tmpl, fn: phaseApplyI18nExpressions },
21185
21802
  { kind: CompilationJobKind.Tmpl, fn: phasePipeVariadic },
21186
21803
  { kind: CompilationJobKind.Both, fn: phasePureLiteralStructures },
21187
21804
  { kind: CompilationJobKind.Tmpl, fn: phaseGenerateProjectionDef },
@@ -21198,9 +21815,12 @@ const phases = [
21198
21815
  { kind: CompilationJobKind.Both, fn: phaseTemporaryVariables },
21199
21816
  { kind: CompilationJobKind.Tmpl, fn: phaseSlotAllocation },
21200
21817
  { kind: CompilationJobKind.Tmpl, fn: phaseResolveI18nPlaceholders },
21818
+ { kind: CompilationJobKind.Tmpl, fn: phasePropagateI18nPlaceholders },
21201
21819
  { kind: CompilationJobKind.Tmpl, fn: phaseI18nMessageExtraction },
21202
21820
  { kind: CompilationJobKind.Tmpl, fn: phaseI18nConstCollection },
21821
+ { kind: CompilationJobKind.Tmpl, fn: phaseConstTraitCollection },
21203
21822
  { kind: CompilationJobKind.Both, fn: phaseConstCollection },
21823
+ { kind: CompilationJobKind.Tmpl, fn: phaseAssignI18nSlotDependencies },
21204
21824
  { kind: CompilationJobKind.Both, fn: phaseVarCounting },
21205
21825
  { kind: CompilationJobKind.Tmpl, fn: phaseGenerateAdvance },
21206
21826
  { kind: CompilationJobKind.Both, fn: phaseVariableOptimization },
@@ -21404,9 +22024,15 @@ function ingestNodes(unit, template) {
21404
22024
  else if (node instanceof BoundText) {
21405
22025
  ingestBoundText(unit, node);
21406
22026
  }
22027
+ else if (node instanceof IfBlock) {
22028
+ ingestIfBlock(unit, node);
22029
+ }
21407
22030
  else if (node instanceof SwitchBlock) {
21408
22031
  ingestSwitchBlock(unit, node);
21409
22032
  }
22033
+ else if (node instanceof DeferredBlock) {
22034
+ ingestDeferBlock(unit, node);
22035
+ }
21410
22036
  else {
21411
22037
  throw new Error(`Unsupported template node: ${node.constructor.name}`);
21412
22038
  }
@@ -21416,31 +22042,47 @@ function ingestNodes(unit, template) {
21416
22042
  * Ingest an element AST from the template into the given `ViewCompilation`.
21417
22043
  */
21418
22044
  function ingestElement(unit, element) {
22045
+ if (element.i18n !== undefined &&
22046
+ !(element.i18n instanceof Message || element.i18n instanceof TagPlaceholder)) {
22047
+ throw Error(`Unhandled i18n metadata type for element: ${element.i18n.constructor.name}`);
22048
+ }
21419
22049
  const staticAttributes = {};
21420
22050
  for (const attr of element.attributes) {
21421
22051
  staticAttributes[attr.name] = attr.value;
21422
22052
  }
21423
22053
  const id = unit.job.allocateXrefId();
21424
22054
  const [namespaceKey, elementName] = splitNsName(element.name);
21425
- const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n, element.startSourceSpan);
22055
+ const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan);
21426
22056
  unit.create.push(startOp);
21427
22057
  ingestBindings(unit, startOp, element);
21428
22058
  ingestReferences(startOp, element);
21429
22059
  ingestNodes(unit, element.children);
21430
- unit.create.push(createElementEndOp(id, element.endSourceSpan));
22060
+ const endOp = createElementEndOp(id, element.endSourceSpan);
22061
+ unit.create.push(endOp);
22062
+ // If there is an i18n message associated with this element, insert i18n start and end ops.
22063
+ if (element.i18n instanceof Message) {
22064
+ const i18nBlockId = unit.job.allocateXrefId();
22065
+ OpList.insertAfter(createI18nStartOp(i18nBlockId, element.i18n), startOp);
22066
+ OpList.insertBefore(createI18nEndOp(i18nBlockId), endOp);
22067
+ }
21431
22068
  }
21432
22069
  /**
21433
22070
  * Ingest an `ng-template` node from the AST into the given `ViewCompilation`.
21434
22071
  */
21435
22072
  function ingestTemplate(unit, tmpl) {
22073
+ if (tmpl.i18n !== undefined &&
22074
+ !(tmpl.i18n instanceof Message || tmpl.i18n instanceof TagPlaceholder)) {
22075
+ throw Error(`Unhandled i18n metadata type for template: ${tmpl.i18n.constructor.name}`);
22076
+ }
21436
22077
  const childView = unit.job.allocateView(unit.xref);
21437
22078
  let tagNameWithoutNamespace = tmpl.tagName;
21438
22079
  let namespacePrefix = '';
21439
22080
  if (tmpl.tagName) {
21440
22081
  [namespacePrefix, tagNameWithoutNamespace] = splitNsName(tmpl.tagName);
21441
22082
  }
22083
+ const i18nPlaceholder = tmpl.i18n instanceof TagPlaceholder ? tmpl.i18n : undefined;
21442
22084
  // TODO: validate the fallback tag name here.
21443
- const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace ?? 'ng-template', namespaceForKey(namespacePrefix), false, tmpl.i18n, tmpl.startSourceSpan);
22085
+ const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace ?? 'ng-template', namespaceForKey(namespacePrefix), false, i18nPlaceholder, tmpl.startSourceSpan);
21444
22086
  unit.create.push(tplOp);
21445
22087
  ingestBindings(unit, tplOp, tmpl);
21446
22088
  ingestReferences(tplOp, tmpl);
@@ -21448,6 +22090,12 @@ function ingestTemplate(unit, tmpl) {
21448
22090
  for (const { name, value } of tmpl.variables) {
21449
22091
  childView.contextVariables.set(name, value);
21450
22092
  }
22093
+ // If there is an i18n message associated with this template, insert i18n start and end ops.
22094
+ if (tmpl.i18n instanceof Message) {
22095
+ const id = unit.job.allocateXrefId();
22096
+ OpList.insertAfter(createI18nStartOp(id, tmpl.i18n), childView.create.head);
22097
+ OpList.insertBefore(createI18nEndOp(id), childView.create.tail);
22098
+ }
21451
22099
  }
21452
22100
  /**
21453
22101
  * Ingest a literal text node from the AST into the given `ViewCompilation`.
@@ -21455,7 +22103,7 @@ function ingestTemplate(unit, tmpl) {
21455
22103
  function ingestContent(unit, content) {
21456
22104
  const op = createProjectionOp(unit.job.allocateXrefId(), content.selector);
21457
22105
  for (const attr of content.attributes) {
21458
- ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, true, false);
22106
+ ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, BindingFlags.TextValue);
21459
22107
  }
21460
22108
  unit.create.push(op);
21461
22109
  }
@@ -21476,35 +22124,109 @@ function ingestBoundText(unit, text) {
21476
22124
  if (!(value instanceof Interpolation$1)) {
21477
22125
  throw new Error(`AssertionError: expected Interpolation for BoundText node, got ${value.constructor.name}`);
21478
22126
  }
22127
+ if (text.i18n !== undefined && !(text.i18n instanceof Container)) {
22128
+ throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n?.constructor.name}`);
22129
+ }
22130
+ const i18nPlaceholders = text.i18n instanceof Container ?
22131
+ text.i18n.children.filter((node) => node instanceof Placeholder) :
22132
+ [];
21479
22133
  const textXref = unit.job.allocateXrefId();
21480
22134
  unit.create.push(createTextOp(textXref, '', text.sourceSpan));
21481
22135
  // TemplateDefinitionBuilder does not generate source maps for sub-expressions inside an
21482
22136
  // interpolation. We copy that behavior in compatibility mode.
21483
22137
  // TODO: is it actually correct to generate these extra maps in modern mode?
21484
22138
  const baseSourceSpan = unit.job.compatibility ? null : text.sourceSpan;
21485
- unit.update.push(createInterpolateTextOp(textXref, new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, unit.job, baseSourceSpan))), text.sourceSpan));
22139
+ unit.update.push(createInterpolateTextOp(textXref, new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, unit.job, baseSourceSpan))), i18nPlaceholders, text.sourceSpan));
22140
+ }
22141
+ /**
22142
+ * Ingest an `@if` block into the given `ViewCompilation`.
22143
+ */
22144
+ function ingestIfBlock(unit, ifBlock) {
22145
+ let firstXref = null;
22146
+ let conditions = [];
22147
+ for (const ifCase of ifBlock.branches) {
22148
+ const cView = unit.job.allocateView(unit.xref);
22149
+ if (ifCase.expressionAlias !== null) {
22150
+ cView.contextVariables.set(ifCase.expressionAlias.name, CTX_REF);
22151
+ }
22152
+ if (firstXref === null) {
22153
+ firstXref = cView.xref;
22154
+ }
22155
+ unit.create.push(createTemplateOp(cView.xref, 'Conditional', Namespace.HTML, true, undefined /* TODO: figure out how i18n works with new control flow */, ifCase.sourceSpan));
22156
+ const caseExpr = ifCase.expression ? convertAst(ifCase.expression, unit.job, null) : null;
22157
+ const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, cView.xref, ifCase.expressionAlias);
22158
+ conditions.push(conditionalCaseExpr);
22159
+ ingestNodes(cView, ifCase.children);
22160
+ }
22161
+ const conditional = createConditionalOp(firstXref, null, conditions, ifBlock.sourceSpan);
22162
+ unit.update.push(conditional);
21486
22163
  }
21487
22164
  /**
21488
- * Ingest a `@switch` block into the given `ViewCompilation`.
22165
+ * Ingest an `@switch` block into the given `ViewCompilation`.
21489
22166
  */
21490
22167
  function ingestSwitchBlock(unit, switchBlock) {
21491
22168
  let firstXref = null;
21492
22169
  let conditions = [];
21493
22170
  for (const switchCase of switchBlock.cases) {
21494
22171
  const cView = unit.job.allocateView(unit.xref);
21495
- if (!firstXref)
22172
+ if (firstXref === null) {
21496
22173
  firstXref = cView.xref;
21497
- unit.create.push(createTemplateOp(cView.xref, 'Case', Namespace.HTML, true, undefined, null));
22174
+ }
22175
+ unit.create.push(createTemplateOp(cView.xref, 'Case', Namespace.HTML, true, undefined /* TODO: figure out how i18n works with new control flow */, switchCase.sourceSpan));
21498
22176
  const caseExpr = switchCase.expression ?
21499
22177
  convertAst(switchCase.expression, unit.job, switchBlock.startSourceSpan) :
21500
22178
  null;
21501
- conditions.push([cView.xref, caseExpr]);
22179
+ const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, cView.xref);
22180
+ conditions.push(conditionalCaseExpr);
21502
22181
  ingestNodes(cView, switchCase.children);
21503
22182
  }
21504
- const conditional = createConditionalOp(firstXref, convertAst(switchBlock.expression, unit.job, switchBlock.startSourceSpan), null);
21505
- conditional.conditions = conditions;
22183
+ const conditional = createConditionalOp(firstXref, convertAst(switchBlock.expression, unit.job, null), conditions, switchBlock.sourceSpan);
21506
22184
  unit.update.push(conditional);
21507
22185
  }
22186
+ function ingestDeferView(unit, suffix, children, sourceSpan) {
22187
+ if (children === undefined) {
22188
+ return null;
22189
+ }
22190
+ const secondaryView = unit.job.allocateView(unit.xref);
22191
+ ingestNodes(secondaryView, children);
22192
+ const templateOp = createTemplateOp(secondaryView.xref, `Defer${suffix}`, Namespace.HTML, true, undefined, sourceSpan);
22193
+ unit.create.push(templateOp);
22194
+ return templateOp;
22195
+ }
22196
+ function ingestDeferBlock(unit, deferBlock) {
22197
+ // Generate the defer main view and all secondary views.
22198
+ const main = ingestDeferView(unit, '', deferBlock.children, deferBlock.sourceSpan);
22199
+ const loading = ingestDeferView(unit, 'Loading', deferBlock.loading?.children, deferBlock.loading?.sourceSpan);
22200
+ const placeholder = ingestDeferView(unit, 'Placeholder', deferBlock.placeholder?.children, deferBlock.placeholder?.sourceSpan);
22201
+ const error = ingestDeferView(unit, 'Error', deferBlock.error?.children, deferBlock.error?.sourceSpan);
22202
+ // Create the main defer op, and ops for all secondary views.
22203
+ const deferOp = createDeferOp(unit.job.allocateXrefId(), main.xref, deferBlock.sourceSpan);
22204
+ unit.create.push(deferOp);
22205
+ if (loading && deferBlock.loading) {
22206
+ deferOp.loading =
22207
+ createDeferSecondaryOp(deferOp.xref, loading.xref, DeferSecondaryKind.Loading);
22208
+ if (deferBlock.loading.afterTime !== null || deferBlock.loading.minimumTime !== null) {
22209
+ deferOp.loading.constValue = [deferBlock.loading.minimumTime, deferBlock.loading.afterTime];
22210
+ }
22211
+ unit.create.push(deferOp.loading);
22212
+ }
22213
+ if (placeholder && deferBlock.placeholder) {
22214
+ deferOp.placeholder = createDeferSecondaryOp(deferOp.xref, placeholder.xref, DeferSecondaryKind.Placeholder);
22215
+ if (deferBlock.placeholder.minimumTime !== null) {
22216
+ deferOp.placeholder.constValue = [deferBlock.placeholder.minimumTime];
22217
+ }
22218
+ unit.create.push(deferOp.placeholder);
22219
+ }
22220
+ if (error && deferBlock.error) {
22221
+ deferOp.error =
22222
+ createDeferSecondaryOp(deferOp.xref, error.xref, DeferSecondaryKind.Error);
22223
+ unit.create.push(deferOp.error);
22224
+ }
22225
+ // Configure all defer conditions.
22226
+ const deferOnOp = createDeferOnOp(unit.job.allocateXrefId(), null);
22227
+ // Add all ops to the view.
22228
+ unit.create.push(deferOnOp);
22229
+ }
21508
22230
  /**
21509
22231
  * Convert a template AST expression into an output AST expression.
21510
22232
  */
@@ -21603,13 +22325,20 @@ function convertAst(ast, job, baseSourceSpan) {
21603
22325
  * to their IR representation.
21604
22326
  */
21605
22327
  function ingestBindings(unit, op, element) {
22328
+ let flags = BindingFlags.None;
22329
+ const isPlainTemplate = element instanceof Template && splitNsName(element.tagName ?? '')[1] === 'ng-template';
21606
22330
  if (element instanceof Template) {
22331
+ flags |= BindingFlags.OnNgTemplateElement;
22332
+ if (isPlainTemplate) {
22333
+ flags |= BindingFlags.BindingTargetsTemplate;
22334
+ }
22335
+ const templateAttrFlags = flags | BindingFlags.BindingTargetsTemplate | BindingFlags.IsStructuralTemplateAttribute;
21607
22336
  for (const attr of element.templateAttrs) {
21608
22337
  if (attr instanceof TextAttribute) {
21609
- ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, true, true);
22338
+ ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, templateAttrFlags | BindingFlags.TextValue);
21610
22339
  }
21611
22340
  else {
21612
- ingestBinding(unit, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, false, true);
22341
+ ingestBinding(unit, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, templateAttrFlags);
21613
22342
  }
21614
22343
  }
21615
22344
  }
@@ -21617,10 +22346,10 @@ function ingestBindings(unit, op, element) {
21617
22346
  // This is only attribute TextLiteral bindings, such as `attr.foo="bar"`. This can never be
21618
22347
  // `[attr.foo]="bar"` or `attr.foo="{{bar}}"`, both of which will be handled as inputs with
21619
22348
  // `BindingType.Attribute`.
21620
- ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, true, false);
22349
+ ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, flags | BindingFlags.TextValue);
21621
22350
  }
21622
22351
  for (const input of element.inputs) {
21623
- ingestBinding(unit, op.xref, input.name, input.value, input.type, input.unit, input.securityContext, input.sourceSpan, false, false);
22352
+ ingestBinding(unit, op.xref, input.name, input.value, input.type, input.unit, input.securityContext, input.sourceSpan, flags);
21624
22353
  }
21625
22354
  for (const output of element.outputs) {
21626
22355
  let listenerOp;
@@ -21629,6 +22358,10 @@ function ingestBindings(unit, op, element) {
21629
22358
  throw Error('Animation listener should have a phase');
21630
22359
  }
21631
22360
  }
22361
+ if (element instanceof Template && !isPlainTemplate) {
22362
+ unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null));
22363
+ continue;
22364
+ }
21632
22365
  listenerOp =
21633
22366
  createListenerOp(op.xref, output.name, op.tag, output.phase, false, output.sourceSpan);
21634
22367
  // if output.handler is a chain, then push each statement from the chain separately, and
@@ -21664,10 +22397,37 @@ const BINDING_KINDS = new Map([
21664
22397
  [3 /* e.BindingType.Style */, BindingKind.StyleProperty],
21665
22398
  [4 /* e.BindingType.Animation */, BindingKind.Animation],
21666
22399
  ]);
21667
- function ingestBinding(view, xref, name, value, type, unit, securityContext, sourceSpan, isTextAttribute, isTemplateBinding) {
22400
+ var BindingFlags;
22401
+ (function (BindingFlags) {
22402
+ BindingFlags[BindingFlags["None"] = 0] = "None";
22403
+ /**
22404
+ * The binding is to a static text literal and not to an expression.
22405
+ */
22406
+ BindingFlags[BindingFlags["TextValue"] = 1] = "TextValue";
22407
+ /**
22408
+ * The binding belongs to the `<ng-template>` side of a `t.Template`.
22409
+ */
22410
+ BindingFlags[BindingFlags["BindingTargetsTemplate"] = 2] = "BindingTargetsTemplate";
22411
+ /**
22412
+ * The binding is on a structural directive.
22413
+ */
22414
+ BindingFlags[BindingFlags["IsStructuralTemplateAttribute"] = 4] = "IsStructuralTemplateAttribute";
22415
+ /**
22416
+ * The binding is on a `t.Template`.
22417
+ */
22418
+ BindingFlags[BindingFlags["OnNgTemplateElement"] = 8] = "OnNgTemplateElement";
22419
+ })(BindingFlags || (BindingFlags = {}));
22420
+ function ingestBinding(view, xref, name, value, type, unit, securityContext, sourceSpan, flags) {
21668
22421
  if (value instanceof ASTWithSource) {
21669
22422
  value = value.ast;
21670
22423
  }
22424
+ if (flags & BindingFlags.OnNgTemplateElement && !(flags & BindingFlags.BindingTargetsTemplate) &&
22425
+ type === 0 /* e.BindingType.Property */) {
22426
+ // This binding only exists for later const extraction, and is not an actual binding to be
22427
+ // created.
22428
+ view.create.push(createExtractedAttributeOp(xref, BindingKind.Property, name, null));
22429
+ return;
22430
+ }
21671
22431
  let expression;
21672
22432
  // TODO: We could easily generate source maps for subexpressions in these cases, but
21673
22433
  // TemplateDefinitionBuilder does not. Should we do so?
@@ -21681,7 +22441,7 @@ function ingestBinding(view, xref, name, value, type, unit, securityContext, sou
21681
22441
  expression = value;
21682
22442
  }
21683
22443
  const kind = BINDING_KINDS.get(type);
21684
- view.update.push(createBindingOp(xref, kind, name, expression, unit, securityContext, isTextAttribute, isTemplateBinding, sourceSpan));
22444
+ view.update.push(createBindingOp(xref, kind, name, expression, unit, securityContext, !!(flags & BindingFlags.TextValue), !!(flags & BindingFlags.IsStructuralTemplateAttribute), sourceSpan));
21685
22445
  }
21686
22446
  /**
21687
22447
  * Process all of the local references on an element-like structure in the template AST and
@@ -22862,13 +23622,13 @@ function normalizeNgContentSelect(selectAttr) {
22862
23622
  /** Pattern for the expression in a for loop block. */
22863
23623
  const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+(.*)/;
22864
23624
  /** Pattern for the tracking expression in a for loop block. */
22865
- const FOR_LOOP_TRACK_PATTERN = /^track\s+(.*)/;
23625
+ const FOR_LOOP_TRACK_PATTERN = /^track\s+([\S\s]*)/;
22866
23626
  /** Pattern for the `as` expression in a conditional block. */
22867
23627
  const CONDITIONAL_ALIAS_PATTERN = /^as\s+(.*)/;
22868
23628
  /** Pattern used to identify an `else if` block. */
22869
23629
  const ELSE_IF_PATTERN = /^else[^\S\r\n]+if/;
22870
23630
  /** Pattern used to identify a `let` parameter. */
22871
- const FOR_LOOP_LET_PATTERN = /^let\s+(.*)/;
23631
+ const FOR_LOOP_LET_PATTERN = /^let\s+([\S\s]*)/;
22872
23632
  /** Names of variables that are allowed to be used in the `let` expression of a `for` loop. */
22873
23633
  const ALLOWED_FOR_LOOP_LET_VARIABLES = new Set(['$index', '$first', '$last', '$even', '$odd', '$count']);
22874
23634
  /**
@@ -22889,28 +23649,33 @@ function isConnectedIfLoopBlock(name) {
22889
23649
  function createIfBlock(ast, connectedBlocks, visitor, bindingParser) {
22890
23650
  const errors = validateIfConnectedBlocks(connectedBlocks);
22891
23651
  const branches = [];
22892
- if (errors.length > 0) {
22893
- return { node: null, errors };
22894
- }
22895
23652
  const mainBlockParams = parseConditionalBlockParameters(ast, errors, bindingParser);
22896
23653
  if (mainBlockParams !== null) {
22897
- branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan));
23654
+ branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan));
22898
23655
  }
22899
- // Assumes that the structure is valid since we validated it above.
22900
23656
  for (const block of connectedBlocks) {
22901
- const children = visitAll(visitor, block.children, block.children);
22902
23657
  if (ELSE_IF_PATTERN.test(block.name)) {
22903
23658
  const params = parseConditionalBlockParameters(block, errors, bindingParser);
22904
23659
  if (params !== null) {
22905
- branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan));
23660
+ const children = visitAll(visitor, block.children, block.children);
23661
+ branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan, block.endSourceSpan));
22906
23662
  }
22907
23663
  }
22908
23664
  else if (block.name === 'else') {
22909
- branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan));
23665
+ const children = visitAll(visitor, block.children, block.children);
23666
+ branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan, block.endSourceSpan));
22910
23667
  }
22911
23668
  }
23669
+ // The outer IfBlock should have a span that encapsulates all branches.
23670
+ const ifBlockStartSourceSpan = branches.length > 0 ? branches[0].startSourceSpan : ast.startSourceSpan;
23671
+ const ifBlockEndSourceSpan = branches.length > 0 ? branches[branches.length - 1].endSourceSpan : ast.endSourceSpan;
23672
+ let wholeSourceSpan = ast.sourceSpan;
23673
+ const lastBranch = branches[branches.length - 1];
23674
+ if (lastBranch !== undefined) {
23675
+ wholeSourceSpan = new ParseSourceSpan(ifBlockStartSourceSpan.start, lastBranch.sourceSpan.end);
23676
+ }
22912
23677
  return {
22913
- node: new IfBlock(branches, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
23678
+ node: new IfBlock(branches, wholeSourceSpan, ast.startSourceSpan, ifBlockEndSourceSpan),
22914
23679
  errors,
22915
23680
  };
22916
23681
  }
@@ -22929,7 +23694,7 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
22929
23694
  errors.push(new ParseError(block.sourceSpan, '@empty block cannot have parameters'));
22930
23695
  }
22931
23696
  else {
22932
- empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan);
23697
+ empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan, block.endSourceSpan);
22933
23698
  }
22934
23699
  }
22935
23700
  else {
@@ -22938,10 +23703,16 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
22938
23703
  }
22939
23704
  if (params !== null) {
22940
23705
  if (params.trackBy === null) {
23706
+ // TODO: We should not fail here, and instead try to produce some AST for the language
23707
+ // service.
22941
23708
  errors.push(new ParseError(ast.sourceSpan, '@for loop must have a "track" expression'));
22942
23709
  }
22943
23710
  else {
22944
- node = new ForLoopBlock(params.itemName, params.expression, params.trackBy, params.context, visitAll(visitor, ast.children, ast.children), empty, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
23711
+ // The `for` block has a main span that includes the `empty` branch. For only the span of the
23712
+ // main `for` body, use `mainSourceSpan`.
23713
+ const endSpan = empty?.endSourceSpan ?? ast.endSourceSpan;
23714
+ const sourceSpan = new ParseSourceSpan(ast.sourceSpan.start, endSpan?.end ?? ast.sourceSpan.end);
23715
+ node = new ForLoopBlock(params.itemName, params.expression, params.trackBy, params.context, visitAll(visitor, ast.children, ast.children), empty, sourceSpan, ast.sourceSpan, ast.startSourceSpan, endSpan);
22945
23716
  }
22946
23717
  }
22947
23718
  return { node, errors };
@@ -22949,21 +23720,25 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
22949
23720
  /** Creates a switch block from an HTML AST node. */
22950
23721
  function createSwitchBlock(ast, visitor, bindingParser) {
22951
23722
  const errors = validateSwitchBlock(ast);
22952
- if (errors.length > 0) {
22953
- return { node: null, errors };
22954
- }
22955
- const primaryExpression = parseBlockParameterToBinding(ast.parameters[0], bindingParser);
23723
+ const primaryExpression = ast.parameters.length > 0 ?
23724
+ parseBlockParameterToBinding(ast.parameters[0], bindingParser) :
23725
+ bindingParser.parseBinding('', false, ast.sourceSpan, 0);
22956
23726
  const cases = [];
23727
+ const unknownBlocks = [];
22957
23728
  let defaultCase = null;
22958
23729
  // Here we assume that all the blocks are valid given that we validated them above.
22959
23730
  for (const node of ast.children) {
22960
23731
  if (!(node instanceof Block)) {
22961
23732
  continue;
22962
23733
  }
23734
+ if ((node.name !== 'case' || node.parameters.length === 0) && node.name !== 'default') {
23735
+ unknownBlocks.push(new UnknownBlock(node.name, node.sourceSpan));
23736
+ continue;
23737
+ }
22963
23738
  const expression = node.name === 'case' ?
22964
23739
  parseBlockParameterToBinding(node.parameters[0], bindingParser) :
22965
23740
  null;
22966
- const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan);
23741
+ const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan, node.endSourceSpan);
22967
23742
  if (expression === null) {
22968
23743
  defaultCase = ast;
22969
23744
  }
@@ -22976,7 +23751,7 @@ function createSwitchBlock(ast, visitor, bindingParser) {
22976
23751
  cases.push(defaultCase);
22977
23752
  }
22978
23753
  return {
22979
- node: new SwitchBlock(primaryExpression, cases, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
23754
+ node: new SwitchBlock(primaryExpression, cases, unknownBlocks, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
22980
23755
  errors
22981
23756
  };
22982
23757
  }
@@ -23020,8 +23795,10 @@ function parseForLoopParameters(block, errors, bindingParser) {
23020
23795
  // Fill out any variables that haven't been defined explicitly.
23021
23796
  for (const variableName of ALLOWED_FOR_LOOP_LET_VARIABLES) {
23022
23797
  if (!result.context.hasOwnProperty(variableName)) {
23023
- result.context[variableName] =
23024
- new Variable(variableName, variableName, block.startSourceSpan, block.startSourceSpan);
23798
+ // Give ambiently-available context variables empty spans at the end of the start of the `for`
23799
+ // block, since they are not explicitly defined.
23800
+ const emptySpanAfterForBlockStart = new ParseSourceSpan(block.startSourceSpan.end, block.startSourceSpan.end);
23801
+ result.context[variableName] = new Variable(variableName, variableName, emptySpanAfterForBlockStart, emptySpanAfterForBlockStart);
23025
23802
  }
23026
23803
  }
23027
23804
  return result;
@@ -23516,7 +24293,17 @@ function createDeferredBlock(ast, connectedBlocks, visitor, bindingParser) {
23516
24293
  const errors = [];
23517
24294
  const { placeholder, loading, error } = parseConnectedBlocks(connectedBlocks, errors, visitor);
23518
24295
  const { triggers, prefetchTriggers } = parsePrimaryTriggers(ast.parameters, bindingParser, errors, placeholder);
23519
- const node = new DeferredBlock(visitAll(visitor, ast.children, ast.children), triggers, prefetchTriggers, placeholder, loading, error, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
24296
+ // The `defer` block has a main span encompassing all of the connected branches as well. For the
24297
+ // span of only the first "main" branch, use `mainSourceSpan`.
24298
+ let lastEndSourceSpan = ast.endSourceSpan;
24299
+ let endOfLastSourceSpan = ast.sourceSpan.end;
24300
+ if (connectedBlocks.length > 0) {
24301
+ const lastConnectedBlock = connectedBlocks[connectedBlocks.length - 1];
24302
+ lastEndSourceSpan = lastConnectedBlock.endSourceSpan;
24303
+ endOfLastSourceSpan = lastConnectedBlock.sourceSpan.end;
24304
+ }
24305
+ const mainDeferredSourceSpan = new ParseSourceSpan(ast.sourceSpan.start, endOfLastSourceSpan);
24306
+ const node = new DeferredBlock(visitAll(visitor, ast.children, ast.children), triggers, prefetchTriggers, placeholder, loading, error, mainDeferredSourceSpan, ast.sourceSpan, ast.startSourceSpan, lastEndSourceSpan);
23520
24307
  return { node, errors };
23521
24308
  }
23522
24309
  function parseConnectedBlocks(connectedBlocks, errors, visitor) {
@@ -23891,26 +24678,6 @@ class HtmlAstToIvyAst {
23891
24678
  if (this.processedNodes.has(block)) {
23892
24679
  return null;
23893
24680
  }
23894
- if (!this.options.enabledBlockTypes.has(block.name)) {
23895
- let errorMessage;
23896
- if (isConnectedDeferLoopBlock(block.name)) {
23897
- errorMessage = `@${block.name} block can only be used after an @defer block.`;
23898
- this.processedNodes.add(block);
23899
- }
23900
- else if (isConnectedForLoopBlock(block.name)) {
23901
- errorMessage = `@${block.name} block can only be used after an @for block.`;
23902
- this.processedNodes.add(block);
23903
- }
23904
- else if (isConnectedIfLoopBlock(block.name)) {
23905
- errorMessage = `@${block.name} block can only be used after an @if or @else if block.`;
23906
- this.processedNodes.add(block);
23907
- }
23908
- else {
23909
- errorMessage = `Unrecognized block @${block.name}.`;
23910
- }
23911
- this.reportError(errorMessage, block.sourceSpan);
23912
- return null;
23913
- }
23914
24681
  let result = null;
23915
24682
  switch (block.name) {
23916
24683
  case 'defer':
@@ -23926,9 +24693,25 @@ class HtmlAstToIvyAst {
23926
24693
  result = createIfBlock(block, this.findConnectedBlocks(index, context, isConnectedIfLoopBlock), this, this.bindingParser);
23927
24694
  break;
23928
24695
  default:
24696
+ let errorMessage;
24697
+ if (isConnectedDeferLoopBlock(block.name)) {
24698
+ errorMessage = `@${block.name} block can only be used after an @defer block.`;
24699
+ this.processedNodes.add(block);
24700
+ }
24701
+ else if (isConnectedForLoopBlock(block.name)) {
24702
+ errorMessage = `@${block.name} block can only be used after an @for block.`;
24703
+ this.processedNodes.add(block);
24704
+ }
24705
+ else if (isConnectedIfLoopBlock(block.name)) {
24706
+ errorMessage = `@${block.name} block can only be used after an @if or @else if block.`;
24707
+ this.processedNodes.add(block);
24708
+ }
24709
+ else {
24710
+ errorMessage = `Unrecognized block @${block.name}.`;
24711
+ }
23929
24712
  result = {
23930
- node: null,
23931
- errors: [new ParseError(block.sourceSpan, `Unrecognized block @${block.name}.`)]
24713
+ node: new UnknownBlock(block.name, block.sourceSpan),
24714
+ errors: [new ParseError(block.sourceSpan, errorMessage)],
23932
24715
  };
23933
24716
  break;
23934
24717
  }
@@ -24517,6 +25300,7 @@ class TemplateDefinitionBuilder {
24517
25300
  this.visitIfBlockBranch = invalid;
24518
25301
  this.visitSwitchBlockCase = invalid;
24519
25302
  this.visitForLoopBlockEmpty = invalid;
25303
+ this.visitUnknownBlock = invalid;
24520
25304
  this._bindingScope = parentBindingScope.nestedScope(level);
24521
25305
  // Turn the relative context file path into an identifier by replacing non-alphanumeric
24522
25306
  // characters with underscores.
@@ -25242,18 +26026,17 @@ class TemplateDefinitionBuilder {
25242
26026
  // callback in order to generate the correct expressions when pipes or pure functions are
25243
26027
  // used inside the branch expressions.
25244
26028
  const branchData = block.branches.map(({ expression, expressionAlias, children, sourceSpan }) => {
25245
- const processedExpression = expression === null ? null : expression.visit(this._valueConverter);
25246
26029
  // If the branch has an alias, it'll be assigned directly to the container's context.
25247
26030
  // We define a variable referring directly to the context so that any nested usages can be
25248
26031
  // rewritten to refer to it.
25249
26032
  const variables = expressionAlias !== null ?
25250
26033
  [new Variable(expressionAlias.name, DIRECT_CONTEXT_REFERENCE, expressionAlias.sourceSpan, expressionAlias.keySpan)] :
25251
26034
  undefined;
25252
- return {
25253
- index: this.createEmbeddedTemplateFn(null, children, '_Conditional', sourceSpan, variables),
25254
- expression: processedExpression,
25255
- alias: expressionAlias
25256
- };
26035
+ // Note: the template needs to be created *before* we process the expression,
26036
+ // otherwise pipes injecting some symbols won't work (see #52102).
26037
+ const index = this.createEmbeddedTemplateFn(null, children, '_Conditional', sourceSpan, variables);
26038
+ const processedExpression = expression === null ? null : expression.visit(this._valueConverter);
26039
+ return { index, expression: processedExpression, alias: expressionAlias };
25257
26040
  });
25258
26041
  // Use the index of the first block as the index for the entire container.
25259
26042
  const containerIndex = branchData[0].index;
@@ -25299,20 +26082,21 @@ class TemplateDefinitionBuilder {
25299
26082
  this.updateInstructionWithAdvance(containerIndex, block.branches[0].sourceSpan, Identifiers.conditional, paramsCallback);
25300
26083
  }
25301
26084
  visitSwitchBlock(block) {
25302
- const blockExpression = block.expression.visit(this._valueConverter);
25303
- this.allocateBindingSlots(null); // Allocate a slot for the primary block expression.
25304
26085
  // We have to process the block in two steps: once here and again in the update instruction
25305
26086
  // callback in order to generate the correct expressions when pipes or pure functions are used.
25306
26087
  const caseData = block.cases.map(currentCase => {
25307
- return {
25308
- index: this.createEmbeddedTemplateFn(null, currentCase.children, '_Case', currentCase.sourceSpan),
25309
- expression: currentCase.expression === null ?
25310
- null :
25311
- currentCase.expression.visit(this._valueConverter)
25312
- };
26088
+ const index = this.createEmbeddedTemplateFn(null, currentCase.children, '_Case', currentCase.sourceSpan);
26089
+ const expression = currentCase.expression === null ?
26090
+ null :
26091
+ currentCase.expression.visit(this._valueConverter);
26092
+ return { index, expression };
25313
26093
  });
25314
26094
  // Use the index of the first block as the index for the entire container.
25315
26095
  const containerIndex = caseData[0].index;
26096
+ // Note: the expression needs to be processed *after* the template,
26097
+ // otherwise pipes injecting some symbols won't work (see #52102).
26098
+ const blockExpression = block.expression.visit(this._valueConverter);
26099
+ this.allocateBindingSlots(null); // Allocate a slot for the primary block expression.
25316
26100
  this.updateInstructionWithAdvance(containerIndex, block.sourceSpan, Identifiers.conditional, () => {
25317
26101
  const generateCases = (caseIndex) => {
25318
26102
  // If we've gone beyond the last branch, return the special -1
@@ -25380,12 +26164,17 @@ class TemplateDefinitionBuilder {
25380
26164
  literal(errorIndex),
25381
26165
  loadingConsts?.length ? this.addToConsts(literalArr(loadingConsts)) : TYPED_NULL_EXPR,
25382
26166
  placeholderConsts ? this.addToConsts(placeholderConsts) : TYPED_NULL_EXPR,
26167
+ (loadingConsts?.length || placeholderConsts) ?
26168
+ importExpr(Identifiers.deferEnableTimerScheduling) :
26169
+ TYPED_NULL_EXPR,
25383
26170
  ]));
25384
- this.createDeferTriggerInstructions(deferredIndex, triggers, metadata, false);
25385
- this.createDeferTriggerInstructions(deferredIndex, prefetchTriggers, metadata, true);
25386
26171
  // Allocate an extra data slot right after a defer block slot to store
25387
26172
  // instance-specific state of that defer block at runtime.
25388
26173
  this.allocateDataSlot();
26174
+ // Note: the triggers need to be processed *after* the various templates,
26175
+ // otherwise pipes injecting some symbols won't work (see #52102).
26176
+ this.createDeferTriggerInstructions(deferredIndex, triggers, metadata, false);
26177
+ this.createDeferTriggerInstructions(deferredIndex, prefetchTriggers, metadata, true);
25389
26178
  }
25390
26179
  createDeferredDepsFunction(name, metadata) {
25391
26180
  if (metadata.deps.length === 0) {
@@ -25477,12 +26266,13 @@ class TemplateDefinitionBuilder {
25477
26266
  // are implicitly inferred by the runtime to index + 1 and index + 2.
25478
26267
  const blockIndex = this.allocateDataSlot();
25479
26268
  const primaryData = this.prepareEmbeddedTemplateFn(block.children, '_For', [block.item, block.contextVariables.$index, block.contextVariables.$count]);
25480
- const emptyData = block.empty === null ?
25481
- null :
25482
- this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty');
25483
26269
  const { expression: trackByExpression, usesComponentInstance: trackByUsesComponentInstance } = this.createTrackByFunction(block);
25484
- const value = block.expression.visit(this._valueConverter);
25485
- this.allocateBindingSlots(value);
26270
+ let emptyData = null;
26271
+ if (block.empty !== null) {
26272
+ emptyData = this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty');
26273
+ // Allocate an extra slot for the empty block tracking.
26274
+ this.allocateBindingSlots(null);
26275
+ }
25486
26276
  this.registerComputedLoopVariables(block, primaryData.scope);
25487
26277
  // `repeaterCreate(0, ...)`
25488
26278
  this.creationInstruction(block.sourceSpan, Identifiers.repeaterCreate, () => {
@@ -25502,6 +26292,11 @@ class TemplateDefinitionBuilder {
25502
26292
  }
25503
26293
  return params;
25504
26294
  });
26295
+ // Note: the expression needs to be processed *after* the template,
26296
+ // otherwise pipes injecting some symbols won't work (see #52102).
26297
+ // Note: we don't allocate binding slots for this expression,
26298
+ // because its value isn't stored in the LView.
26299
+ const value = block.expression.visit(this._valueConverter);
25505
26300
  // `repeater(0, iterable)`
25506
26301
  this.updateInstruction(block.sourceSpan, Identifiers.repeater, () => [literal(blockIndex), this.convertPropertyBinding(value)]);
25507
26302
  }
@@ -26377,7 +27172,7 @@ function parseTemplate(template, templateUrl, options = {}) {
26377
27172
  leadingTriviaChars: LEADING_TRIVIA_CHARS,
26378
27173
  ...options,
26379
27174
  tokenizeExpansionForms: true,
26380
- tokenizeBlocks: options.enabledBlockTypes != null && options.enabledBlockTypes.size > 0,
27175
+ tokenizeBlocks: options.enableBlockSyntax ?? true,
26381
27176
  });
26382
27177
  if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
26383
27178
  parseResult.errors.length > 0) {
@@ -26429,10 +27224,7 @@ function parseTemplate(template, templateUrl, options = {}) {
26429
27224
  rootNodes = visitAll(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
26430
27225
  }
26431
27226
  }
26432
- const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, {
26433
- collectCommentNodes: !!options.collectCommentNodes,
26434
- enabledBlockTypes: options.enabledBlockTypes || new Set(),
26435
- });
27227
+ const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, { collectCommentNodes: !!options.collectCommentNodes });
26436
27228
  errors.push(...parseResult.errors, ...i18nMetaResult.errors);
26437
27229
  const parsedTemplate = {
26438
27230
  interpolationConfig,
@@ -26707,14 +27499,14 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
26707
27499
  // - either as an array:
26708
27500
  // `consts: [['one', 'two'], ['three', 'four']]`
26709
27501
  // - or as a factory function in case additional statements are present (to support i18n):
26710
- // `consts: function() { var i18n_0; if (ngI18nClosureMode) {...} else {...} return [i18n_0];
27502
+ // `consts: () => { var i18n_0; if (ngI18nClosureMode) {...} else {...} return [i18n_0];
26711
27503
  // }`
26712
27504
  const { constExpressions, prepareStatements } = templateBuilder.getConsts();
26713
27505
  if (constExpressions.length > 0) {
26714
27506
  let constsExpr = literalArr(constExpressions);
26715
27507
  // Prepare statements are present - turn `consts` into a function.
26716
27508
  if (prepareStatements.length > 0) {
26717
- constsExpr = fn([], [...prepareStatements, new ReturnStatement(constsExpr)]);
27509
+ constsExpr = arrowFn([], [...prepareStatements, new ReturnStatement(constsExpr)]);
26718
27510
  }
26719
27511
  definitionMap.set('consts', constsExpr);
26720
27512
  }
@@ -26735,7 +27527,9 @@ function compileComponentFromMetadata(meta, constantPool, bindingParser) {
26735
27527
  definitionMap.set('vars', literal(tpl.root.vars));
26736
27528
  if (tpl.consts.length > 0) {
26737
27529
  if (tpl.constsInitializers.length > 0) {
26738
- definitionMap.set('consts', fn([], [...tpl.constsInitializers, new ReturnStatement(literalArr(tpl.consts))]));
27530
+ definitionMap.set('consts', arrowFn([], [
27531
+ ...tpl.constsInitializers, new ReturnStatement(literalArr(tpl.consts))
27532
+ ]));
26739
27533
  }
26740
27534
  else {
26741
27535
  definitionMap.set('consts', literalArr(tpl.consts));
@@ -26829,11 +27623,11 @@ function compileDeclarationList(list, mode) {
26829
27623
  return list;
26830
27624
  case 1 /* DeclarationListEmitMode.Closure */:
26831
27625
  // directives: function () { return [MyDir]; }
26832
- return fn([], [new ReturnStatement(list)]);
27626
+ return arrowFn([], list);
26833
27627
  case 2 /* DeclarationListEmitMode.ClosureResolved */:
26834
27628
  // directives: function () { return [MyDir].map(ng.resolveForwardRef); }
26835
27629
  const resolvedList = list.prop('map').callFn([importExpr(Identifiers.resolveForwardRef)]);
26836
- return fn([], [new ReturnStatement(resolvedList)]);
27630
+ return arrowFn([], resolvedList);
26837
27631
  case 3 /* DeclarationListEmitMode.RuntimeResolved */:
26838
27632
  throw new Error(`Unsupported with an array of pre-resolved dependencies`);
26839
27633
  }
@@ -27523,6 +28317,7 @@ class Scope {
27523
28317
  visitTextAttribute(attr) { }
27524
28318
  visitIcu(icu) { }
27525
28319
  visitDeferredTrigger(trigger) { }
28320
+ visitUnknownBlock(block) { }
27526
28321
  maybeDeclare(thing) {
27527
28322
  // Declare something with a name, as long as that name isn't taken.
27528
28323
  if (!this.namedEntities.has(thing.name)) {
@@ -27724,6 +28519,7 @@ class DirectiveBinder {
27724
28519
  visitBoundText(text) { }
27725
28520
  visitIcu(icu) { }
27726
28521
  visitDeferredTrigger(trigger) { }
28522
+ visitUnknownBlock(block) { }
27727
28523
  }
27728
28524
  /**
27729
28525
  * Processes a template and extract metadata about expressions and symbols within.
@@ -27852,6 +28648,8 @@ class TemplateBinder extends RecursiveAstVisitor {
27852
28648
  visitText(text) { }
27853
28649
  visitContent(content) { }
27854
28650
  visitTextAttribute(attribute) { }
28651
+ visitUnknownBlock(block) { }
28652
+ visitDeferredTrigger() { }
27855
28653
  visitIcu(icu) {
27856
28654
  Object.keys(icu.vars).forEach(key => icu.vars[key].visit(this));
27857
28655
  Object.keys(icu.placeholders).forEach(key => icu.placeholders[key].visit(this));
@@ -27866,15 +28664,12 @@ class TemplateBinder extends RecursiveAstVisitor {
27866
28664
  visitDeferredBlock(deferred) {
27867
28665
  this.deferBlocks.add(deferred);
27868
28666
  this.ingestScopedNode(deferred);
28667
+ deferred.triggers.when?.value.visit(this);
28668
+ deferred.prefetchTriggers.when?.value.visit(this);
27869
28669
  deferred.placeholder && this.visitNode(deferred.placeholder);
27870
28670
  deferred.loading && this.visitNode(deferred.loading);
27871
28671
  deferred.error && this.visitNode(deferred.error);
27872
28672
  }
27873
- visitDeferredTrigger(trigger) {
27874
- if (trigger instanceof BoundDeferredTrigger) {
27875
- trigger.value.visit(this);
27876
- }
27877
- }
27878
28673
  visitDeferredBlockPlaceholder(block) {
27879
28674
  this.ingestScopedNode(block);
27880
28675
  }
@@ -28113,11 +28908,6 @@ function extractScopedNodeEntities(rootScope) {
28113
28908
  class ResourceLoader {
28114
28909
  }
28115
28910
 
28116
- let enabledBlockTypes;
28117
- /** Temporary utility that enables specific block types in JIT compilations. */
28118
- function ɵsetEnabledBlockTypes(types) {
28119
- enabledBlockTypes = types.length > 0 ? new Set(types) : undefined;
28120
- }
28121
28911
  class CompilerFacadeImpl {
28122
28912
  constructor(jitEvaluator = new JitEvaluator()) {
28123
28913
  this.jitEvaluator = jitEvaluator;
@@ -28523,7 +29313,7 @@ function convertPipeDeclarationToMetadata(pipe) {
28523
29313
  function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces, interpolation) {
28524
29314
  const interpolationConfig = interpolation ? InterpolationConfig.fromArray(interpolation) : DEFAULT_INTERPOLATION_CONFIG;
28525
29315
  // Parse the template and check for errors.
28526
- const parsed = parseTemplate(template, sourceMapUrl, { preserveWhitespaces, interpolationConfig, enabledBlockTypes });
29316
+ const parsed = parseTemplate(template, sourceMapUrl, { preserveWhitespaces, interpolationConfig });
28527
29317
  if (parsed.errors !== null) {
28528
29318
  const errors = parsed.errors.map(err => err.toString()).join(', ');
28529
29319
  throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`);
@@ -28736,13 +29526,11 @@ function publishFacade(global) {
28736
29526
  * @description
28737
29527
  * Entry point for all public APIs of the compiler package.
28738
29528
  */
28739
- const VERSION = new Version('17.0.0-next.6');
29529
+ const VERSION = new Version('17.0.0-next.8');
28740
29530
 
28741
29531
  class CompilerConfig {
28742
- constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
29532
+ constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
28743
29533
  this.defaultEncapsulation = defaultEncapsulation;
28744
- this.useJit = !!useJit;
28745
- this.missingTranslation = missingTranslation;
28746
29534
  this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
28747
29535
  this.strictInjectionParameters = strictInjectionParameters === true;
28748
29536
  }
@@ -30232,6 +31020,31 @@ function compileComponentClassMetadata(metadata, deferrableTypes) {
30232
31020
  return iife.callFn([]);
30233
31021
  }
30234
31022
 
31023
+ /**
31024
+ * Generate an ngDevMode guarded call to setClassDebugInfo with the debug info about the class
31025
+ * (e.g., the file name in which the class is defined)
31026
+ */
31027
+ function compileClassDebugInfo(debugInfo) {
31028
+ const debugInfoObject = {
31029
+ className: debugInfo.className,
31030
+ };
31031
+ // Include file path and line number only if the file relative path is calculated successfully.
31032
+ if (debugInfo.filePath) {
31033
+ debugInfoObject.filePath = debugInfo.filePath;
31034
+ debugInfoObject.lineNumber = debugInfo.lineNumber;
31035
+ }
31036
+ // Include forbidOrphanRendering only if it's set to true (to reduce generated code)
31037
+ if (debugInfo.forbidOrphanRendering) {
31038
+ debugInfoObject.forbidOrphanRendering = literal(true);
31039
+ }
31040
+ const fnCall = importExpr(Identifiers.setClassDebugInfo).callFn([
31041
+ debugInfo.type,
31042
+ mapLiteral(debugInfoObject),
31043
+ ]);
31044
+ const iife = arrowFn([], [devOnlyGuardedExpression(fnCall).toStmt()]);
31045
+ return iife.callFn([]);
31046
+ }
31047
+
30235
31048
  /**
30236
31049
  * Every time we make a breaking change to the declaration interface or partial-linker behavior, we
30237
31050
  * must update this constant to prevent old partial-linkers from incorrectly processing the
@@ -30243,7 +31056,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
30243
31056
  function compileDeclareClassMetadata(metadata) {
30244
31057
  const definitionMap = new DefinitionMap();
30245
31058
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
30246
- definitionMap.set('version', literal('17.0.0-next.6'));
31059
+ definitionMap.set('version', literal('17.0.0-next.8'));
30247
31060
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30248
31061
  definitionMap.set('type', metadata.type);
30249
31062
  definitionMap.set('decorators', metadata.decorators);
@@ -30351,7 +31164,7 @@ function createDirectiveDefinitionMap(meta) {
30351
31164
  // in 16.1 is actually used.
30352
31165
  const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
30353
31166
  definitionMap.set('minVersion', literal(minVersion));
30354
- definitionMap.set('version', literal('17.0.0-next.6'));
31167
+ definitionMap.set('version', literal('17.0.0-next.8'));
30355
31168
  // e.g. `type: MyDirective`
30356
31169
  definitionMap.set('type', meta.type.value);
30357
31170
  if (meta.isStandalone) {
@@ -30477,10 +31290,17 @@ function compileDeclareComponentFromMetadata(meta, template, additionalTemplateI
30477
31290
  */
30478
31291
  function createComponentDefinitionMap(meta, template, templateInfo) {
30479
31292
  const definitionMap = createDirectiveDefinitionMap(meta);
31293
+ const blockVisitor = new BlockPresenceVisitor();
31294
+ visitAll$1(blockVisitor, template.nodes);
30480
31295
  definitionMap.set('template', getTemplateExpression(template, templateInfo));
30481
31296
  if (templateInfo.isInline) {
30482
31297
  definitionMap.set('isInline', literal(true));
30483
31298
  }
31299
+ // Set the minVersion to 17.0.0 if the component is using at least one block in its template.
31300
+ // We don't do this for templates without blocks, in order to preserve backwards compatibility.
31301
+ if (blockVisitor.hasBlocks) {
31302
+ definitionMap.set('minVersion', literal('17.0.0'));
31303
+ }
30484
31304
  definitionMap.set('styles', toOptionalLiteralArray(meta.styles, literal));
30485
31305
  definitionMap.set('dependencies', compileUsedDependenciesMetadata(meta));
30486
31306
  definitionMap.set('viewProviders', meta.viewProviders);
@@ -30573,6 +31393,42 @@ function compileUsedDependenciesMetadata(meta) {
30573
31393
  }
30574
31394
  });
30575
31395
  }
31396
+ class BlockPresenceVisitor extends RecursiveVisitor$1 {
31397
+ constructor() {
31398
+ super(...arguments);
31399
+ this.hasBlocks = false;
31400
+ }
31401
+ visitDeferredBlock() {
31402
+ this.hasBlocks = true;
31403
+ }
31404
+ visitDeferredBlockPlaceholder() {
31405
+ this.hasBlocks = true;
31406
+ }
31407
+ visitDeferredBlockLoading() {
31408
+ this.hasBlocks = true;
31409
+ }
31410
+ visitDeferredBlockError() {
31411
+ this.hasBlocks = true;
31412
+ }
31413
+ visitIfBlock() {
31414
+ this.hasBlocks = true;
31415
+ }
31416
+ visitIfBlockBranch() {
31417
+ this.hasBlocks = true;
31418
+ }
31419
+ visitForLoopBlock() {
31420
+ this.hasBlocks = true;
31421
+ }
31422
+ visitForLoopBlockEmpty() {
31423
+ this.hasBlocks = true;
31424
+ }
31425
+ visitSwitchBlock() {
31426
+ this.hasBlocks = true;
31427
+ }
31428
+ visitSwitchBlockCase() {
31429
+ this.hasBlocks = true;
31430
+ }
31431
+ }
30576
31432
 
30577
31433
  /**
30578
31434
  * Every time we make a breaking change to the declaration interface or partial-linker behavior, we
@@ -30585,7 +31441,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
30585
31441
  function compileDeclareFactoryFunction(meta) {
30586
31442
  const definitionMap = new DefinitionMap();
30587
31443
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
30588
- definitionMap.set('version', literal('17.0.0-next.6'));
31444
+ definitionMap.set('version', literal('17.0.0-next.8'));
30589
31445
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30590
31446
  definitionMap.set('type', meta.type.value);
30591
31447
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -30620,7 +31476,7 @@ function compileDeclareInjectableFromMetadata(meta) {
30620
31476
  function createInjectableDefinitionMap(meta) {
30621
31477
  const definitionMap = new DefinitionMap();
30622
31478
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
30623
- definitionMap.set('version', literal('17.0.0-next.6'));
31479
+ definitionMap.set('version', literal('17.0.0-next.8'));
30624
31480
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30625
31481
  definitionMap.set('type', meta.type.value);
30626
31482
  // Only generate providedIn property if it has a non-null value
@@ -30671,7 +31527,7 @@ function compileDeclareInjectorFromMetadata(meta) {
30671
31527
  function createInjectorDefinitionMap(meta) {
30672
31528
  const definitionMap = new DefinitionMap();
30673
31529
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
30674
- definitionMap.set('version', literal('17.0.0-next.6'));
31530
+ definitionMap.set('version', literal('17.0.0-next.8'));
30675
31531
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30676
31532
  definitionMap.set('type', meta.type.value);
30677
31533
  definitionMap.set('providers', meta.providers);
@@ -30704,7 +31560,7 @@ function createNgModuleDefinitionMap(meta) {
30704
31560
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
30705
31561
  }
30706
31562
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
30707
- definitionMap.set('version', literal('17.0.0-next.6'));
31563
+ definitionMap.set('version', literal('17.0.0-next.8'));
30708
31564
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30709
31565
  definitionMap.set('type', meta.type.value);
30710
31566
  // We only generate the keys in the metadata if the arrays contain values.
@@ -30755,7 +31611,7 @@ function compileDeclarePipeFromMetadata(meta) {
30755
31611
  function createPipeDefinitionMap(meta) {
30756
31612
  const definitionMap = new DefinitionMap();
30757
31613
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
30758
- definitionMap.set('version', literal('17.0.0-next.6'));
31614
+ definitionMap.set('version', literal('17.0.0-next.8'));
30759
31615
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30760
31616
  // e.g. `type: MyPipe`
30761
31617
  definitionMap.set('type', meta.type.value);
@@ -30788,5 +31644,5 @@ publishFacade(_global);
30788
31644
 
30789
31645
  // This file is not used to build this module. It is only used during editing
30790
31646
 
30791
- export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, ArrowFunctionExpr, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, 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 };
31647
+ export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, ArrowFunctionExpr, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, 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, UnknownBlock as TmplAstUnknownBlock, 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, compileClassDebugInfo, 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, literal, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
30792
31648
  //# sourceMappingURL=compiler.mjs.map