@angular/compiler 17.0.0-next.7 → 17.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/esm2022/src/compiler.mjs +4 -3
  2. package/esm2022/src/config.mjs +2 -4
  3. package/esm2022/src/ml_parser/html_tags.mjs +4 -4
  4. package/esm2022/src/ml_parser/lexer.mjs +18 -10
  5. package/esm2022/src/ml_parser/parser.mjs +28 -10
  6. package/esm2022/src/ml_parser/tokens.mjs +1 -1
  7. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  8. package/esm2022/src/render3/partial/directive.mjs +1 -1
  9. package/esm2022/src/render3/partial/factory.mjs +1 -1
  10. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  11. package/esm2022/src/render3/partial/injector.mjs +1 -1
  12. package/esm2022/src/render3/partial/ng_module.mjs +1 -1
  13. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  14. package/esm2022/src/render3/r3_ast.mjs +37 -19
  15. package/esm2022/src/render3/r3_class_debug_info_compiler.mjs +36 -0
  16. package/esm2022/src/render3/r3_control_flow.mjs +40 -23
  17. package/esm2022/src/render3/r3_deferred_blocks.mjs +13 -3
  18. package/esm2022/src/render3/r3_identifiers.mjs +3 -1
  19. package/esm2022/src/render3/r3_template_transform.mjs +5 -2
  20. package/esm2022/src/render3/view/t2_binder.mjs +8 -7
  21. package/esm2022/src/render3/view/template.mjs +35 -24
  22. package/esm2022/src/shadow_css.mjs +10 -5
  23. package/esm2022/src/template/pipeline/ir/src/enums.mjs +25 -1
  24. package/esm2022/src/template/pipeline/ir/src/expression.mjs +3 -1
  25. package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +20 -3
  26. package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +16 -3
  27. package/esm2022/src/template/pipeline/ir/src/traits.mjs +1 -1
  28. package/esm2022/src/template/pipeline/src/emit.mjs +9 -1
  29. package/esm2022/src/template/pipeline/src/ingest.mjs +47 -12
  30. package/esm2022/src/template/pipeline/src/instruction.mjs +14 -6
  31. package/esm2022/src/template/pipeline/src/phases/apply_i18n_expressions.mjs +3 -3
  32. package/esm2022/src/template/pipeline/src/phases/assign_i18n_slot_dependencies.mjs +33 -0
  33. package/esm2022/src/template/pipeline/src/phases/generate_advance.mjs +1 -19
  34. package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +1 -2
  35. package/esm2022/src/template/pipeline/src/phases/i18n_const_collection.mjs +3 -4
  36. package/esm2022/src/template/pipeline/src/phases/i18n_message_extraction.mjs +25 -12
  37. package/esm2022/src/template/pipeline/src/phases/i18n_text_extraction.mjs +2 -2
  38. package/esm2022/src/template/pipeline/src/phases/icu_extraction.mjs +53 -0
  39. package/esm2022/src/template/pipeline/src/phases/local_refs.mjs +1 -2
  40. package/esm2022/src/template/pipeline/src/phases/namespace.mjs +2 -2
  41. package/esm2022/src/template/pipeline/src/phases/naming.mjs +3 -2
  42. package/esm2022/src/template/pipeline/src/phases/ng_container.mjs +1 -6
  43. package/esm2022/src/template/pipeline/src/phases/propagate_i18n_blocks.mjs +57 -0
  44. package/esm2022/src/template/pipeline/src/phases/reify.mjs +3 -3
  45. package/esm2022/src/template/pipeline/src/phases/resolve_i18n_placeholders.mjs +233 -50
  46. package/esm2022/src/template/pipeline/src/phases/resolve_sanitizers.mjs +2 -3
  47. package/esm2022/src/template/pipeline/src/phases/wrap_icus.mjs +34 -0
  48. package/esm2022/src/version.mjs +1 -1
  49. package/fesm2022/compiler.mjs +756 -236
  50. package/fesm2022/compiler.mjs.map +1 -1
  51. package/index.d.ts +77 -12
  52. package/package.json +2 -8
  53. package/esm2022/src/render3/view/block_syntax_switch.mjs +0 -13
  54. package/esm2022/testing/index.mjs +0 -13
  55. package/esm2022/testing/public_api.mjs +0 -16
  56. package/esm2022/testing/src/testing.mjs +0 -29
  57. package/esm2022/testing/testing.mjs +0 -5
  58. package/fesm2022/testing.mjs +0 -39
  59. package/fesm2022/testing.mjs.map +0 -1
  60. 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-rc.0
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 = [];
@@ -8297,7 +8317,7 @@ class ShadowCss {
8297
8317
  // (ie: ".\fc ber" for ".über") is not a separator between 2 selectors
8298
8318
  // also keep in mind that backslashes are replaced by a placeholder by SafeSelector
8299
8319
  // These escaped selectors happen for example when esbuild runs with optimization.minify.
8300
- if (part.match(_placeholderRe) && selector[res.index + 1]?.match(/[a-fA-F\d]/)) {
8320
+ if (part.match(/__esc-ph-(\d+)__/) && selector[res.index + 1]?.match(/[a-fA-F\d]/)) {
8301
8321
  continue;
8302
8322
  }
8303
8323
  shouldScope = shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1;
@@ -8328,7 +8348,13 @@ class SafeSelector {
8328
8348
  // pseudo-class, but writing `.foo\:blue` will match, because the colon was escaped.
8329
8349
  // Replace all escape sequences (`\` followed by a character) with a placeholder so
8330
8350
  // that our handling of pseudo-selectors doesn't mess with them.
8331
- selector = this._escapeRegexMatches(selector, /(\\.)/g);
8351
+ // Escaped characters have a specific placeholder so they can be detected separately.
8352
+ selector = selector.replace(/(\\.)/g, (_, keep) => {
8353
+ const replaceBy = `__esc-ph-${this.index}__`;
8354
+ this.placeholders.push(keep);
8355
+ this.index++;
8356
+ return replaceBy;
8357
+ });
8332
8358
  // Replaces the expression in `:nth-child(2n + 1)` with a placeholder.
8333
8359
  // WS and "+" would otherwise be interpreted as selector separators.
8334
8360
  this._content = selector.replace(/(:nth-[-\w]+)(\([^)]+\))/g, (_, pseudo, exp) => {
@@ -8339,7 +8365,7 @@ class SafeSelector {
8339
8365
  });
8340
8366
  }
8341
8367
  restore(content) {
8342
- return content.replace(_placeholderRe, (_ph, index) => this.placeholders[+index]);
8368
+ return content.replace(/__(?:ph|esc-ph)-(\d+)__/g, (_ph, index) => this.placeholders[+index]);
8343
8369
  }
8344
8370
  content() {
8345
8371
  return this._content;
@@ -8391,7 +8417,6 @@ const _commentRe = /\/\*[\s\S]*?\*\//g;
8391
8417
  const _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=/g;
8392
8418
  const COMMENT_PLACEHOLDER = '%COMMENT%';
8393
8419
  const _commentWithHashPlaceHolderRe = new RegExp(COMMENT_PLACEHOLDER, 'g');
8394
- const _placeholderRe = /__ph-(\d+)__/g;
8395
8420
  const BLOCK_PLACEHOLDER = '%BLOCK%';
8396
8421
  const _ruleRe = new RegExp(`(\\s*(?:${COMMENT_PLACEHOLDER}\\s*)*)([^;\\{\\}]+?)(\\s*)((?:{%BLOCK%}?\\s*;?)|(?:\\s*;))`, 'g');
8397
8422
  const CONTENT_PAIRS = new Map([['{', '}']]);
@@ -8821,6 +8846,14 @@ var OpKind;
8821
8846
  * An instruction that applies a set of i18n expressions.
8822
8847
  */
8823
8848
  OpKind[OpKind["I18nApply"] = 38] = "I18nApply";
8849
+ /**
8850
+ * An instruction to create an ICU expression.
8851
+ */
8852
+ OpKind[OpKind["Icu"] = 39] = "Icu";
8853
+ /**
8854
+ * An instruction to update an ICU expression.
8855
+ */
8856
+ OpKind[OpKind["IcuUpdate"] = 40] = "IcuUpdate";
8824
8857
  })(OpKind || (OpKind = {}));
8825
8858
  /**
8826
8859
  * Distinguishes different kinds of IR expressions.
@@ -8999,6 +9032,22 @@ var BindingKind;
8999
9032
  */
9000
9033
  BindingKind[BindingKind["Animation"] = 6] = "Animation";
9001
9034
  })(BindingKind || (BindingKind = {}));
9035
+ /**
9036
+ * Enumeration of possible times i18n params can be resolved.
9037
+ */
9038
+ var I18nParamResolutionTime;
9039
+ (function (I18nParamResolutionTime) {
9040
+ /**
9041
+ * Param is resolved at message creation time. Most params should be resolved at message creation
9042
+ * time. However, ICU params need to be handled in post-processing.
9043
+ */
9044
+ I18nParamResolutionTime[I18nParamResolutionTime["Creation"] = 0] = "Creation";
9045
+ /**
9046
+ * Param is resolved during post-processing. This should be used for params who's value comes from
9047
+ * an ICU.
9048
+ */
9049
+ I18nParamResolutionTime[I18nParamResolutionTime["Postproccessing"] = 1] = "Postproccessing";
9050
+ })(I18nParamResolutionTime || (I18nParamResolutionTime = {}));
9002
9051
 
9003
9052
  /**
9004
9053
  * Marker symbol for `ConsumesSlotOpTrait`.
@@ -9297,12 +9346,14 @@ function createConditionalOp(target, test, conditions, sourceSpan) {
9297
9346
  /**
9298
9347
  * Create an i18n expression op.
9299
9348
  */
9300
- function createI18nExpressionOp(target, expression, i18nPlaceholder, sourceSpan) {
9349
+ function createI18nExpressionOp(owner, expression, i18nPlaceholder, resolutionTime, sourceSpan) {
9301
9350
  return {
9302
9351
  kind: OpKind.I18nExpression,
9303
- target,
9352
+ owner,
9353
+ target: owner,
9304
9354
  expression,
9305
9355
  i18nPlaceholder,
9356
+ resolutionTime,
9306
9357
  sourceSpan,
9307
9358
  ...NEW_OP,
9308
9359
  ...TRAIT_CONSUMES_VARS,
@@ -9321,6 +9372,17 @@ function createI18nApplyOp(target, sourceSpan) {
9321
9372
  ...TRAIT_USES_SLOT_INDEX,
9322
9373
  };
9323
9374
  }
9375
+ /**
9376
+ * Creates an op to update an ICU expression.
9377
+ */
9378
+ function createIcuUpdateOp(xref, sourceSpan) {
9379
+ return {
9380
+ kind: OpKind.IcuUpdate,
9381
+ xref,
9382
+ sourceSpan,
9383
+ ...NEW_OP,
9384
+ };
9385
+ }
9324
9386
 
9325
9387
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
9326
9388
  /**
@@ -10043,6 +10105,8 @@ function transformExpressionsInOp(op, transform, flags) {
10043
10105
  case OpKind.Advance:
10044
10106
  case OpKind.Namespace:
10045
10107
  case OpKind.I18nApply:
10108
+ case OpKind.Icu:
10109
+ case OpKind.IcuUpdate:
10046
10110
  // These operations contain no expressions.
10047
10111
  break;
10048
10112
  default:
@@ -10448,7 +10512,7 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
10448
10512
  /**
10449
10513
  * Create a `TemplateOp`.
10450
10514
  */
10451
- function createTemplateOp(xref, tag, namespace, generatedInBlock, i18n, sourceSpan) {
10515
+ function createTemplateOp(xref, tag, namespace, generatedInBlock, i18nPlaceholder, sourceSpan) {
10452
10516
  return {
10453
10517
  kind: OpKind.Template,
10454
10518
  xref,
@@ -10460,6 +10524,7 @@ function createTemplateOp(xref, tag, namespace, generatedInBlock, i18n, sourceSp
10460
10524
  localRefs: [],
10461
10525
  nonBindable: false,
10462
10526
  namespace,
10527
+ i18nPlaceholder,
10463
10528
  sourceSpan,
10464
10529
  ...TRAIT_CONSUMES_SLOT,
10465
10530
  ...NEW_OP,
@@ -10633,13 +10698,17 @@ function createExtractedMessageOp(owner, expression, statements) {
10633
10698
  /**
10634
10699
  * Create an `I18nStartOp`.
10635
10700
  */
10636
- function createI18nStartOp(xref, message) {
10701
+ function createI18nStartOp(xref, message, root) {
10637
10702
  return {
10638
10703
  kind: OpKind.I18nStart,
10639
10704
  xref,
10705
+ root: root ?? xref,
10640
10706
  message,
10641
10707
  params: new Map(),
10708
+ postprocessingParams: new Map(),
10642
10709
  messageIndex: null,
10710
+ subTemplateIndex: null,
10711
+ needsPostprocessing: false,
10643
10712
  ...NEW_OP,
10644
10713
  ...TRAIT_CONSUMES_SLOT,
10645
10714
  };
@@ -10654,6 +10723,18 @@ function createI18nEndOp(xref) {
10654
10723
  ...NEW_OP,
10655
10724
  };
10656
10725
  }
10726
+ /**
10727
+ * Creates an op to create an ICU expression.
10728
+ */
10729
+ function createIcuOp(xref, message, sourceSpan) {
10730
+ return {
10731
+ kind: OpKind.Icu,
10732
+ xref,
10733
+ message,
10734
+ sourceSpan,
10735
+ ...NEW_OP,
10736
+ };
10737
+ }
10657
10738
  function literalOrArrayLiteral$1(value) {
10658
10739
  if (Array.isArray(value)) {
10659
10740
  return literalArr(value.map(literalOrArrayLiteral$1));
@@ -11019,7 +11100,7 @@ function phaseApplyI18nExpressions(job) {
11019
11100
  // Only add apply after expressions that are not followed by more expressions.
11020
11101
  if (op.kind === OpKind.I18nExpression && needsApplication(op)) {
11021
11102
  // TODO: what should be the source span for the apply op?
11022
- OpList.insertAfter(createI18nApplyOp(op.target, null), op);
11103
+ OpList.insertAfter(createI18nApplyOp(op.owner, null), op);
11023
11104
  }
11024
11105
  }
11025
11106
  }
@@ -11033,12 +11114,37 @@ function needsApplication(op) {
11033
11114
  return true;
11034
11115
  }
11035
11116
  // If the next op is an expression targeting a different i18n block, we need to apply.
11036
- if (op.next.target !== op.target) {
11117
+ if (op.next.owner !== op.owner) {
11037
11118
  return true;
11038
11119
  }
11039
11120
  return false;
11040
11121
  }
11041
11122
 
11123
+ /**
11124
+ * Updates i18n expression ops to depend on the last slot in their owning i18n block.
11125
+ */
11126
+ function phaseAssignI18nSlotDependencies(job) {
11127
+ const i18nLastSlotConsumers = new Map();
11128
+ let lastSlotConsumer = null;
11129
+ for (const unit of job.units) {
11130
+ // Record the last consumed slot before each i18n end instruction.
11131
+ for (const op of unit.create) {
11132
+ if (op.kind === OpKind.I18nEnd) {
11133
+ i18nLastSlotConsumers.set(op.xref, lastSlotConsumer);
11134
+ }
11135
+ if (hasConsumesSlotTrait(op)) {
11136
+ lastSlotConsumer = op.xref;
11137
+ }
11138
+ }
11139
+ // Assign i18n expressions to target the last slot in its owning block.
11140
+ for (const op of unit.update) {
11141
+ if (op.kind === OpKind.I18nExpression) {
11142
+ op.target = i18nLastSlotConsumers.get(op.owner);
11143
+ }
11144
+ }
11145
+ }
11146
+ }
11147
+
11042
11148
  /**
11043
11149
  * Gets a map of all elements in the given view by their xref id.
11044
11150
  */
@@ -11793,31 +11899,13 @@ function phaseGenerateAdvance(job) {
11793
11899
  for (const unit of job.units) {
11794
11900
  // First build a map of all of the declarations in the view that have assigned slots.
11795
11901
  const slotMap = new Map();
11796
- let lastSlotOp = null;
11797
11902
  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
11903
  if (!hasConsumesSlotTrait(op)) {
11815
11904
  continue;
11816
11905
  }
11817
11906
  else if (op.slot === null) {
11818
11907
  throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
11819
11908
  }
11820
- lastSlotOp = op;
11821
11909
  slotMap.set(op.xref, op.slot);
11822
11910
  }
11823
11911
  // Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
@@ -11955,7 +12043,6 @@ function getScopeForView(view, parent) {
11955
12043
  }
11956
12044
  for (const op of view.create) {
11957
12045
  switch (op.kind) {
11958
- case OpKind.Element:
11959
12046
  case OpKind.ElementStart:
11960
12047
  case OpKind.Template:
11961
12048
  if (!Array.isArray(op.localRefs)) {
@@ -12123,9 +12210,8 @@ function phaseI18nConstCollection(job) {
12123
12210
  // Assign const index to i18n ops that messages were extracted from.
12124
12211
  for (const unit of job.units) {
12125
12212
  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];
12213
+ if (op.kind === OpKind.I18nStart) {
12214
+ op.messageIndex = messageConstIndices[op.root];
12129
12215
  }
12130
12216
  }
12131
12217
  }
@@ -14421,7 +14507,7 @@ let TAG_DEFINITIONS;
14421
14507
  function getHtmlTagDefinition(tagName) {
14422
14508
  if (!TAG_DEFINITIONS) {
14423
14509
  DEFAULT_TAG_DEFINITION = new HtmlTagDefinition({ canSelfClose: true });
14424
- TAG_DEFINITIONS = {
14510
+ TAG_DEFINITIONS = Object.assign(Object.create(null), {
14425
14511
  'base': new HtmlTagDefinition({ isVoid: true }),
14426
14512
  'meta': new HtmlTagDefinition({ isVoid: true }),
14427
14513
  'area': new HtmlTagDefinition({ isVoid: true }),
@@ -14483,9 +14569,9 @@ function getHtmlTagDefinition(tagName) {
14483
14569
  contentType: { default: TagContentType.ESCAPABLE_RAW_TEXT, svg: TagContentType.PARSABLE_DATA }
14484
14570
  }),
14485
14571
  'textarea': new HtmlTagDefinition({ contentType: TagContentType.ESCAPABLE_RAW_TEXT, ignoreFirstLf: true }),
14486
- };
14572
+ });
14487
14573
  new DomElementSchemaRegistry().allKnownElementNames().forEach(knownTagName => {
14488
- if (!TAG_DEFINITIONS.hasOwnProperty(knownTagName) && getNsPrefix(knownTagName) === null) {
14574
+ if (!TAG_DEFINITIONS[knownTagName] && getNsPrefix(knownTagName) === null) {
14489
14575
  TAG_DEFINITIONS[knownTagName] = new HtmlTagDefinition({ canSelfClose: false });
14490
14576
  }
14491
14577
  });
@@ -17078,7 +17164,7 @@ class _Tokenizer {
17078
17164
  this.handleError(e);
17079
17165
  }
17080
17166
  }
17081
- this._beginToken(28 /* TokenType.EOF */);
17167
+ this._beginToken(29 /* TokenType.EOF */);
17082
17168
  this._endToken([]);
17083
17169
  }
17084
17170
  _getBlockName() {
@@ -17099,7 +17185,7 @@ class _Tokenizer {
17099
17185
  }
17100
17186
  _consumeBlockStart(start) {
17101
17187
  this._beginToken(24 /* TokenType.BLOCK_OPEN_START */, start);
17102
- this._endToken([this._getBlockName()]);
17188
+ const startToken = this._endToken([this._getBlockName()]);
17103
17189
  if (this._cursor.peek() === $LPAREN) {
17104
17190
  // Advance past the opening paren.
17105
17191
  this._cursor.advance();
@@ -17107,14 +17193,22 @@ class _Tokenizer {
17107
17193
  this._consumeBlockParameters();
17108
17194
  // Allow spaces before the closing paren.
17109
17195
  this._attemptCharCodeUntilFn(isNotWhitespace);
17110
- // Skip over the closing paren.
17111
- this._requireCharCode($RPAREN);
17112
- // Allow spaces after the paren.
17113
- this._attemptCharCodeUntilFn(isNotWhitespace);
17196
+ if (this._attemptCharCode($RPAREN)) {
17197
+ // Allow spaces after the paren.
17198
+ this._attemptCharCodeUntilFn(isNotWhitespace);
17199
+ }
17200
+ else {
17201
+ startToken.type = 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */;
17202
+ return;
17203
+ }
17204
+ }
17205
+ if (this._attemptCharCode($LBRACE)) {
17206
+ this._beginToken(25 /* TokenType.BLOCK_OPEN_END */);
17207
+ this._endToken([]);
17208
+ }
17209
+ else {
17210
+ startToken.type = 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */;
17114
17211
  }
17115
- this._beginToken(25 /* TokenType.BLOCK_OPEN_END */);
17116
- this._requireCharCode($LBRACE);
17117
- this._endToken([]);
17118
17212
  }
17119
17213
  _consumeBlockEnd(start) {
17120
17214
  this._beginToken(26 /* TokenType.BLOCK_CLOSE */, start);
@@ -18087,7 +18181,7 @@ class _TreeBuilder {
18087
18181
  this._advance();
18088
18182
  }
18089
18183
  build() {
18090
- while (this._peek.type !== 28 /* TokenType.EOF */) {
18184
+ while (this._peek.type !== 29 /* TokenType.EOF */) {
18091
18185
  if (this._peek.type === 0 /* TokenType.TAG_OPEN_START */ ||
18092
18186
  this._peek.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) {
18093
18187
  this._consumeStartTag(this._advance());
@@ -18119,6 +18213,10 @@ class _TreeBuilder {
18119
18213
  this._closeVoidElement();
18120
18214
  this._consumeBlockClose(this._advance());
18121
18215
  }
18216
+ else if (this._peek.type === 28 /* TokenType.INCOMPLETE_BLOCK_OPEN */) {
18217
+ this._closeVoidElement();
18218
+ this._consumeIncompleteBlock(this._advance());
18219
+ }
18122
18220
  else {
18123
18221
  // Skip all other tokens...
18124
18222
  this._advance();
@@ -18192,7 +18290,7 @@ class _TreeBuilder {
18192
18290
  if (!exp)
18193
18291
  return null;
18194
18292
  const end = this._advance();
18195
- exp.push({ type: 28 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan });
18293
+ exp.push({ type: 29 /* TokenType.EOF */, parts: [], sourceSpan: end.sourceSpan });
18196
18294
  // parse everything in between { and }
18197
18295
  const expansionCaseParser = new _TreeBuilder(exp, this.getTagDefinition);
18198
18296
  expansionCaseParser.build();
@@ -18232,7 +18330,7 @@ class _TreeBuilder {
18232
18330
  return null;
18233
18331
  }
18234
18332
  }
18235
- if (this._peek.type === 28 /* TokenType.EOF */) {
18333
+ if (this._peek.type === 29 /* TokenType.EOF */) {
18236
18334
  this.errors.push(TreeError.create(null, start.sourceSpan, `Invalid ICU message. Missing '}'.`));
18237
18335
  return null;
18238
18336
  }
@@ -18434,17 +18532,31 @@ class _TreeBuilder {
18434
18532
  const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
18435
18533
  const block = new Block(token.parts[0], parameters, [], span, startSpan);
18436
18534
  this._pushContainer(block, false);
18437
- return block;
18438
18535
  }
18439
18536
  _consumeBlockClose(token) {
18440
- const previousContainer = this._getContainer();
18441
18537
  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}`));
18538
+ this.errors.push(TreeError.create(null, token.sourceSpan, `Unexpected closing block. The block may have been closed earlier. ` +
18539
+ `If you meant to write the } character, you should use the "}" ` +
18540
+ `HTML entity instead.`));
18446
18541
  }
18447
18542
  }
18543
+ _consumeIncompleteBlock(token) {
18544
+ const parameters = [];
18545
+ while (this._peek.type === 27 /* TokenType.BLOCK_PARAMETER */) {
18546
+ const paramToken = this._advance();
18547
+ parameters.push(new BlockParameter(paramToken.parts[0], paramToken.sourceSpan));
18548
+ }
18549
+ const end = this._peek.sourceSpan.fullStart;
18550
+ const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
18551
+ // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
18552
+ const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
18553
+ const block = new Block(token.parts[0], parameters, [], span, startSpan);
18554
+ this._pushContainer(block, false);
18555
+ // Incomplete blocks don't have children so we close them immediately and report an error.
18556
+ this._popContainer(null, Block, null);
18557
+ this.errors.push(TreeError.create(token.parts[0], span, `Incomplete block "${token.parts[0]}". If you meant to write the @ character, ` +
18558
+ `you should use the "@" HTML entity instead.`));
18559
+ }
18448
18560
  _getContainer() {
18449
18561
  return this._containerStack.length > 0 ? this._containerStack[this._containerStack.length - 1] :
18450
18562
  null;
@@ -18997,17 +19109,29 @@ function phaseI18nMessageExtraction(job) {
18997
19109
  const fileBasedI18nSuffix = job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
18998
19110
  for (const unit of job.units) {
18999
19111
  for (const op of unit.create) {
19000
- 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));
19112
+ if (op.kind === OpKind.I18nStart) {
19113
+ // Only extract messages from root i18n ops, not sub-template ones.
19114
+ if (op.xref === op.root) {
19115
+ // Sort the params map to match the ordering in TemplateDefinitionBuilder.
19116
+ const params = new Map([...op.params.entries()].sort());
19117
+ const mainVar = variable(job.pool.uniqueName(TRANSLATION_VAR_PREFIX));
19118
+ // Closure Compiler requires const names to start with `MSG_` but disallows any other
19119
+ // const to start with `MSG_`. We define a variable starting with `MSG_` just for the
19120
+ // `goog.getMsg` call
19121
+ const closureVar = i18nGenerateClosureVar(job.pool, op.message.id, fileBasedI18nSuffix, job.i18nUseExternalIds);
19122
+ let transformFn = undefined;
19123
+ // If nescessary, add a post-processing step and resolve any placeholder params that are
19124
+ // set in post-processing.
19125
+ if (op.needsPostprocessing) {
19126
+ const extraTransformFnParams = [];
19127
+ if (op.postprocessingParams.size > 0) {
19128
+ extraTransformFnParams.push(literalMap([...op.postprocessingParams.entries()].map(([key, value]) => ({ key, value, quoted: true }))));
19129
+ }
19130
+ transformFn = (expr) => importExpr(Identifiers.i18nPostprocess).callFn([expr, ...extraTransformFnParams]);
19131
+ }
19132
+ const statements = getTranslationDeclStmts$1(op.message, mainVar, closureVar, params, transformFn);
19133
+ unit.create.push(createExtractedMessageOp(op.xref, mainVar, statements));
19134
+ }
19011
19135
  }
19012
19136
  }
19013
19137
  }
@@ -19118,7 +19242,7 @@ function phaseI18nTextExtraction(job) {
19118
19242
  for (let i = 0; i < op.interpolation.expressions.length; i++) {
19119
19243
  const expr = op.interpolation.expressions[i];
19120
19244
  const placeholder = op.i18nPlaceholders[i];
19121
- ops.push(createI18nExpressionOp(i18nBlockId, expr, placeholder, expr.sourceSpan ?? op.sourceSpan));
19245
+ ops.push(createI18nExpressionOp(i18nBlockId, expr, placeholder.name, I18nParamResolutionTime.Creation, expr.sourceSpan ?? op.sourceSpan));
19122
19246
  }
19123
19247
  if (ops.length > 0) {
19124
19248
  // ops.push(ir.createI18nApplyOp(i18nBlockId, op.i18nPlaceholders, op.sourceSpan));
@@ -19130,6 +19254,50 @@ function phaseI18nTextExtraction(job) {
19130
19254
  }
19131
19255
  }
19132
19256
 
19257
+ /**
19258
+ * Extracts ICUs into i18n expressions.
19259
+ */
19260
+ function phaseIcuExtraction(job) {
19261
+ for (const unit of job.units) {
19262
+ // Build a map of ICU to the i18n block they belong to, then remove the `Icu` ops.
19263
+ const icus = new Map();
19264
+ let currentI18nId = null;
19265
+ for (const op of unit.create) {
19266
+ switch (op.kind) {
19267
+ case OpKind.I18nStart:
19268
+ currentI18nId = op.xref;
19269
+ break;
19270
+ case OpKind.I18nEnd:
19271
+ currentI18nId = null;
19272
+ break;
19273
+ case OpKind.Icu:
19274
+ if (currentI18nId === null) {
19275
+ throw Error('Unexpected ICU outside of an i18n block.');
19276
+ }
19277
+ icus.set(op.xref, { message: op.message, i18nBlockId: currentI18nId });
19278
+ OpList.remove(op);
19279
+ break;
19280
+ }
19281
+ }
19282
+ // Replace the `IcuUpdate` ops with `i18nExpr` ops.
19283
+ for (const op of unit.update) {
19284
+ switch (op.kind) {
19285
+ case OpKind.IcuUpdate:
19286
+ const { message, i18nBlockId } = icus.get(op.xref);
19287
+ const icuNode = message.nodes.find((n) => n instanceof Icu);
19288
+ if (icuNode === undefined) {
19289
+ throw Error('Could not find ICU in i18n AST');
19290
+ }
19291
+ if (icuNode.expressionPlaceholder === undefined) {
19292
+ throw Error('ICU is missing an i18n placeholder');
19293
+ }
19294
+ OpList.replace(op, createI18nExpressionOp(i18nBlockId, new LexicalReadExpr(icuNode.expression), icuNode.expressionPlaceholder, I18nParamResolutionTime.Postproccessing, null));
19295
+ break;
19296
+ }
19297
+ }
19298
+ }
19299
+ }
19300
+
19133
19301
  /**
19134
19302
  * Lifts local reference declarations on element-like structures within each view into an entry in
19135
19303
  * the `consts` array for the whole component.
@@ -19139,7 +19307,6 @@ function phaseLocalRefs(job) {
19139
19307
  for (const op of unit.create) {
19140
19308
  switch (op.kind) {
19141
19309
  case OpKind.ElementStart:
19142
- case OpKind.Element:
19143
19310
  case OpKind.Template:
19144
19311
  if (!Array.isArray(op.localRefs)) {
19145
19312
  throw new Error(`AssertionError: expected localRefs to be an array still`);
@@ -19172,7 +19339,7 @@ function phaseNamespace(job) {
19172
19339
  for (const unit of job.units) {
19173
19340
  let activeNamespace = Namespace.HTML;
19174
19341
  for (const op of unit.create) {
19175
- if (op.kind !== OpKind.Element && op.kind !== OpKind.ElementStart) {
19342
+ if (op.kind !== OpKind.ElementStart) {
19176
19343
  continue;
19177
19344
  }
19178
19345
  if (op.namespace !== activeNamespace) {
@@ -19317,7 +19484,8 @@ function addNamesToView(unit, baseName, state, compatibility) {
19317
19484
  if (op.slot === null) {
19318
19485
  throw new Error(`Expected slot to be assigned`);
19319
19486
  }
19320
- addNamesToView(childView, `${baseName}_${prefixWithNamespace(op.tag, op.namespace)}_${op.slot}`, state, compatibility);
19487
+ const tagToken = op.tag === null ? '' : '_' + prefixWithNamespace(op.tag, op.namespace);
19488
+ addNamesToView(childView, `${baseName}${tagToken}_${op.slot}`, state, compatibility);
19321
19489
  break;
19322
19490
  case OpKind.StyleProp:
19323
19491
  op.name = normalizeStylePropName(op.name);
@@ -19451,11 +19619,6 @@ function phaseNgContainer(job) {
19451
19619
  for (const unit of job.units) {
19452
19620
  const updatedElementXrefs = new Set();
19453
19621
  for (const op of unit.create) {
19454
- if (op.kind === OpKind.Element && op.tag === CONTAINER_TAG) {
19455
- // Transmute the `Element` instruction to `Container`.
19456
- op.kind = OpKind.Container;
19457
- updatedElementXrefs.add(op.xref);
19458
- }
19459
19622
  if (op.kind === OpKind.ElementStart && op.tag === CONTAINER_TAG) {
19460
19623
  // Transmute the `ElementStart` instruction to `ContainerStart`.
19461
19624
  op.kind = OpKind.ContainerStart;
@@ -19739,6 +19902,55 @@ function phasePipeVariadic(job) {
19739
19902
  }
19740
19903
  }
19741
19904
 
19905
+ /**
19906
+ * Propagate i18n blocks down through child templates that act as placeholders in the root i18n
19907
+ * message.
19908
+ */
19909
+ function phasePropagateI18nBlocks(job) {
19910
+ propagateI18nBlocksToTemplates(job.root, 0);
19911
+ }
19912
+ /**
19913
+ * Propagates i18n ops in the given view through to any child views recursively.
19914
+ */
19915
+ function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
19916
+ let i18nBlock = null;
19917
+ for (const op of unit.create) {
19918
+ switch (op.kind) {
19919
+ case OpKind.I18nStart:
19920
+ op.subTemplateIndex = subTemplateIndex === 0 ? null : subTemplateIndex;
19921
+ i18nBlock = op;
19922
+ break;
19923
+ case OpKind.I18nEnd:
19924
+ i18nBlock = null;
19925
+ break;
19926
+ case OpKind.Template:
19927
+ const templateView = unit.job.views.get(op.xref);
19928
+ // We found an <ng-template> inside an i18n block; increment the sub-template counter and
19929
+ // wrap the template's view in a child i18n block.
19930
+ if (op.i18nPlaceholder !== undefined) {
19931
+ if (i18nBlock === null) {
19932
+ throw Error('Expected template with i18n placeholder to be in an i18n block.');
19933
+ }
19934
+ subTemplateIndex++;
19935
+ wrapTemplateWithI18n(templateView, i18nBlock);
19936
+ }
19937
+ // Continue traversing inside the template's view.
19938
+ propagateI18nBlocksToTemplates(templateView, subTemplateIndex);
19939
+ }
19940
+ }
19941
+ }
19942
+ /**
19943
+ * Wraps a template view with i18n start and end ops.
19944
+ */
19945
+ function wrapTemplateWithI18n(unit, parentI18n) {
19946
+ // Only add i18n ops if they have not already been propagated to this template.
19947
+ if (unit.create.head.next?.kind !== OpKind.I18nStart) {
19948
+ const id = unit.job.allocateXrefId();
19949
+ OpList.insertAfter(createI18nStartOp(id, parentI18n.message, parentI18n.root), unit.create.head);
19950
+ OpList.insertBefore(createI18nEndOp(id), unit.create.tail);
19951
+ }
19952
+ }
19953
+
19742
19954
  function phasePureFunctionExtraction(job) {
19743
19955
  for (const view of job.units) {
19744
19956
  for (const op of view.ops()) {
@@ -19869,7 +20081,7 @@ function elementContainerEnd() {
19869
20081
  }
19870
20082
  function template(slot, templateFnRef, decls, vars, tag, constIndex, sourceSpan) {
19871
20083
  const args = [literal(slot), templateFnRef, literal(decls), literal(vars)];
19872
- if (tag !== null) {
20084
+ if (tag !== null || constIndex !== null) {
19873
20085
  args.push(literal(tag));
19874
20086
  if (constIndex !== null) {
19875
20087
  args.push(literal(constIndex));
@@ -19975,11 +20187,19 @@ function projection(slot, projectionSlotIndex, attributes) {
19975
20187
  }
19976
20188
  return call(Identifiers.projection, args, null);
19977
20189
  }
19978
- function i18nStart(slot, constIndex) {
19979
- return call(Identifiers.i18nStart, [literal(slot), literal(constIndex)], null);
20190
+ function i18nStart(slot, constIndex, subTemplateIndex) {
20191
+ const args = [literal(slot), literal(constIndex)];
20192
+ if (subTemplateIndex !== null) {
20193
+ args.push(literal(subTemplateIndex));
20194
+ }
20195
+ return call(Identifiers.i18nStart, args, null);
19980
20196
  }
19981
- function i18n(slot, constIndex) {
19982
- return call(Identifiers.i18n, [literal(slot), literal(constIndex)], null);
20197
+ function i18n(slot, constIndex, subTemplateIndex) {
20198
+ const args = [literal(slot), literal(constIndex)];
20199
+ if (subTemplateIndex) {
20200
+ args.push(literal(subTemplateIndex));
20201
+ }
20202
+ return call(Identifiers.i18n, args, null);
19983
20203
  }
19984
20204
  function i18nEnd() {
19985
20205
  return call(Identifiers.i18nEnd, [], null);
@@ -20362,13 +20582,13 @@ function reifyCreateOperations(unit, ops) {
20362
20582
  OpList.replace(op, elementContainerEnd());
20363
20583
  break;
20364
20584
  case OpKind.I18nStart:
20365
- OpList.replace(op, i18nStart(op.slot, op.messageIndex));
20585
+ OpList.replace(op, i18nStart(op.slot, op.messageIndex, op.subTemplateIndex));
20366
20586
  break;
20367
20587
  case OpKind.I18nEnd:
20368
20588
  OpList.replace(op, i18nEnd());
20369
20589
  break;
20370
20590
  case OpKind.I18n:
20371
- OpList.replace(op, i18n(op.slot, op.messageIndex));
20591
+ OpList.replace(op, i18n(op.slot, op.messageIndex, op.subTemplateIndex));
20372
20592
  break;
20373
20593
  case OpKind.Template:
20374
20594
  if (!(unit instanceof ViewCompilationUnit)) {
@@ -20706,96 +20926,279 @@ function resolveDollarEvent(unit, ops) {
20706
20926
  * The escape sequence used indicate message param values.
20707
20927
  */
20708
20928
  const ESCAPE = '\uFFFD';
20929
+ /**
20930
+ * Marker used to indicate an element tag.
20931
+ */
20932
+ const ELEMENT_MARKER = '#';
20933
+ /**
20934
+ * Marker used to indicate a template tag.
20935
+ */
20936
+ const TEMPLATE_MARKER = '*';
20937
+ /**
20938
+ * Marker used to indicate closing of an element or template tag.
20939
+ */
20940
+ const TAG_CLOSE_MARKER = '/';
20941
+ /**
20942
+ * Marker used to indicate the sub-template context.
20943
+ */
20944
+ const CONTEXT_MARKER = ':';
20945
+ /**
20946
+ * Marker used to indicate the start of a list of values.
20947
+ */
20948
+ const LIST_START_MARKER = '[';
20949
+ /**
20950
+ * Marker used to indicate the end of a list of values.
20951
+ */
20952
+ const LIST_END_MARKER = ']';
20953
+ /**
20954
+ * Delimiter used to separate multiple values in a list.
20955
+ */
20956
+ const LIST_DELIMITER = '|';
20957
+ /**
20958
+ * Flags that describe what an i18n param value. These determine how the value is serialized into
20959
+ * the final map.
20960
+ */
20961
+ var I18nParamValueFlags;
20962
+ (function (I18nParamValueFlags) {
20963
+ I18nParamValueFlags[I18nParamValueFlags["None"] = 0] = "None";
20964
+ /**
20965
+ * This value represtents an element tag.
20966
+ */
20967
+ I18nParamValueFlags[I18nParamValueFlags["ElementTag"] = 1] = "ElementTag";
20968
+ /**
20969
+ * This value represents a template tag.
20970
+ */
20971
+ I18nParamValueFlags[I18nParamValueFlags["TemplateTag"] = 2] = "TemplateTag";
20972
+ /**
20973
+ * This value represents the opening of a tag.
20974
+ */
20975
+ I18nParamValueFlags[I18nParamValueFlags["OpenTag"] = 4] = "OpenTag";
20976
+ /**
20977
+ * This value represents the closing of a tag.
20978
+ */
20979
+ I18nParamValueFlags[I18nParamValueFlags["CloseTag"] = 8] = "CloseTag";
20980
+ })(I18nParamValueFlags || (I18nParamValueFlags = {}));
20981
+ /**
20982
+ * Represents the complete i18n params map for an i18n op.
20983
+ */
20984
+ class I18nPlaceholderParams {
20985
+ constructor() {
20986
+ this.values = new Map();
20987
+ }
20988
+ /**
20989
+ * Adds a new value to the params map.
20990
+ */
20991
+ addValue(placeholder, value, subTemplateIndex, resolutionTime, flags) {
20992
+ const placeholderValues = this.values.get(placeholder) ?? [];
20993
+ placeholderValues.push({ value, subTemplateIndex, resolutionTime, flags });
20994
+ this.values.set(placeholder, placeholderValues);
20995
+ }
20996
+ /**
20997
+ * Saves the params map, in serialized form, into the given i18n op.
20998
+ */
20999
+ saveToOp(op) {
21000
+ for (const [placeholder, placeholderValues] of this.values) {
21001
+ // We need to run post-processing for any 1i8n ops that contain parameters with more than
21002
+ // one value, even if there are no parameters resolved at post-processing time.
21003
+ const creationValues = placeholderValues.filter(({ resolutionTime }) => resolutionTime === I18nParamResolutionTime.Creation);
21004
+ if (creationValues.length > 1) {
21005
+ op.needsPostprocessing = true;
21006
+ }
21007
+ // Save creation time params to op.
21008
+ const serializedCreationValues = this.serializeValues(creationValues);
21009
+ if (serializedCreationValues !== null) {
21010
+ op.params.set(placeholder, literal(serializedCreationValues));
21011
+ }
21012
+ // Save post-processing time params to op.
21013
+ const serializedPostprocessingValues = this.serializeValues(placeholderValues.filter(({ resolutionTime }) => resolutionTime === I18nParamResolutionTime.Postproccessing));
21014
+ if (serializedPostprocessingValues !== null) {
21015
+ op.needsPostprocessing = true;
21016
+ op.postprocessingParams.set(placeholder, literal(serializedPostprocessingValues));
21017
+ }
21018
+ }
21019
+ }
21020
+ /**
21021
+ * Merges another param map into this one.
21022
+ */
21023
+ merge(other) {
21024
+ for (const [placeholder, otherValues] of other.values) {
21025
+ const currentValues = this.values.get(placeholder) || [];
21026
+ // Child element close tag params should be prepended to maintain the same order as
21027
+ // TemplateDefinitionBuilder.
21028
+ const flags = otherValues[0].flags;
21029
+ if ((flags & I18nParamValueFlags.CloseTag) && !(flags & I18nParamValueFlags.OpenTag)) {
21030
+ this.values.set(placeholder, [...otherValues, ...currentValues]);
21031
+ }
21032
+ else {
21033
+ this.values.set(placeholder, [...currentValues, ...otherValues]);
21034
+ }
21035
+ }
21036
+ }
21037
+ /**
21038
+ * Serializes a list of i18n placeholder values.
21039
+ */
21040
+ serializeValues(values) {
21041
+ if (values.length === 0) {
21042
+ return null;
21043
+ }
21044
+ const serializedValues = values.map(value => this.serializeValue(value));
21045
+ return serializedValues.length === 1 ?
21046
+ serializedValues[0] :
21047
+ `${LIST_START_MARKER}${serializedValues.join(LIST_DELIMITER)}${LIST_END_MARKER}`;
21048
+ }
21049
+ /**
21050
+ * Serializes a single i18n placeholder value.
21051
+ */
21052
+ serializeValue(value) {
21053
+ let tagMarker = '';
21054
+ let closeMarker = '';
21055
+ if (value.flags & I18nParamValueFlags.ElementTag) {
21056
+ tagMarker = ELEMENT_MARKER;
21057
+ }
21058
+ else if (value.flags & I18nParamValueFlags.TemplateTag) {
21059
+ tagMarker = TEMPLATE_MARKER;
21060
+ }
21061
+ if (tagMarker !== '') {
21062
+ closeMarker = value.flags & I18nParamValueFlags.CloseTag ? TAG_CLOSE_MARKER : '';
21063
+ }
21064
+ const context = value.subTemplateIndex === null ? '' : `${CONTEXT_MARKER}${value.subTemplateIndex}`;
21065
+ // Self-closing tags use a special form that concatenates the start and close tag values.
21066
+ if ((value.flags & I18nParamValueFlags.OpenTag) &&
21067
+ (value.flags & I18nParamValueFlags.CloseTag)) {
21068
+ return `${ESCAPE}${tagMarker}${value.value}${context}${ESCAPE}${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
21069
+ }
21070
+ return `${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
21071
+ }
21072
+ }
20709
21073
  /**
20710
21074
  * Resolve the placeholders in i18n messages.
20711
21075
  */
20712
21076
  function phaseResolveI18nPlaceholders(job) {
21077
+ const params = new Map();
21078
+ const i18nOps = new Map();
21079
+ resolvePlaceholders(job, params, i18nOps);
21080
+ propagatePlaceholders(params, i18nOps);
21081
+ // After colleccting all params, save them to the i18n ops.
21082
+ for (const [xref, i18nOpParams] of params) {
21083
+ i18nOpParams.saveToOp(i18nOps.get(xref));
21084
+ }
21085
+ // Validate the root i18n ops have all placeholders filled in.
21086
+ for (const op of i18nOps.values()) {
21087
+ if (op.xref === op.root) {
21088
+ for (const placeholder in op.message.placeholders) {
21089
+ if (!op.params.has(placeholder) && !op.postprocessingParams.has(placeholder)) {
21090
+ throw Error(`Failed to resolve i18n placeholder: ${placeholder}`);
21091
+ }
21092
+ }
21093
+ }
21094
+ }
21095
+ }
21096
+ /**
21097
+ * Resolve placeholders for each i18n op.
21098
+ */
21099
+ function resolvePlaceholders(job, params, i18nOps) {
20713
21100
  for (const unit of job.units) {
20714
- const i18nOps = new Map();
20715
- let startTagSlots = new Map();
20716
- let closeTagSlots = new Map();
21101
+ const elements = new Map();
20717
21102
  let currentI18nOp = null;
20718
21103
  // Record slots for tag name placeholders.
20719
21104
  for (const op of unit.create) {
20720
21105
  switch (op.kind) {
20721
21106
  case OpKind.I18nStart:
20722
- case OpKind.I18n:
20723
- // Initialize collected slots for a new i18n block.
20724
21107
  i18nOps.set(op.xref, op);
20725
21108
  currentI18nOp = op.kind === OpKind.I18nStart ? op : null;
20726
- startTagSlots = new Map();
20727
- closeTagSlots = new Map();
20728
21109
  break;
20729
21110
  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
21111
  currentI18nOp = null;
20741
21112
  break;
20742
- case OpKind.Element:
20743
21113
  case OpKind.ElementStart:
20744
- // Record slots for tag placeholders.
20745
- if (op.i18nPlaceholder != undefined) {
21114
+ // For elements with i18n placeholders, record its slot value in the params map under the
21115
+ // corresponding tag start placeholder.
21116
+ if (op.i18nPlaceholder !== undefined) {
20746
21117
  if (currentI18nOp === null) {
20747
21118
  throw Error('i18n tag placeholder should only occur inside an i18n block');
20748
21119
  }
20749
- if (!op.slot) {
20750
- throw Error('Slots should be allocated before i18n placeholder resolution');
20751
- }
21120
+ elements.set(op.xref, op);
20752
21121
  const { startName, closeName } = op.i18nPlaceholder;
20753
- addTagSlot(startTagSlots, startName, op.slot);
20754
- addTagSlot(closeTagSlots, closeName, op.slot);
21122
+ let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.OpenTag;
21123
+ // For self-closing tags, there is no close tag placeholder. Instead, the start tag
21124
+ // placeholder accounts for the start and close of the element.
21125
+ if (closeName === '') {
21126
+ flags |= I18nParamValueFlags.CloseTag;
21127
+ }
21128
+ addParam(params, currentI18nOp, startName, op.slot, currentI18nOp.subTemplateIndex, I18nParamResolutionTime.Creation, flags);
21129
+ }
21130
+ break;
21131
+ case OpKind.ElementEnd:
21132
+ const startOp = elements.get(op.xref);
21133
+ if (startOp && startOp.i18nPlaceholder !== undefined) {
21134
+ if (currentI18nOp === null) {
21135
+ throw Error('i18n tag placeholder should only occur inside an i18n block');
21136
+ }
21137
+ const { closeName } = startOp.i18nPlaceholder;
21138
+ // Self-closing tags don't have a closing tag placeholder.
21139
+ if (closeName !== '') {
21140
+ addParam(params, currentI18nOp, closeName, startOp.slot, currentI18nOp.subTemplateIndex, I18nParamResolutionTime.Creation, I18nParamValueFlags.ElementTag | I18nParamValueFlags.CloseTag);
21141
+ }
21142
+ }
21143
+ break;
21144
+ case OpKind.Template:
21145
+ if (op.i18nPlaceholder !== undefined) {
21146
+ if (currentI18nOp === null) {
21147
+ throw Error('i18n tag placeholder should only occur inside an i18n block');
21148
+ }
21149
+ const subTemplateIndex = getSubTemplateIndexForTemplateTag(job, currentI18nOp, op);
21150
+ addParam(params, currentI18nOp, op.i18nPlaceholder.startName, op.slot, subTemplateIndex, I18nParamResolutionTime.Creation, I18nParamValueFlags.TemplateTag);
21151
+ addParam(params, currentI18nOp, op.i18nPlaceholder.closeName, op.slot, subTemplateIndex, I18nParamResolutionTime.Creation, I18nParamValueFlags.TemplateTag | I18nParamValueFlags.CloseTag);
20755
21152
  }
20756
21153
  break;
20757
21154
  }
20758
21155
  }
20759
- // Fill in values for each of the expression placeholders applied in i18nApply operations.
21156
+ // Fill in values for each of the i18n expression placeholders.
20760
21157
  const i18nBlockPlaceholderIndices = new Map();
20761
21158
  for (const op of unit.update) {
20762
21159
  if (op.kind === OpKind.I18nExpression) {
20763
- const i18nOp = i18nOps.get(op.target);
20764
- let index = i18nBlockPlaceholderIndices.get(op.target) || 0;
21160
+ const i18nOp = i18nOps.get(op.owner);
21161
+ let index = i18nBlockPlaceholderIndices.get(op.owner) || 0;
20765
21162
  if (!i18nOp) {
20766
21163
  throw Error('Cannot find corresponding i18nStart for i18nExpr');
20767
21164
  }
20768
- i18nOp.params.set(op.i18nPlaceholder.name, literal(`${ESCAPE}${index++}${ESCAPE}`));
20769
- i18nBlockPlaceholderIndices.set(op.target, index);
20770
- }
20771
- }
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
- }
21165
+ addParam(params, i18nOp, op.i18nPlaceholder, index++, i18nOp.subTemplateIndex, op.resolutionTime);
21166
+ i18nBlockPlaceholderIndices.set(op.owner, index);
20778
21167
  }
20779
21168
  }
20780
21169
  }
20781
21170
  }
20782
21171
  /**
20783
- * Updates the given slots map with the specified slot.
21172
+ * Add a param to the params map for the given i18n op.
20784
21173
  */
20785
- function addTagSlot(tagSlots, placeholder, slot) {
20786
- const slots = tagSlots.get(placeholder) || [];
20787
- slots.push(slot);
20788
- tagSlots.set(placeholder, slots);
21174
+ function addParam(params, i18nOp, placeholder, value, subTemplateIndex, resolutionTime, flags = I18nParamValueFlags.None) {
21175
+ const i18nOpParams = params.get(i18nOp.xref) || new I18nPlaceholderParams();
21176
+ i18nOpParams.addValue(placeholder, value, subTemplateIndex, resolutionTime, flags);
21177
+ params.set(i18nOp.xref, i18nOpParams);
21178
+ }
21179
+ /**
21180
+ * Get the subTemplateIndex for the given template op. For template ops, use the subTemplateIndex of
21181
+ * the child i18n block inside the template.
21182
+ */
21183
+ function getSubTemplateIndexForTemplateTag(job, i18nOp, op) {
21184
+ for (const childOp of job.views.get(op.xref).create) {
21185
+ if (childOp.kind === OpKind.I18nStart) {
21186
+ return childOp.subTemplateIndex;
21187
+ }
21188
+ }
21189
+ return i18nOp.subTemplateIndex;
20789
21190
  }
20790
21191
  /**
20791
- * Serializes a list of slots to a string literal expression.
21192
+ * Propagate placeholders up to their root i18n op.
20792
21193
  */
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]);
21194
+ function propagatePlaceholders(params, i18nOps) {
21195
+ for (const [xref, opParams] of params) {
21196
+ const op = i18nOps.get(xref);
21197
+ if (op.xref !== op.root) {
21198
+ const rootParams = params.get(op.root) || new I18nPlaceholderParams();
21199
+ rootParams.merge(opParams);
21200
+ }
20797
21201
  }
20798
- return literal(`[${slotStrings.join('|')}]`);
20799
21202
  }
20800
21203
 
20801
21204
  /**
@@ -20938,8 +21341,7 @@ function phaseResolveSanitizers(job) {
20938
21341
  * Checks whether the given op represents an iframe element.
20939
21342
  */
20940
21343
  function isIframeElement$1(op) {
20941
- return (op.kind === OpKind.Element || op.kind === OpKind.ElementStart) &&
20942
- op.tag.toLowerCase() === 'iframe';
21344
+ return op.kind === OpKind.ElementStart && op.tag?.toLowerCase() === 'iframe';
20943
21345
  }
20944
21346
 
20945
21347
  function phaseSaveRestoreView(job) {
@@ -21553,18 +21955,47 @@ function allowConservativeInlining(decl, target) {
21553
21955
  }
21554
21956
  }
21555
21957
 
21958
+ /**
21959
+ * Wraps ICUs that do not already belong to an i18n block in a new i18n block.
21960
+ */
21961
+ function phaseWrapIcus(job) {
21962
+ for (const unit of job.units) {
21963
+ let currentI18nOp = null;
21964
+ for (const op of unit.create) {
21965
+ switch (op.kind) {
21966
+ case OpKind.I18nStart:
21967
+ currentI18nOp = op;
21968
+ break;
21969
+ case OpKind.I18nEnd:
21970
+ currentI18nOp = null;
21971
+ break;
21972
+ case OpKind.Icu:
21973
+ if (currentI18nOp === null) {
21974
+ const id = job.allocateXrefId();
21975
+ OpList.insertBefore(createI18nStartOp(id, op.message), op);
21976
+ OpList.insertAfter(createI18nEndOp(id), op);
21977
+ }
21978
+ break;
21979
+ }
21980
+ }
21981
+ }
21982
+ }
21983
+
21556
21984
  const phases = [
21557
21985
  { kind: CompilationJobKind.Tmpl, fn: phaseRemoveContentSelectors },
21558
21986
  { kind: CompilationJobKind.Host, fn: phaseHostStylePropertyParsing },
21559
21987
  { kind: CompilationJobKind.Tmpl, fn: phaseNamespace },
21560
21988
  { kind: CompilationJobKind.Both, fn: phaseStyleBindingSpecialization },
21561
21989
  { kind: CompilationJobKind.Both, fn: phaseBindingSpecialization },
21990
+ { kind: CompilationJobKind.Tmpl, fn: phasePropagateI18nBlocks },
21991
+ { kind: CompilationJobKind.Tmpl, fn: phaseWrapIcus },
21562
21992
  { kind: CompilationJobKind.Both, fn: phaseAttributeExtraction },
21563
21993
  { kind: CompilationJobKind.Both, fn: phaseParseExtractedStyles },
21564
21994
  { kind: CompilationJobKind.Tmpl, fn: phaseRemoveEmptyBindings },
21565
21995
  { kind: CompilationJobKind.Tmpl, fn: phaseConditionals },
21566
21996
  { kind: CompilationJobKind.Tmpl, fn: phasePipeCreation },
21567
21997
  { kind: CompilationJobKind.Tmpl, fn: phaseI18nTextExtraction },
21998
+ { kind: CompilationJobKind.Tmpl, fn: phaseIcuExtraction },
21568
21999
  { kind: CompilationJobKind.Tmpl, fn: phaseApplyI18nExpressions },
21569
22000
  { kind: CompilationJobKind.Tmpl, fn: phasePipeVariadic },
21570
22001
  { kind: CompilationJobKind.Both, fn: phasePureLiteralStructures },
@@ -21586,6 +22017,7 @@ const phases = [
21586
22017
  { kind: CompilationJobKind.Tmpl, fn: phaseI18nConstCollection },
21587
22018
  { kind: CompilationJobKind.Tmpl, fn: phaseConstTraitCollection },
21588
22019
  { kind: CompilationJobKind.Both, fn: phaseConstCollection },
22020
+ { kind: CompilationJobKind.Tmpl, fn: phaseAssignI18nSlotDependencies },
21589
22021
  { kind: CompilationJobKind.Both, fn: phaseVarCounting },
21590
22022
  { kind: CompilationJobKind.Tmpl, fn: phaseGenerateAdvance },
21591
22023
  { kind: CompilationJobKind.Both, fn: phaseVariableOptimization },
@@ -21798,6 +22230,9 @@ function ingestNodes(unit, template) {
21798
22230
  else if (node instanceof DeferredBlock) {
21799
22231
  ingestDeferBlock(unit, node);
21800
22232
  }
22233
+ else if (node instanceof Icu$1) {
22234
+ ingestIcu(unit, node);
22235
+ }
21801
22236
  else {
21802
22237
  throw new Error(`Unsupported template node: ${node.constructor.name}`);
21803
22238
  }
@@ -21835,7 +22270,8 @@ function ingestElement(unit, element) {
21835
22270
  * Ingest an `ng-template` node from the AST into the given `ViewCompilation`.
21836
22271
  */
21837
22272
  function ingestTemplate(unit, tmpl) {
21838
- if (tmpl.i18n !== undefined && !(tmpl.i18n instanceof Message)) {
22273
+ if (tmpl.i18n !== undefined &&
22274
+ !(tmpl.i18n instanceof Message || tmpl.i18n instanceof TagPlaceholder)) {
21839
22275
  throw Error(`Unhandled i18n metadata type for template: ${tmpl.i18n.constructor.name}`);
21840
22276
  }
21841
22277
  const childView = unit.job.allocateView(unit.xref);
@@ -21844,8 +22280,8 @@ function ingestTemplate(unit, tmpl) {
21844
22280
  if (tmpl.tagName) {
21845
22281
  [namespacePrefix, tagNameWithoutNamespace] = splitNsName(tmpl.tagName);
21846
22282
  }
21847
- // TODO: validate the fallback tag name here.
21848
- const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace ?? 'ng-template', namespaceForKey(namespacePrefix), false, undefined, tmpl.startSourceSpan);
22283
+ const i18nPlaceholder = tmpl.i18n instanceof TagPlaceholder ? tmpl.i18n : undefined;
22284
+ const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace, namespaceForKey(namespacePrefix), false, i18nPlaceholder, tmpl.startSourceSpan);
21849
22285
  unit.create.push(tplOp);
21850
22286
  ingestBindings(unit, tplOp, tmpl);
21851
22287
  ingestReferences(tplOp, tmpl);
@@ -21853,8 +22289,10 @@ function ingestTemplate(unit, tmpl) {
21853
22289
  for (const { name, value } of tmpl.variables) {
21854
22290
  childView.contextVariables.set(name, value);
21855
22291
  }
21856
- // If there is an i18n message associated with this template, insert i18n start and end ops.
21857
- if (tmpl.i18n instanceof Message) {
22292
+ // If this is a plain template and there is an i18n message associated with it, insert i18n start
22293
+ // and end ops. For structural directive templates, the i18n ops will be added when ingesting the
22294
+ // element/template the directive is placed on.
22295
+ if (isPlainTemplate(tmpl) && tmpl.i18n instanceof Message) {
21858
22296
  const id = unit.job.allocateXrefId();
21859
22297
  OpList.insertAfter(createI18nStartOp(id, tmpl.i18n), childView.create.head);
21860
22298
  OpList.insertBefore(createI18nEndOp(id), childView.create.tail);
@@ -21888,7 +22326,7 @@ function ingestBoundText(unit, text) {
21888
22326
  throw new Error(`AssertionError: expected Interpolation for BoundText node, got ${value.constructor.name}`);
21889
22327
  }
21890
22328
  if (text.i18n !== undefined && !(text.i18n instanceof Container)) {
21891
- throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n.constructor.name}`);
22329
+ throw Error(`Unhandled i18n metadata type for text interpolation: ${text.i18n?.constructor.name}`);
21892
22330
  }
21893
22331
  const i18nPlaceholders = text.i18n instanceof Container ?
21894
22332
  text.i18n.children.filter((node) => node instanceof Placeholder) :
@@ -21915,7 +22353,7 @@ function ingestIfBlock(unit, ifBlock) {
21915
22353
  if (firstXref === null) {
21916
22354
  firstXref = cView.xref;
21917
22355
  }
21918
- unit.create.push(createTemplateOp(cView.xref, 'Conditional', Namespace.HTML, true, undefined, ifCase.sourceSpan));
22356
+ unit.create.push(createTemplateOp(cView.xref, 'Conditional', Namespace.HTML, true, undefined /* TODO: figure out how i18n works with new control flow */, ifCase.sourceSpan));
21919
22357
  const caseExpr = ifCase.expression ? convertAst(ifCase.expression, unit.job, null) : null;
21920
22358
  const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, cView.xref, ifCase.expressionAlias);
21921
22359
  conditions.push(conditionalCaseExpr);
@@ -21935,7 +22373,7 @@ function ingestSwitchBlock(unit, switchBlock) {
21935
22373
  if (firstXref === null) {
21936
22374
  firstXref = cView.xref;
21937
22375
  }
21938
- unit.create.push(createTemplateOp(cView.xref, 'Case', Namespace.HTML, true, undefined, switchCase.sourceSpan));
22376
+ unit.create.push(createTemplateOp(cView.xref, 'Case', Namespace.HTML, true, undefined /* TODO: figure out how i18n works with new control flow */, switchCase.sourceSpan));
21939
22377
  const caseExpr = switchCase.expression ?
21940
22378
  convertAst(switchCase.expression, unit.job, switchBlock.startSourceSpan) :
21941
22379
  null;
@@ -21990,6 +22428,16 @@ function ingestDeferBlock(unit, deferBlock) {
21990
22428
  // Add all ops to the view.
21991
22429
  unit.create.push(deferOnOp);
21992
22430
  }
22431
+ function ingestIcu(unit, icu) {
22432
+ if (icu.i18n instanceof Message) {
22433
+ const xref = unit.job.allocateXrefId();
22434
+ unit.create.push(createIcuOp(xref, icu.i18n, null));
22435
+ unit.update.push(createIcuUpdateOp(xref, null));
22436
+ }
22437
+ else {
22438
+ throw Error(`Unhandled i18n metadata type for ICU: ${icu.i18n?.constructor.name}`);
22439
+ }
22440
+ }
21993
22441
  /**
21994
22442
  * Convert a template AST expression into an output AST expression.
21995
22443
  */
@@ -22083,16 +22531,35 @@ function convertAst(ast, job, baseSourceSpan) {
22083
22531
  throw new Error(`Unhandled expression type: ${ast.constructor.name}`);
22084
22532
  }
22085
22533
  }
22534
+ /**
22535
+ * Checks whether the given template is a plain ng-template (as opposed to another kind of template
22536
+ * such as a structural directive template or control flow template). This is checked based on the
22537
+ * tagName. We can expect that only plain ng-templates will come through with a tagName of
22538
+ * 'ng-template'.
22539
+ *
22540
+ * Here are some of the cases we expect:
22541
+ *
22542
+ * | Angular HTML | Template tagName |
22543
+ * | ---------------------------------- | ------------------ |
22544
+ * | `<ng-template>` | 'ng-template' |
22545
+ * | `<div *ngIf="true">` | 'div' |
22546
+ * | `<svg><ng-template>` | 'svg:ng-template' |
22547
+ * | `@if (true) {` | 'Conditional' |
22548
+ * | `<ng-template *ngIf>` (plain) | 'ng-template' |
22549
+ * | `<ng-template *ngIf>` (structural) | null |
22550
+ */
22551
+ function isPlainTemplate(tmpl) {
22552
+ return splitNsName(tmpl.tagName ?? '')[1] === 'ng-template';
22553
+ }
22086
22554
  /**
22087
22555
  * Process all of the bindings on an element-like structure in the template AST and convert them
22088
22556
  * to their IR representation.
22089
22557
  */
22090
22558
  function ingestBindings(unit, op, element) {
22091
22559
  let flags = BindingFlags.None;
22092
- const isPlainTemplate = element instanceof Template && splitNsName(element.tagName ?? '')[1] === 'ng-template';
22093
22560
  if (element instanceof Template) {
22094
22561
  flags |= BindingFlags.OnNgTemplateElement;
22095
- if (isPlainTemplate) {
22562
+ if (element instanceof Template && isPlainTemplate(element)) {
22096
22563
  flags |= BindingFlags.BindingTargetsTemplate;
22097
22564
  }
22098
22565
  const templateAttrFlags = flags | BindingFlags.BindingTargetsTemplate | BindingFlags.IsStructuralTemplateAttribute;
@@ -22121,7 +22588,7 @@ function ingestBindings(unit, op, element) {
22121
22588
  throw Error('Animation listener should have a phase');
22122
22589
  }
22123
22590
  }
22124
- if (element instanceof Template && !isPlainTemplate) {
22591
+ if (element instanceof Template && !isPlainTemplate(element)) {
22125
22592
  unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null));
22126
22593
  continue;
22127
22594
  }
@@ -23385,13 +23852,13 @@ function normalizeNgContentSelect(selectAttr) {
23385
23852
  /** Pattern for the expression in a for loop block. */
23386
23853
  const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+(.*)/;
23387
23854
  /** Pattern for the tracking expression in a for loop block. */
23388
- const FOR_LOOP_TRACK_PATTERN = /^track\s+(.*)/;
23855
+ const FOR_LOOP_TRACK_PATTERN = /^track\s+([\S\s]*)/;
23389
23856
  /** Pattern for the `as` expression in a conditional block. */
23390
23857
  const CONDITIONAL_ALIAS_PATTERN = /^as\s+(.*)/;
23391
23858
  /** Pattern used to identify an `else if` block. */
23392
23859
  const ELSE_IF_PATTERN = /^else[^\S\r\n]+if/;
23393
23860
  /** Pattern used to identify a `let` parameter. */
23394
- const FOR_LOOP_LET_PATTERN = /^let\s+(.*)/;
23861
+ const FOR_LOOP_LET_PATTERN = /^let\s+([\S\s]*)/;
23395
23862
  /** Names of variables that are allowed to be used in the `let` expression of a `for` loop. */
23396
23863
  const ALLOWED_FOR_LOOP_LET_VARIABLES = new Set(['$index', '$first', '$last', '$even', '$odd', '$count']);
23397
23864
  /**
@@ -23412,28 +23879,33 @@ function isConnectedIfLoopBlock(name) {
23412
23879
  function createIfBlock(ast, connectedBlocks, visitor, bindingParser) {
23413
23880
  const errors = validateIfConnectedBlocks(connectedBlocks);
23414
23881
  const branches = [];
23415
- if (errors.length > 0) {
23416
- return { node: null, errors };
23417
- }
23418
23882
  const mainBlockParams = parseConditionalBlockParameters(ast, errors, bindingParser);
23419
23883
  if (mainBlockParams !== null) {
23420
- branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan));
23884
+ branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan));
23421
23885
  }
23422
- // Assumes that the structure is valid since we validated it above.
23423
23886
  for (const block of connectedBlocks) {
23424
- const children = visitAll(visitor, block.children, block.children);
23425
23887
  if (ELSE_IF_PATTERN.test(block.name)) {
23426
23888
  const params = parseConditionalBlockParameters(block, errors, bindingParser);
23427
23889
  if (params !== null) {
23428
- branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan));
23890
+ const children = visitAll(visitor, block.children, block.children);
23891
+ branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan, block.endSourceSpan));
23429
23892
  }
23430
23893
  }
23431
23894
  else if (block.name === 'else') {
23432
- branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan));
23895
+ const children = visitAll(visitor, block.children, block.children);
23896
+ branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan, block.endSourceSpan));
23433
23897
  }
23434
23898
  }
23899
+ // The outer IfBlock should have a span that encapsulates all branches.
23900
+ const ifBlockStartSourceSpan = branches.length > 0 ? branches[0].startSourceSpan : ast.startSourceSpan;
23901
+ const ifBlockEndSourceSpan = branches.length > 0 ? branches[branches.length - 1].endSourceSpan : ast.endSourceSpan;
23902
+ let wholeSourceSpan = ast.sourceSpan;
23903
+ const lastBranch = branches[branches.length - 1];
23904
+ if (lastBranch !== undefined) {
23905
+ wholeSourceSpan = new ParseSourceSpan(ifBlockStartSourceSpan.start, lastBranch.sourceSpan.end);
23906
+ }
23435
23907
  return {
23436
- node: new IfBlock(branches, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
23908
+ node: new IfBlock(branches, wholeSourceSpan, ast.startSourceSpan, ifBlockEndSourceSpan),
23437
23909
  errors,
23438
23910
  };
23439
23911
  }
@@ -23452,7 +23924,7 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
23452
23924
  errors.push(new ParseError(block.sourceSpan, '@empty block cannot have parameters'));
23453
23925
  }
23454
23926
  else {
23455
- empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan);
23927
+ empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan, block.endSourceSpan);
23456
23928
  }
23457
23929
  }
23458
23930
  else {
@@ -23461,10 +23933,16 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
23461
23933
  }
23462
23934
  if (params !== null) {
23463
23935
  if (params.trackBy === null) {
23936
+ // TODO: We should not fail here, and instead try to produce some AST for the language
23937
+ // service.
23464
23938
  errors.push(new ParseError(ast.sourceSpan, '@for loop must have a "track" expression'));
23465
23939
  }
23466
23940
  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);
23941
+ // The `for` block has a main span that includes the `empty` branch. For only the span of the
23942
+ // main `for` body, use `mainSourceSpan`.
23943
+ const endSpan = empty?.endSourceSpan ?? ast.endSourceSpan;
23944
+ const sourceSpan = new ParseSourceSpan(ast.sourceSpan.start, endSpan?.end ?? ast.sourceSpan.end);
23945
+ 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
23946
  }
23469
23947
  }
23470
23948
  return { node, errors };
@@ -23472,21 +23950,25 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
23472
23950
  /** Creates a switch block from an HTML AST node. */
23473
23951
  function createSwitchBlock(ast, visitor, bindingParser) {
23474
23952
  const errors = validateSwitchBlock(ast);
23475
- if (errors.length > 0) {
23476
- return { node: null, errors };
23477
- }
23478
- const primaryExpression = parseBlockParameterToBinding(ast.parameters[0], bindingParser);
23953
+ const primaryExpression = ast.parameters.length > 0 ?
23954
+ parseBlockParameterToBinding(ast.parameters[0], bindingParser) :
23955
+ bindingParser.parseBinding('', false, ast.sourceSpan, 0);
23479
23956
  const cases = [];
23957
+ const unknownBlocks = [];
23480
23958
  let defaultCase = null;
23481
23959
  // Here we assume that all the blocks are valid given that we validated them above.
23482
23960
  for (const node of ast.children) {
23483
23961
  if (!(node instanceof Block)) {
23484
23962
  continue;
23485
23963
  }
23964
+ if ((node.name !== 'case' || node.parameters.length === 0) && node.name !== 'default') {
23965
+ unknownBlocks.push(new UnknownBlock(node.name, node.sourceSpan));
23966
+ continue;
23967
+ }
23486
23968
  const expression = node.name === 'case' ?
23487
23969
  parseBlockParameterToBinding(node.parameters[0], bindingParser) :
23488
23970
  null;
23489
- const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan);
23971
+ const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan, node.endSourceSpan);
23490
23972
  if (expression === null) {
23491
23973
  defaultCase = ast;
23492
23974
  }
@@ -23499,7 +23981,7 @@ function createSwitchBlock(ast, visitor, bindingParser) {
23499
23981
  cases.push(defaultCase);
23500
23982
  }
23501
23983
  return {
23502
- node: new SwitchBlock(primaryExpression, cases, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
23984
+ node: new SwitchBlock(primaryExpression, cases, unknownBlocks, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
23503
23985
  errors
23504
23986
  };
23505
23987
  }
@@ -23543,8 +24025,10 @@ function parseForLoopParameters(block, errors, bindingParser) {
23543
24025
  // Fill out any variables that haven't been defined explicitly.
23544
24026
  for (const variableName of ALLOWED_FOR_LOOP_LET_VARIABLES) {
23545
24027
  if (!result.context.hasOwnProperty(variableName)) {
23546
- result.context[variableName] =
23547
- new Variable(variableName, variableName, block.startSourceSpan, block.startSourceSpan);
24028
+ // Give ambiently-available context variables empty spans at the end of the start of the `for`
24029
+ // block, since they are not explicitly defined.
24030
+ const emptySpanAfterForBlockStart = new ParseSourceSpan(block.startSourceSpan.end, block.startSourceSpan.end);
24031
+ result.context[variableName] = new Variable(variableName, variableName, emptySpanAfterForBlockStart, emptySpanAfterForBlockStart);
23548
24032
  }
23549
24033
  }
23550
24034
  return result;
@@ -24039,7 +24523,17 @@ function createDeferredBlock(ast, connectedBlocks, visitor, bindingParser) {
24039
24523
  const errors = [];
24040
24524
  const { placeholder, loading, error } = parseConnectedBlocks(connectedBlocks, errors, visitor);
24041
24525
  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);
24526
+ // The `defer` block has a main span encompassing all of the connected branches as well. For the
24527
+ // span of only the first "main" branch, use `mainSourceSpan`.
24528
+ let lastEndSourceSpan = ast.endSourceSpan;
24529
+ let endOfLastSourceSpan = ast.sourceSpan.end;
24530
+ if (connectedBlocks.length > 0) {
24531
+ const lastConnectedBlock = connectedBlocks[connectedBlocks.length - 1];
24532
+ lastEndSourceSpan = lastConnectedBlock.endSourceSpan;
24533
+ endOfLastSourceSpan = lastConnectedBlock.sourceSpan.end;
24534
+ }
24535
+ const mainDeferredSourceSpan = new ParseSourceSpan(ast.sourceSpan.start, endOfLastSourceSpan);
24536
+ const node = new DeferredBlock(visitAll(visitor, ast.children, ast.children), triggers, prefetchTriggers, placeholder, loading, error, mainDeferredSourceSpan, ast.sourceSpan, ast.startSourceSpan, lastEndSourceSpan);
24043
24537
  return { node, errors };
24044
24538
  }
24045
24539
  function parseConnectedBlocks(connectedBlocks, errors, visitor) {
@@ -24445,7 +24939,10 @@ class HtmlAstToIvyAst {
24445
24939
  else {
24446
24940
  errorMessage = `Unrecognized block @${block.name}.`;
24447
24941
  }
24448
- result = { node: null, errors: [new ParseError(block.sourceSpan, errorMessage)] };
24942
+ result = {
24943
+ node: new UnknownBlock(block.name, block.sourceSpan),
24944
+ errors: [new ParseError(block.sourceSpan, errorMessage)],
24945
+ };
24449
24946
  break;
24450
24947
  }
24451
24948
  this.errors.push(...result.errors);
@@ -24686,19 +25183,6 @@ function textContents(node) {
24686
25183
  }
24687
25184
  }
24688
25185
 
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
25186
  var TagType;
24703
25187
  (function (TagType) {
24704
25188
  TagType[TagType["ELEMENT"] = 0] = "ELEMENT";
@@ -25046,6 +25530,7 @@ class TemplateDefinitionBuilder {
25046
25530
  this.visitIfBlockBranch = invalid;
25047
25531
  this.visitSwitchBlockCase = invalid;
25048
25532
  this.visitForLoopBlockEmpty = invalid;
25533
+ this.visitUnknownBlock = invalid;
25049
25534
  this._bindingScope = parentBindingScope.nestedScope(level);
25050
25535
  // Turn the relative context file path into an identifier by replacing non-alphanumeric
25051
25536
  // characters with underscores.
@@ -25771,18 +26256,17 @@ class TemplateDefinitionBuilder {
25771
26256
  // callback in order to generate the correct expressions when pipes or pure functions are
25772
26257
  // used inside the branch expressions.
25773
26258
  const branchData = block.branches.map(({ expression, expressionAlias, children, sourceSpan }) => {
25774
- const processedExpression = expression === null ? null : expression.visit(this._valueConverter);
25775
26259
  // If the branch has an alias, it'll be assigned directly to the container's context.
25776
26260
  // We define a variable referring directly to the context so that any nested usages can be
25777
26261
  // rewritten to refer to it.
25778
26262
  const variables = expressionAlias !== null ?
25779
26263
  [new Variable(expressionAlias.name, DIRECT_CONTEXT_REFERENCE, expressionAlias.sourceSpan, expressionAlias.keySpan)] :
25780
26264
  undefined;
25781
- return {
25782
- index: this.createEmbeddedTemplateFn(null, children, '_Conditional', sourceSpan, variables),
25783
- expression: processedExpression,
25784
- alias: expressionAlias
25785
- };
26265
+ // Note: the template needs to be created *before* we process the expression,
26266
+ // otherwise pipes injecting some symbols won't work (see #52102).
26267
+ const index = this.createEmbeddedTemplateFn(null, children, '_Conditional', sourceSpan, variables);
26268
+ const processedExpression = expression === null ? null : expression.visit(this._valueConverter);
26269
+ return { index, expression: processedExpression, alias: expressionAlias };
25786
26270
  });
25787
26271
  // Use the index of the first block as the index for the entire container.
25788
26272
  const containerIndex = branchData[0].index;
@@ -25828,20 +26312,21 @@ class TemplateDefinitionBuilder {
25828
26312
  this.updateInstructionWithAdvance(containerIndex, block.branches[0].sourceSpan, Identifiers.conditional, paramsCallback);
25829
26313
  }
25830
26314
  visitSwitchBlock(block) {
25831
- const blockExpression = block.expression.visit(this._valueConverter);
25832
- this.allocateBindingSlots(null); // Allocate a slot for the primary block expression.
25833
26315
  // We have to process the block in two steps: once here and again in the update instruction
25834
26316
  // callback in order to generate the correct expressions when pipes or pure functions are used.
25835
26317
  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
- };
26318
+ const index = this.createEmbeddedTemplateFn(null, currentCase.children, '_Case', currentCase.sourceSpan);
26319
+ const expression = currentCase.expression === null ?
26320
+ null :
26321
+ currentCase.expression.visit(this._valueConverter);
26322
+ return { index, expression };
25842
26323
  });
25843
26324
  // Use the index of the first block as the index for the entire container.
25844
26325
  const containerIndex = caseData[0].index;
26326
+ // Note: the expression needs to be processed *after* the template,
26327
+ // otherwise pipes injecting some symbols won't work (see #52102).
26328
+ const blockExpression = block.expression.visit(this._valueConverter);
26329
+ this.allocateBindingSlots(null); // Allocate a slot for the primary block expression.
25845
26330
  this.updateInstructionWithAdvance(containerIndex, block.sourceSpan, Identifiers.conditional, () => {
25846
26331
  const generateCases = (caseIndex) => {
25847
26332
  // If we've gone beyond the last branch, return the special -1
@@ -25909,12 +26394,17 @@ class TemplateDefinitionBuilder {
25909
26394
  literal(errorIndex),
25910
26395
  loadingConsts?.length ? this.addToConsts(literalArr(loadingConsts)) : TYPED_NULL_EXPR,
25911
26396
  placeholderConsts ? this.addToConsts(placeholderConsts) : TYPED_NULL_EXPR,
26397
+ (loadingConsts?.length || placeholderConsts) ?
26398
+ importExpr(Identifiers.deferEnableTimerScheduling) :
26399
+ TYPED_NULL_EXPR,
25912
26400
  ]));
25913
- this.createDeferTriggerInstructions(deferredIndex, triggers, metadata, false);
25914
- this.createDeferTriggerInstructions(deferredIndex, prefetchTriggers, metadata, true);
25915
26401
  // Allocate an extra data slot right after a defer block slot to store
25916
26402
  // instance-specific state of that defer block at runtime.
25917
26403
  this.allocateDataSlot();
26404
+ // Note: the triggers need to be processed *after* the various templates,
26405
+ // otherwise pipes injecting some symbols won't work (see #52102).
26406
+ this.createDeferTriggerInstructions(deferredIndex, triggers, metadata, false);
26407
+ this.createDeferTriggerInstructions(deferredIndex, prefetchTriggers, metadata, true);
25918
26408
  }
25919
26409
  createDeferredDepsFunction(name, metadata) {
25920
26410
  if (metadata.deps.length === 0) {
@@ -26006,12 +26496,13 @@ class TemplateDefinitionBuilder {
26006
26496
  // are implicitly inferred by the runtime to index + 1 and index + 2.
26007
26497
  const blockIndex = this.allocateDataSlot();
26008
26498
  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
26499
  const { expression: trackByExpression, usesComponentInstance: trackByUsesComponentInstance } = this.createTrackByFunction(block);
26013
- const value = block.expression.visit(this._valueConverter);
26014
- this.allocateBindingSlots(value);
26500
+ let emptyData = null;
26501
+ if (block.empty !== null) {
26502
+ emptyData = this.prepareEmbeddedTemplateFn(block.empty.children, '_ForEmpty');
26503
+ // Allocate an extra slot for the empty block tracking.
26504
+ this.allocateBindingSlots(null);
26505
+ }
26015
26506
  this.registerComputedLoopVariables(block, primaryData.scope);
26016
26507
  // `repeaterCreate(0, ...)`
26017
26508
  this.creationInstruction(block.sourceSpan, Identifiers.repeaterCreate, () => {
@@ -26031,6 +26522,11 @@ class TemplateDefinitionBuilder {
26031
26522
  }
26032
26523
  return params;
26033
26524
  });
26525
+ // Note: the expression needs to be processed *after* the template,
26526
+ // otherwise pipes injecting some symbols won't work (see #52102).
26527
+ // Note: we don't allocate binding slots for this expression,
26528
+ // because its value isn't stored in the LView.
26529
+ const value = block.expression.visit(this._valueConverter);
26034
26530
  // `repeater(0, iterable)`
26035
26531
  this.updateInstruction(block.sourceSpan, Identifiers.repeater, () => [literal(blockIndex), this.convertPropertyBinding(value)]);
26036
26532
  }
@@ -26906,7 +27402,7 @@ function parseTemplate(template, templateUrl, options = {}) {
26906
27402
  leadingTriviaChars: LEADING_TRIVIA_CHARS,
26907
27403
  ...options,
26908
27404
  tokenizeExpansionForms: true,
26909
- tokenizeBlocks: options.enableBlockSyntax ?? BLOCK_SYNTAX_ENABLED_DEFAULT,
27405
+ tokenizeBlocks: options.enableBlockSyntax ?? true,
26910
27406
  });
26911
27407
  if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
26912
27408
  parseResult.errors.length > 0) {
@@ -28051,6 +28547,7 @@ class Scope {
28051
28547
  visitTextAttribute(attr) { }
28052
28548
  visitIcu(icu) { }
28053
28549
  visitDeferredTrigger(trigger) { }
28550
+ visitUnknownBlock(block) { }
28054
28551
  maybeDeclare(thing) {
28055
28552
  // Declare something with a name, as long as that name isn't taken.
28056
28553
  if (!this.namedEntities.has(thing.name)) {
@@ -28252,6 +28749,7 @@ class DirectiveBinder {
28252
28749
  visitBoundText(text) { }
28253
28750
  visitIcu(icu) { }
28254
28751
  visitDeferredTrigger(trigger) { }
28752
+ visitUnknownBlock(block) { }
28255
28753
  }
28256
28754
  /**
28257
28755
  * Processes a template and extract metadata about expressions and symbols within.
@@ -28380,6 +28878,8 @@ class TemplateBinder extends RecursiveAstVisitor {
28380
28878
  visitText(text) { }
28381
28879
  visitContent(content) { }
28382
28880
  visitTextAttribute(attribute) { }
28881
+ visitUnknownBlock(block) { }
28882
+ visitDeferredTrigger() { }
28383
28883
  visitIcu(icu) {
28384
28884
  Object.keys(icu.vars).forEach(key => icu.vars[key].visit(this));
28385
28885
  Object.keys(icu.placeholders).forEach(key => icu.placeholders[key].visit(this));
@@ -28394,15 +28894,12 @@ class TemplateBinder extends RecursiveAstVisitor {
28394
28894
  visitDeferredBlock(deferred) {
28395
28895
  this.deferBlocks.add(deferred);
28396
28896
  this.ingestScopedNode(deferred);
28897
+ deferred.triggers.when?.value.visit(this);
28898
+ deferred.prefetchTriggers.when?.value.visit(this);
28397
28899
  deferred.placeholder && this.visitNode(deferred.placeholder);
28398
28900
  deferred.loading && this.visitNode(deferred.loading);
28399
28901
  deferred.error && this.visitNode(deferred.error);
28400
28902
  }
28401
- visitDeferredTrigger(trigger) {
28402
- if (trigger instanceof BoundDeferredTrigger) {
28403
- trigger.value.visit(this);
28404
- }
28405
- }
28406
28903
  visitDeferredBlockPlaceholder(block) {
28407
28904
  this.ingestScopedNode(block);
28408
28905
  }
@@ -29259,13 +29756,11 @@ function publishFacade(global) {
29259
29756
  * @description
29260
29757
  * Entry point for all public APIs of the compiler package.
29261
29758
  */
29262
- const VERSION = new Version('17.0.0-next.7');
29759
+ const VERSION = new Version('17.0.0-rc.0');
29263
29760
 
29264
29761
  class CompilerConfig {
29265
- constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
29762
+ constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
29266
29763
  this.defaultEncapsulation = defaultEncapsulation;
29267
- this.useJit = !!useJit;
29268
- this.missingTranslation = missingTranslation;
29269
29764
  this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
29270
29765
  this.strictInjectionParameters = strictInjectionParameters === true;
29271
29766
  }
@@ -30755,6 +31250,31 @@ function compileComponentClassMetadata(metadata, deferrableTypes) {
30755
31250
  return iife.callFn([]);
30756
31251
  }
30757
31252
 
31253
+ /**
31254
+ * Generate an ngDevMode guarded call to setClassDebugInfo with the debug info about the class
31255
+ * (e.g., the file name in which the class is defined)
31256
+ */
31257
+ function compileClassDebugInfo(debugInfo) {
31258
+ const debugInfoObject = {
31259
+ className: debugInfo.className,
31260
+ };
31261
+ // Include file path and line number only if the file relative path is calculated successfully.
31262
+ if (debugInfo.filePath) {
31263
+ debugInfoObject.filePath = debugInfo.filePath;
31264
+ debugInfoObject.lineNumber = debugInfo.lineNumber;
31265
+ }
31266
+ // Include forbidOrphanRendering only if it's set to true (to reduce generated code)
31267
+ if (debugInfo.forbidOrphanRendering) {
31268
+ debugInfoObject.forbidOrphanRendering = literal(true);
31269
+ }
31270
+ const fnCall = importExpr(Identifiers.setClassDebugInfo).callFn([
31271
+ debugInfo.type,
31272
+ mapLiteral(debugInfoObject),
31273
+ ]);
31274
+ const iife = arrowFn([], [devOnlyGuardedExpression(fnCall).toStmt()]);
31275
+ return iife.callFn([]);
31276
+ }
31277
+
30758
31278
  /**
30759
31279
  * Every time we make a breaking change to the declaration interface or partial-linker behavior, we
30760
31280
  * must update this constant to prevent old partial-linkers from incorrectly processing the
@@ -30766,7 +31286,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
30766
31286
  function compileDeclareClassMetadata(metadata) {
30767
31287
  const definitionMap = new DefinitionMap();
30768
31288
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
30769
- definitionMap.set('version', literal('17.0.0-next.7'));
31289
+ definitionMap.set('version', literal('17.0.0-rc.0'));
30770
31290
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30771
31291
  definitionMap.set('type', metadata.type);
30772
31292
  definitionMap.set('decorators', metadata.decorators);
@@ -30874,7 +31394,7 @@ function createDirectiveDefinitionMap(meta) {
30874
31394
  // in 16.1 is actually used.
30875
31395
  const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
30876
31396
  definitionMap.set('minVersion', literal(minVersion));
30877
- definitionMap.set('version', literal('17.0.0-next.7'));
31397
+ definitionMap.set('version', literal('17.0.0-rc.0'));
30878
31398
  // e.g. `type: MyDirective`
30879
31399
  definitionMap.set('type', meta.type.value);
30880
31400
  if (meta.isStandalone) {
@@ -31151,7 +31671,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
31151
31671
  function compileDeclareFactoryFunction(meta) {
31152
31672
  const definitionMap = new DefinitionMap();
31153
31673
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
31154
- definitionMap.set('version', literal('17.0.0-next.7'));
31674
+ definitionMap.set('version', literal('17.0.0-rc.0'));
31155
31675
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31156
31676
  definitionMap.set('type', meta.type.value);
31157
31677
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -31186,7 +31706,7 @@ function compileDeclareInjectableFromMetadata(meta) {
31186
31706
  function createInjectableDefinitionMap(meta) {
31187
31707
  const definitionMap = new DefinitionMap();
31188
31708
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
31189
- definitionMap.set('version', literal('17.0.0-next.7'));
31709
+ definitionMap.set('version', literal('17.0.0-rc.0'));
31190
31710
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31191
31711
  definitionMap.set('type', meta.type.value);
31192
31712
  // Only generate providedIn property if it has a non-null value
@@ -31237,7 +31757,7 @@ function compileDeclareInjectorFromMetadata(meta) {
31237
31757
  function createInjectorDefinitionMap(meta) {
31238
31758
  const definitionMap = new DefinitionMap();
31239
31759
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
31240
- definitionMap.set('version', literal('17.0.0-next.7'));
31760
+ definitionMap.set('version', literal('17.0.0-rc.0'));
31241
31761
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31242
31762
  definitionMap.set('type', meta.type.value);
31243
31763
  definitionMap.set('providers', meta.providers);
@@ -31270,7 +31790,7 @@ function createNgModuleDefinitionMap(meta) {
31270
31790
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
31271
31791
  }
31272
31792
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
31273
- definitionMap.set('version', literal('17.0.0-next.7'));
31793
+ definitionMap.set('version', literal('17.0.0-rc.0'));
31274
31794
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31275
31795
  definitionMap.set('type', meta.type.value);
31276
31796
  // We only generate the keys in the metadata if the arrays contain values.
@@ -31321,7 +31841,7 @@ function compileDeclarePipeFromMetadata(meta) {
31321
31841
  function createPipeDefinitionMap(meta) {
31322
31842
  const definitionMap = new DefinitionMap();
31323
31843
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
31324
- definitionMap.set('version', literal('17.0.0-next.7'));
31844
+ definitionMap.set('version', literal('17.0.0-rc.0'));
31325
31845
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31326
31846
  // e.g. `type: MyPipe`
31327
31847
  definitionMap.set('type', meta.type.value);
@@ -31354,5 +31874,5 @@ publishFacade(_global);
31354
31874
 
31355
31875
  // This file is not used to build this module. It is only used during editing
31356
31876
 
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 };
31877
+ 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
31878
  //# sourceMappingURL=compiler.mjs.map