@angular/compiler 17.0.3 → 17.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/esm2022/src/compiler.mjs +2 -3
  2. package/esm2022/src/expression_parser/parser.mjs +2 -2
  3. package/esm2022/src/i18n/digest.mjs +4 -1
  4. package/esm2022/src/i18n/extractor_merger.mjs +4 -2
  5. package/esm2022/src/i18n/i18n_ast.mjs +27 -1
  6. package/esm2022/src/i18n/i18n_html_parser.mjs +2 -2
  7. package/esm2022/src/i18n/i18n_parser.mjs +23 -6
  8. package/esm2022/src/i18n/message_bundle.mjs +7 -1
  9. package/esm2022/src/i18n/serializers/placeholder.mjs +29 -1
  10. package/esm2022/src/i18n/serializers/serializer.mjs +6 -1
  11. package/esm2022/src/i18n/serializers/xliff.mjs +7 -1
  12. package/esm2022/src/i18n/serializers/xliff2.mjs +19 -1
  13. package/esm2022/src/i18n/serializers/xmb.mjs +12 -1
  14. package/esm2022/src/i18n/translation_bundle.mjs +6 -1
  15. package/esm2022/src/jit_compiler_facade.mjs +2 -2
  16. package/esm2022/src/ml_parser/ast.mjs +4 -4
  17. package/esm2022/src/ml_parser/defaults.mjs +24 -0
  18. package/esm2022/src/ml_parser/lexer.mjs +2 -2
  19. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  20. package/esm2022/src/render3/partial/component.mjs +2 -2
  21. package/esm2022/src/render3/partial/directive.mjs +1 -1
  22. package/esm2022/src/render3/partial/factory.mjs +1 -1
  23. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  24. package/esm2022/src/render3/partial/injector.mjs +1 -1
  25. package/esm2022/src/render3/partial/ng_module.mjs +1 -1
  26. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  27. package/esm2022/src/render3/r3_ast.mjs +17 -9
  28. package/esm2022/src/render3/r3_control_flow.mjs +7 -7
  29. package/esm2022/src/render3/r3_deferred_blocks.mjs +5 -5
  30. package/esm2022/src/render3/view/api.mjs +1 -1
  31. package/esm2022/src/render3/view/i18n/context.mjs +13 -1
  32. package/esm2022/src/render3/view/i18n/get_msg_utils.mjs +4 -1
  33. package/esm2022/src/render3/view/i18n/icu_serializer.mjs +4 -1
  34. package/esm2022/src/render3/view/i18n/localize_utils.mjs +6 -1
  35. package/esm2022/src/render3/view/i18n/meta.mjs +5 -4
  36. package/esm2022/src/render3/view/template.mjs +79 -33
  37. package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +2 -1
  38. package/esm2022/src/template/pipeline/src/instruction.mjs +3 -3
  39. package/esm2022/src/template/pipeline/src/phases/reify.mjs +2 -2
  40. package/esm2022/src/template/pipeline/src/phases/resolve_i18n_icu_placeholders.mjs +12 -5
  41. package/esm2022/src/template_parser/binding_parser.mjs +1 -1
  42. package/esm2022/src/version.mjs +1 -1
  43. package/fesm2022/compiler.mjs +288 -76
  44. package/fesm2022/compiler.mjs.map +1 -1
  45. package/index.d.ts +36 -12
  46. package/package.json +2 -2
  47. package/esm2022/src/ml_parser/interpolation_config.mjs +0 -23
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v17.0.3
2
+ * @license Angular v17.0.4
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -539,6 +539,9 @@ class _SerializerVisitor {
539
539
  visitIcuPlaceholder(ph, context) {
540
540
  return `<ph icu name="${ph.name}">${ph.value.visit(this)}</ph>`;
541
541
  }
542
+ visitBlockPlaceholder(ph, context) {
543
+ return `<ph block name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`;
544
+ }
542
545
  }
543
546
  const serializerVisitor$1 = new _SerializerVisitor();
544
547
  function serializeNodes(nodes) {
@@ -3847,43 +3850,47 @@ class BlockNode {
3847
3850
  }
3848
3851
  }
3849
3852
  class DeferredBlockPlaceholder extends BlockNode {
3850
- constructor(children, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan) {
3853
+ constructor(children, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
3851
3854
  super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
3852
3855
  this.children = children;
3853
3856
  this.minimumTime = minimumTime;
3857
+ this.i18n = i18n;
3854
3858
  }
3855
3859
  visit(visitor) {
3856
3860
  return visitor.visitDeferredBlockPlaceholder(this);
3857
3861
  }
3858
3862
  }
3859
3863
  class DeferredBlockLoading extends BlockNode {
3860
- constructor(children, afterTime, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan) {
3864
+ constructor(children, afterTime, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
3861
3865
  super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
3862
3866
  this.children = children;
3863
3867
  this.afterTime = afterTime;
3864
3868
  this.minimumTime = minimumTime;
3869
+ this.i18n = i18n;
3865
3870
  }
3866
3871
  visit(visitor) {
3867
3872
  return visitor.visitDeferredBlockLoading(this);
3868
3873
  }
3869
3874
  }
3870
3875
  class DeferredBlockError extends BlockNode {
3871
- constructor(children, nameSpan, sourceSpan, startSourceSpan, endSourceSpan) {
3876
+ constructor(children, nameSpan, sourceSpan, startSourceSpan, endSourceSpan, i18n) {
3872
3877
  super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
3873
3878
  this.children = children;
3879
+ this.i18n = i18n;
3874
3880
  }
3875
3881
  visit(visitor) {
3876
3882
  return visitor.visitDeferredBlockError(this);
3877
3883
  }
3878
3884
  }
3879
3885
  class DeferredBlock extends BlockNode {
3880
- constructor(children, triggers, prefetchTriggers, placeholder, loading, error, nameSpan, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan) {
3886
+ constructor(children, triggers, prefetchTriggers, placeholder, loading, error, nameSpan, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan, i18n) {
3881
3887
  super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
3882
3888
  this.children = children;
3883
3889
  this.placeholder = placeholder;
3884
3890
  this.loading = loading;
3885
3891
  this.error = error;
3886
3892
  this.mainBlockSpan = mainBlockSpan;
3893
+ this.i18n = i18n;
3887
3894
  this.triggers = triggers;
3888
3895
  this.prefetchTriggers = prefetchTriggers;
3889
3896
  // We cache the keys since we know that they won't change and we
@@ -3922,17 +3929,18 @@ class SwitchBlock extends BlockNode {
3922
3929
  }
3923
3930
  }
3924
3931
  class SwitchBlockCase extends BlockNode {
3925
- constructor(expression, children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
3932
+ constructor(expression, children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
3926
3933
  super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
3927
3934
  this.expression = expression;
3928
3935
  this.children = children;
3936
+ this.i18n = i18n;
3929
3937
  }
3930
3938
  visit(visitor) {
3931
3939
  return visitor.visitSwitchBlockCase(this);
3932
3940
  }
3933
3941
  }
3934
3942
  class ForLoopBlock extends BlockNode {
3935
- constructor(item, expression, trackBy, trackKeywordSpan, contextVariables, children, empty, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan, nameSpan) {
3943
+ constructor(item, expression, trackBy, trackKeywordSpan, contextVariables, children, empty, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
3936
3944
  super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
3937
3945
  this.item = item;
3938
3946
  this.expression = expression;
@@ -3942,15 +3950,17 @@ class ForLoopBlock extends BlockNode {
3942
3950
  this.children = children;
3943
3951
  this.empty = empty;
3944
3952
  this.mainBlockSpan = mainBlockSpan;
3953
+ this.i18n = i18n;
3945
3954
  }
3946
3955
  visit(visitor) {
3947
3956
  return visitor.visitForLoopBlock(this);
3948
3957
  }
3949
3958
  }
3950
3959
  class ForLoopBlockEmpty extends BlockNode {
3951
- constructor(children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
3960
+ constructor(children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
3952
3961
  super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
3953
3962
  this.children = children;
3963
+ this.i18n = i18n;
3954
3964
  }
3955
3965
  visit(visitor) {
3956
3966
  return visitor.visitForLoopBlockEmpty(this);
@@ -3966,11 +3976,12 @@ class IfBlock extends BlockNode {
3966
3976
  }
3967
3977
  }
3968
3978
  class IfBlockBranch extends BlockNode {
3969
- constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
3979
+ constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan, endSourceSpan, nameSpan, i18n) {
3970
3980
  super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
3971
3981
  this.expression = expression;
3972
3982
  this.children = children;
3973
3983
  this.expressionAlias = expressionAlias;
3984
+ this.i18n = i18n;
3974
3985
  }
3975
3986
  visit(visitor) {
3976
3987
  return visitor.visitIfBlockBranch(this);
@@ -4240,6 +4251,21 @@ class IcuPlaceholder {
4240
4251
  return visitor.visitIcuPlaceholder(this, context);
4241
4252
  }
4242
4253
  }
4254
+ class BlockPlaceholder {
4255
+ constructor(name, parameters, startName, closeName, children, sourceSpan, startSourceSpan, endSourceSpan) {
4256
+ this.name = name;
4257
+ this.parameters = parameters;
4258
+ this.startName = startName;
4259
+ this.closeName = closeName;
4260
+ this.children = children;
4261
+ this.sourceSpan = sourceSpan;
4262
+ this.startSourceSpan = startSourceSpan;
4263
+ this.endSourceSpan = endSourceSpan;
4264
+ }
4265
+ visit(visitor, context) {
4266
+ return visitor.visitBlockPlaceholder(this, context);
4267
+ }
4268
+ }
4243
4269
  // Clone the AST
4244
4270
  class CloneVisitor {
4245
4271
  visitText(text, context) {
@@ -4265,6 +4291,10 @@ class CloneVisitor {
4265
4291
  visitIcuPlaceholder(ph, context) {
4266
4292
  return new IcuPlaceholder(ph.value, ph.name, ph.sourceSpan);
4267
4293
  }
4294
+ visitBlockPlaceholder(ph, context) {
4295
+ const children = ph.children.map(n => n.visit(this, context));
4296
+ return new BlockPlaceholder(ph.name, ph.parameters, ph.startName, ph.closeName, children, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
4297
+ }
4268
4298
  }
4269
4299
  // Visit all the nodes recursively
4270
4300
  class RecurseVisitor {
@@ -4282,6 +4312,9 @@ class RecurseVisitor {
4282
4312
  }
4283
4313
  visitPlaceholder(ph, context) { }
4284
4314
  visitIcuPlaceholder(ph, context) { }
4315
+ visitBlockPlaceholder(ph, context) {
4316
+ ph.children.forEach(child => child.visit(this));
4317
+ }
4285
4318
  }
4286
4319
  /**
4287
4320
  * Serialize the message to the Localize backtick string format that would appear in compiled code.
@@ -4312,6 +4345,10 @@ class LocalizeMessageStringVisitor {
4312
4345
  visitIcuPlaceholder(ph) {
4313
4346
  return `{$${ph.name}}`;
4314
4347
  }
4348
+ visitBlockPlaceholder(ph) {
4349
+ const children = ph.children.map(child => child.visit(this)).join('');
4350
+ return `{$${ph.startName}}${children}{$${ph.closeName}}`;
4351
+ }
4315
4352
  }
4316
4353
 
4317
4354
  class Serializer {
@@ -4354,6 +4391,11 @@ class SimplePlaceholderMapper extends RecurseVisitor {
4354
4391
  visitPlaceholder(ph, context) {
4355
4392
  this.visitPlaceholderName(ph.name);
4356
4393
  }
4394
+ visitBlockPlaceholder(ph, context) {
4395
+ this.visitPlaceholderName(ph.startName);
4396
+ super.visitBlockPlaceholder(ph, context);
4397
+ this.visitPlaceholderName(ph.closeName);
4398
+ }
4357
4399
  visitIcuPlaceholder(ph, context) {
4358
4400
  this.visitPlaceholderName(ph.name);
4359
4401
  }
@@ -4566,6 +4608,17 @@ class _Visitor$1 {
4566
4608
  new Tag(_PLACEHOLDER_TAG$3, { name: ph.name }, [exTag, interpolationAsText])
4567
4609
  ];
4568
4610
  }
4611
+ visitBlockPlaceholder(ph, context) {
4612
+ const startAsText = new Text$1(`@${ph.name}`);
4613
+ const startEx = new Tag(_EXAMPLE_TAG, {}, [startAsText]);
4614
+ // TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
4615
+ const startTagPh = new Tag(_PLACEHOLDER_TAG$3, { name: ph.startName }, [startEx, startAsText]);
4616
+ const closeAsText = new Text$1(`}`);
4617
+ const closeEx = new Tag(_EXAMPLE_TAG, {}, [closeAsText]);
4618
+ // TC requires PH to have a non empty EX, and uses the text node to show the "original" value.
4619
+ const closeTagPh = new Tag(_PLACEHOLDER_TAG$3, { name: ph.closeName }, [closeEx, closeAsText]);
4620
+ return [startTagPh, ...this.serialize(ph.children), closeTagPh];
4621
+ }
4569
4622
  visitIcuPlaceholder(ph, context) {
4570
4623
  const icuExpression = ph.value.expression;
4571
4624
  const icuType = ph.value.type;
@@ -5211,6 +5264,7 @@ class InterpolationConfig {
5211
5264
  }
5212
5265
  }
5213
5266
  const DEFAULT_INTERPOLATION_CONFIG = new InterpolationConfig('{{', '}}');
5267
+ const DEFAULT_CONTAINER_BLOCKS = new Set(['switch']);
5214
5268
 
5215
5269
  const $EOF = 0;
5216
5270
  const $BSPACE = 8;
@@ -9414,6 +9468,7 @@ function createRepeaterOp(repeaterCreate, targetSlot, collection, sourceSpan) {
9414
9468
  collection,
9415
9469
  sourceSpan,
9416
9470
  ...NEW_OP,
9471
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
9417
9472
  };
9418
9473
  }
9419
9474
  function createDeferWhenOp(target, expr, prefetch, sourceSpan) {
@@ -12723,6 +12778,9 @@ class IcuSerializerVisitor {
12723
12778
  visitPlaceholder(ph) {
12724
12779
  return this.formatPh(ph.name);
12725
12780
  }
12781
+ visitBlockPlaceholder(ph) {
12782
+ return `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
12783
+ }
12726
12784
  visitIcuPlaceholder(ph, context) {
12727
12785
  return this.formatPh(ph.name);
12728
12786
  }
@@ -14446,12 +14504,12 @@ class Comment {
14446
14504
  return visitor.visitComment(this, context);
14447
14505
  }
14448
14506
  }
14449
- class Block {
14450
- constructor(name, parameters, children, sourceSpan, nameSpan, startSourceSpan, endSourceSpan = null) {
14507
+ class Block extends NodeWithI18n {
14508
+ constructor(name, parameters, children, sourceSpan, nameSpan, startSourceSpan, endSourceSpan = null, i18n) {
14509
+ super(sourceSpan, i18n);
14451
14510
  this.name = name;
14452
14511
  this.parameters = parameters;
14453
14512
  this.children = children;
14454
- this.sourceSpan = sourceSpan;
14455
14513
  this.nameSpan = nameSpan;
14456
14514
  this.startSourceSpan = startSourceSpan;
14457
14515
  this.endSourceSpan = endSourceSpan;
@@ -15137,6 +15195,24 @@ class PlaceholderRegistry {
15137
15195
  getUniquePlaceholder(name) {
15138
15196
  return this._generateUniqueName(name.toUpperCase());
15139
15197
  }
15198
+ getStartBlockPlaceholderName(name, parameters) {
15199
+ const signature = this._hashBlock(name, parameters);
15200
+ if (this._signatureToName[signature]) {
15201
+ return this._signatureToName[signature];
15202
+ }
15203
+ const placeholder = this._generateUniqueName(`START_BLOCK_${this._toSnakeCase(name)}`);
15204
+ this._signatureToName[signature] = placeholder;
15205
+ return placeholder;
15206
+ }
15207
+ getCloseBlockPlaceholderName(name) {
15208
+ const signature = this._hashClosingBlock(name);
15209
+ if (this._signatureToName[signature]) {
15210
+ return this._signatureToName[signature];
15211
+ }
15212
+ const placeholder = this._generateUniqueName(`CLOSE_BLOCK_${this._toSnakeCase(name)}`);
15213
+ this._signatureToName[signature] = placeholder;
15214
+ return placeholder;
15215
+ }
15140
15216
  // Generate a hash for a tag - does not take attribute order into account
15141
15217
  _hashTag(tag, attrs, isVoid) {
15142
15218
  const start = `<${tag}`;
@@ -15147,6 +15223,16 @@ class PlaceholderRegistry {
15147
15223
  _hashClosingTag(tag) {
15148
15224
  return this._hashTag(`/${tag}`, {}, false);
15149
15225
  }
15226
+ _hashBlock(name, parameters) {
15227
+ const params = parameters.length === 0 ? '' : ` (${parameters.sort().join('; ')})`;
15228
+ return `@${name}${params} {}`;
15229
+ }
15230
+ _hashClosingBlock(name) {
15231
+ return this._hashBlock(`close_${name}`, []);
15232
+ }
15233
+ _toSnakeCase(name) {
15234
+ return name.toUpperCase().replace(/[^A-Z0-9]/g, '_');
15235
+ }
15150
15236
  _generateUniqueName(base) {
15151
15237
  const seen = this._placeHolderNameCounts.hasOwnProperty(base);
15152
15238
  if (!seen) {
@@ -15163,17 +15249,18 @@ const _expParser = new Parser$1(new Lexer());
15163
15249
  /**
15164
15250
  * Returns a function converting html nodes to an i18n Message given an interpolationConfig
15165
15251
  */
15166
- function createI18nMessageFactory(interpolationConfig) {
15167
- const visitor = new _I18nVisitor(_expParser, interpolationConfig);
15252
+ function createI18nMessageFactory(interpolationConfig, containerBlocks) {
15253
+ const visitor = new _I18nVisitor(_expParser, interpolationConfig, containerBlocks);
15168
15254
  return (nodes, meaning, description, customId, visitNodeFn) => visitor.toI18nMessage(nodes, meaning, description, customId, visitNodeFn);
15169
15255
  }
15170
15256
  function noopVisitNodeFn(_html, i18n) {
15171
15257
  return i18n;
15172
15258
  }
15173
15259
  class _I18nVisitor {
15174
- constructor(_expressionParser, _interpolationConfig) {
15260
+ constructor(_expressionParser, _interpolationConfig, _containerBlocks) {
15175
15261
  this._expressionParser = _expressionParser;
15176
15262
  this._interpolationConfig = _interpolationConfig;
15263
+ this._containerBlocks = _containerBlocks;
15177
15264
  }
15178
15265
  toI18nMessage(nodes, meaning = '', description = '', customId = '', visitNodeFn) {
15179
15266
  const context = {
@@ -15260,10 +15347,26 @@ class _I18nVisitor {
15260
15347
  }
15261
15348
  visitBlock(block, context) {
15262
15349
  const children = visitAll(this, block.children, context);
15263
- const node = new Container(children, block.sourceSpan);
15350
+ if (this._containerBlocks.has(block.name)) {
15351
+ return new Container(children, block.sourceSpan);
15352
+ }
15353
+ const parameters = block.parameters.map(param => param.expression);
15354
+ const startPhName = context.placeholderRegistry.getStartBlockPlaceholderName(block.name, parameters);
15355
+ const closePhName = context.placeholderRegistry.getCloseBlockPlaceholderName(block.name);
15356
+ context.placeholderToContent[startPhName] = {
15357
+ text: block.startSourceSpan.toString(),
15358
+ sourceSpan: block.startSourceSpan,
15359
+ };
15360
+ context.placeholderToContent[closePhName] = {
15361
+ text: block.endSourceSpan ? block.endSourceSpan.toString() : '}',
15362
+ sourceSpan: block.endSourceSpan ?? block.sourceSpan,
15363
+ };
15364
+ const node = new BlockPlaceholder(block.name, parameters, startPhName, closePhName, children, block.sourceSpan, block.startSourceSpan, block.endSourceSpan);
15264
15365
  return context.visitNodeFn(block, node);
15265
15366
  }
15266
- visitBlockParameter(_parameter, _context) { }
15367
+ visitBlockParameter(_parameter, _context) {
15368
+ throw new Error('Unreachable code');
15369
+ }
15267
15370
  /**
15268
15371
  * Convert, text and interpolated tokens up into text and placeholder pieces.
15269
15372
  *
@@ -19132,17 +19235,18 @@ const setI18nRefs = (htmlNode, i18nNode) => {
19132
19235
  * stored with other element's and attribute's information.
19133
19236
  */
19134
19237
  class I18nMetaVisitor {
19135
- constructor(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG, keepI18nAttrs = false, enableI18nLegacyMessageIdFormat = false) {
19238
+ constructor(interpolationConfig = DEFAULT_INTERPOLATION_CONFIG, keepI18nAttrs = false, enableI18nLegacyMessageIdFormat = false, containerBlocks = DEFAULT_CONTAINER_BLOCKS) {
19136
19239
  this.interpolationConfig = interpolationConfig;
19137
19240
  this.keepI18nAttrs = keepI18nAttrs;
19138
19241
  this.enableI18nLegacyMessageIdFormat = enableI18nLegacyMessageIdFormat;
19242
+ this.containerBlocks = containerBlocks;
19139
19243
  // whether visited nodes contain i18n information
19140
19244
  this.hasI18nMeta = false;
19141
19245
  this._errors = [];
19142
19246
  }
19143
19247
  _generateI18nMessage(nodes, meta = '', visitNodeFn) {
19144
19248
  const { meaning, description, customId } = this._parseMetadata(meta);
19145
- const createI18nMessage = createI18nMessageFactory(this.interpolationConfig);
19249
+ const createI18nMessage = createI18nMessageFactory(this.interpolationConfig, this.containerBlocks);
19146
19250
  const message = createI18nMessage(nodes, meaning, description, customId, visitNodeFn);
19147
19251
  this._setMessageId(message, meta);
19148
19252
  this._setLegacyIds(message, meta);
@@ -19443,6 +19547,9 @@ class GetMsgSerializerVisitor {
19443
19547
  visitPlaceholder(ph) {
19444
19548
  return this.formatPh(ph.name);
19445
19549
  }
19550
+ visitBlockPlaceholder(ph) {
19551
+ return `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`;
19552
+ }
19446
19553
  visitIcuPlaceholder(ph, context) {
19447
19554
  return this.formatPh(ph.name);
19448
19555
  }
@@ -19496,6 +19603,11 @@ class LocalizeSerializerVisitor {
19496
19603
  visitPlaceholder(ph) {
19497
19604
  this.pieces.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan));
19498
19605
  }
19606
+ visitBlockPlaceholder(ph) {
19607
+ this.pieces.push(this.createPlaceholderPiece(ph.startName, ph.startSourceSpan ?? ph.sourceSpan));
19608
+ ph.children.forEach(child => child.visit(this));
19609
+ this.pieces.push(this.createPlaceholderPiece(ph.closeName, ph.endSourceSpan ?? ph.sourceSpan));
19610
+ }
19499
19611
  visitIcuPlaceholder(ph) {
19500
19612
  this.pieces.push(this.createPlaceholderPiece(ph.name, ph.sourceSpan, this.placeholderToMessage[ph.name]));
19501
19613
  }
@@ -20850,8 +20962,8 @@ function repeaterCreate(slot, viewFnName, decls, vars, tag, constIndex, trackByF
20850
20962
  }
20851
20963
  return call(Identifiers.repeaterCreate, args, sourceSpan);
20852
20964
  }
20853
- function repeater(metadataSlot, collection, sourceSpan) {
20854
- return call(Identifiers.repeater, [literal(metadataSlot), collection], sourceSpan);
20965
+ function repeater(collection, sourceSpan) {
20966
+ return call(Identifiers.repeater, [collection], sourceSpan);
20855
20967
  }
20856
20968
  function deferWhen(prefetch, expr, sourceSpan) {
20857
20969
  return call(prefetch ? Identifiers.deferPrefetchWhen : Identifiers.deferWhen, [expr], sourceSpan);
@@ -21459,7 +21571,7 @@ function reifyUpdateOperations(_unit, ops) {
21459
21571
  OpList.replace(op, conditional(op.targetSlot.slot, op.processed, op.contextValue, op.sourceSpan));
21460
21572
  break;
21461
21573
  case OpKind.Repeater:
21462
- OpList.replace(op, repeater(op.targetSlot.slot, op.collection, op.sourceSpan));
21574
+ OpList.replace(op, repeater(op.collection, op.sourceSpan));
21463
21575
  break;
21464
21576
  case OpKind.DeferWhen:
21465
21577
  OpList.replace(op, deferWhen(op.prefetch, op.expr, op.sourceSpan));
@@ -21886,10 +21998,9 @@ class ResolveIcuPlaceholdersVisitor extends RecurseVisitor {
21886
21998
  super();
21887
21999
  this.params = params;
21888
22000
  }
21889
- visitTagPlaceholder(placeholder) {
21890
- super.visitTagPlaceholder(placeholder);
21891
- // Add the start and end source span for tag placeholders. These need to be recorded for
21892
- // elements inside ICUs. The slots for the elements were recorded separately under the i18n
22001
+ visitContainerPlaceholder(placeholder) {
22002
+ // Add the start and end source span for container placeholders. These need to be recorded for
22003
+ // elements inside ICUs. The slots for the nodes were recorded separately under the i18n
21893
22004
  // block's context as part of the `resolveI18nElementPlaceholders` phase.
21894
22005
  if (placeholder.startName && placeholder.startSourceSpan &&
21895
22006
  !this.params.has(placeholder.startName)) {
@@ -21908,6 +22019,14 @@ class ResolveIcuPlaceholdersVisitor extends RecurseVisitor {
21908
22019
  }]);
21909
22020
  }
21910
22021
  }
22022
+ visitTagPlaceholder(placeholder) {
22023
+ super.visitTagPlaceholder(placeholder);
22024
+ this.visitContainerPlaceholder(placeholder);
22025
+ }
22026
+ visitBlockPlaceholder(placeholder) {
22027
+ super.visitBlockPlaceholder(placeholder);
22028
+ this.visitContainerPlaceholder(placeholder);
22029
+ }
21911
22030
  }
21912
22031
 
21913
22032
  /**
@@ -25102,19 +25221,19 @@ function createIfBlock(ast, connectedBlocks, visitor, bindingParser) {
25102
25221
  const branches = [];
25103
25222
  const mainBlockParams = parseConditionalBlockParameters(ast, errors, bindingParser);
25104
25223
  if (mainBlockParams !== null) {
25105
- branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.nameSpan));
25224
+ branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.nameSpan, ast.i18n));
25106
25225
  }
25107
25226
  for (const block of connectedBlocks) {
25108
25227
  if (ELSE_IF_PATTERN.test(block.name)) {
25109
25228
  const params = parseConditionalBlockParameters(block, errors, bindingParser);
25110
25229
  if (params !== null) {
25111
25230
  const children = visitAll(visitor, block.children, block.children);
25112
- branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan));
25231
+ branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan, block.i18n));
25113
25232
  }
25114
25233
  }
25115
25234
  else if (block.name === 'else') {
25116
25235
  const children = visitAll(visitor, block.children, block.children);
25117
- branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan));
25236
+ branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan, block.i18n));
25118
25237
  }
25119
25238
  }
25120
25239
  // The outer IfBlock should have a span that encapsulates all branches.
@@ -25145,7 +25264,7 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
25145
25264
  errors.push(new ParseError(block.sourceSpan, '@empty block cannot have parameters'));
25146
25265
  }
25147
25266
  else {
25148
- empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan);
25267
+ empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan, block.i18n);
25149
25268
  }
25150
25269
  }
25151
25270
  else {
@@ -25163,7 +25282,7 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
25163
25282
  // main `for` body, use `mainSourceSpan`.
25164
25283
  const endSpan = empty?.endSourceSpan ?? ast.endSourceSpan;
25165
25284
  const sourceSpan = new ParseSourceSpan(ast.sourceSpan.start, endSpan?.end ?? ast.sourceSpan.end);
25166
- node = new ForLoopBlock(params.itemName, params.expression, params.trackBy.expression, params.trackBy.keywordSpan, params.context, visitAll(visitor, ast.children, ast.children), empty, sourceSpan, ast.sourceSpan, ast.startSourceSpan, endSpan, ast.nameSpan);
25285
+ node = new ForLoopBlock(params.itemName, params.expression, params.trackBy.expression, params.trackBy.keywordSpan, params.context, visitAll(visitor, ast.children, ast.children), empty, sourceSpan, ast.sourceSpan, ast.startSourceSpan, endSpan, ast.nameSpan, ast.i18n);
25167
25286
  }
25168
25287
  }
25169
25288
  return { node, errors };
@@ -25189,7 +25308,7 @@ function createSwitchBlock(ast, visitor, bindingParser) {
25189
25308
  const expression = node.name === 'case' ?
25190
25309
  parseBlockParameterToBinding(node.parameters[0], bindingParser) :
25191
25310
  null;
25192
- const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.nameSpan);
25311
+ const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.nameSpan, node.i18n);
25193
25312
  if (expression === null) {
25194
25313
  defaultCase = ast;
25195
25314
  }
@@ -25776,7 +25895,7 @@ function createDeferredBlock(ast, connectedBlocks, visitor, bindingParser) {
25776
25895
  endOfLastSourceSpan = lastConnectedBlock.sourceSpan.end;
25777
25896
  }
25778
25897
  const sourceSpanWithConnectedBlocks = new ParseSourceSpan(ast.sourceSpan.start, endOfLastSourceSpan);
25779
- const node = new DeferredBlock(visitAll(visitor, ast.children, ast.children), triggers, prefetchTriggers, placeholder, loading, error, ast.nameSpan, sourceSpanWithConnectedBlocks, ast.sourceSpan, ast.startSourceSpan, lastEndSourceSpan);
25898
+ const node = new DeferredBlock(visitAll(visitor, ast.children, ast.children), triggers, prefetchTriggers, placeholder, loading, error, ast.nameSpan, sourceSpanWithConnectedBlocks, ast.sourceSpan, ast.startSourceSpan, lastEndSourceSpan, ast.i18n);
25780
25899
  return { node, errors };
25781
25900
  }
25782
25901
  function parseConnectedBlocks(connectedBlocks, errors, visitor) {
@@ -25839,7 +25958,7 @@ function parsePlaceholderBlock(ast, visitor) {
25839
25958
  throw new Error(`Unrecognized parameter in @placeholder block: "${param.expression}"`);
25840
25959
  }
25841
25960
  }
25842
- return new DeferredBlockPlaceholder(visitAll(visitor, ast.children, ast.children), minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
25961
+ return new DeferredBlockPlaceholder(visitAll(visitor, ast.children, ast.children), minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
25843
25962
  }
25844
25963
  function parseLoadingBlock(ast, visitor) {
25845
25964
  let afterTime = null;
@@ -25869,13 +25988,13 @@ function parseLoadingBlock(ast, visitor) {
25869
25988
  throw new Error(`Unrecognized parameter in @loading block: "${param.expression}"`);
25870
25989
  }
25871
25990
  }
25872
- return new DeferredBlockLoading(visitAll(visitor, ast.children, ast.children), afterTime, minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
25991
+ return new DeferredBlockLoading(visitAll(visitor, ast.children, ast.children), afterTime, minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
25873
25992
  }
25874
25993
  function parseErrorBlock(ast, visitor) {
25875
25994
  if (ast.parameters.length > 0) {
25876
25995
  throw new Error(`@error block cannot have parameters`);
25877
25996
  }
25878
- return new DeferredBlockError(visitAll(visitor, ast.children, ast.children), ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
25997
+ return new DeferredBlockError(visitAll(visitor, ast.children, ast.children), ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.i18n);
25879
25998
  }
25880
25999
  function parsePrimaryTriggers(params, bindingParser, errors, placeholder) {
25881
26000
  const triggers = {};
@@ -26475,6 +26594,11 @@ class I18nContext {
26475
26594
  const content = { type, index, ctx: this.id, isVoid: node.isVoid, closed };
26476
26595
  updatePlaceholderMap(this.placeholders, ph, content);
26477
26596
  }
26597
+ appendBlockPart(node, index, closed) {
26598
+ const ph = closed ? node.closeName : node.startName;
26599
+ const content = { type: TagType.TEMPLATE, index, ctx: this.id, closed };
26600
+ updatePlaceholderMap(this.placeholders, ph, content);
26601
+ }
26478
26602
  get icus() {
26479
26603
  return this._registry.icus;
26480
26604
  }
@@ -26507,6 +26631,13 @@ class I18nContext {
26507
26631
  this.appendTag(TagType.TEMPLATE, node, index, true);
26508
26632
  this._unresolvedCtxCount++;
26509
26633
  }
26634
+ appendBlock(node, index) {
26635
+ // add open and close tags at the same time,
26636
+ // since we process nested templates separately
26637
+ this.appendBlockPart(node, index, false);
26638
+ this.appendBlockPart(node, index, true);
26639
+ this._unresolvedCtxCount++;
26640
+ }
26510
26641
  appendElement(node, index, closed) {
26511
26642
  this.appendTag(TagType.ELEMENT, node, index, closed);
26512
26643
  }
@@ -26785,13 +26916,19 @@ class TemplateDefinitionBuilder {
26785
26916
  this.creationInstruction(null, Identifiers.pipe, [literal(slot), literal(name)]);
26786
26917
  });
26787
26918
  }
26788
- buildTemplateFunction(nodes, variables, ngContentSelectorsOffset = 0, i18n) {
26919
+ buildTemplateFunction(nodes, variables, ngContentSelectorsOffset = 0, i18n, variableAliases) {
26789
26920
  this._ngContentSelectorsOffset = ngContentSelectorsOffset;
26790
26921
  if (this._namespace !== Identifiers.namespaceHTML) {
26791
26922
  this.creationInstruction(null, this._namespace);
26792
26923
  }
26793
26924
  // Create variable bindings
26794
- variables.forEach(v => this.registerContextVariables(v));
26925
+ variables.forEach(v => {
26926
+ const alias = variableAliases?.[v.name];
26927
+ this.registerContextVariables(v.name, v.value);
26928
+ if (alias) {
26929
+ this.registerContextVariables(alias, v.value);
26930
+ }
26931
+ });
26795
26932
  // Initiate i18n context in case:
26796
26933
  // - this template has parent i18n context
26797
26934
  // - or the template has i18n meta associated with it,
@@ -26885,12 +27022,12 @@ class TemplateDefinitionBuilder {
26885
27022
  this._constants.prepareStatements.push(...statements);
26886
27023
  return _ref;
26887
27024
  }
26888
- registerContextVariables(variable$1) {
27025
+ registerContextVariables(name, value) {
26889
27026
  const scopedName = this._bindingScope.freshReferenceName();
26890
27027
  const retrievalLevel = this.level;
26891
- const isDirect = variable$1.value === DIRECT_CONTEXT_REFERENCE;
26892
- const lhs = variable(variable$1.name + scopedName);
26893
- this._bindingScope.set(retrievalLevel, variable$1.name, scope => {
27028
+ const isDirect = value === DIRECT_CONTEXT_REFERENCE;
27029
+ const lhs = variable(name + scopedName);
27030
+ this._bindingScope.set(retrievalLevel, name, scope => {
26894
27031
  // If we're at the top level and we're referring to the context variable directly, we
26895
27032
  // can do so through the implicit receiver, instead of renaming it. Note that this does
26896
27033
  // not apply to listeners, because they need to restore the context.
@@ -26926,7 +27063,7 @@ class TemplateDefinitionBuilder {
26926
27063
  return [
26927
27064
  // e.g. const $items$ = x(2) for direct context references and
26928
27065
  // const $item$ = x(2).$implicit for indirect ones.
26929
- lhs.set(isDirect ? rhs : rhs.prop(variable$1.value || IMPLICIT_REFERENCE)).toConstDecl()
27066
+ lhs.set(isDirect ? rhs : rhs.prop(value || IMPLICIT_REFERENCE)).toConstDecl()
26930
27067
  ];
26931
27068
  });
26932
27069
  }
@@ -27349,10 +27486,15 @@ class TemplateDefinitionBuilder {
27349
27486
  this.creationInstruction(span, isNgContainer$1 ? Identifiers.elementContainerEnd : Identifiers.elementEnd);
27350
27487
  }
27351
27488
  }
27352
- prepareEmbeddedTemplateFn(children, contextNameSuffix, variables = [], i18n) {
27489
+ prepareEmbeddedTemplateFn(children, contextNameSuffix, variables = [], i18nMeta, variableAliases) {
27353
27490
  const index = this.allocateDataSlot();
27354
- if (this.i18n && i18n) {
27355
- this.i18n.appendTemplate(i18n, index);
27491
+ if (this.i18n && i18nMeta) {
27492
+ if (i18nMeta instanceof BlockPlaceholder) {
27493
+ this.i18n.appendBlock(i18nMeta, index);
27494
+ }
27495
+ else {
27496
+ this.i18n.appendTemplate(i18nMeta, index);
27497
+ }
27356
27498
  }
27357
27499
  const contextName = `${this.contextName}${contextNameSuffix}_${index}`;
27358
27500
  const name = `${contextName}_Template`;
@@ -27363,7 +27505,7 @@ class TemplateDefinitionBuilder {
27363
27505
  // be able to support bindings in nested templates to local refs that occur after the
27364
27506
  // template definition. e.g. <div *ngIf="showing">{{ foo }}</div> <div #foo></div>
27365
27507
  this._nestedTemplateFns.push(() => {
27366
- const templateFunctionExpr = visitor.buildTemplateFunction(children, variables, this._ngContentReservedSlots.length + this._ngContentSelectorsOffset, i18n);
27508
+ const templateFunctionExpr = visitor.buildTemplateFunction(children, variables, this._ngContentReservedSlots.length + this._ngContentSelectorsOffset, i18nMeta, variableAliases);
27367
27509
  this.constantPool.statements.push(templateFunctionExpr.toDeclStmt(name));
27368
27510
  if (visitor._ngContentReservedSlots.length) {
27369
27511
  this._ngContentReservedSlots.push(...visitor._ngContentReservedSlots);
@@ -27520,7 +27662,7 @@ class TemplateDefinitionBuilder {
27520
27662
  }
27521
27663
  // Note: the template needs to be created *before* we process the expression,
27522
27664
  // otherwise pipes injecting some symbols won't work (see #52102).
27523
- const templateIndex = this.createEmbeddedTemplateFn(tagName, children, '_Conditional', sourceSpan, variables, attrsExprs);
27665
+ const templateIndex = this.createEmbeddedTemplateFn(tagName, children, '_Conditional', sourceSpan, variables, attrsExprs, undefined, branch.i18n);
27524
27666
  const processedExpression = expression === null ? null : expression.visit(this._valueConverter);
27525
27667
  return { index: templateIndex, expression: processedExpression, alias: expressionAlias };
27526
27668
  });
@@ -27571,7 +27713,7 @@ class TemplateDefinitionBuilder {
27571
27713
  // We have to process the block in two steps: once here and again in the update instruction
27572
27714
  // callback in order to generate the correct expressions when pipes or pure functions are used.
27573
27715
  const caseData = block.cases.map(currentCase => {
27574
- const index = this.createEmbeddedTemplateFn(null, currentCase.children, '_Case', currentCase.sourceSpan);
27716
+ const index = this.createEmbeddedTemplateFn(null, currentCase.children, '_Case', currentCase.sourceSpan, undefined, undefined, undefined, currentCase.i18n);
27575
27717
  const expression = currentCase.expression === null ?
27576
27718
  null :
27577
27719
  currentCase.expression.visit(this._valueConverter);
@@ -27619,23 +27761,21 @@ class TemplateDefinitionBuilder {
27619
27761
  if (!metadata) {
27620
27762
  throw new Error('Could not resolve `defer` block metadata. Block may need to be analyzed.');
27621
27763
  }
27622
- const primaryTemplateIndex = this.createEmbeddedTemplateFn(null, deferred.children, '_Defer', deferred.sourceSpan);
27623
- const loadingIndex = loading ?
27624
- this.createEmbeddedTemplateFn(null, loading.children, '_DeferLoading', loading.sourceSpan) :
27764
+ const primaryTemplateIndex = this.createEmbeddedTemplateFn(null, deferred.children, '_Defer', deferred.sourceSpan, undefined, undefined, undefined, deferred.i18n);
27765
+ const loadingIndex = loading ? this.createEmbeddedTemplateFn(null, loading.children, '_DeferLoading', loading.sourceSpan, undefined, undefined, undefined, loading.i18n) :
27625
27766
  null;
27626
27767
  const loadingConsts = loading ?
27627
27768
  trimTrailingNulls([literal(loading.minimumTime), literal(loading.afterTime)]) :
27628
27769
  null;
27629
27770
  const placeholderIndex = placeholder ?
27630
- this.createEmbeddedTemplateFn(null, placeholder.children, '_DeferPlaceholder', placeholder.sourceSpan) :
27771
+ this.createEmbeddedTemplateFn(null, placeholder.children, '_DeferPlaceholder', placeholder.sourceSpan, undefined, undefined, undefined, placeholder.i18n) :
27631
27772
  null;
27632
27773
  const placeholderConsts = placeholder && placeholder.minimumTime !== null ?
27633
27774
  // TODO(crisbeto): potentially pass the time directly instead of storing it in the `consts`
27634
27775
  // since the placeholder block can only have one parameter?
27635
27776
  literalArr([literal(placeholder.minimumTime)]) :
27636
27777
  null;
27637
- const errorIndex = error ?
27638
- this.createEmbeddedTemplateFn(null, error.children, '_DeferError', error.sourceSpan) :
27778
+ const errorIndex = error ? this.createEmbeddedTemplateFn(null, error.children, '_DeferError', error.sourceSpan, undefined, undefined, undefined, error.i18n) :
27639
27779
  null;
27640
27780
  // Note: we generate this last so the index matches the instruction order.
27641
27781
  const deferredIndex = this.allocateDataSlot();
@@ -27789,11 +27929,18 @@ class TemplateDefinitionBuilder {
27789
27929
  // are implicitly inferred by the runtime to index + 1 and index + 2.
27790
27930
  const blockIndex = this.allocateDataSlot();
27791
27931
  const { tagName, attrsExprs } = this.inferProjectionDataFromInsertionPoint(block);
27792
- const primaryData = this.prepareEmbeddedTemplateFn(block.children, '_For', [block.item, block.contextVariables.$index, block.contextVariables.$count]);
27932
+ const primaryData = this.prepareEmbeddedTemplateFn(block.children, '_For', [block.item, block.contextVariables.$index, block.contextVariables.$count], block.i18n, {
27933
+ // We need to provide level-specific versions of `$index` and `$count`, because
27934
+ // they're used when deriving the remaining variables (`$odd`, `$even` etc.) while at the
27935
+ // same time being available implicitly. Without these aliases, we wouldn't be able to
27936
+ // access the `$index` of a parent loop from inside of a nested loop.
27937
+ [block.contextVariables.$index.name]: this.getLevelSpecificVariableName('$index', this.level + 1),
27938
+ [block.contextVariables.$count.name]: this.getLevelSpecificVariableName('$count', this.level + 1),
27939
+ });
27793
27940
  const { expression: trackByExpression, usesComponentInstance: trackByUsesComponentInstance } = this.createTrackByFunction(block);
27794
27941
  let emptyData = null;
27795
27942
  if (block.empty !== null) {
27796
- emptyData = this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty');
27943
+ emptyData = this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty', undefined, block.empty.i18n);
27797
27944
  // Allocate an extra slot for the empty block tracking.
27798
27945
  this.allocateBindingSlots(null);
27799
27946
  }
@@ -27823,17 +27970,44 @@ class TemplateDefinitionBuilder {
27823
27970
  // Note: we don't allocate binding slots for this expression,
27824
27971
  // because its value isn't stored in the LView.
27825
27972
  const value = block.expression.visit(this._valueConverter);
27826
- // `repeater(0, iterable)`
27827
- this.updateInstruction(block.sourceSpan, Identifiers.repeater, () => [literal(blockIndex), this.convertPropertyBinding(value)]);
27973
+ // `advance(x); repeater(iterable)`
27974
+ this.updateInstructionWithAdvance(blockIndex, block.sourceSpan, Identifiers.repeater, () => [this.convertPropertyBinding(value)]);
27828
27975
  }
27829
27976
  registerComputedLoopVariables(block, bindingScope) {
27830
- const indexLocalName = block.contextVariables.$index.name;
27831
- const countLocalName = block.contextVariables.$count.name;
27832
27977
  const level = bindingScope.bindingLevel;
27833
- bindingScope.set(level, block.contextVariables.$odd.name, scope => scope.get(indexLocalName).modulo(literal(2)).notIdentical(literal(0)));
27834
- bindingScope.set(level, block.contextVariables.$even.name, scope => scope.get(indexLocalName).modulo(literal(2)).identical(literal(0)));
27835
- bindingScope.set(level, block.contextVariables.$first.name, scope => scope.get(indexLocalName).identical(literal(0)));
27836
- bindingScope.set(level, block.contextVariables.$last.name, scope => scope.get(indexLocalName).identical(scope.get(countLocalName).minus(literal(1))));
27978
+ bindingScope.set(level, block.contextVariables.$odd.name, (scope, retrievalLevel) => {
27979
+ return this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$index')
27980
+ .modulo(literal(2))
27981
+ .notIdentical(literal(0));
27982
+ });
27983
+ bindingScope.set(level, block.contextVariables.$even.name, (scope, retrievalLevel) => {
27984
+ return this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$index')
27985
+ .modulo(literal(2))
27986
+ .identical(literal(0));
27987
+ });
27988
+ bindingScope.set(level, block.contextVariables.$first.name, (scope, retrievalLevel) => {
27989
+ return this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$index')
27990
+ .identical(literal(0));
27991
+ });
27992
+ bindingScope.set(level, block.contextVariables.$last.name, (scope, retrievalLevel) => {
27993
+ const index = this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$index');
27994
+ const count = this.getLevelSpecificForLoopVariable(block, scope, retrievalLevel, '$count');
27995
+ return index.identical(count.minus(literal(1)));
27996
+ });
27997
+ }
27998
+ getLevelSpecificVariableName(name, level) {
27999
+ // We use the `ɵ` here to ensure that there are no name conflicts with user-defined variables.
28000
+ return `ɵ${name}_${level}`;
28001
+ }
28002
+ /**
28003
+ * Gets the name of a for loop variable at a specific binding level. This allows us to look
28004
+ * up implicitly shadowed variables like `$index` and `$count` at a specific level.
28005
+ */
28006
+ getLevelSpecificForLoopVariable(block, scope, retrievalLevel, name) {
28007
+ const scopeName = scope.bindingLevel === retrievalLevel ?
28008
+ block.contextVariables[name].name :
28009
+ this.getLevelSpecificVariableName(name, retrievalLevel);
28010
+ return scope.get(scopeName);
27837
28011
  }
27838
28012
  optimizeTrackByFunction(block) {
27839
28013
  const indexLocalName = block.contextVariables.$index.name;
@@ -28371,7 +28545,7 @@ class BindingScope {
28371
28545
  if (value.declareLocalCallback && !value.declare) {
28372
28546
  value.declare = true;
28373
28547
  }
28374
- return typeof value.lhs === 'function' ? value.lhs(this) : value.lhs;
28548
+ return typeof value.lhs === 'function' ? value.lhs(this, value.retrievalLevel) : value.lhs;
28375
28549
  }
28376
28550
  current = current.parent;
28377
28551
  }
@@ -28479,7 +28653,9 @@ class BindingScope {
28479
28653
  const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0);
28480
28654
  componentValue.declare = true;
28481
28655
  this.maybeRestoreView();
28482
- const lhs = typeof componentValue.lhs === 'function' ? componentValue.lhs(this) : componentValue.lhs;
28656
+ const lhs = typeof componentValue.lhs === 'function' ?
28657
+ componentValue.lhs(this, componentValue.retrievalLevel) :
28658
+ componentValue.lhs;
28483
28659
  return name === DIRECT_CONTEXT_REFERENCE ? lhs : lhs.prop(name);
28484
28660
  }
28485
28661
  maybeRestoreView() {
@@ -31064,7 +31240,7 @@ function publishFacade(global) {
31064
31240
  * @description
31065
31241
  * Entry point for all public APIs of the compiler package.
31066
31242
  */
31067
- const VERSION = new Version('17.0.3');
31243
+ const VERSION = new Version('17.0.4');
31068
31244
 
31069
31245
  class CompilerConfig {
31070
31246
  constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
@@ -31297,7 +31473,8 @@ class _Visitor {
31297
31473
  this._errors = [];
31298
31474
  this._messages = [];
31299
31475
  this._inImplicitNode = false;
31300
- this._createI18nMessage = createI18nMessageFactory(interpolationConfig);
31476
+ this._createI18nMessage =
31477
+ createI18nMessageFactory(interpolationConfig, DEFAULT_CONTAINER_BLOCKS);
31301
31478
  }
31302
31479
  // looks for translatable attributes
31303
31480
  _visitAttributesOf(el) {
@@ -31605,6 +31782,12 @@ class _WriteVisitor$1 {
31605
31782
  visitPlaceholder(ph, context) {
31606
31783
  return [new Tag(_PLACEHOLDER_TAG$2, { id: ph.name, 'equiv-text': `{{${ph.value}}}` })];
31607
31784
  }
31785
+ visitBlockPlaceholder(ph, context) {
31786
+ const ctype = `x-${ph.name.toLowerCase().replace(/[^a-z0-9]/g, '-')}`;
31787
+ const startTagPh = new Tag(_PLACEHOLDER_TAG$2, { id: ph.startName, ctype, 'equiv-text': `@${ph.name}` });
31788
+ const closeTagPh = new Tag(_PLACEHOLDER_TAG$2, { id: ph.closeName, ctype, 'equiv-text': `}` });
31789
+ return [startTagPh, ...this.serialize(ph.children), closeTagPh];
31790
+ }
31608
31791
  visitIcuPlaceholder(ph, context) {
31609
31792
  const equivText = `{${ph.value.expression}, ${ph.value.type}, ${Object.keys(ph.value.cases).map((value) => value + ' {...}').join(' ')}}`;
31610
31793
  return [new Tag(_PLACEHOLDER_TAG$2, { id: ph.name, 'equiv-text': equivText })];
@@ -31876,6 +32059,24 @@ class _WriteVisitor {
31876
32059
  disp: `{{${ph.value}}}`,
31877
32060
  })];
31878
32061
  }
32062
+ visitBlockPlaceholder(ph, context) {
32063
+ const tagPc = new Tag(_PLACEHOLDER_SPANNING_TAG, {
32064
+ id: (this._nextPlaceholderId++).toString(),
32065
+ equivStart: ph.startName,
32066
+ equivEnd: ph.closeName,
32067
+ type: 'other',
32068
+ dispStart: `@${ph.name}`,
32069
+ dispEnd: `}`,
32070
+ });
32071
+ const nodes = [].concat(...ph.children.map(node => node.visit(this)));
32072
+ if (nodes.length) {
32073
+ nodes.forEach((node) => tagPc.children.push(node));
32074
+ }
32075
+ else {
32076
+ tagPc.children.push(new Text$1(''));
32077
+ }
32078
+ return [tagPc];
32079
+ }
31879
32080
  visitIcuPlaceholder(ph, context) {
31880
32081
  const cases = Object.keys(ph.value.cases).map((value) => value + ' {...}').join(' ');
31881
32082
  const idStr = (this._nextPlaceholderId++).toString();
@@ -32324,6 +32525,11 @@ class I18nToHtmlVisitor {
32324
32525
  // An ICU placeholder references the source message to be serialized
32325
32526
  return this._convertToText(this._srcMsg.placeholderToMessage[ph.name]);
32326
32527
  }
32528
+ visitBlockPlaceholder(ph, context) {
32529
+ const params = ph.parameters.length === 0 ? '' : ` (${ph.parameters.join('; ')})`;
32530
+ const children = ph.children.map((c) => c.visit(this)).join('');
32531
+ return `@${ph.name}${params} {${children}}`;
32532
+ }
32327
32533
  /**
32328
32534
  * Convert a source message to a translated text string:
32329
32535
  * - text nodes are replaced with their translation,
@@ -32476,6 +32682,12 @@ class MapPlaceholderNames extends CloneVisitor {
32476
32682
  const children = ph.children.map(n => n.visit(this, mapper));
32477
32683
  return new TagPlaceholder(ph.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
32478
32684
  }
32685
+ visitBlockPlaceholder(ph, mapper) {
32686
+ const startName = mapper.toPublicName(ph.startName);
32687
+ const closeName = ph.closeName ? mapper.toPublicName(ph.closeName) : ph.closeName;
32688
+ const children = ph.children.map(n => n.visit(this, mapper));
32689
+ return new BlockPlaceholder(ph.name, ph.parameters, startName, closeName, children, ph.sourceSpan, ph.startSourceSpan, ph.endSourceSpan);
32690
+ }
32479
32691
  visitPlaceholder(ph, mapper) {
32480
32692
  return new Placeholder(ph.value, mapper.toPublicName(ph.name), ph.sourceSpan);
32481
32693
  }
@@ -32594,7 +32806,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
32594
32806
  function compileDeclareClassMetadata(metadata) {
32595
32807
  const definitionMap = new DefinitionMap();
32596
32808
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
32597
- definitionMap.set('version', literal('17.0.3'));
32809
+ definitionMap.set('version', literal('17.0.4'));
32598
32810
  definitionMap.set('ngImport', importExpr(Identifiers.core));
32599
32811
  definitionMap.set('type', metadata.type);
32600
32812
  definitionMap.set('decorators', metadata.decorators);
@@ -32702,7 +32914,7 @@ function createDirectiveDefinitionMap(meta) {
32702
32914
  // in 16.1 is actually used.
32703
32915
  const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
32704
32916
  definitionMap.set('minVersion', literal(minVersion));
32705
- definitionMap.set('version', literal('17.0.3'));
32917
+ definitionMap.set('version', literal('17.0.4'));
32706
32918
  // e.g. `type: MyDirective`
32707
32919
  definitionMap.set('type', meta.type.value);
32708
32920
  if (meta.isStandalone) {
@@ -32979,7 +33191,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
32979
33191
  function compileDeclareFactoryFunction(meta) {
32980
33192
  const definitionMap = new DefinitionMap();
32981
33193
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
32982
- definitionMap.set('version', literal('17.0.3'));
33194
+ definitionMap.set('version', literal('17.0.4'));
32983
33195
  definitionMap.set('ngImport', importExpr(Identifiers.core));
32984
33196
  definitionMap.set('type', meta.type.value);
32985
33197
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -33014,7 +33226,7 @@ function compileDeclareInjectableFromMetadata(meta) {
33014
33226
  function createInjectableDefinitionMap(meta) {
33015
33227
  const definitionMap = new DefinitionMap();
33016
33228
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
33017
- definitionMap.set('version', literal('17.0.3'));
33229
+ definitionMap.set('version', literal('17.0.4'));
33018
33230
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33019
33231
  definitionMap.set('type', meta.type.value);
33020
33232
  // Only generate providedIn property if it has a non-null value
@@ -33065,7 +33277,7 @@ function compileDeclareInjectorFromMetadata(meta) {
33065
33277
  function createInjectorDefinitionMap(meta) {
33066
33278
  const definitionMap = new DefinitionMap();
33067
33279
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
33068
- definitionMap.set('version', literal('17.0.3'));
33280
+ definitionMap.set('version', literal('17.0.4'));
33069
33281
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33070
33282
  definitionMap.set('type', meta.type.value);
33071
33283
  definitionMap.set('providers', meta.providers);
@@ -33098,7 +33310,7 @@ function createNgModuleDefinitionMap(meta) {
33098
33310
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
33099
33311
  }
33100
33312
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
33101
- definitionMap.set('version', literal('17.0.3'));
33313
+ definitionMap.set('version', literal('17.0.4'));
33102
33314
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33103
33315
  definitionMap.set('type', meta.type.value);
33104
33316
  // We only generate the keys in the metadata if the arrays contain values.
@@ -33149,7 +33361,7 @@ function compileDeclarePipeFromMetadata(meta) {
33149
33361
  function createPipeDefinitionMap(meta) {
33150
33362
  const definitionMap = new DefinitionMap();
33151
33363
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
33152
- definitionMap.set('version', literal('17.0.3'));
33364
+ definitionMap.set('version', literal('17.0.4'));
33153
33365
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33154
33366
  // e.g. `type: MyPipe`
33155
33367
  definitionMap.set('type', meta.type.value);