@angular/compiler 17.0.0-next.7 → 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 (49) hide show
  1. package/esm2022/src/compiler.mjs +4 -3
  2. package/esm2022/src/config.mjs +2 -4
  3. package/esm2022/src/ml_parser/lexer.mjs +18 -10
  4. package/esm2022/src/ml_parser/parser.mjs +28 -10
  5. package/esm2022/src/ml_parser/tokens.mjs +1 -1
  6. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  7. package/esm2022/src/render3/partial/directive.mjs +1 -1
  8. package/esm2022/src/render3/partial/factory.mjs +1 -1
  9. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  10. package/esm2022/src/render3/partial/injector.mjs +1 -1
  11. package/esm2022/src/render3/partial/ng_module.mjs +1 -1
  12. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  13. package/esm2022/src/render3/r3_ast.mjs +37 -19
  14. package/esm2022/src/render3/r3_class_debug_info_compiler.mjs +36 -0
  15. package/esm2022/src/render3/r3_control_flow.mjs +40 -23
  16. package/esm2022/src/render3/r3_deferred_blocks.mjs +13 -3
  17. package/esm2022/src/render3/r3_identifiers.mjs +3 -1
  18. package/esm2022/src/render3/r3_template_transform.mjs +5 -2
  19. package/esm2022/src/render3/view/t2_binder.mjs +8 -7
  20. package/esm2022/src/render3/view/template.mjs +35 -24
  21. package/esm2022/src/template/pipeline/ir/src/expression.mjs +1 -1
  22. package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +6 -3
  23. package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +4 -3
  24. package/esm2022/src/template/pipeline/ir/src/traits.mjs +1 -1
  25. package/esm2022/src/template/pipeline/src/emit.mjs +7 -1
  26. package/esm2022/src/template/pipeline/src/ingest.mjs +8 -6
  27. package/esm2022/src/template/pipeline/src/instruction.mjs +13 -5
  28. package/esm2022/src/template/pipeline/src/phases/apply_i18n_expressions.mjs +3 -3
  29. package/esm2022/src/template/pipeline/src/phases/assign_i18n_slot_dependencies.mjs +33 -0
  30. package/esm2022/src/template/pipeline/src/phases/generate_advance.mjs +1 -19
  31. package/esm2022/src/template/pipeline/src/phases/i18n_const_collection.mjs +3 -4
  32. package/esm2022/src/template/pipeline/src/phases/i18n_message_extraction.mjs +14 -11
  33. package/esm2022/src/template/pipeline/src/phases/propagate_i18n_blocks.mjs +57 -0
  34. package/esm2022/src/template/pipeline/src/phases/propagate_i18n_placeholders.mjs +39 -0
  35. package/esm2022/src/template/pipeline/src/phases/reify.mjs +3 -3
  36. package/esm2022/src/template/pipeline/src/phases/resolve_i18n_placeholders.mjs +131 -46
  37. package/esm2022/src/version.mjs +1 -1
  38. package/fesm2022/compiler.mjs +495 -205
  39. package/fesm2022/compiler.mjs.map +1 -1
  40. package/index.d.ts +77 -12
  41. package/package.json +2 -8
  42. package/esm2022/src/render3/view/block_syntax_switch.mjs +0 -13
  43. package/esm2022/testing/index.mjs +0 -13
  44. package/esm2022/testing/public_api.mjs +0 -16
  45. package/esm2022/testing/src/testing.mjs +0 -29
  46. package/esm2022/testing/testing.mjs +0 -5
  47. package/fesm2022/testing.mjs +0 -39
  48. package/fesm2022/testing.mjs.map +0 -1
  49. package/testing/index.d.ts +0 -25
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v17.0.0-next.7
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 }; }
@@ -3868,12 +3870,13 @@ class DeferredBlockError {
3868
3870
  }
3869
3871
  }
3870
3872
  class DeferredBlock {
3871
- constructor(children, triggers, prefetchTriggers, placeholder, loading, error, sourceSpan, startSourceSpan, endSourceSpan) {
3873
+ constructor(children, triggers, prefetchTriggers, placeholder, loading, error, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan) {
3872
3874
  this.children = children;
3873
3875
  this.placeholder = placeholder;
3874
3876
  this.loading = loading;
3875
3877
  this.error = error;
3876
3878
  this.sourceSpan = sourceSpan;
3879
+ this.mainBlockSpan = mainBlockSpan;
3877
3880
  this.startSourceSpan = startSourceSpan;
3878
3881
  this.endSourceSpan = endSourceSpan;
3879
3882
  this.triggers = triggers;
@@ -3890,20 +3893,23 @@ class DeferredBlock {
3890
3893
  this.visitTriggers(this.definedTriggers, this.triggers, visitor);
3891
3894
  this.visitTriggers(this.definedPrefetchTriggers, this.prefetchTriggers, visitor);
3892
3895
  visitAll$1(visitor, this.children);
3893
- this.placeholder && visitor.visitDeferredBlockPlaceholder(this.placeholder);
3894
- this.loading && visitor.visitDeferredBlockLoading(this.loading);
3895
- this.error && visitor.visitDeferredBlockError(this.error);
3896
+ const remainingBlocks = [this.placeholder, this.loading, this.error].filter(x => x !== null);
3897
+ visitAll$1(visitor, remainingBlocks);
3896
3898
  }
3897
3899
  visitTriggers(keys, triggers, visitor) {
3898
- for (const key of keys) {
3899
- visitor.visitDeferredTrigger(triggers[key]);
3900
- }
3900
+ visitAll$1(visitor, keys.map(k => triggers[k]));
3901
3901
  }
3902
3902
  }
3903
3903
  class SwitchBlock {
3904
- 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) {
3905
3910
  this.expression = expression;
3906
3911
  this.cases = cases;
3912
+ this.unknownBlocks = unknownBlocks;
3907
3913
  this.sourceSpan = sourceSpan;
3908
3914
  this.startSourceSpan = startSourceSpan;
3909
3915
  this.endSourceSpan = endSourceSpan;
@@ -3913,18 +3919,19 @@ class SwitchBlock {
3913
3919
  }
3914
3920
  }
3915
3921
  class SwitchBlockCase {
3916
- constructor(expression, children, sourceSpan, startSourceSpan) {
3922
+ constructor(expression, children, sourceSpan, startSourceSpan, endSourceSpan) {
3917
3923
  this.expression = expression;
3918
3924
  this.children = children;
3919
3925
  this.sourceSpan = sourceSpan;
3920
3926
  this.startSourceSpan = startSourceSpan;
3927
+ this.endSourceSpan = endSourceSpan;
3921
3928
  }
3922
3929
  visit(visitor) {
3923
3930
  return visitor.visitSwitchBlockCase(this);
3924
3931
  }
3925
3932
  }
3926
3933
  class ForLoopBlock {
3927
- constructor(item, expression, trackBy, contextVariables, children, empty, sourceSpan, startSourceSpan, endSourceSpan) {
3934
+ constructor(item, expression, trackBy, contextVariables, children, empty, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan) {
3928
3935
  this.item = item;
3929
3936
  this.expression = expression;
3930
3937
  this.trackBy = trackBy;
@@ -3932,6 +3939,7 @@ class ForLoopBlock {
3932
3939
  this.children = children;
3933
3940
  this.empty = empty;
3934
3941
  this.sourceSpan = sourceSpan;
3942
+ this.mainBlockSpan = mainBlockSpan;
3935
3943
  this.startSourceSpan = startSourceSpan;
3936
3944
  this.endSourceSpan = endSourceSpan;
3937
3945
  }
@@ -3940,10 +3948,11 @@ class ForLoopBlock {
3940
3948
  }
3941
3949
  }
3942
3950
  class ForLoopBlockEmpty {
3943
- constructor(children, sourceSpan, startSourceSpan) {
3951
+ constructor(children, sourceSpan, startSourceSpan, endSourceSpan) {
3944
3952
  this.children = children;
3945
3953
  this.sourceSpan = sourceSpan;
3946
3954
  this.startSourceSpan = startSourceSpan;
3955
+ this.endSourceSpan = endSourceSpan;
3947
3956
  }
3948
3957
  visit(visitor) {
3949
3958
  return visitor.visitForLoopBlockEmpty(this);
@@ -3961,17 +3970,27 @@ class IfBlock {
3961
3970
  }
3962
3971
  }
3963
3972
  class IfBlockBranch {
3964
- constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan) {
3973
+ constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan, endSourceSpan) {
3965
3974
  this.expression = expression;
3966
3975
  this.children = children;
3967
3976
  this.expressionAlias = expressionAlias;
3968
3977
  this.sourceSpan = sourceSpan;
3969
3978
  this.startSourceSpan = startSourceSpan;
3979
+ this.endSourceSpan = endSourceSpan;
3970
3980
  }
3971
3981
  visit(visitor) {
3972
3982
  return visitor.visitIfBlockBranch(this);
3973
3983
  }
3974
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
+ }
3975
3994
  class Template {
3976
3995
  constructor(
3977
3996
  // tagName is the name of the container element, if applicable.
@@ -4078,10 +4097,9 @@ class RecursiveVisitor$1 {
4078
4097
  visitAll$1(this, block.children);
4079
4098
  }
4080
4099
  visitForLoopBlock(block) {
4081
- block.item.visit(this);
4082
- visitAll$1(this, Object.values(block.contextVariables));
4083
- visitAll$1(this, block.children);
4084
- 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);
4085
4103
  }
4086
4104
  visitForLoopBlockEmpty(block) {
4087
4105
  visitAll$1(this, block.children);
@@ -4090,8 +4108,9 @@ class RecursiveVisitor$1 {
4090
4108
  visitAll$1(this, block.branches);
4091
4109
  }
4092
4110
  visitIfBlockBranch(block) {
4093
- visitAll$1(this, block.children);
4094
- block.expressionAlias?.visit(this);
4111
+ const blockItems = block.children;
4112
+ block.expressionAlias && blockItems.push(block.expressionAlias);
4113
+ visitAll$1(this, blockItems);
4095
4114
  }
4096
4115
  visitContent(content) { }
4097
4116
  visitVariable(variable) { }
@@ -4103,6 +4122,7 @@ class RecursiveVisitor$1 {
4103
4122
  visitBoundText(text) { }
4104
4123
  visitIcu(icu) { }
4105
4124
  visitDeferredTrigger(trigger) { }
4125
+ visitUnknownBlock(block) { }
4106
4126
  }
4107
4127
  function visitAll$1(visitor, nodes) {
4108
4128
  const result = [];
@@ -9297,10 +9317,11 @@ function createConditionalOp(target, test, conditions, sourceSpan) {
9297
9317
  /**
9298
9318
  * Create an i18n expression op.
9299
9319
  */
9300
- function createI18nExpressionOp(target, expression, i18nPlaceholder, sourceSpan) {
9320
+ function createI18nExpressionOp(owner, expression, i18nPlaceholder, sourceSpan) {
9301
9321
  return {
9302
9322
  kind: OpKind.I18nExpression,
9303
- target,
9323
+ owner,
9324
+ target: owner,
9304
9325
  expression,
9305
9326
  i18nPlaceholder,
9306
9327
  sourceSpan,
@@ -10448,7 +10469,7 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
10448
10469
  /**
10449
10470
  * Create a `TemplateOp`.
10450
10471
  */
10451
- function createTemplateOp(xref, tag, namespace, generatedInBlock, i18n, sourceSpan) {
10472
+ function createTemplateOp(xref, tag, namespace, generatedInBlock, i18nPlaceholder, sourceSpan) {
10452
10473
  return {
10453
10474
  kind: OpKind.Template,
10454
10475
  xref,
@@ -10460,6 +10481,7 @@ function createTemplateOp(xref, tag, namespace, generatedInBlock, i18n, sourceSp
10460
10481
  localRefs: [],
10461
10482
  nonBindable: false,
10462
10483
  namespace,
10484
+ i18nPlaceholder,
10463
10485
  sourceSpan,
10464
10486
  ...TRAIT_CONSUMES_SLOT,
10465
10487
  ...NEW_OP,
@@ -10633,13 +10655,15 @@ function createExtractedMessageOp(owner, expression, statements) {
10633
10655
  /**
10634
10656
  * Create an `I18nStartOp`.
10635
10657
  */
10636
- function createI18nStartOp(xref, message) {
10658
+ function createI18nStartOp(xref, message, root) {
10637
10659
  return {
10638
10660
  kind: OpKind.I18nStart,
10639
10661
  xref,
10662
+ root: root ?? xref,
10640
10663
  message,
10641
10664
  params: new Map(),
10642
10665
  messageIndex: null,
10666
+ subTemplateIndex: null,
10643
10667
  ...NEW_OP,
10644
10668
  ...TRAIT_CONSUMES_SLOT,
10645
10669
  };
@@ -11019,7 +11043,7 @@ function phaseApplyI18nExpressions(job) {
11019
11043
  // Only add apply after expressions that are not followed by more expressions.
11020
11044
  if (op.kind === OpKind.I18nExpression && needsApplication(op)) {
11021
11045
  // TODO: what should be the source span for the apply op?
11022
- OpList.insertAfter(createI18nApplyOp(op.target, null), op);
11046
+ OpList.insertAfter(createI18nApplyOp(op.owner, null), op);
11023
11047
  }
11024
11048
  }
11025
11049
  }
@@ -11033,12 +11057,37 @@ function needsApplication(op) {
11033
11057
  return true;
11034
11058
  }
11035
11059
  // If the next op is an expression targeting a different i18n block, we need to apply.
11036
- if (op.next.target !== op.target) {
11060
+ if (op.next.owner !== op.owner) {
11037
11061
  return true;
11038
11062
  }
11039
11063
  return false;
11040
11064
  }
11041
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
+
11042
11091
  /**
11043
11092
  * Gets a map of all elements in the given view by their xref id.
11044
11093
  */
@@ -11793,31 +11842,13 @@ function phaseGenerateAdvance(job) {
11793
11842
  for (const unit of job.units) {
11794
11843
  // First build a map of all of the declarations in the view that have assigned slots.
11795
11844
  const slotMap = new Map();
11796
- let lastSlotOp = null;
11797
11845
  for (const op of unit.create) {
11798
- // For i18n blocks, we want to advance to the last element index in the block before invoking
11799
- // `i18nExp` instructions, to make sure the necessary lifecycle hooks of components/directives
11800
- // are properly flushed.
11801
- if (op.kind === OpKind.I18nEnd) {
11802
- if (lastSlotOp === null) {
11803
- throw Error('Expected to have encountered an op prior to i18nEnd that consumes a slot');
11804
- }
11805
- // TODO(mmalerba): For empty i18n blocks, we move to the next slot to match
11806
- // TemplateDefinitionBuilder. This seems like just a quirk resulting from the special
11807
- // handling of i18n blocks that can be removed when compatibility is no longer required.
11808
- let lastSlot = lastSlotOp.slot;
11809
- if (lastSlotOp.kind === OpKind.I18nStart && job.compatibility) {
11810
- lastSlot++;
11811
- }
11812
- slotMap.set(op.xref, lastSlot);
11813
- }
11814
11846
  if (!hasConsumesSlotTrait(op)) {
11815
11847
  continue;
11816
11848
  }
11817
11849
  else if (op.slot === null) {
11818
11850
  throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
11819
11851
  }
11820
- lastSlotOp = op;
11821
11852
  slotMap.set(op.xref, op.slot);
11822
11853
  }
11823
11854
  // Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
@@ -12123,9 +12154,8 @@ function phaseI18nConstCollection(job) {
12123
12154
  // Assign const index to i18n ops that messages were extracted from.
12124
12155
  for (const unit of job.units) {
12125
12156
  for (const op of unit.create) {
12126
- if ((op.kind === OpKind.I18nStart || op.kind === OpKind.I18n) &&
12127
- messageConstIndices[op.xref] !== undefined) {
12128
- op.messageIndex = messageConstIndices[op.xref];
12157
+ if (op.kind === OpKind.I18nStart || op.kind === OpKind.I18n) {
12158
+ op.messageIndex = messageConstIndices[op.root];
12129
12159
  }
12130
12160
  }
12131
12161
  }
@@ -17078,7 +17108,7 @@ class _Tokenizer {
17078
17108
  this.handleError(e);
17079
17109
  }
17080
17110
  }
17081
- this._beginToken(28 /* TokenType.EOF */);
17111
+ this._beginToken(29 /* TokenType.EOF */);
17082
17112
  this._endToken([]);
17083
17113
  }
17084
17114
  _getBlockName() {
@@ -17099,7 +17129,7 @@ class _Tokenizer {
17099
17129
  }
17100
17130
  _consumeBlockStart(start) {
17101
17131
  this._beginToken(24 /* TokenType.BLOCK_OPEN_START */, start);
17102
- this._endToken([this._getBlockName()]);
17132
+ const startToken = this._endToken([this._getBlockName()]);
17103
17133
  if (this._cursor.peek() === $LPAREN) {
17104
17134
  // Advance past the opening paren.
17105
17135
  this._cursor.advance();
@@ -17107,14 +17137,22 @@ class _Tokenizer {
17107
17137
  this._consumeBlockParameters();
17108
17138
  // Allow spaces before the closing paren.
17109
17139
  this._attemptCharCodeUntilFn(isNotWhitespace);
17110
- // Skip over the closing paren.
17111
- this._requireCharCode($RPAREN);
17112
- // Allow spaces after the paren.
17113
- 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 */;
17114
17155
  }
17115
- this._beginToken(25 /* TokenType.BLOCK_OPEN_END */);
17116
- this._requireCharCode($LBRACE);
17117
- this._endToken([]);
17118
17156
  }
17119
17157
  _consumeBlockEnd(start) {
17120
17158
  this._beginToken(26 /* TokenType.BLOCK_CLOSE */, start);
@@ -18087,7 +18125,7 @@ class _TreeBuilder {
18087
18125
  this._advance();
18088
18126
  }
18089
18127
  build() {
18090
- while (this._peek.type !== 28 /* TokenType.EOF */) {
18128
+ while (this._peek.type !== 29 /* TokenType.EOF */) {
18091
18129
  if (this._peek.type === 0 /* TokenType.TAG_OPEN_START */ ||
18092
18130
  this._peek.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) {
18093
18131
  this._consumeStartTag(this._advance());
@@ -18119,6 +18157,10 @@ class _TreeBuilder {
18119
18157
  this._closeVoidElement();
18120
18158
  this._consumeBlockClose(this._advance());
18121
18159
  }
18160
+ else if (this._peek.type === 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */) {
18161
+ this._closeVoidElement();
18162
+ this._consumeIncompleteBlock(this._advance());
18163
+ }
18122
18164
  else {
18123
18165
  // Skip all other tokens...
18124
18166
  this._advance();
@@ -18192,7 +18234,7 @@ class _TreeBuilder {
18192
18234
  if (!exp)
18193
18235
  return null;
18194
18236
  const end = this._advance();
18195
- exp.push({ type: 28 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan });
18237
+ exp.push({ type: 29 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan });
18196
18238
  // parse everything in between { and }
18197
18239
  const expansionCaseParser = new _TreeBuilder(exp, this.getTagDefinition);
18198
18240
  expansionCaseParser.build();
@@ -18232,7 +18274,7 @@ class _TreeBuilder {
18232
18274
  return null;
18233
18275
  }
18234
18276
  }
18235
- if (this._peek.type === 28 /* TokenType.EOF */) {
18277
+ if (this._peek.type === 29 /* TokenType.EOF */) {
18236
18278
  this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
18237
18279
  return null;
18238
18280
  }
@@ -18434,17 +18476,31 @@ class _TreeBuilder {
18434
18476
  const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
18435
18477
  const block = new Block(token.parts[0], parameters, [], span, startSpan);
18436
18478
  this._pushContainer(block, false);
18437
- return block;
18438
18479
  }
18439
18480
  _consumeBlockClose(token) {
18440
- const previousContainer = this._getContainer();
18441
18481
  if (!this._popContainer(null, Block, token.sourceSpan)) {
18442
- const context = previousContainer instanceof Element ?
18443
- `There is an unclosed "${previousContainer.name}" HTML tag that may have to be closed first.` :
18444
- `The block may have been closed earlier.`;
18445
- 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.`));
18446
18485
  }
18447
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));
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.`));
18503
+ }
18448
18504
  _getContainer() {
18449
18505
  return this._containerStack.length > 0 ? this._containerStack[this._containerStack.length - 1] :
18450
18506
  null;
@@ -18998,16 +19054,19 @@ function phaseI18nMessageExtraction(job) {
18998
19054
  for (const unit of job.units) {
18999
19055
  for (const op of unit.create) {
19000
19056
  if ((op.kind === OpKind.I18nStart || op.kind === OpKind.I18n)) {
19001
- // Sort the params map to match the ordering in TemplateDefinitionBuilder.
19002
- const params = new Map([...op.params.entries()].sort());
19003
- const mainVar = variable(job.pool.uniqueName(TRANSLATION_VAR_PREFIX));
19004
- // Closure Compiler requires const names to start with `MSG_` but disallows any other const
19005
- // to start with `MSG_`. We define a variable starting with `MSG_` just for the
19006
- // `goog.getMsg` call
19007
- const closureVar = i18nGenerateClosureVar(job.pool, op.message.id, fileBasedI18nSuffix, job.i18nUseExternalIds);
19008
- // TODO: figure out transformFn.
19009
- const statements = getTranslationDeclStmts$1(op.message, mainVar, closureVar, params, undefined /*transformFn*/);
19010
- unit.create.push(createExtractedMessageOp(op.xref, mainVar, statements));
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
+ }
19011
19070
  }
19012
19071
  }
19013
19072
  }
@@ -19739,6 +19798,86 @@ function phasePipeVariadic(job) {
19739
19798
  }
19740
19799
  }
19741
19800
 
19801
+ /**
19802
+ * Propagate i18n blocks down through child templates that act as placeholders in the root i18n
19803
+ * message.
19804
+ */
19805
+ function phasePropagateI18nBlocks(job) {
19806
+ propagateI18nBlocksToTemplates(job.root, 0);
19807
+ }
19808
+ /**
19809
+ * Propagates i18n ops in the given view through to any child views recursively.
19810
+ */
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
+ }
19838
+ /**
19839
+ * Wraps a template view with i18n start and end ops.
19840
+ */
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();
19853
+ for (const unit of job.units) {
19854
+ for (const op of unit.create) {
19855
+ if (op.kind === OpKind.I18nStart) {
19856
+ i18nOps.set(op.xref, op);
19857
+ }
19858
+ }
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);
19866
+ }
19867
+ }
19868
+ }
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
+ }
19878
+ }
19879
+ }
19880
+
19742
19881
  function phasePureFunctionExtraction(job) {
19743
19882
  for (const view of job.units) {
19744
19883
  for (const op of view.ops()) {
@@ -19975,11 +20114,19 @@ function projection(slot, projectionSlotIndex, attributes) {
19975
20114
  }
19976
20115
  return call(Identifiers.projection, args, null);
19977
20116
  }
19978
- function i18nStart(slot, constIndex) {
19979
- 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);
19980
20123
  }
19981
- function i18n(slot, constIndex) {
19982
- return call(Identifiers.i18n, [literal(slot), literal(constIndex)], 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);
19983
20130
  }
19984
20131
  function i18nEnd() {
19985
20132
  return call(Identifiers.i18nEnd, [], null);
@@ -20362,13 +20509,13 @@ function reifyCreateOperations(unit, ops) {
20362
20509
  OpList.replace(op, elementContainerEnd());
20363
20510
  break;
20364
20511
  case OpKind.I18nStart:
20365
- OpList.replace(op, i18nStart(op.slot, op.messageIndex));
20512
+ OpList.replace(op, i18nStart(op.slot, op.messageIndex, op.subTemplateIndex));
20366
20513
  break;
20367
20514
  case OpKind.I18nEnd:
20368
20515
  OpList.replace(op, i18nEnd());
20369
20516
  break;
20370
20517
  case OpKind.I18n:
20371
- OpList.replace(op, i18n(op.slot, op.messageIndex));
20518
+ OpList.replace(op, i18n(op.slot, op.messageIndex, op.subTemplateIndex));
20372
20519
  break;
20373
20520
  case OpKind.Template:
20374
20521
  if (!(unit instanceof ViewCompilationUnit)) {
@@ -20706,96 +20853,181 @@ function resolveDollarEvent(unit, ops) {
20706
20853
  * The escape sequence used indicate message param values.
20707
20854
  */
20708
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
+ }
20709
20952
  /**
20710
20953
  * Resolve the placeholders in i18n messages.
20711
20954
  */
20712
20955
  function phaseResolveI18nPlaceholders(job) {
20713
20956
  for (const unit of job.units) {
20714
20957
  const i18nOps = new Map();
20715
- let startTagSlots = new Map();
20716
- let closeTagSlots = new Map();
20958
+ const params = new Map();
20717
20959
  let currentI18nOp = null;
20718
20960
  // Record slots for tag name placeholders.
20719
20961
  for (const op of unit.create) {
20720
20962
  switch (op.kind) {
20721
20963
  case OpKind.I18nStart:
20722
20964
  case OpKind.I18n:
20723
- // Initialize collected slots for a new i18n block.
20724
20965
  i18nOps.set(op.xref, op);
20725
20966
  currentI18nOp = op.kind === OpKind.I18nStart ? op : null;
20726
- startTagSlots = new Map();
20727
- closeTagSlots = new Map();
20728
20967
  break;
20729
20968
  case OpKind.I18nEnd:
20730
- // Add values for tag placeholders.
20731
- if (currentI18nOp === null) {
20732
- throw Error('Missing corresponding i18n start op for i18n end op');
20733
- }
20734
- for (const [placeholder, slots] of startTagSlots) {
20735
- currentI18nOp.params.set(placeholder, serializeSlots(slots, true));
20736
- }
20737
- for (const [placeholder, slots] of closeTagSlots) {
20738
- currentI18nOp.params.set(placeholder, serializeSlots(slots, false));
20739
- }
20740
20969
  currentI18nOp = null;
20741
20970
  break;
20742
20971
  case OpKind.Element:
20743
20972
  case OpKind.ElementStart:
20744
- // Record slots for tag placeholders.
20745
- if (op.i18nPlaceholder != undefined) {
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) {
20746
20977
  if (currentI18nOp === null) {
20747
20978
  throw Error('i18n tag placeholder should only occur inside an i18n block');
20748
20979
  }
20749
- if (!op.slot) {
20750
- throw Error('Slots should be allocated before i18n placeholder resolution');
20751
- }
20752
20980
  const { startName, closeName } = op.i18nPlaceholder;
20753
- addTagSlot(startTagSlots, startName, op.slot);
20754
- addTagSlot(closeTagSlots, closeName, op.slot);
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);
20755
20986
  }
20756
20987
  break;
20757
20988
  }
20758
20989
  }
20759
- // Fill in values for each of the expression placeholders applied in i18nApply operations.
20990
+ // Fill in values for each of the i18n expression placeholders.
20760
20991
  const i18nBlockPlaceholderIndices = new Map();
20761
20992
  for (const op of unit.update) {
20762
20993
  if (op.kind === OpKind.I18nExpression) {
20763
- const i18nOp = i18nOps.get(op.target);
20764
- let index = i18nBlockPlaceholderIndices.get(op.target) || 0;
20994
+ const i18nOp = i18nOps.get(op.owner);
20995
+ let index = i18nBlockPlaceholderIndices.get(op.owner) || 0;
20765
20996
  if (!i18nOp) {
20766
20997
  throw Error('Cannot find corresponding i18nStart for i18nExpr');
20767
20998
  }
20768
- i18nOp.params.set(op.i18nPlaceholder.name, literal(`${ESCAPE}${index++}${ESCAPE}`));
20769
- i18nBlockPlaceholderIndices.set(op.target, index);
20999
+ addParam(params, i18nOp, op.i18nPlaceholder.name, index++, i18nOp.subTemplateIndex);
21000
+ i18nBlockPlaceholderIndices.set(op.owner, index);
20770
21001
  }
20771
21002
  }
20772
- // Verify that all placeholders have been resolved.
20773
- for (const op of i18nOps.values()) {
20774
- for (const placeholder in op.message.placeholders) {
20775
- if (!op.params.has(placeholder)) {
20776
- throw Error(`Failed to resolve i18n placeholder: ${placeholder}`);
20777
- }
20778
- }
21003
+ // After colleccting all params, save them to the i18n ops.
21004
+ for (const [xref, i18nOpParams] of params) {
21005
+ i18nOpParams.saveToOp(i18nOps.get(xref));
20779
21006
  }
20780
21007
  }
20781
21008
  }
20782
21009
  /**
20783
- * Updates the given slots map with the specified slot.
21010
+ * Add a param to the params map for the given i18n op.
20784
21011
  */
20785
- function addTagSlot(tagSlots, placeholder, slot) {
20786
- const slots = tagSlots.get(placeholder) || [];
20787
- slots.push(slot);
20788
- tagSlots.set(placeholder, slots);
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);
20789
21016
  }
20790
21017
  /**
20791
- * Serializes a list of slots to a string literal expression.
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.
20792
21021
  */
20793
- function serializeSlots(slots, start) {
20794
- const slotStrings = slots.map(slot => `${ESCAPE}${start ? '' : '/'}#${slot}${ESCAPE}`);
20795
- if (slotStrings.length === 1) {
20796
- return literal(slotStrings[0]);
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
+ }
21028
+ }
20797
21029
  }
20798
- return literal(`[${slotStrings.join('|')}]`);
21030
+ return i18nOp.subTemplateIndex;
20799
21031
  }
20800
21032
 
20801
21033
  /**
@@ -21559,6 +21791,7 @@ const phases = [
21559
21791
  { kind: CompilationJobKind.Tmpl, fn: phaseNamespace },
21560
21792
  { kind: CompilationJobKind.Both, fn: phaseStyleBindingSpecialization },
21561
21793
  { kind: CompilationJobKind.Both, fn: phaseBindingSpecialization },
21794
+ { kind: CompilationJobKind.Tmpl, fn: phasePropagateI18nBlocks },
21562
21795
  { kind: CompilationJobKind.Both, fn: phaseAttributeExtraction },
21563
21796
  { kind: CompilationJobKind.Both, fn: phaseParseExtractedStyles },
21564
21797
  { kind: CompilationJobKind.Tmpl, fn: phaseRemoveEmptyBindings },
@@ -21582,10 +21815,12 @@ const phases = [
21582
21815
  { kind: CompilationJobKind.Both, fn: phaseTemporaryVariables },
21583
21816
  { kind: CompilationJobKind.Tmpl, fn: phaseSlotAllocation },
21584
21817
  { kind: CompilationJobKind.Tmpl, fn: phaseResolveI18nPlaceholders },
21818
+ { kind: CompilationJobKind.Tmpl, fn: phasePropagateI18nPlaceholders },
21585
21819
  { kind: CompilationJobKind.Tmpl, fn: phaseI18nMessageExtraction },
21586
21820
  { kind: CompilationJobKind.Tmpl, fn: phaseI18nConstCollection },
21587
21821
  { kind: CompilationJobKind.Tmpl, fn: phaseConstTraitCollection },
21588
21822
  { kind: CompilationJobKind.Both, fn: phaseConstCollection },
21823
+ { kind: CompilationJobKind.Tmpl, fn: phaseAssignI18nSlotDependencies },
21589
21824
  { kind: CompilationJobKind.Both, fn: phaseVarCounting },
21590
21825
  { kind: CompilationJobKind.Tmpl, fn: phaseGenerateAdvance },
21591
21826
  { kind: CompilationJobKind.Both, fn: phaseVariableOptimization },
@@ -21835,7 +22070,8 @@ function ingestElement(unit, element) {
21835
22070
  * Ingest an `ng-template` node from the AST into the given `ViewCompilation`.
21836
22071
  */
21837
22072
  function ingestTemplate(unit, tmpl) {
21838
- if (tmpl.i18n !== undefined && !(tmpl.i18n instanceof Message)) {
22073
+ if (tmpl.i18n !== undefined &&
22074
+ !(tmpl.i18n instanceof Message || tmpl.i18n instanceof TagPlaceholder)) {
21839
22075
  throw Error(`Unhandled i18n metadata type for template: ${tmpl.i18n.constructor.name}`);
21840
22076
  }
21841
22077
  const childView = unit.job.allocateView(unit.xref);
@@ -21844,8 +22080,9 @@ function ingestTemplate(unit, tmpl) {
21844
22080
  if (tmpl.tagName) {
21845
22081
  [namespacePrefix, tagNameWithoutNamespace] = splitNsName(tmpl.tagName);
21846
22082
  }
22083
+ const i18nPlaceholder = tmpl.i18n instanceof TagPlaceholder ? tmpl.i18n : undefined;
21847
22084
  // TODO: validate the fallback tag name here.
21848
- const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace ?? 'ng-template', namespaceForKey(namespacePrefix), false, undefined, tmpl.startSourceSpan);
22085
+ const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace ?? 'ng-template', namespaceForKey(namespacePrefix), false, i18nPlaceholder, tmpl.startSourceSpan);
21849
22086
  unit.create.push(tplOp);
21850
22087
  ingestBindings(unit, tplOp, tmpl);
21851
22088
  ingestReferences(tplOp, tmpl);
@@ -21888,7 +22125,7 @@ function ingestBoundText(unit, text) {
21888
22125
  throw new Error(`AssertionError: expected Interpolation for BoundText node, got ${value.constructor.name}`);
21889
22126
  }
21890
22127
  if (text.i18n !== undefined && !(text.i18n instanceof Container)) {
21891
- throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n.constructor.name}`);
22128
+ throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n?.constructor.name}`);
21892
22129
  }
21893
22130
  const i18nPlaceholders = text.i18n instanceof Container ?
21894
22131
  text.i18n.children.filter((node) => node instanceof Placeholder) :
@@ -21915,7 +22152,7 @@ function ingestIfBlock(unit, ifBlock) {
21915
22152
  if (firstXref === null) {
21916
22153
  firstXref = cView.xref;
21917
22154
  }
21918
- unit.create.push(createTemplateOp(cView.xref, 'Conditional', Namespace.HTML, true, undefined, ifCase.sourceSpan));
22155
+ unit.create.push(createTemplateOp(cView.xref, 'Conditional', Namespace.HTML, true, undefined /* TODO: figure out how i18n works with new control flow */, ifCase.sourceSpan));
21919
22156
  const caseExpr = ifCase.expression ? convertAst(ifCase.expression, unit.job, null) : null;
21920
22157
  const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, cView.xref, ifCase.expressionAlias);
21921
22158
  conditions.push(conditionalCaseExpr);
@@ -21935,7 +22172,7 @@ function ingestSwitchBlock(unit, switchBlock) {
21935
22172
  if (firstXref === null) {
21936
22173
  firstXref = cView.xref;
21937
22174
  }
21938
- unit.create.push(createTemplateOp(cView.xref, 'Case', Namespace.HTML, true, undefined, switchCase.sourceSpan));
22175
+ unit.create.push(createTemplateOp(cView.xref, 'Case', Namespace.HTML, true, undefined /* TODO: figure out how i18n works with new control flow */, switchCase.sourceSpan));
21939
22176
  const caseExpr = switchCase.expression ?
21940
22177
  convertAst(switchCase.expression, unit.job, switchBlock.startSourceSpan) :
21941
22178
  null;
@@ -23385,13 +23622,13 @@ function normalizeNgContentSelect(selectAttr) {
23385
23622
  /** Pattern for the expression in a for loop block. */
23386
23623
  const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+(.*)/;
23387
23624
  /** Pattern for the tracking expression in a for loop block. */
23388
- const FOR_LOOP_TRACK_PATTERN = /^track\s+(.*)/;
23625
+ const FOR_LOOP_TRACK_PATTERN = /^track\s+([\S\s]*)/;
23389
23626
  /** Pattern for the `as` expression in a conditional block. */
23390
23627
  const CONDITIONAL_ALIAS_PATTERN = /^as\s+(.*)/;
23391
23628
  /** Pattern used to identify an `else if` block. */
23392
23629
  const ELSE_IF_PATTERN = /^else[^\S\r\n]+if/;
23393
23630
  /** Pattern used to identify a `let` parameter. */
23394
- const FOR_LOOP_LET_PATTERN = /^let\s+(.*)/;
23631
+ const FOR_LOOP_LET_PATTERN = /^let\s+([\S\s]*)/;
23395
23632
  /** Names of variables that are allowed to be used in the `let` expression of a `for` loop. */
23396
23633
  const ALLOWED_FOR_LOOP_LET_VARIABLES = new Set(['$index', '$first', '$last', '$even', '$odd', '$count']);
23397
23634
  /**
@@ -23412,28 +23649,33 @@ function isConnectedIfLoopBlock(name) {
23412
23649
  function createIfBlock(ast, connectedBlocks, visitor, bindingParser) {
23413
23650
  const errors = validateIfConnectedBlocks(connectedBlocks);
23414
23651
  const branches = [];
23415
- if (errors.length > 0) {
23416
- return { node: null, errors };
23417
- }
23418
23652
  const mainBlockParams = parseConditionalBlockParameters(ast, errors, bindingParser);
23419
23653
  if (mainBlockParams !== null) {
23420
- 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));
23421
23655
  }
23422
- // Assumes that the structure is valid since we validated it above.
23423
23656
  for (const block of connectedBlocks) {
23424
- const children = visitAll(visitor, block.children, block.children);
23425
23657
  if (ELSE_IF_PATTERN.test(block.name)) {
23426
23658
  const params = parseConditionalBlockParameters(block, errors, bindingParser);
23427
23659
  if (params !== null) {
23428
- 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));
23429
23662
  }
23430
23663
  }
23431
23664
  else if (block.name === 'else') {
23432
- 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));
23433
23667
  }
23434
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
+ }
23435
23677
  return {
23436
- node: new IfBlock(branches, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
23678
+ node: new IfBlock(branches, wholeSourceSpan, ast.startSourceSpan, ifBlockEndSourceSpan),
23437
23679
  errors,
23438
23680
  };
23439
23681
  }
@@ -23452,7 +23694,7 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
23452
23694
  errors.push(new ParseError(block.sourceSpan, '@empty block cannot have parameters'));
23453
23695
  }
23454
23696
  else {
23455
- 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);
23456
23698
  }
23457
23699
  }
23458
23700
  else {
@@ -23461,10 +23703,16 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
23461
23703
  }
23462
23704
  if (params !== null) {
23463
23705
  if (params.trackBy === null) {
23706
+ // TODO: We should not fail here, and instead try to produce some AST for the language
23707
+ // service.
23464
23708
  errors.push(new ParseError(ast.sourceSpan, '@for loop must have a "track" expression'));
23465
23709
  }
23466
23710
  else {
23467
- 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);
23468
23716
  }
23469
23717
  }
23470
23718
  return { node, errors };
@@ -23472,21 +23720,25 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
23472
23720
  /** Creates a switch block from an HTML AST node. */
23473
23721
  function createSwitchBlock(ast, visitor, bindingParser) {
23474
23722
  const errors = validateSwitchBlock(ast);
23475
- if (errors.length > 0) {
23476
- return { node: null, errors };
23477
- }
23478
- 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);
23479
23726
  const cases = [];
23727
+ const unknownBlocks = [];
23480
23728
  let defaultCase = null;
23481
23729
  // Here we assume that all the blocks are valid given that we validated them above.
23482
23730
  for (const node of ast.children) {
23483
23731
  if (!(node instanceof Block)) {
23484
23732
  continue;
23485
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
+ }
23486
23738
  const expression = node.name === 'case' ?
23487
23739
  parseBlockParameterToBinding(node.parameters[0], bindingParser) :
23488
23740
  null;
23489
- 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);
23490
23742
  if (expression === null) {
23491
23743
  defaultCase = ast;
23492
23744
  }
@@ -23499,7 +23751,7 @@ function createSwitchBlock(ast, visitor, bindingParser) {
23499
23751
  cases.push(defaultCase);
23500
23752
  }
23501
23753
  return {
23502
- node: new SwitchBlock(primaryExpression, cases, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
23754
+ node: new SwitchBlock(primaryExpression, cases, unknownBlocks, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
23503
23755
  errors
23504
23756
  };
23505
23757
  }
@@ -23543,8 +23795,10 @@ function parseForLoopParameters(block, errors, bindingParser) {
23543
23795
  // Fill out any variables that haven't been defined explicitly.
23544
23796
  for (const variableName of ALLOWED_FOR_LOOP_LET_VARIABLES) {
23545
23797
  if (!result.context.hasOwnProperty(variableName)) {
23546
- result.context[variableName] =
23547
- 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);
23548
23802
  }
23549
23803
  }
23550
23804
  return result;
@@ -24039,7 +24293,17 @@ function createDeferredBlock(ast, connectedBlocks, visitor, bindingParser) {
24039
24293
  const errors = [];
24040
24294
  const { placeholder, loading, error } = parseConnectedBlocks(connectedBlocks, errors, visitor);
24041
24295
  const { triggers, prefetchTriggers } = parsePrimaryTriggers(ast.parameters, bindingParser, errors, placeholder);
24042
- 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);
24043
24307
  return { node, errors };
24044
24308
  }
24045
24309
  function parseConnectedBlocks(connectedBlocks, errors, visitor) {
@@ -24445,7 +24709,10 @@ class HtmlAstToIvyAst {
24445
24709
  else {
24446
24710
  errorMessage = `Unrecognized block @${block.name}.`;
24447
24711
  }
24448
- result = { node: null, errors: [new ParseError(block.sourceSpan, errorMessage)] };
24712
+ result = {
24713
+ node: new UnknownBlock(block.name, block.sourceSpan),
24714
+ errors: [new ParseError(block.sourceSpan, errorMessage)],
24715
+ };
24449
24716
  break;
24450
24717
  }
24451
24718
  this.errors.push(...result.errors);
@@ -24686,19 +24953,6 @@ function textContents(node) {
24686
24953
  }
24687
24954
  }
24688
24955
 
24689
- /*!
24690
- * @license
24691
- * Copyright Google LLC All Rights Reserved.
24692
- *
24693
- * Use of this source code is governed by an MIT-style license that can be
24694
- * found in the LICENSE file at https://angular.io/license
24695
- */
24696
- /**
24697
- * Whether the @ block syntax is enabled by default. This constant exists
24698
- * so that we can temporarily disable the syntax internally.
24699
- */
24700
- const BLOCK_SYNTAX_ENABLED_DEFAULT = true;
24701
-
24702
24956
  var TagType;
24703
24957
  (function (TagType) {
24704
24958
  TagType[TagType["ELEMENT"] = 0] = "ELEMENT";
@@ -25046,6 +25300,7 @@ class TemplateDefinitionBuilder {
25046
25300
  this.visitIfBlockBranch = invalid;
25047
25301
  this.visitSwitchBlockCase = invalid;
25048
25302
  this.visitForLoopBlockEmpty = invalid;
25303
+ this.visitUnknownBlock = invalid;
25049
25304
  this._bindingScope = parentBindingScope.nestedScope(level);
25050
25305
  // Turn the relative context file path into an identifier by replacing non-alphanumeric
25051
25306
  // characters with underscores.
@@ -25771,18 +26026,17 @@ class TemplateDefinitionBuilder {
25771
26026
  // callback in order to generate the correct expressions when pipes or pure functions are
25772
26027
  // used inside the branch expressions.
25773
26028
  const branchData = block.branches.map(({ expression, expressionAlias, children, sourceSpan }) => {
25774
- const processedExpression = expression === null ? null : expression.visit(this._valueConverter);
25775
26029
  // If the branch has an alias, it'll be assigned directly to the container's context.
25776
26030
  // We define a variable referring directly to the context so that any nested usages can be
25777
26031
  // rewritten to refer to it.
25778
26032
  const variables = expressionAlias !== null ?
25779
26033
  [new Variable(expressionAlias.name, DIRECT_CONTEXT_REFERENCE, expressionAlias.sourceSpan, expressionAlias.keySpan)] :
25780
26034
  undefined;
25781
- return {
25782
- index: this.createEmbeddedTemplateFn(null, children, '_Conditional', sourceSpan, variables),
25783
- expression: processedExpression,
25784
- alias: expressionAlias
25785
- };
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 };
25786
26040
  });
25787
26041
  // Use the index of the first block as the index for the entire container.
25788
26042
  const containerIndex = branchData[0].index;
@@ -25828,20 +26082,21 @@ class TemplateDefinitionBuilder {
25828
26082
  this.updateInstructionWithAdvance(containerIndex, block.branches[0].sourceSpan, Identifiers.conditional, paramsCallback);
25829
26083
  }
25830
26084
  visitSwitchBlock(block) {
25831
- const blockExpression = block.expression.visit(this._valueConverter);
25832
- this.allocateBindingSlots(null); // Allocate a slot for the primary block expression.
25833
26085
  // We have to process the block in two steps: once here and again in the update instruction
25834
26086
  // callback in order to generate the correct expressions when pipes or pure functions are used.
25835
26087
  const caseData = block.cases.map(currentCase => {
25836
- return {
25837
- index: this.createEmbeddedTemplateFn(null, currentCase.children, '_Case', currentCase.sourceSpan),
25838
- expression: currentCase.expression === null ?
25839
- null :
25840
- currentCase.expression.visit(this._valueConverter)
25841
- };
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 };
25842
26093
  });
25843
26094
  // Use the index of the first block as the index for the entire container.
25844
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.
25845
26100
  this.updateInstructionWithAdvance(containerIndex, block.sourceSpan, Identifiers.conditional, () => {
25846
26101
  const generateCases = (caseIndex) => {
25847
26102
  // If we've gone beyond the last branch, return the special -1
@@ -25909,12 +26164,17 @@ class TemplateDefinitionBuilder {
25909
26164
  literal(errorIndex),
25910
26165
  loadingConsts?.length ? this.addToConsts(literalArr(loadingConsts)) : TYPED_NULL_EXPR,
25911
26166
  placeholderConsts ? this.addToConsts(placeholderConsts) : TYPED_NULL_EXPR,
26167
+ (loadingConsts?.length || placeholderConsts) ?
26168
+ importExpr(Identifiers.deferEnableTimerScheduling) :
26169
+ TYPED_NULL_EXPR,
25912
26170
  ]));
25913
- this.createDeferTriggerInstructions(deferredIndex, triggers, metadata, false);
25914
- this.createDeferTriggerInstructions(deferredIndex, prefetchTriggers, metadata, true);
25915
26171
  // Allocate an extra data slot right after a defer block slot to store
25916
26172
  // instance-specific state of that defer block at runtime.
25917
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);
25918
26178
  }
25919
26179
  createDeferredDepsFunction(name, metadata) {
25920
26180
  if (metadata.deps.length === 0) {
@@ -26006,12 +26266,13 @@ class TemplateDefinitionBuilder {
26006
26266
  // are implicitly inferred by the runtime to index + 1 and index + 2.
26007
26267
  const blockIndex = this.allocateDataSlot();
26008
26268
  const primaryData = this.prepareEmbeddedTemplateFn(block.children, '_For', [block.item, block.contextVariables.$index, block.contextVariables.$count]);
26009
- const emptyData = block.empty === null ?
26010
- null :
26011
- this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty');
26012
26269
  const { expression: trackByExpression, usesComponentInstance: trackByUsesComponentInstance } = this.createTrackByFunction(block);
26013
- const value = block.expression.visit(this._valueConverter);
26014
- 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
+ }
26015
26276
  this.registerComputedLoopVariables(block, primaryData.scope);
26016
26277
  // `repeaterCreate(0, ...)`
26017
26278
  this.creationInstruction(block.sourceSpan, Identifiers.repeaterCreate, () => {
@@ -26031,6 +26292,11 @@ class TemplateDefinitionBuilder {
26031
26292
  }
26032
26293
  return params;
26033
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);
26034
26300
  // `repeater(0, iterable)`
26035
26301
  this.updateInstruction(block.sourceSpan, Identifiers.repeater, () => [literal(blockIndex), this.convertPropertyBinding(value)]);
26036
26302
  }
@@ -26906,7 +27172,7 @@ function parseTemplate(template, templateUrl, options = {}) {
26906
27172
  leadingTriviaChars: LEADING_TRIVIA_CHARS,
26907
27173
  ...options,
26908
27174
  tokenizeExpansionForms: true,
26909
- tokenizeBlocks: options.enableBlockSyntax ?? BLOCK_SYNTAX_ENABLED_DEFAULT,
27175
+ tokenizeBlocks: options.enableBlockSyntax ?? true,
26910
27176
  });
26911
27177
  if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
26912
27178
  parseResult.errors.length > 0) {
@@ -28051,6 +28317,7 @@ class Scope {
28051
28317
  visitTextAttribute(attr) { }
28052
28318
  visitIcu(icu) { }
28053
28319
  visitDeferredTrigger(trigger) { }
28320
+ visitUnknownBlock(block) { }
28054
28321
  maybeDeclare(thing) {
28055
28322
  // Declare something with a name, as long as that name isn't taken.
28056
28323
  if (!this.namedEntities.has(thing.name)) {
@@ -28252,6 +28519,7 @@ class DirectiveBinder {
28252
28519
  visitBoundText(text) { }
28253
28520
  visitIcu(icu) { }
28254
28521
  visitDeferredTrigger(trigger) { }
28522
+ visitUnknownBlock(block) { }
28255
28523
  }
28256
28524
  /**
28257
28525
  * Processes a template and extract metadata about expressions and symbols within.
@@ -28380,6 +28648,8 @@ class TemplateBinder extends RecursiveAstVisitor {
28380
28648
  visitText(text) { }
28381
28649
  visitContent(content) { }
28382
28650
  visitTextAttribute(attribute) { }
28651
+ visitUnknownBlock(block) { }
28652
+ visitDeferredTrigger() { }
28383
28653
  visitIcu(icu) {
28384
28654
  Object.keys(icu.vars).forEach(key => icu.vars[key].visit(this));
28385
28655
  Object.keys(icu.placeholders).forEach(key => icu.placeholders[key].visit(this));
@@ -28394,15 +28664,12 @@ class TemplateBinder extends RecursiveAstVisitor {
28394
28664
  visitDeferredBlock(deferred) {
28395
28665
  this.deferBlocks.add(deferred);
28396
28666
  this.ingestScopedNode(deferred);
28667
+ deferred.triggers.when?.value.visit(this);
28668
+ deferred.prefetchTriggers.when?.value.visit(this);
28397
28669
  deferred.placeholder && this.visitNode(deferred.placeholder);
28398
28670
  deferred.loading && this.visitNode(deferred.loading);
28399
28671
  deferred.error && this.visitNode(deferred.error);
28400
28672
  }
28401
- visitDeferredTrigger(trigger) {
28402
- if (trigger instanceof BoundDeferredTrigger) {
28403
- trigger.value.visit(this);
28404
- }
28405
- }
28406
28673
  visitDeferredBlockPlaceholder(block) {
28407
28674
  this.ingestScopedNode(block);
28408
28675
  }
@@ -29259,13 +29526,11 @@ function publishFacade(global) {
29259
29526
  * @description
29260
29527
  * Entry point for all public APIs of the compiler package.
29261
29528
  */
29262
- const VERSION = new Version('17.0.0-next.7');
29529
+ const VERSION = new Version('17.0.0-next.8');
29263
29530
 
29264
29531
  class CompilerConfig {
29265
- constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
29532
+ constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
29266
29533
  this.defaultEncapsulation = defaultEncapsulation;
29267
- this.useJit = !!useJit;
29268
- this.missingTranslation = missingTranslation;
29269
29534
  this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
29270
29535
  this.strictInjectionParameters = strictInjectionParameters === true;
29271
29536
  }
@@ -30755,6 +31020,31 @@ function compileComponentClassMetadata(metadata, deferrableTypes) {
30755
31020
  return iife.callFn([]);
30756
31021
  }
30757
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
+
30758
31048
  /**
30759
31049
  * Every time we make a breaking change to the declaration interface or partial-linker behavior, we
30760
31050
  * must update this constant to prevent old partial-linkers from incorrectly processing the
@@ -30766,7 +31056,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
30766
31056
  function compileDeclareClassMetadata(metadata) {
30767
31057
  const definitionMap = new DefinitionMap();
30768
31058
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
30769
- definitionMap.set('version', literal('17.0.0-next.7'));
31059
+ definitionMap.set('version', literal('17.0.0-next.8'));
30770
31060
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30771
31061
  definitionMap.set('type', metadata.type);
30772
31062
  definitionMap.set('decorators', metadata.decorators);
@@ -30874,7 +31164,7 @@ function createDirectiveDefinitionMap(meta) {
30874
31164
  // in 16.1 is actually used.
30875
31165
  const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
30876
31166
  definitionMap.set('minVersion', literal(minVersion));
30877
- definitionMap.set('version', literal('17.0.0-next.7'));
31167
+ definitionMap.set('version', literal('17.0.0-next.8'));
30878
31168
  // e.g. `type: MyDirective`
30879
31169
  definitionMap.set('type', meta.type.value);
30880
31170
  if (meta.isStandalone) {
@@ -31151,7 +31441,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
31151
31441
  function compileDeclareFactoryFunction(meta) {
31152
31442
  const definitionMap = new DefinitionMap();
31153
31443
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
31154
- definitionMap.set('version', literal('17.0.0-next.7'));
31444
+ definitionMap.set('version', literal('17.0.0-next.8'));
31155
31445
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31156
31446
  definitionMap.set('type', meta.type.value);
31157
31447
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -31186,7 +31476,7 @@ function compileDeclareInjectableFromMetadata(meta) {
31186
31476
  function createInjectableDefinitionMap(meta) {
31187
31477
  const definitionMap = new DefinitionMap();
31188
31478
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
31189
- definitionMap.set('version', literal('17.0.0-next.7'));
31479
+ definitionMap.set('version', literal('17.0.0-next.8'));
31190
31480
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31191
31481
  definitionMap.set('type', meta.type.value);
31192
31482
  // Only generate providedIn property if it has a non-null value
@@ -31237,7 +31527,7 @@ function compileDeclareInjectorFromMetadata(meta) {
31237
31527
  function createInjectorDefinitionMap(meta) {
31238
31528
  const definitionMap = new DefinitionMap();
31239
31529
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
31240
- definitionMap.set('version', literal('17.0.0-next.7'));
31530
+ definitionMap.set('version', literal('17.0.0-next.8'));
31241
31531
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31242
31532
  definitionMap.set('type', meta.type.value);
31243
31533
  definitionMap.set('providers', meta.providers);
@@ -31270,7 +31560,7 @@ function createNgModuleDefinitionMap(meta) {
31270
31560
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
31271
31561
  }
31272
31562
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
31273
- definitionMap.set('version', literal('17.0.0-next.7'));
31563
+ definitionMap.set('version', literal('17.0.0-next.8'));
31274
31564
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31275
31565
  definitionMap.set('type', meta.type.value);
31276
31566
  // We only generate the keys in the metadata if the arrays contain values.
@@ -31321,7 +31611,7 @@ function compileDeclarePipeFromMetadata(meta) {
31321
31611
  function createPipeDefinitionMap(meta) {
31322
31612
  const definitionMap = new DefinitionMap();
31323
31613
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
31324
- definitionMap.set('version', literal('17.0.0-next.7'));
31614
+ definitionMap.set('version', literal('17.0.0-next.8'));
31325
31615
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31326
31616
  // e.g. `type: MyPipe`
31327
31617
  definitionMap.set('type', meta.type.value);
@@ -31354,5 +31644,5 @@ publishFacade(_global);
31354
31644
 
31355
31645
  // This file is not used to build this module. It is only used during editing
31356
31646
 
31357
- 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 };
31358
31648
  //# sourceMappingURL=compiler.mjs.map