@angular/compiler 17.0.4 → 17.0.5

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 (24) hide show
  1. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  2. package/esm2022/src/render3/partial/directive.mjs +1 -1
  3. package/esm2022/src/render3/partial/factory.mjs +1 -1
  4. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  5. package/esm2022/src/render3/partial/injector.mjs +1 -1
  6. package/esm2022/src/render3/partial/ng_module.mjs +1 -1
  7. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  8. package/esm2022/src/render3/view/compiler.mjs +6 -4
  9. package/esm2022/src/template/pipeline/ir/src/enums.mjs +9 -1
  10. package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +3 -2
  11. package/esm2022/src/template/pipeline/src/emit.mjs +1 -3
  12. package/esm2022/src/template/pipeline/src/phases/assign_i18n_slot_dependencies.mjs +2 -7
  13. package/esm2022/src/template/pipeline/src/phases/create_i18n_contexts.mjs +20 -6
  14. package/esm2022/src/template/pipeline/src/phases/extract_i18n_messages.mjs +94 -23
  15. package/esm2022/src/template/pipeline/src/phases/propagate_i18n_blocks.mjs +3 -2
  16. package/esm2022/src/template/pipeline/src/phases/resolve_i18n_element_placeholders.mjs +70 -57
  17. package/esm2022/src/template/pipeline/src/phases/resolve_i18n_expression_placeholders.mjs +4 -4
  18. package/esm2022/src/template/pipeline/src/phases/resolve_i18n_icu_placeholders.mjs +5 -21
  19. package/esm2022/src/version.mjs +1 -1
  20. package/fesm2022/compiler.mjs +215 -178
  21. package/fesm2022/compiler.mjs.map +1 -1
  22. package/index.d.ts +1 -1
  23. package/package.json +2 -2
  24. package/esm2022/src/template/pipeline/src/phases/merge_i18n_contexts.mjs +0 -59
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v17.0.4
2
+ * @license Angular v17.0.5
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -9195,6 +9195,14 @@ var DerivedRepeaterVarIdentity;
9195
9195
  DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Even"] = 2] = "Even";
9196
9196
  DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Odd"] = 3] = "Odd";
9197
9197
  })(DerivedRepeaterVarIdentity || (DerivedRepeaterVarIdentity = {}));
9198
+ /**
9199
+ * Kinds of i18n contexts. They can be created because of root i18n blocks, or ICUs.
9200
+ */
9201
+ var I18nContextKind;
9202
+ (function (I18nContextKind) {
9203
+ I18nContextKind[I18nContextKind["RootI18n"] = 0] = "RootI18n";
9204
+ I18nContextKind[I18nContextKind["Icu"] = 1] = "Icu";
9205
+ })(I18nContextKind || (I18nContextKind = {}));
9198
9206
 
9199
9207
  /**
9200
9208
  * Marker symbol for `ConsumesSlotOpTrait`.
@@ -10979,9 +10987,10 @@ function createIcuEndOp(xref) {
10979
10987
  ...NEW_OP,
10980
10988
  };
10981
10989
  }
10982
- function createI18nContextOp(xref, i18nBlock, message, sourceSpan) {
10990
+ function createI18nContextOp(contextKind, xref, i18nBlock, message, sourceSpan) {
10983
10991
  return {
10984
10992
  kind: OpKind.I18nContext,
10993
+ contextKind,
10985
10994
  xref,
10986
10995
  i18nBlock,
10987
10996
  message,
@@ -11267,7 +11276,6 @@ function needsApplication(i18nContexts, op) {
11267
11276
  */
11268
11277
  function assignI18nSlotDependencies(job) {
11269
11278
  const i18nLastSlotConsumers = new Map();
11270
- const i18nContexts = new Map();
11271
11279
  let lastSlotConsumer = null;
11272
11280
  let currentI18nOp = null;
11273
11281
  for (const unit of job.units) {
@@ -11284,16 +11292,12 @@ function assignI18nSlotDependencies(job) {
11284
11292
  i18nLastSlotConsumers.set(currentI18nOp.xref, lastSlotConsumer);
11285
11293
  currentI18nOp = null;
11286
11294
  break;
11287
- case OpKind.I18nContext:
11288
- i18nContexts.set(op.xref, op);
11289
- break;
11290
11295
  }
11291
11296
  }
11292
11297
  // Assign i18n expressions to target the last slot in its owning block.
11293
11298
  for (const op of unit.update) {
11294
11299
  if (op.kind === OpKind.I18nExpression) {
11295
- const i18nContext = i18nContexts.get(op.context);
11296
- op.target = i18nLastSlotConsumers.get(i18nContext.i18nBlock);
11300
+ op.target = i18nLastSlotConsumers.get(op.target);
11297
11301
  }
11298
11302
  }
11299
11303
  }
@@ -11902,17 +11906,22 @@ function createDeferDepsFns(job) {
11902
11906
  * message.)
11903
11907
  */
11904
11908
  function createI18nContexts(job) {
11909
+ const rootContexts = new Map();
11905
11910
  let currentI18nOp = null;
11906
11911
  let xref;
11907
11912
  for (const unit of job.units) {
11908
11913
  for (const op of unit.create) {
11909
11914
  switch (op.kind) {
11910
11915
  case OpKind.I18nStart:
11911
- // Each i18n block gets its own context.
11912
- xref = job.allocateXrefId();
11913
- unit.create.push(createI18nContextOp(xref, op.xref, op.message, null));
11914
- op.context = xref;
11915
11916
  currentI18nOp = op;
11917
+ // Each root i18n block gets its own context, child ones refer to the context for their
11918
+ // root block.
11919
+ if (op.xref === op.root) {
11920
+ xref = job.allocateXrefId();
11921
+ unit.create.push(createI18nContextOp(I18nContextKind.RootI18n, xref, op.xref, op.message, null));
11922
+ op.context = xref;
11923
+ rootContexts.set(op.xref, xref);
11924
+ }
11916
11925
  break;
11917
11926
  case OpKind.I18nEnd:
11918
11927
  currentI18nOp = null;
@@ -11926,7 +11935,7 @@ function createI18nContexts(job) {
11926
11935
  if (op.message.id !== currentI18nOp.message.id) {
11927
11936
  // There was an enclosing i18n block around this ICU somewhere.
11928
11937
  xref = job.allocateXrefId();
11929
- unit.create.push(createI18nContextOp(xref, currentI18nOp.xref, op.message, null));
11938
+ unit.create.push(createI18nContextOp(I18nContextKind.Icu, xref, currentI18nOp.xref, op.message, null));
11930
11939
  op.context = xref;
11931
11940
  }
11932
11941
  else {
@@ -11938,6 +11947,15 @@ function createI18nContexts(job) {
11938
11947
  }
11939
11948
  }
11940
11949
  }
11950
+ // Assign contexts to child i18n blocks, now that all root i18n blocks have their context
11951
+ // assigned.
11952
+ for (const unit of job.units) {
11953
+ for (const op of unit.create) {
11954
+ if (op.kind === OpKind.I18nStart && op.xref !== op.root) {
11955
+ op.context = rootContexts.get(op.root);
11956
+ }
11957
+ }
11958
+ }
11941
11959
  }
11942
11960
 
11943
11961
  /**
@@ -12320,11 +12338,9 @@ const LIST_DELIMITER = '|';
12320
12338
  * used in the final output.
12321
12339
  */
12322
12340
  function extractI18nMessages(job) {
12323
- // Save the i18n context ops for later use.
12341
+ // Save the i18n start and i18n context ops for later use.
12324
12342
  const i18nContexts = new Map();
12325
- // Record which contexts represent i18n blocks (any other contexts are assumed to have been
12326
- // created from ICUs).
12327
- const i18nBlockContexts = new Set();
12343
+ const i18nBlocks = new Map();
12328
12344
  for (const unit of job.units) {
12329
12345
  for (const op of unit.create) {
12330
12346
  switch (op.kind) {
@@ -12332,7 +12348,7 @@ function extractI18nMessages(job) {
12332
12348
  i18nContexts.set(op.xref, op);
12333
12349
  break;
12334
12350
  case OpKind.I18nStart:
12335
- i18nBlockContexts.add(op.context);
12351
+ i18nBlocks.set(op.xref, op);
12336
12352
  break;
12337
12353
  }
12338
12354
  }
@@ -12359,11 +12375,12 @@ function extractI18nMessages(job) {
12359
12375
  if (!op.context) {
12360
12376
  throw Error('ICU op should have its context set.');
12361
12377
  }
12362
- if (!i18nBlockContexts.has(op.context)) {
12363
- const i18nContext = i18nContexts.get(op.context);
12378
+ const i18nContext = i18nContexts.get(op.context);
12379
+ if (i18nContext.contextKind === I18nContextKind.Icu) {
12364
12380
  const subMessage = createI18nMessage(job, i18nContext, op.messagePlaceholder);
12365
12381
  unit.create.push(subMessage);
12366
- const parentMessage = i18nBlockMessages.get(i18nContext.i18nBlock);
12382
+ const rootI18nId = i18nBlocks.get(i18nContext.i18nBlock).root;
12383
+ const parentMessage = i18nBlockMessages.get(rootI18nId);
12367
12384
  parentMessage?.subMessages.push(subMessage.xref);
12368
12385
  }
12369
12386
  OpList.remove(op);
@@ -12379,38 +12396,110 @@ function extractI18nMessages(job) {
12379
12396
  * Create an i18n message op from an i18n context op.
12380
12397
  */
12381
12398
  function createI18nMessage(job, context, messagePlaceholder) {
12382
- let needsPostprocessing = context.postprocessingParams.size > 0;
12383
- for (const values of context.params.values()) {
12384
- if (values.length > 1) {
12385
- needsPostprocessing = true;
12386
- }
12387
- }
12388
- return createI18nMessageOp(job.allocateXrefId(), context.i18nBlock, context.message, messagePlaceholder ?? null, formatParams(context.params), formatParams(context.postprocessingParams), needsPostprocessing);
12399
+ let [formattedParams, needsPostprocessing] = formatParams(context.params);
12400
+ const [formattedPostprocessingParams] = formatParams(context.postprocessingParams);
12401
+ needsPostprocessing ||= formattedPostprocessingParams.size > 0;
12402
+ return createI18nMessageOp(job.allocateXrefId(), context.i18nBlock, context.message, messagePlaceholder ?? null, formattedParams, formattedPostprocessingParams, needsPostprocessing);
12389
12403
  }
12390
12404
  /**
12391
12405
  * Formats a map of `I18nParamValue[]` values into a map of `Expression` values.
12406
+ * @return A tuple of the formatted params and a boolean indicating whether postprocessing is needed
12407
+ * for any of the params
12392
12408
  */
12393
12409
  function formatParams(params) {
12394
- const result = new Map();
12410
+ const formattedParams = new Map();
12411
+ let needsPostprocessing = false;
12395
12412
  for (const [placeholder, placeholderValues] of params) {
12396
- const serializedValues = formatParamValues(placeholderValues);
12413
+ const [serializedValues, paramNeedsPostprocessing] = formatParamValues(placeholderValues);
12414
+ needsPostprocessing ||= paramNeedsPostprocessing;
12397
12415
  if (serializedValues !== null) {
12398
- result.set(placeholder, literal(formatParamValues(placeholderValues)));
12416
+ formattedParams.set(placeholder, literal(serializedValues));
12399
12417
  }
12400
12418
  }
12401
- return result;
12419
+ return [formattedParams, needsPostprocessing];
12402
12420
  }
12403
12421
  /**
12404
12422
  * Formats an `I18nParamValue[]` into a string (or null for empty array).
12423
+ * @return A tuple of the formatted value and a boolean indicating whether postprocessing is needed
12424
+ * for the value
12405
12425
  */
12406
12426
  function formatParamValues(values) {
12407
12427
  if (values.length === 0) {
12408
- return null;
12428
+ return [null, false];
12409
12429
  }
12430
+ collapseElementTemplatePairs(values);
12410
12431
  const serializedValues = values.map(value => formatValue(value));
12411
12432
  return serializedValues.length === 1 ?
12412
- serializedValues[0] :
12413
- `${LIST_START_MARKER}${serializedValues.join(LIST_DELIMITER)}${LIST_END_MARKER}`;
12433
+ [serializedValues[0], false] :
12434
+ [`${LIST_START_MARKER}${serializedValues.join(LIST_DELIMITER)}${LIST_END_MARKER}`, true];
12435
+ }
12436
+ /**
12437
+ * Collapses element/template pairs that refer to the same subTemplateIndex, i.e. elements and
12438
+ * templates that refer to the same element instance.
12439
+ *
12440
+ * This accounts for the case of a structural directive inside an i18n block, e.g.:
12441
+ * ```
12442
+ * <div i18n>
12443
+ * <div *ngIf="condition">
12444
+ * </div>
12445
+ * ```
12446
+ *
12447
+ * In this case, both the element start and template start placeholders are the same,
12448
+ * and we collapse them down into a single compound placeholder value. Rather than produce
12449
+ * `[\uFFFD#1:1\uFFFD|\uFFFD*2:1\uFFFD]`, we want to produce `\uFFFD#1:1\uFFFD\uFFFD*2:1\uFFFD`,
12450
+ * likewise for the closing of the element/template.
12451
+ */
12452
+ function collapseElementTemplatePairs(values) {
12453
+ // Record the indicies of element and template values in the values array by subTemplateIndex.
12454
+ const valueIndiciesBySubTemplateIndex = new Map();
12455
+ for (let i = 0; i < values.length; i++) {
12456
+ const value = values[i];
12457
+ if (value.subTemplateIndex !== null &&
12458
+ (value.flags & (I18nParamValueFlags.ElementTag | I18nParamValueFlags.TemplateTag))) {
12459
+ const valueIndicies = valueIndiciesBySubTemplateIndex.get(value.subTemplateIndex) ?? [];
12460
+ valueIndicies.push(i);
12461
+ valueIndiciesBySubTemplateIndex.set(value.subTemplateIndex, valueIndicies);
12462
+ }
12463
+ }
12464
+ // For each subTemplateIndex, check if any values can be collapsed.
12465
+ for (const [subTemplateIndex, valueIndicies] of valueIndiciesBySubTemplateIndex) {
12466
+ if (valueIndicies.length > 1) {
12467
+ const elementIndex = valueIndicies.find(index => values[index].flags & I18nParamValueFlags.ElementTag);
12468
+ const templateIndex = valueIndicies.find(index => values[index].flags & I18nParamValueFlags.TemplateTag);
12469
+ // If the values list contains both an element and template value, we can collapse.
12470
+ if (elementIndex !== undefined && templateIndex !== undefined) {
12471
+ const elementValue = values[elementIndex];
12472
+ const templateValue = values[templateIndex];
12473
+ // To match the TemplateDefinitionBuilder output, flip the order depending on whether the
12474
+ // values represent a closing or opening tag (or both).
12475
+ // TODO(mmalerba): Figure out if this makes a difference in terms of either functionality,
12476
+ // or the resulting message ID. If not, we can remove the special-casing in the future.
12477
+ let compundValue;
12478
+ if ((elementValue.flags & I18nParamValueFlags.OpenTag) &&
12479
+ (elementValue.flags & I18nParamValueFlags.CloseTag)) {
12480
+ // TODO(mmalerba): Is this a TDB bug? I don't understand why it would put the template
12481
+ // value twice.
12482
+ compundValue = `${formatValue(templateValue)}${formatValue(elementValue)}${formatValue(templateValue)}`;
12483
+ }
12484
+ else if (elementValue.flags & I18nParamValueFlags.OpenTag) {
12485
+ compundValue = `${formatValue(templateValue)}${formatValue(elementValue)}`;
12486
+ }
12487
+ else {
12488
+ compundValue = `${formatValue(elementValue)}${formatValue(templateValue)}`;
12489
+ }
12490
+ // Replace the element value with the combined value.
12491
+ values.splice(elementIndex, 1, { value: compundValue, subTemplateIndex, flags: I18nParamValueFlags.None });
12492
+ // Replace the template value with null to preserve the indicies we calculated earlier.
12493
+ values.splice(templateIndex, 1, null);
12494
+ }
12495
+ }
12496
+ }
12497
+ // Strip out any nulled out values we introduced above.
12498
+ for (let i = values.length - 1; i >= 0; i--) {
12499
+ if (values[i] === null) {
12500
+ values.splice(i, 1);
12501
+ }
12502
+ }
12414
12503
  }
12415
12504
  /**
12416
12505
  * Formats a single `I18nParamValue` into a string
@@ -19938,57 +20027,6 @@ function serializeLocalRefs(refs) {
19938
20027
  return literalArr(constRefs);
19939
20028
  }
19940
20029
 
19941
- /**
19942
- * Merge i18n contexts for child i18n blocks into their ancestor root contexts.
19943
- */
19944
- function mergeI18nContexts(job) {
19945
- // Record all of the i18n and extracted message ops for use later.
19946
- const i18nOps = new Map();
19947
- const i18nContexts = new Map();
19948
- for (const unit of job.units) {
19949
- for (const op of unit.create) {
19950
- switch (op.kind) {
19951
- case OpKind.I18nStart:
19952
- if (!op.context) {
19953
- throw Error('I18n op should have its context set.');
19954
- }
19955
- i18nOps.set(op.xref, op);
19956
- break;
19957
- case OpKind.I18nContext:
19958
- i18nContexts.set(op.xref, op);
19959
- break;
19960
- }
19961
- }
19962
- }
19963
- // For each non-root i18n op, merge its context into the root i18n op's context.
19964
- for (const childI18nOp of i18nOps.values()) {
19965
- if (childI18nOp.xref !== childI18nOp.root) {
19966
- const childContext = i18nContexts.get(childI18nOp.context);
19967
- const rootI18nOp = i18nOps.get(childI18nOp.root);
19968
- const rootContext = i18nContexts.get(rootI18nOp.context);
19969
- mergeParams(rootContext.params, childContext.params);
19970
- mergeParams(rootContext.postprocessingParams, childContext.postprocessingParams);
19971
- }
19972
- }
19973
- }
19974
- /**
19975
- * Merges the params in the `from` map to into the `to` map.
19976
- */
19977
- function mergeParams(to, from) {
19978
- for (const [placeholder, fromValues] of from) {
19979
- const toValues = to.get(placeholder) || [];
19980
- // TODO(mmalerba): Child element close tag params should be prepended to maintain the same order
19981
- // as TemplateDefinitionBuilder. Can be cleaned up when compatibility is no longer required.
19982
- const flags = fromValues[0].flags;
19983
- if ((flags & I18nParamValueFlags.CloseTag) && !(flags & I18nParamValueFlags.OpenTag)) {
19984
- to.set(placeholder, [...fromValues, ...toValues]);
19985
- }
19986
- else {
19987
- to.set(placeholder, [...toValues, ...fromValues]);
19988
- }
19989
- }
19990
- }
19991
-
19992
20030
  /**
19993
20031
  * Change namespaces between HTML, SVG and MathML, depending on the next element.
19994
20032
  */
@@ -20652,9 +20690,10 @@ function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
20652
20690
  wrapTemplateWithI18n(templateView, i18nBlock);
20653
20691
  }
20654
20692
  // Continue traversing inside the template's view.
20655
- propagateI18nBlocksToTemplates(templateView, subTemplateIndex);
20693
+ subTemplateIndex = propagateI18nBlocksToTemplates(templateView, subTemplateIndex);
20656
20694
  }
20657
20695
  }
20696
+ return subTemplateIndex;
20658
20697
  }
20659
20698
  /**
20660
20699
  * Wraps a template view with i18n start and end ops.
@@ -21834,66 +21873,79 @@ function resolveI18nElementPlaceholders(job) {
21834
21873
  }
21835
21874
  }
21836
21875
  }
21837
- for (const unit of job.units) {
21838
- // Track the current i18n op and corresponding i18n context op as we step through the creation
21839
- // IR.
21840
- let currentOps = null;
21841
- for (const op of unit.create) {
21842
- switch (op.kind) {
21843
- case OpKind.I18nStart:
21844
- if (!op.context) {
21845
- throw Error('Could not find i18n context for i18n op');
21876
+ resolvePlaceholdersForView(job, job.root, i18nContexts, elements);
21877
+ }
21878
+ function resolvePlaceholdersForView(job, unit, i18nContexts, elements) {
21879
+ // Track the current i18n op and corresponding i18n context op as we step through the creation
21880
+ // IR.
21881
+ let currentOps = null;
21882
+ for (const op of unit.create) {
21883
+ switch (op.kind) {
21884
+ case OpKind.I18nStart:
21885
+ if (!op.context) {
21886
+ throw Error('Could not find i18n context for i18n op');
21887
+ }
21888
+ currentOps = { i18nBlock: op, i18nContext: i18nContexts.get(op.context) };
21889
+ break;
21890
+ case OpKind.I18nEnd:
21891
+ currentOps = null;
21892
+ break;
21893
+ case OpKind.ElementStart:
21894
+ // For elements with i18n placeholders, record its slot value in the params map under the
21895
+ // corresponding tag start placeholder.
21896
+ if (op.i18nPlaceholder !== undefined) {
21897
+ if (currentOps === null) {
21898
+ throw Error('i18n tag placeholder should only occur inside an i18n block');
21846
21899
  }
21847
- currentOps = { i18nBlock: op, i18nContext: i18nContexts.get(op.context) };
21848
- break;
21849
- case OpKind.I18nEnd:
21850
- currentOps = null;
21851
- break;
21852
- case OpKind.ElementStart:
21853
- // For elements with i18n placeholders, record its slot value in the params map under the
21854
- // corresponding tag start placeholder.
21855
- if (op.i18nPlaceholder !== undefined) {
21856
- if (currentOps === null) {
21857
- throw Error('i18n tag placeholder should only occur inside an i18n block');
21858
- }
21859
- const { startName, closeName } = op.i18nPlaceholder;
21860
- let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.OpenTag;
21861
- // For self-closing tags, there is no close tag placeholder. Instead, the start tag
21862
- // placeholder accounts for the start and close of the element.
21863
- if (closeName === '') {
21864
- flags |= I18nParamValueFlags.CloseTag;
21865
- }
21866
- addParam(currentOps.i18nContext.params, startName, op.handle.slot, currentOps.i18nBlock.subTemplateIndex, flags);
21900
+ const { startName, closeName } = op.i18nPlaceholder;
21901
+ let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.OpenTag;
21902
+ // For self-closing tags, there is no close tag placeholder. Instead, the start tag
21903
+ // placeholder accounts for the start and close of the element.
21904
+ if (closeName === '') {
21905
+ flags |= I18nParamValueFlags.CloseTag;
21867
21906
  }
21868
- break;
21869
- case OpKind.ElementEnd:
21870
- // For elements with i18n placeholders, record its slot value in the params map under the
21871
- // corresponding tag close placeholder.
21872
- const startOp = elements.get(op.xref);
21873
- if (startOp && startOp.i18nPlaceholder !== undefined) {
21874
- if (currentOps === null) {
21875
- throw Error('i18n tag placeholder should only occur inside an i18n block');
21876
- }
21877
- const { closeName } = startOp.i18nPlaceholder;
21878
- // Self-closing tags don't have a closing tag placeholder.
21879
- if (closeName !== '') {
21880
- addParam(currentOps.i18nContext.params, closeName, startOp.handle.slot, currentOps.i18nBlock.subTemplateIndex, I18nParamValueFlags.ElementTag | I18nParamValueFlags.CloseTag);
21881
- }
21907
+ addParam(currentOps.i18nContext.params, startName, op.handle.slot, currentOps.i18nBlock.subTemplateIndex, flags);
21908
+ }
21909
+ break;
21910
+ case OpKind.ElementEnd:
21911
+ // For elements with i18n placeholders, record its slot value in the params map under the
21912
+ // corresponding tag close placeholder.
21913
+ const startOp = elements.get(op.xref);
21914
+ if (startOp && startOp.i18nPlaceholder !== undefined) {
21915
+ if (currentOps === null) {
21916
+ throw Error('i18n tag placeholder should only occur inside an i18n block');
21882
21917
  }
21883
- break;
21884
- case OpKind.Template:
21885
- // For templates with i18n placeholders, record its slot value in the params map under the
21886
- // corresponding template start and close placeholders.
21887
- if (op.i18nPlaceholder !== undefined) {
21888
- if (currentOps === null) {
21889
- throw Error('i18n tag placeholder should only occur inside an i18n block');
21890
- }
21891
- const subTemplateIndex = getSubTemplateIndexForTemplateTag(job, currentOps.i18nBlock, op);
21892
- addParam(currentOps.i18nContext.params, op.i18nPlaceholder.startName, op.handle.slot, subTemplateIndex, I18nParamValueFlags.TemplateTag);
21893
- addParam(currentOps.i18nContext.params, op.i18nPlaceholder.closeName, op.handle.slot, subTemplateIndex, I18nParamValueFlags.TemplateTag | I18nParamValueFlags.CloseTag);
21918
+ const { closeName } = startOp.i18nPlaceholder;
21919
+ // Self-closing tags don't have a closing tag placeholder.
21920
+ if (closeName !== '') {
21921
+ addParam(currentOps.i18nContext.params, closeName, startOp.handle.slot, currentOps.i18nBlock.subTemplateIndex, I18nParamValueFlags.ElementTag | I18nParamValueFlags.CloseTag);
21894
21922
  }
21895
- break;
21896
- }
21923
+ }
21924
+ break;
21925
+ case OpKind.Template:
21926
+ // For templates with i18n placeholders, record its slot value in the params map under the
21927
+ // corresponding template start and close placeholders.
21928
+ if (op.i18nPlaceholder !== undefined) {
21929
+ if (currentOps === null) {
21930
+ throw Error('i18n tag placeholder should only occur inside an i18n block');
21931
+ }
21932
+ let startFlags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.OpenTag;
21933
+ const subTemplateIndex = getSubTemplateIndexForTemplateTag(job, currentOps.i18nBlock, op);
21934
+ const { startName, closeName } = op.i18nPlaceholder;
21935
+ const isSelfClosing = closeName === '';
21936
+ if (isSelfClosing) {
21937
+ startFlags |= I18nParamValueFlags.CloseTag;
21938
+ }
21939
+ addParam(currentOps.i18nContext.params, startName, op.handle.slot, subTemplateIndex, startFlags);
21940
+ resolvePlaceholdersForView(job, job.views.get(op.xref), i18nContexts, elements);
21941
+ if (!isSelfClosing) {
21942
+ addParam(currentOps.i18nContext.params, closeName, op.handle.slot, subTemplateIndex, I18nParamValueFlags.TemplateTag | I18nParamValueFlags.CloseTag);
21943
+ }
21944
+ }
21945
+ else {
21946
+ resolvePlaceholdersForView(job, job.views.get(op.xref), i18nContexts, elements);
21947
+ }
21948
+ break;
21897
21949
  }
21898
21950
  }
21899
21951
  }
@@ -21941,8 +21993,8 @@ function resolveI18nExpressionPlaceholders(job) {
21941
21993
  for (const op of unit.update) {
21942
21994
  if (op.kind === OpKind.I18nExpression) {
21943
21995
  const i18nContext = i18nContexts.get(op.context);
21944
- const index = expressionIndices.get(i18nContext.i18nBlock) || 0;
21945
- const subTemplateIndex = subTemplateIndicies.get(i18nContext.i18nBlock);
21996
+ const index = expressionIndices.get(op.target) || 0;
21997
+ const subTemplateIndex = subTemplateIndicies.get(op.target);
21946
21998
  // Add the expression index in the appropriate params map.
21947
21999
  const params = op.resolutionTime === I18nParamResolutionTime.Creation ?
21948
22000
  i18nContext.params :
@@ -21954,7 +22006,7 @@ function resolveI18nExpressionPlaceholders(job) {
21954
22006
  flags: I18nParamValueFlags.ExpressionIndex
21955
22007
  });
21956
22008
  params.set(op.i18nPlaceholder, values);
21957
- expressionIndices.set(i18nContext.i18nBlock, index + 1);
22009
+ expressionIndices.set(op.target, index + 1);
21958
22010
  }
21959
22011
  }
21960
22012
  }
@@ -21964,28 +22016,12 @@ function resolveI18nExpressionPlaceholders(job) {
21964
22016
  * Resolves placeholders for element tags inside of an ICU.
21965
22017
  */
21966
22018
  function resolveI18nIcuPlaceholders(job) {
21967
- const contextOps = new Map();
21968
22019
  for (const unit of job.units) {
21969
22020
  for (const op of unit.create) {
21970
- switch (op.kind) {
21971
- case OpKind.I18nContext:
21972
- contextOps.set(op.xref, op);
21973
- break;
21974
- }
21975
- }
21976
- }
21977
- for (const unit of job.units) {
21978
- for (const op of unit.create) {
21979
- switch (op.kind) {
21980
- case OpKind.IcuStart:
21981
- if (op.context === null) {
21982
- throw Error('Icu should have its i18n context set.');
21983
- }
21984
- const i18nContext = contextOps.get(op.context);
21985
- for (const node of op.message.nodes) {
21986
- node.visit(new ResolveIcuPlaceholdersVisitor(i18nContext.postprocessingParams));
21987
- }
21988
- break;
22021
+ if (op.kind === OpKind.I18nContext && op.contextKind === I18nContextKind.Icu) {
22022
+ for (const node of op.message.nodes) {
22023
+ node.visit(new ResolveIcuPlaceholdersVisitor(op.postprocessingParams));
22024
+ }
21989
22025
  }
21990
22026
  }
21991
22027
  }
@@ -23155,7 +23191,6 @@ const phases = [
23155
23191
  { kind: CompilationJobKind.Tmpl, fn: resolveI18nElementPlaceholders },
23156
23192
  { kind: CompilationJobKind.Tmpl, fn: resolveI18nExpressionPlaceholders },
23157
23193
  { kind: CompilationJobKind.Tmpl, fn: resolveI18nIcuPlaceholders },
23158
- { kind: CompilationJobKind.Tmpl, fn: mergeI18nContexts },
23159
23194
  { kind: CompilationJobKind.Tmpl, fn: extractI18nMessages },
23160
23195
  { kind: CompilationJobKind.Tmpl, fn: generateTrackFns },
23161
23196
  { kind: CompilationJobKind.Tmpl, fn: collectI18nConsts },
@@ -29127,6 +29162,11 @@ function addFeatures(definitionMap, meta) {
29127
29162
  break;
29128
29163
  }
29129
29164
  }
29165
+ // Note: host directives feature needs to be inserted before the
29166
+ // inheritance feature to ensure the correct execution order.
29167
+ if (meta.hostDirectives?.length) {
29168
+ features.push(importExpr(Identifiers.HostDirectivesFeature).callFn([createHostDirectivesFeatureArg(meta.hostDirectives)]));
29169
+ }
29130
29170
  if (meta.usesInheritance) {
29131
29171
  features.push(importExpr(Identifiers.InheritDefinitionFeature));
29132
29172
  }
@@ -29140,9 +29180,6 @@ function addFeatures(definitionMap, meta) {
29140
29180
  if (meta.hasOwnProperty('template') && meta.isStandalone) {
29141
29181
  features.push(importExpr(Identifiers.StandaloneFeature));
29142
29182
  }
29143
- if (meta.hostDirectives?.length) {
29144
- features.push(importExpr(Identifiers.HostDirectivesFeature).callFn([createHostDirectivesFeatureArg(meta.hostDirectives)]));
29145
- }
29146
29183
  if (features.length) {
29147
29184
  definitionMap.set('features', literalArr(features));
29148
29185
  }
@@ -31240,7 +31277,7 @@ function publishFacade(global) {
31240
31277
  * @description
31241
31278
  * Entry point for all public APIs of the compiler package.
31242
31279
  */
31243
- const VERSION = new Version('17.0.4');
31280
+ const VERSION = new Version('17.0.5');
31244
31281
 
31245
31282
  class CompilerConfig {
31246
31283
  constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
@@ -32806,7 +32843,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
32806
32843
  function compileDeclareClassMetadata(metadata) {
32807
32844
  const definitionMap = new DefinitionMap();
32808
32845
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
32809
- definitionMap.set('version', literal('17.0.4'));
32846
+ definitionMap.set('version', literal('17.0.5'));
32810
32847
  definitionMap.set('ngImport', importExpr(Identifiers.core));
32811
32848
  definitionMap.set('type', metadata.type);
32812
32849
  definitionMap.set('decorators', metadata.decorators);
@@ -32914,7 +32951,7 @@ function createDirectiveDefinitionMap(meta) {
32914
32951
  // in 16.1 is actually used.
32915
32952
  const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
32916
32953
  definitionMap.set('minVersion', literal(minVersion));
32917
- definitionMap.set('version', literal('17.0.4'));
32954
+ definitionMap.set('version', literal('17.0.5'));
32918
32955
  // e.g. `type: MyDirective`
32919
32956
  definitionMap.set('type', meta.type.value);
32920
32957
  if (meta.isStandalone) {
@@ -33191,7 +33228,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
33191
33228
  function compileDeclareFactoryFunction(meta) {
33192
33229
  const definitionMap = new DefinitionMap();
33193
33230
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
33194
- definitionMap.set('version', literal('17.0.4'));
33231
+ definitionMap.set('version', literal('17.0.5'));
33195
33232
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33196
33233
  definitionMap.set('type', meta.type.value);
33197
33234
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -33226,7 +33263,7 @@ function compileDeclareInjectableFromMetadata(meta) {
33226
33263
  function createInjectableDefinitionMap(meta) {
33227
33264
  const definitionMap = new DefinitionMap();
33228
33265
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
33229
- definitionMap.set('version', literal('17.0.4'));
33266
+ definitionMap.set('version', literal('17.0.5'));
33230
33267
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33231
33268
  definitionMap.set('type', meta.type.value);
33232
33269
  // Only generate providedIn property if it has a non-null value
@@ -33277,7 +33314,7 @@ function compileDeclareInjectorFromMetadata(meta) {
33277
33314
  function createInjectorDefinitionMap(meta) {
33278
33315
  const definitionMap = new DefinitionMap();
33279
33316
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
33280
- definitionMap.set('version', literal('17.0.4'));
33317
+ definitionMap.set('version', literal('17.0.5'));
33281
33318
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33282
33319
  definitionMap.set('type', meta.type.value);
33283
33320
  definitionMap.set('providers', meta.providers);
@@ -33310,7 +33347,7 @@ function createNgModuleDefinitionMap(meta) {
33310
33347
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
33311
33348
  }
33312
33349
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
33313
- definitionMap.set('version', literal('17.0.4'));
33350
+ definitionMap.set('version', literal('17.0.5'));
33314
33351
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33315
33352
  definitionMap.set('type', meta.type.value);
33316
33353
  // We only generate the keys in the metadata if the arrays contain values.
@@ -33361,7 +33398,7 @@ function compileDeclarePipeFromMetadata(meta) {
33361
33398
  function createPipeDefinitionMap(meta) {
33362
33399
  const definitionMap = new DefinitionMap();
33363
33400
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
33364
- definitionMap.set('version', literal('17.0.4'));
33401
+ definitionMap.set('version', literal('17.0.5'));
33365
33402
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33366
33403
  // e.g. `type: MyPipe`
33367
33404
  definitionMap.set('type', meta.type.value);