@angular/compiler 17.1.0-next.3 → 17.1.0-next.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/esm2022/src/compiler.mjs +2 -2
  2. package/esm2022/src/compiler_facade_interface.mjs +1 -1
  3. package/esm2022/src/jit_compiler_facade.mjs +46 -17
  4. package/esm2022/src/render3/partial/api.mjs +1 -1
  5. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  6. package/esm2022/src/render3/partial/directive.mjs +112 -17
  7. package/esm2022/src/render3/partial/factory.mjs +1 -1
  8. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  9. package/esm2022/src/render3/partial/injector.mjs +1 -1
  10. package/esm2022/src/render3/partial/ng_module.mjs +1 -1
  11. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  12. package/esm2022/src/render3/r3_identifiers.mjs +4 -1
  13. package/esm2022/src/render3/view/api.mjs +1 -1
  14. package/esm2022/src/render3/view/compiler.mjs +24 -9
  15. package/esm2022/src/render3/view/util.mjs +8 -2
  16. package/esm2022/src/template/pipeline/ir/src/enums.mjs +9 -17
  17. package/esm2022/src/template/pipeline/ir/src/expression.mjs +12 -20
  18. package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +14 -6
  19. package/esm2022/src/template/pipeline/ir/src/ops/host.mjs +4 -2
  20. package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +15 -9
  21. package/esm2022/src/template/pipeline/src/emit.mjs +4 -4
  22. package/esm2022/src/template/pipeline/src/ingest.mjs +240 -155
  23. package/esm2022/src/template/pipeline/src/instruction.mjs +14 -14
  24. package/esm2022/src/template/pipeline/src/phases/assign_i18n_slot_dependencies.mjs +40 -56
  25. package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +15 -8
  26. package/esm2022/src/template/pipeline/src/phases/binding_specialization.mjs +4 -4
  27. package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +13 -4
  28. package/esm2022/src/template/pipeline/src/phases/create_i18n_contexts.mjs +23 -1
  29. package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +7 -1
  30. package/esm2022/src/template/pipeline/src/phases/i18n_const_collection.mjs +10 -6
  31. package/esm2022/src/template/pipeline/src/phases/parse_extracted_styles.mjs +4 -3
  32. package/esm2022/src/template/pipeline/src/phases/propagate_i18n_blocks.mjs +27 -12
  33. package/esm2022/src/template/pipeline/src/phases/reify.mjs +12 -15
  34. package/esm2022/src/template/pipeline/src/phases/resolve_i18n_element_placeholders.mjs +60 -14
  35. package/esm2022/src/template/pipeline/src/phases/resolve_sanitizers.mjs +78 -14
  36. package/esm2022/src/template/pipeline/src/phases/slot_allocation.mjs +3 -1
  37. package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +3 -1
  38. package/esm2022/src/version.mjs +1 -1
  39. package/fesm2022/compiler.mjs +778 -392
  40. package/fesm2022/compiler.mjs.map +1 -1
  41. package/index.d.ts +39 -6
  42. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v17.1.0-next.3
2
+ * @license Angular v17.1.0-next.4
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -2636,6 +2636,9 @@ class Identifiers {
2636
2636
  static { this.trustConstantHtml = { name: 'ɵɵtrustConstantHtml', moduleName: CORE }; }
2637
2637
  static { this.trustConstantResourceUrl = { name: 'ɵɵtrustConstantResourceUrl', moduleName: CORE }; }
2638
2638
  static { this.validateIframeAttribute = { name: 'ɵɵvalidateIframeAttribute', moduleName: CORE }; }
2639
+ // type-checking
2640
+ static { this.InputSignalBrandWriteType = { name: 'ɵINPUT_SIGNAL_BRAND_WRITE_TYPE', moduleName: CORE }; }
2641
+ static { this.UnwrapDirectiveSignalInputs = { name: 'ɵUnwrapDirectiveSignalInputs', moduleName: CORE }; }
2639
2642
  }
2640
2643
 
2641
2644
  const DASH_CASE_REGEXP = /-+([a-z0-9])/g;
@@ -4957,6 +4960,12 @@ function asLiteral(value) {
4957
4960
  }
4958
4961
  return literal(value, INFERRED_TYPE);
4959
4962
  }
4963
+ /**
4964
+ * Serializes inputs and outputs for `defineDirective` and `defineComponent`.
4965
+ *
4966
+ * This will attempt to generate optimized data structures to minimize memory or
4967
+ * file size of fully compiled applications.
4968
+ */
4960
4969
  function conditionallyCreateDirectiveBindingLiteral(map, keepDeclared) {
4961
4970
  const keys = Object.getOwnPropertyNames(map);
4962
4971
  if (keys.length === 0) {
@@ -9064,23 +9073,27 @@ var ExpressionKind;
9064
9073
  * An expression representing a sanitizer function.
9065
9074
  */
9066
9075
  ExpressionKind[ExpressionKind["SanitizerExpr"] = 20] = "SanitizerExpr";
9076
+ /**
9077
+ * An expression representing a function to create trusted values.
9078
+ */
9079
+ ExpressionKind[ExpressionKind["TrustedValueFnExpr"] = 21] = "TrustedValueFnExpr";
9067
9080
  /**
9068
9081
  * An expression that will cause a literal slot index to be emitted.
9069
9082
  */
9070
- ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 21] = "SlotLiteralExpr";
9083
+ ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 22] = "SlotLiteralExpr";
9071
9084
  /**
9072
9085
  * A test expression for a conditional op.
9073
9086
  */
9074
- ExpressionKind[ExpressionKind["ConditionalCase"] = 22] = "ConditionalCase";
9087
+ ExpressionKind[ExpressionKind["ConditionalCase"] = 23] = "ConditionalCase";
9075
9088
  /**
9076
9089
  * A variable for use inside a repeater, providing one of the ambiently-available context
9077
9090
  * properties ($even, $first, etc.).
9078
9091
  */
9079
- ExpressionKind[ExpressionKind["DerivedRepeaterVar"] = 23] = "DerivedRepeaterVar";
9092
+ ExpressionKind[ExpressionKind["DerivedRepeaterVar"] = 24] = "DerivedRepeaterVar";
9080
9093
  /**
9081
9094
  * An expression that will be automatically extracted to the component const array.
9082
9095
  */
9083
- ExpressionKind[ExpressionKind["ConstCollected"] = 24] = "ConstCollected";
9096
+ ExpressionKind[ExpressionKind["ConstCollected"] = 25] = "ConstCollected";
9084
9097
  })(ExpressionKind || (ExpressionKind = {}));
9085
9098
  var VariableFlags;
9086
9099
  (function (VariableFlags) {
@@ -9124,18 +9137,6 @@ var CompatibilityMode;
9124
9137
  CompatibilityMode[CompatibilityMode["Normal"] = 0] = "Normal";
9125
9138
  CompatibilityMode[CompatibilityMode["TemplateDefinitionBuilder"] = 1] = "TemplateDefinitionBuilder";
9126
9139
  })(CompatibilityMode || (CompatibilityMode = {}));
9127
- /**
9128
- * Represents functions used to sanitize different pieces of a template.
9129
- */
9130
- var SanitizerFn;
9131
- (function (SanitizerFn) {
9132
- SanitizerFn[SanitizerFn["Html"] = 0] = "Html";
9133
- SanitizerFn[SanitizerFn["Script"] = 1] = "Script";
9134
- SanitizerFn[SanitizerFn["Style"] = 2] = "Style";
9135
- SanitizerFn[SanitizerFn["Url"] = 3] = "Url";
9136
- SanitizerFn[SanitizerFn["ResourceUrl"] = 4] = "ResourceUrl";
9137
- SanitizerFn[SanitizerFn["IframeAttribute"] = 5] = "IframeAttribute";
9138
- })(SanitizerFn || (SanitizerFn = {}));
9139
9140
  /**
9140
9141
  * Enumeration of the different kinds of `@defer` secondary blocks.
9141
9142
  */
@@ -9414,7 +9415,7 @@ class Interpolation {
9414
9415
  /**
9415
9416
  * Create a `BindingOp`, not yet transformed into a particular type of binding.
9416
9417
  */
9417
- function createBindingOp(target, kind, name, expression, unit, securityContext, isTextAttribute, isStructuralTemplate, i18nContext, sourceSpan) {
9418
+ function createBindingOp(target, kind, name, expression, unit, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
9418
9419
  return {
9419
9420
  kind: OpKind.Binding,
9420
9421
  bindingKind: kind,
@@ -9424,8 +9425,10 @@ function createBindingOp(target, kind, name, expression, unit, securityContext,
9424
9425
  unit,
9425
9426
  securityContext,
9426
9427
  isTextAttribute,
9427
- isStructuralTemplate: isStructuralTemplate,
9428
- i18nContext,
9428
+ isStructuralTemplateAttribute,
9429
+ templateKind,
9430
+ i18nContext: null,
9431
+ i18nMessage,
9429
9432
  sourceSpan,
9430
9433
  ...NEW_OP,
9431
9434
  };
@@ -9433,7 +9436,7 @@ function createBindingOp(target, kind, name, expression, unit, securityContext,
9433
9436
  /**
9434
9437
  * Create a `PropertyOp`.
9435
9438
  */
9436
- function createPropertyOp(target, name, expression, isAnimationTrigger, securityContext, isStructuralTemplate, i18nContext, sourceSpan) {
9439
+ function createPropertyOp(target, name, expression, isAnimationTrigger, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
9437
9440
  return {
9438
9441
  kind: OpKind.Property,
9439
9442
  target,
@@ -9442,8 +9445,10 @@ function createPropertyOp(target, name, expression, isAnimationTrigger, security
9442
9445
  isAnimationTrigger,
9443
9446
  securityContext,
9444
9447
  sanitizer: null,
9445
- isStructuralTemplate,
9448
+ isStructuralTemplateAttribute,
9449
+ templateKind,
9446
9450
  i18nContext,
9451
+ i18nMessage,
9447
9452
  sourceSpan,
9448
9453
  ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
9449
9454
  ...TRAIT_CONSUMES_VARS,
@@ -9508,7 +9513,7 @@ function createClassMapOp(xref, expression, sourceSpan) {
9508
9513
  /**
9509
9514
  * Create an `AttributeOp`.
9510
9515
  */
9511
- function createAttributeOp(target, name, expression, securityContext, isTextAttribute, isStructuralTemplate, i18nContext, sourceSpan) {
9516
+ function createAttributeOp(target, name, expression, securityContext, isTextAttribute, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
9512
9517
  return {
9513
9518
  kind: OpKind.Attribute,
9514
9519
  target,
@@ -9517,8 +9522,10 @@ function createAttributeOp(target, name, expression, securityContext, isTextAttr
9517
9522
  securityContext,
9518
9523
  sanitizer: null,
9519
9524
  isTextAttribute,
9520
- isStructuralTemplate,
9521
- i18nContext,
9525
+ isStructuralTemplateAttribute,
9526
+ templateKind,
9527
+ i18nContext: null,
9528
+ i18nMessage,
9522
9529
  sourceSpan,
9523
9530
  ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
9524
9531
  ...TRAIT_CONSUMES_VARS,
@@ -10152,24 +10159,6 @@ class ReadTemporaryExpr extends ExpressionBase {
10152
10159
  return r;
10153
10160
  }
10154
10161
  }
10155
- class SanitizerExpr extends ExpressionBase {
10156
- constructor(fn) {
10157
- super();
10158
- this.fn = fn;
10159
- this.kind = ExpressionKind.SanitizerExpr;
10160
- }
10161
- visitExpression(visitor, context) { }
10162
- isEquivalent(e) {
10163
- return e instanceof SanitizerExpr && e.fn === this.fn;
10164
- }
10165
- isConstant() {
10166
- return true;
10167
- }
10168
- clone() {
10169
- return new SanitizerExpr(this.fn);
10170
- }
10171
- transformInternalExpressions() { }
10172
- }
10173
10162
  class SlotLiteralExpr extends ExpressionBase {
10174
10163
  constructor(slot) {
10175
10164
  super();
@@ -10300,7 +10289,6 @@ function transformExpressionsInOp(op, transform, flags) {
10300
10289
  case OpKind.ClassProp:
10301
10290
  case OpKind.ClassMap:
10302
10291
  case OpKind.Binding:
10303
- case OpKind.HostProperty:
10304
10292
  if (op.expression instanceof Interpolation) {
10305
10293
  transformExpressionsInInterpolation(op.expression, transform, flags);
10306
10294
  }
@@ -10309,6 +10297,7 @@ function transformExpressionsInOp(op, transform, flags) {
10309
10297
  }
10310
10298
  break;
10311
10299
  case OpKind.Property:
10300
+ case OpKind.HostProperty:
10312
10301
  case OpKind.Attribute:
10313
10302
  if (op.expression instanceof Interpolation) {
10314
10303
  transformExpressionsInInterpolation(op.expression, transform, flags);
@@ -10354,6 +10343,8 @@ function transformExpressionsInOp(op, transform, flags) {
10354
10343
  case OpKind.ExtractedAttribute:
10355
10344
  op.expression =
10356
10345
  op.expression && transformExpressionsInExpression(op.expression, transform, flags);
10346
+ op.trustedValueFn = op.trustedValueFn &&
10347
+ transformExpressionsInExpression(op.trustedValueFn, transform, flags);
10357
10348
  break;
10358
10349
  case OpKind.RepeaterCreate:
10359
10350
  op.track = transformExpressionsInExpression(op.track, transform, flags);
@@ -10485,6 +10476,14 @@ function transformExpressionsInExpression(expr, transform, flags) {
10485
10476
  else if (expr instanceof NotExpr) {
10486
10477
  expr.condition = transformExpressionsInExpression(expr.condition, transform, flags);
10487
10478
  }
10479
+ else if (expr instanceof TaggedTemplateExpr) {
10480
+ expr.tag = transformExpressionsInExpression(expr.tag, transform, flags);
10481
+ expr.template.expressions =
10482
+ expr.template.expressions.map(e => transformExpressionsInExpression(e, transform, flags));
10483
+ }
10484
+ else if (expr instanceof WrappedNodeExpr) {
10485
+ // TODO: Do we need to transform any TS nodes nested inside of this expression?
10486
+ }
10488
10487
  else if (expr instanceof ReadVarExpr || expr instanceof ExternalExpr ||
10489
10488
  expr instanceof LiteralExpr) {
10490
10489
  // No action for these types.
@@ -10846,7 +10845,7 @@ function createTemplateOp(xref, templateKind, tag, functionNameSuffix, namespace
10846
10845
  ...NEW_OP,
10847
10846
  };
10848
10847
  }
10849
- function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, sourceSpan) {
10848
+ function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, i18nPlaceholder, emptyI18nPlaceholder, sourceSpan) {
10850
10849
  return {
10851
10850
  kind: OpKind.RepeaterCreate,
10852
10851
  attributes: null,
@@ -10864,6 +10863,8 @@ function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, so
10864
10863
  vars: null,
10865
10864
  varNames,
10866
10865
  usesComponentInstance: false,
10866
+ i18nPlaceholder,
10867
+ emptyI18nPlaceholder,
10867
10868
  sourceSpan,
10868
10869
  ...TRAIT_CONSUMES_SLOT,
10869
10870
  ...NEW_OP,
@@ -10912,7 +10913,9 @@ function createTextOp(xref, initialValue, sourceSpan) {
10912
10913
  /**
10913
10914
  * Create a `ListenerOp`. Host bindings reuse all the listener logic.
10914
10915
  */
10915
- function createListenerOp(target, targetSlot, name, tag, animationPhase, hostListener, sourceSpan) {
10916
+ function createListenerOp(target, targetSlot, name, tag, handlerOps, animationPhase, eventTarget, hostListener, sourceSpan) {
10917
+ const handlerList = new OpList();
10918
+ handlerList.push(handlerOps);
10916
10919
  return {
10917
10920
  kind: OpKind.Listener,
10918
10921
  target,
@@ -10920,11 +10923,12 @@ function createListenerOp(target, targetSlot, name, tag, animationPhase, hostLis
10920
10923
  tag,
10921
10924
  hostListener,
10922
10925
  name,
10923
- handlerOps: new OpList(),
10926
+ handlerOps: handlerList,
10924
10927
  handlerFnName: null,
10925
10928
  consumesDollarEvent: false,
10926
10929
  isAnimationListener: animationPhase !== null,
10927
- animationPhase: animationPhase,
10930
+ animationPhase,
10931
+ eventTarget,
10928
10932
  sourceSpan,
10929
10933
  ...NEW_OP,
10930
10934
  };
@@ -10971,7 +10975,7 @@ function createProjectionOp(xref, selector, i18nPlaceholder, attributes, sourceS
10971
10975
  /**
10972
10976
  * Create an `ExtractedAttributeOp`.
10973
10977
  */
10974
- function createExtractedAttributeOp(target, bindingKind, name, expression, i18nContext) {
10978
+ function createExtractedAttributeOp(target, bindingKind, name, expression, i18nContext, i18nMessage, securityContext) {
10975
10979
  return {
10976
10980
  kind: OpKind.ExtractedAttribute,
10977
10981
  target,
@@ -10979,6 +10983,9 @@ function createExtractedAttributeOp(target, bindingKind, name, expression, i18nC
10979
10983
  name,
10980
10984
  expression,
10981
10985
  i18nContext,
10986
+ i18nMessage,
10987
+ securityContext,
10988
+ trustedValueFn: null,
10982
10989
  ...NEW_OP,
10983
10990
  };
10984
10991
  }
@@ -11121,13 +11128,15 @@ function literalOrArrayLiteral$1(value) {
11121
11128
  return literal(value, INFERRED_TYPE);
11122
11129
  }
11123
11130
 
11124
- function createHostPropertyOp(name, expression, isAnimationTrigger, i18nContext, sourceSpan) {
11131
+ function createHostPropertyOp(name, expression, isAnimationTrigger, i18nContext, securityContext, sourceSpan) {
11125
11132
  return {
11126
11133
  kind: OpKind.HostProperty,
11127
11134
  name,
11128
11135
  expression,
11129
11136
  isAnimationTrigger,
11130
11137
  i18nContext,
11138
+ securityContext,
11139
+ sanitizer: null,
11131
11140
  sourceSpan,
11132
11141
  ...TRAIT_CONSUMES_VARS,
11133
11142
  ...NEW_OP,
@@ -11407,68 +11416,52 @@ function needsApplication(i18nContexts, op) {
11407
11416
  * after the last update instruction that depends on that slot.
11408
11417
  */
11409
11418
  function assignI18nSlotDependencies(job) {
11410
- const i18nLastSlotConsumers = new Map();
11411
- let lastSlotConsumer = null;
11412
- let currentI18nOp = null;
11413
11419
  for (const unit of job.units) {
11414
- // Record the last consumed slot before each i18n end instruction.
11415
- for (const op of unit.create) {
11416
- if (hasConsumesSlotTrait(op)) {
11417
- lastSlotConsumer = op.xref;
11420
+ // The first update op.
11421
+ let updateOp = unit.update.head;
11422
+ // I18n expressions currently being moved during the iteration.
11423
+ let i18nExpressionsInProgress = [];
11424
+ // Non-null while we are iterating through an i18nStart/i18nEnd pair
11425
+ let state = null;
11426
+ for (const createOp of unit.create) {
11427
+ if (createOp.kind === OpKind.I18nStart) {
11428
+ state = {
11429
+ blockXref: createOp.xref,
11430
+ lastSlotConsumer: createOp.xref,
11431
+ };
11418
11432
  }
11419
- switch (op.kind) {
11420
- case OpKind.I18nStart:
11421
- currentI18nOp = op;
11422
- break;
11423
- case OpKind.I18nEnd:
11424
- if (currentI18nOp === null) {
11425
- throw new Error('AssertionError: Expected an active I18n block while calculating last slot consumers');
11433
+ else if (createOp.kind === OpKind.I18nEnd) {
11434
+ for (const op of i18nExpressionsInProgress) {
11435
+ op.target = state.lastSlotConsumer;
11436
+ OpList.insertBefore(op, updateOp);
11437
+ }
11438
+ i18nExpressionsInProgress.length = 0;
11439
+ state = null;
11440
+ }
11441
+ if (hasConsumesSlotTrait(createOp)) {
11442
+ if (state !== null) {
11443
+ state.lastSlotConsumer = createOp.xref;
11444
+ }
11445
+ while (true) {
11446
+ if (updateOp.next === null) {
11447
+ break;
11426
11448
  }
11427
- if (lastSlotConsumer === null) {
11428
- throw new Error('AssertionError: Expected a last slot consumer while calculating last slot consumers');
11449
+ if (state !== null && updateOp.kind === OpKind.I18nExpression &&
11450
+ updateOp.usage === I18nExpressionFor.I18nText &&
11451
+ updateOp.i18nOwner === state.blockXref) {
11452
+ const opToRemove = updateOp;
11453
+ updateOp = updateOp.next;
11454
+ OpList.remove(opToRemove);
11455
+ i18nExpressionsInProgress.push(opToRemove);
11456
+ continue;
11429
11457
  }
11430
- i18nLastSlotConsumers.set(currentI18nOp.xref, lastSlotConsumer);
11431
- currentI18nOp = null;
11432
- break;
11433
- }
11434
- }
11435
- // Expresions that are currently being moved.
11436
- let opsToMove = [];
11437
- // Previously we found the last slot-consuming create mode op in the i18n block. That op will be
11438
- // the new target for any moved i18n expresion inside the i18n block, and that op's slot is
11439
- // stored here.
11440
- let moveAfterTarget = null;
11441
- // This is the last target in the create IR that we saw during iteration. Eventally, it will be
11442
- // equal to moveAfterTarget. But wait! We need to find the *last* such op whose target is equal
11443
- // to `moveAfterTarget`.
11444
- let previousTarget = null;
11445
- for (const op of unit.update) {
11446
- if (hasDependsOnSlotContextTrait(op)) {
11447
- // We've found an op that depends on another slot other than the one that we want to move
11448
- // the expressions to, after previously having seen the one we want to move to.
11449
- if (moveAfterTarget !== null && previousTarget === moveAfterTarget &&
11450
- op.target !== previousTarget) {
11451
- OpList.insertBefore(opsToMove, op);
11452
- moveAfterTarget = null;
11453
- opsToMove = [];
11454
- }
11455
- previousTarget = op.target;
11456
- }
11457
- if (op.kind === OpKind.I18nExpression && op.usage === I18nExpressionFor.I18nText) {
11458
- // This is an I18nExpressionOps that is used for text (not attributes).
11459
- OpList.remove(op);
11460
- opsToMove.push(op);
11461
- const target = i18nLastSlotConsumers.get(op.i18nOwner);
11462
- if (target === undefined) {
11463
- throw new Error('AssertionError: Expected to find a last slot consumer for an I18nExpressionOp');
11458
+ if (hasDependsOnSlotContextTrait(updateOp) && updateOp.target !== createOp.xref) {
11459
+ break;
11460
+ }
11461
+ updateOp = updateOp.next;
11464
11462
  }
11465
- op.target = target;
11466
- moveAfterTarget = op.target;
11467
11463
  }
11468
11464
  }
11469
- if (moveAfterTarget !== null) {
11470
- unit.update.push(opsToMove);
11471
- }
11472
11465
  }
11473
11466
  }
11474
11467
 
@@ -11501,19 +11494,21 @@ function extractAttributes(job) {
11501
11494
  case OpKind.Property:
11502
11495
  if (!op.isAnimationTrigger) {
11503
11496
  let bindingKind;
11504
- if (op.i18nContext !== null) {
11497
+ if (op.i18nMessage !== null && op.templateKind === null) {
11505
11498
  // If the binding has an i18n context, it is an i18n attribute, and should have that
11506
11499
  // kind in the consts array.
11507
11500
  bindingKind = BindingKind.I18n;
11508
11501
  }
11509
- else if (op.isStructuralTemplate) {
11510
- // TODO: How do i18n attributes on templates work?!
11502
+ else if (op.isStructuralTemplateAttribute) {
11511
11503
  bindingKind = BindingKind.Template;
11512
11504
  }
11513
11505
  else {
11514
11506
  bindingKind = BindingKind.Property;
11515
11507
  }
11516
- OpList.insertBefore(createExtractedAttributeOp(op.target, bindingKind, op.name, null, null), lookupElement$2(elements, op.target));
11508
+ OpList.insertBefore(
11509
+ // Deliberaly null i18nMessage value
11510
+ createExtractedAttributeOp(op.target, bindingKind, op.name, /* expression */ null, /* i18nContext */ null,
11511
+ /* i18nMessage */ null, op.securityContext), lookupElement$2(elements, op.target));
11517
11512
  }
11518
11513
  break;
11519
11514
  case OpKind.StyleProp:
@@ -11524,12 +11519,16 @@ function extractAttributes(job) {
11524
11519
  // mode.
11525
11520
  if (unit.job.compatibility === CompatibilityMode.TemplateDefinitionBuilder &&
11526
11521
  op.expression instanceof EmptyExpr) {
11527
- OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null, null), lookupElement$2(elements, op.target));
11522
+ OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.Property, op.name, /* expression */ null,
11523
+ /* i18nContext */ null,
11524
+ /* i18nMessage */ null, SecurityContext.STYLE), lookupElement$2(elements, op.target));
11528
11525
  }
11529
11526
  break;
11530
11527
  case OpKind.Listener:
11531
11528
  if (!op.isAnimationListener) {
11532
- const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, op.name, null, null);
11529
+ const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, op.name, /* expression */ null,
11530
+ /* i18nContext */ null,
11531
+ /* i18nMessage */ null, SecurityContext.NONE);
11533
11532
  if (job.kind === CompilationJobKind.Host) {
11534
11533
  // This attribute will apply to the enclosing host binding compilation unit, so order
11535
11534
  // doesn't matter.
@@ -11578,7 +11577,7 @@ function extractAttributeOp(unit, op, elements) {
11578
11577
  }
11579
11578
  }
11580
11579
  if (extractable) {
11581
- const extractedAttributeOp = createExtractedAttributeOp(op.target, op.isStructuralTemplate ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression, op.i18nContext);
11580
+ const extractedAttributeOp = createExtractedAttributeOp(op.target, op.isStructuralTemplateAttribute ? BindingKind.Template : BindingKind.Attribute, op.name, op.expression, op.i18nContext, op.i18nMessage, op.securityContext);
11582
11581
  if (unit.job.kind === CompilationJobKind.Host) {
11583
11582
  // This attribute will apply to the enclosing host binding compilation unit, so order doesn't
11584
11583
  // matter.
@@ -11625,16 +11624,16 @@ function specializeBindings(job) {
11625
11624
  target.nonBindable = true;
11626
11625
  }
11627
11626
  else {
11628
- OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplate, op.i18nContext, op.sourceSpan));
11627
+ OpList.replace(op, createAttributeOp(op.target, op.name, op.expression, op.securityContext, op.isTextAttribute, op.isStructuralTemplateAttribute, op.templateKind, op.i18nMessage, op.sourceSpan));
11629
11628
  }
11630
11629
  break;
11631
11630
  case BindingKind.Property:
11632
11631
  case BindingKind.Animation:
11633
11632
  if (job.kind === CompilationJobKind.Host) {
11634
- OpList.replace(op, createHostPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.Animation, op.i18nContext, op.sourceSpan));
11633
+ OpList.replace(op, createHostPropertyOp(op.name, op.expression, op.bindingKind === BindingKind.Animation, op.i18nContext, op.securityContext, op.sourceSpan));
11635
11634
  }
11636
11635
  else {
11637
- OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.Animation, op.securityContext, op.isStructuralTemplate, op.i18nContext, op.sourceSpan));
11636
+ OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.Animation, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
11638
11637
  }
11639
11638
  break;
11640
11639
  case BindingKind.I18n:
@@ -11871,7 +11870,7 @@ function collectElementConsts(job) {
11871
11870
  if (op.kind === OpKind.ExtractedAttribute) {
11872
11871
  const attributes = allElementAttributes.get(op.target) || new ElementAttributes();
11873
11872
  allElementAttributes.set(op.target, attributes);
11874
- attributes.add(op.bindingKind, op.name, op.expression);
11873
+ attributes.add(op.bindingKind, op.name, op.expression, op.trustedValueFn);
11875
11874
  OpList.remove(op);
11876
11875
  }
11877
11876
  }
@@ -11937,11 +11936,12 @@ class ElementAttributes {
11937
11936
  get i18n() {
11938
11937
  return this.byKind.get(BindingKind.I18n) ?? FLYWEIGHT_ARRAY;
11939
11938
  }
11940
- add(kind, name, value) {
11939
+ add(kind, name, value, trustedValueFn) {
11941
11940
  if (this.known.has(name)) {
11942
11941
  return;
11943
11942
  }
11944
11943
  this.known.add(name);
11944
+ // TODO: Can this be its own phase
11945
11945
  if (name === 'ngProjectAs') {
11946
11946
  if (value === null || !(value instanceof LiteralExpr) || (value.value == null) ||
11947
11947
  (typeof value.value?.toString() !== 'string')) {
@@ -11957,7 +11957,15 @@ class ElementAttributes {
11957
11957
  if (value === null) {
11958
11958
  throw Error('Attribute, i18n attribute, & style element attributes must have a value');
11959
11959
  }
11960
- array.push(value);
11960
+ if (trustedValueFn !== null) {
11961
+ if (!isStringLiteral(value)) {
11962
+ throw Error('AssertionError: extracted attribute value should be string literal');
11963
+ }
11964
+ array.push(taggedTemplate(trustedValueFn, new TemplateLiteral([new TemplateLiteralElement(value.value)], []), undefined, value.sourceSpan));
11965
+ }
11966
+ else {
11967
+ array.push(value);
11968
+ }
11961
11969
  }
11962
11970
  }
11963
11971
  arrayFor(kind) {
@@ -12101,6 +12109,9 @@ function createI18nContexts(job) {
12101
12109
  const rootContexts = new Map();
12102
12110
  let currentI18nOp = null;
12103
12111
  let xref;
12112
+ // We use the message instead of the message ID, because placeholder values might differ even
12113
+ // when IDs are the same.
12114
+ const messageToContext = new Map();
12104
12115
  for (const unit of job.units) {
12105
12116
  for (const op of unit.create) {
12106
12117
  switch (op.kind) {
@@ -12138,6 +12149,25 @@ function createI18nContexts(job) {
12138
12149
  break;
12139
12150
  }
12140
12151
  }
12152
+ for (const op of unit.ops()) {
12153
+ switch (op.kind) {
12154
+ case OpKind.Binding:
12155
+ case OpKind.Property:
12156
+ case OpKind.Attribute:
12157
+ case OpKind.ExtractedAttribute:
12158
+ if (!op.i18nMessage) {
12159
+ continue;
12160
+ }
12161
+ if (!messageToContext.has(op.i18nMessage)) {
12162
+ // create the context
12163
+ const i18nContext = job.allocateXrefId();
12164
+ unit.create.push(createI18nContextOp(I18nContextKind.Attr, i18nContext, null, op.i18nMessage, null));
12165
+ messageToContext.set(op.i18nMessage, i18nContext);
12166
+ }
12167
+ op.i18nContext = messageToContext.get(op.i18nMessage);
12168
+ break;
12169
+ }
12170
+ }
12141
12171
  }
12142
12172
  // Assign contexts to child i18n blocks, now that all root i18n blocks have their context
12143
12173
  // assigned.
@@ -12812,9 +12842,15 @@ function recursivelyProcessView(view, parentScope) {
12812
12842
  for (const op of view.create) {
12813
12843
  switch (op.kind) {
12814
12844
  case OpKind.Template:
12845
+ // Descend into child embedded views.
12846
+ recursivelyProcessView(view.job.views.get(op.xref), scope);
12847
+ break;
12815
12848
  case OpKind.RepeaterCreate:
12816
12849
  // Descend into child embedded views.
12817
12850
  recursivelyProcessView(view.job.views.get(op.xref), scope);
12851
+ if (op.emptyView) {
12852
+ recursivelyProcessView(view.job.views.get(op.emptyView), scope);
12853
+ }
12818
12854
  break;
12819
12855
  case OpKind.Listener:
12820
12856
  // Prepend variables to listener handler functions.
@@ -19954,7 +19990,7 @@ const ESCAPE = '\uFFFD';
19954
19990
  function collectI18nConsts(job) {
19955
19991
  const fileBasedI18nSuffix = job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
19956
19992
  // Step One: Build up various lookup maps we need to collect all the consts.
19957
- // Context Xref -> Extracted Attribute Op
19993
+ // Context Xref -> Extracted Attribute Ops
19958
19994
  const extractedAttributesByI18nContext = new Map();
19959
19995
  // Element/ElementStart Xref -> I18n Attributes config op
19960
19996
  const i18nAttributesByElement = new Map();
@@ -19965,7 +20001,9 @@ function collectI18nConsts(job) {
19965
20001
  for (const unit of job.units) {
19966
20002
  for (const op of unit.ops()) {
19967
20003
  if (op.kind === OpKind.ExtractedAttribute && op.i18nContext !== null) {
19968
- extractedAttributesByI18nContext.set(op.i18nContext, op);
20004
+ const attributes = extractedAttributesByI18nContext.get(op.i18nContext) ?? [];
20005
+ attributes.push(op);
20006
+ extractedAttributesByI18nContext.set(op.i18nContext, attributes);
19969
20007
  }
19970
20008
  else if (op.kind === OpKind.I18nAttributes) {
19971
20009
  i18nAttributesByElement.set(op.target, op);
@@ -20010,9 +20048,11 @@ function collectI18nConsts(job) {
20010
20048
  i18nValuesByContext.set(op.i18nContext, mainVar);
20011
20049
  // This i18n message may correspond to an individual extracted attribute. If so, The
20012
20050
  // value of that attribute is updated to read the extracted i18n variable.
20013
- const attributeForMessage = extractedAttributesByI18nContext.get(op.i18nContext);
20014
- if (attributeForMessage !== undefined) {
20015
- attributeForMessage.expression = mainVar;
20051
+ const attributesForMessage = extractedAttributesByI18nContext.get(op.i18nContext);
20052
+ if (attributesForMessage !== undefined) {
20053
+ for (const attr of attributesForMessage) {
20054
+ attr.expression = mainVar.clone();
20055
+ }
20016
20056
  }
20017
20057
  }
20018
20058
  }
@@ -20800,14 +20840,14 @@ function parseExtractedStyles(job) {
20800
20840
  if (op.name === 'style') {
20801
20841
  const parsedStyles = parse(op.expression.value);
20802
20842
  for (let i = 0; i < parsedStyles.length - 1; i += 2) {
20803
- OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1]), null), op);
20843
+ OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.StyleProperty, parsedStyles[i], literal(parsedStyles[i + 1]), null, null, SecurityContext.STYLE), op);
20804
20844
  }
20805
20845
  OpList.remove(op);
20806
20846
  }
20807
20847
  else if (op.name === 'class') {
20808
20848
  const parsedClasses = op.expression.value.trim().split(/\s+/g);
20809
20849
  for (const parsedClass of parsedClasses) {
20810
- OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null, null), op);
20850
+ OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.ClassName, parsedClass, null, null, null, SecurityContext.NONE), op);
20811
20851
  }
20812
20852
  OpList.remove(op);
20813
20853
  }
@@ -20973,22 +21013,37 @@ function propagateI18nBlocksToTemplates(unit, subTemplateIndex) {
20973
21013
  i18nBlock = null;
20974
21014
  break;
20975
21015
  case OpKind.Template:
20976
- const templateView = unit.job.views.get(op.xref);
20977
- // We found an <ng-template> inside an i18n block; increment the sub-template counter and
20978
- // wrap the template's view in a child i18n block.
20979
- if (op.i18nPlaceholder !== undefined) {
20980
- if (i18nBlock === null) {
20981
- throw Error('Expected template with i18n placeholder to be in an i18n block.');
20982
- }
20983
- subTemplateIndex++;
20984
- wrapTemplateWithI18n(templateView, i18nBlock);
21016
+ subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.xref), i18nBlock, op.i18nPlaceholder, subTemplateIndex);
21017
+ break;
21018
+ case OpKind.RepeaterCreate:
21019
+ // Propagate i18n blocks to the @for template.
21020
+ const forView = unit.job.views.get(op.xref);
21021
+ subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.xref), i18nBlock, op.i18nPlaceholder, subTemplateIndex);
21022
+ // Then if there's an @empty template, propagate the i18n blocks for it as well.
21023
+ if (op.emptyView !== null) {
21024
+ subTemplateIndex = propagateI18nBlocksForView(unit.job.views.get(op.emptyView), i18nBlock, op.emptyI18nPlaceholder, subTemplateIndex);
20985
21025
  }
20986
- // Continue traversing inside the template's view.
20987
- subTemplateIndex = propagateI18nBlocksToTemplates(templateView, subTemplateIndex);
21026
+ break;
20988
21027
  }
20989
21028
  }
20990
21029
  return subTemplateIndex;
20991
21030
  }
21031
+ /**
21032
+ * Propagate i18n blocks for a view.
21033
+ */
21034
+ function propagateI18nBlocksForView(view, i18nBlock, i18nPlaceholder, subTemplateIndex) {
21035
+ // We found an <ng-template> inside an i18n block; increment the sub-template counter and
21036
+ // wrap the template's view in a child i18n block.
21037
+ if (i18nPlaceholder !== undefined) {
21038
+ if (i18nBlock === null) {
21039
+ throw Error('Expected template with i18n placeholder to be in an i18n block.');
21040
+ }
21041
+ subTemplateIndex++;
21042
+ wrapTemplateWithI18n(view, i18nBlock);
21043
+ }
21044
+ // Continue traversing inside the template's view.
21045
+ return propagateI18nBlocksToTemplates(view, subTemplateIndex);
21046
+ }
20992
21047
  /**
20993
21048
  * Wraps a template view with i18n start and end ops.
20994
21049
  */
@@ -21154,17 +21209,13 @@ function disableBindings() {
21154
21209
  function enableBindings() {
21155
21210
  return call(Identifiers.enableBindings, [], null);
21156
21211
  }
21157
- function listener(name, handlerFn, sourceSpan) {
21158
- return call(Identifiers.listener, [
21159
- literal(name),
21160
- handlerFn,
21161
- ], sourceSpan);
21162
- }
21163
- function syntheticHostListener(name, handlerFn, sourceSpan) {
21164
- return call(Identifiers.syntheticHostListener, [
21165
- literal(name),
21166
- handlerFn,
21167
- ], sourceSpan);
21212
+ function listener(name, handlerFn, eventTargetResolver, syntheticHost, sourceSpan) {
21213
+ const args = [literal(name), handlerFn];
21214
+ if (eventTargetResolver !== null) {
21215
+ args.push(literal(false)); // `useCapture` flag, defaults to `false`
21216
+ args.push(importExpr(eventTargetResolver));
21217
+ }
21218
+ return call(syntheticHost ? Identifiers.syntheticHostListener : Identifiers.listener, args, sourceSpan);
21168
21219
  }
21169
21220
  function pipe(slot, name) {
21170
21221
  return call(Identifiers.pipe, [
@@ -21425,8 +21476,12 @@ function classMapInterpolate(strings, expressions, sourceSpan) {
21425
21476
  const interpolationArgs = collateInterpolationArgs(strings, expressions);
21426
21477
  return callVariadicInstruction(CLASS_MAP_INTERPOLATE_CONFIG, [], interpolationArgs, [], sourceSpan);
21427
21478
  }
21428
- function hostProperty(name, expression, sourceSpan) {
21429
- return call(Identifiers.hostProperty, [literal(name), expression], sourceSpan);
21479
+ function hostProperty(name, expression, sanitizer, sourceSpan) {
21480
+ const args = [literal(name), expression];
21481
+ if (sanitizer !== null) {
21482
+ args.push(sanitizer);
21483
+ }
21484
+ return call(Identifiers.hostProperty, args, sourceSpan);
21430
21485
  }
21431
21486
  function syntheticHostProperty(name, expression, sourceSpan) {
21432
21487
  return call(Identifiers.syntheticHostProperty, [literal(name), expression], sourceSpan);
@@ -21644,14 +21699,12 @@ function callVariadicInstruction(config, baseArgs, interpolationArgs, extraArgs,
21644
21699
  }
21645
21700
 
21646
21701
  /**
21647
- * Map of sanitizers to their identifier.
21702
+ * Map of target resolvers for event listeners.
21648
21703
  */
21649
- const sanitizerIdentifierMap = new Map([
21650
- [SanitizerFn.Html, Identifiers.sanitizeHtml],
21651
- [SanitizerFn.IframeAttribute, Identifiers.validateIframeAttribute],
21652
- [SanitizerFn.ResourceUrl, Identifiers.sanitizeResourceUrl],
21653
- [SanitizerFn.Script, Identifiers.sanitizeScript],
21654
- [SanitizerFn.Style, Identifiers.sanitizeStyle], [SanitizerFn.Url, Identifiers.sanitizeUrl]
21704
+ const GLOBAL_TARGET_RESOLVERS$1 = new Map([
21705
+ ['window', Identifiers.resolveWindow],
21706
+ ['document', Identifiers.resolveDocument],
21707
+ ['body', Identifiers.resolveBody],
21655
21708
  ]);
21656
21709
  /**
21657
21710
  * Compiles semantic operations across all views and generates output `o.Statement`s with actual
@@ -21728,10 +21781,11 @@ function reifyCreateOperations(unit, ops) {
21728
21781
  break;
21729
21782
  case OpKind.Listener:
21730
21783
  const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
21731
- const reified = op.hostListener && op.isAnimationListener ?
21732
- syntheticHostListener(op.name, listenerFn, op.sourceSpan) :
21733
- listener(op.name, listenerFn, op.sourceSpan);
21734
- OpList.replace(op, reified);
21784
+ const eventTargetResolver = op.eventTarget ? GLOBAL_TARGET_RESOLVERS$1.get(op.eventTarget) : null;
21785
+ if (eventTargetResolver === undefined) {
21786
+ throw new Error(`AssertionError: unknown event target ${op.eventTarget}`);
21787
+ }
21788
+ OpList.replace(op, listener(op.name, listenerFn, eventTargetResolver, op.hostListener && op.isAnimationListener, op.sourceSpan));
21735
21789
  break;
21736
21790
  case OpKind.Variable:
21737
21791
  if (op.variable.name === null) {
@@ -21894,7 +21948,7 @@ function reifyUpdateOperations(_unit, ops) {
21894
21948
  OpList.replace(op, syntheticHostProperty(op.name, op.expression, op.sourceSpan));
21895
21949
  }
21896
21950
  else {
21897
- OpList.replace(op, hostProperty(op.name, op.expression, op.sourceSpan));
21951
+ OpList.replace(op, hostProperty(op.name, op.expression, op.sanitizer, op.sourceSpan));
21898
21952
  }
21899
21953
  }
21900
21954
  break;
@@ -21973,8 +22027,6 @@ function reifyIrExpression(expr) {
21973
22027
  return pipeBind(expr.targetSlot.slot, expr.varOffset, expr.args);
21974
22028
  case ExpressionKind.PipeBindingVariadic:
21975
22029
  return pipeBindV(expr.targetSlot.slot, expr.varOffset, expr.args);
21976
- case ExpressionKind.SanitizerExpr:
21977
- return importExpr(sanitizerIdentifierMap.get(expr.fn));
21978
22030
  case ExpressionKind.SlotLiteralExpr:
21979
22031
  return literal(expr.slot.slot);
21980
22032
  default:
@@ -22267,10 +22319,11 @@ function resolvePlaceholdersForView(job, unit, i18nContexts, elements, pendingSt
22267
22319
  }
22268
22320
  break;
22269
22321
  case OpKind.Template:
22322
+ const view = job.views.get(op.xref);
22270
22323
  if (op.i18nPlaceholder === undefined) {
22271
22324
  // If there is no i18n placeholder, just recurse into the view in case it contains i18n
22272
22325
  // blocks.
22273
- resolvePlaceholdersForView(job, job.views.get(op.xref), i18nContexts, elements);
22326
+ resolvePlaceholdersForView(job, view, i18nContexts, elements);
22274
22327
  }
22275
22328
  else {
22276
22329
  if (currentOps === null) {
@@ -22281,14 +22334,59 @@ function resolvePlaceholdersForView(job, unit, i18nContexts, elements, pendingSt
22281
22334
  // the current template as a pending structural directive to be recorded when we find
22282
22335
  // the element, content, or template it belongs to. This allows us to create combined
22283
22336
  // values that represent, e.g. the start of a template and element at the same time.
22284
- resolvePlaceholdersForView(job, job.views.get(op.xref), i18nContexts, elements, op);
22337
+ resolvePlaceholdersForView(job, view, i18nContexts, elements, op);
22285
22338
  }
22286
22339
  else {
22287
22340
  // If this is some other kind of template, we can record its start, recurse into its
22288
22341
  // view, and then record its end.
22289
- recordTemplateStart(job, op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
22290
- resolvePlaceholdersForView(job, job.views.get(op.xref), i18nContexts, elements);
22291
- recordTemplateClose(job, op, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
22342
+ recordTemplateStart(job, view, op.handle.slot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
22343
+ resolvePlaceholdersForView(job, view, i18nContexts, elements);
22344
+ recordTemplateClose(job, view, op.handle.slot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
22345
+ pendingStructuralDirective = undefined;
22346
+ }
22347
+ }
22348
+ break;
22349
+ case OpKind.RepeaterCreate:
22350
+ if (pendingStructuralDirective !== undefined) {
22351
+ throw Error('AssertionError: Unexpected structural directive associated with @for block');
22352
+ }
22353
+ // RepeaterCreate has 3 slots: the first is for the op itself, the second is for the @for
22354
+ // template and the (optional) third is for the @empty template.
22355
+ const forSlot = op.handle.slot + 1;
22356
+ const forView = job.views.get(op.xref);
22357
+ // First record all of the placeholders for the @for template.
22358
+ if (op.i18nPlaceholder === undefined) {
22359
+ // If there is no i18n placeholder, just recurse into the view in case it contains i18n
22360
+ // blocks.
22361
+ resolvePlaceholdersForView(job, forView, i18nContexts, elements);
22362
+ }
22363
+ else {
22364
+ if (currentOps === null) {
22365
+ throw Error('i18n tag placeholder should only occur inside an i18n block');
22366
+ }
22367
+ recordTemplateStart(job, forView, forSlot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
22368
+ resolvePlaceholdersForView(job, forView, i18nContexts, elements);
22369
+ recordTemplateClose(job, forView, forSlot, op.i18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
22370
+ pendingStructuralDirective = undefined;
22371
+ }
22372
+ // Then if there's an @empty template, add its placeholders as well.
22373
+ if (op.emptyView !== null) {
22374
+ // RepeaterCreate has 3 slots: the first is for the op itself, the second is for the @for
22375
+ // template and the (optional) third is for the @empty template.
22376
+ const emptySlot = op.handle.slot + 2;
22377
+ const emptyView = job.views.get(op.emptyView);
22378
+ if (op.emptyI18nPlaceholder === undefined) {
22379
+ // If there is no i18n placeholder, just recurse into the view in case it contains i18n
22380
+ // blocks.
22381
+ resolvePlaceholdersForView(job, emptyView, i18nContexts, elements);
22382
+ }
22383
+ else {
22384
+ if (currentOps === null) {
22385
+ throw Error('i18n tag placeholder should only occur inside an i18n block');
22386
+ }
22387
+ recordTemplateStart(job, emptyView, emptySlot, op.emptyI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
22388
+ resolvePlaceholdersForView(job, emptyView, i18nContexts, elements);
22389
+ recordTemplateClose(job, emptyView, emptySlot, op.emptyI18nPlaceholder, currentOps.i18nContext, currentOps.i18nBlock, pendingStructuralDirective);
22292
22390
  pendingStructuralDirective = undefined;
22293
22391
  }
22294
22392
  }
@@ -22336,8 +22434,8 @@ function recordElementClose(op, i18nContext, i18nBlock, structuralDirective) {
22336
22434
  /**
22337
22435
  * Records an i18n param value for the start of a template.
22338
22436
  */
22339
- function recordTemplateStart(job, op, i18nContext, i18nBlock, structuralDirective) {
22340
- let { startName, closeName } = op.i18nPlaceholder;
22437
+ function recordTemplateStart(job, view, slot, i18nPlaceholder, i18nContext, i18nBlock, structuralDirective) {
22438
+ let { startName, closeName } = i18nPlaceholder;
22341
22439
  let flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.OpenTag;
22342
22440
  // For self-closing tags, there is no close tag placeholder. Instead, the start tag
22343
22441
  // placeholder accounts for the start and close of the element.
@@ -22352,20 +22450,20 @@ function recordTemplateStart(job, op, i18nContext, i18nBlock, structuralDirectiv
22352
22450
  }
22353
22451
  // Record the start of the template. For the sub-template index, pass the index for the template's
22354
22452
  // view, rather than the current i18n block's index.
22355
- addParam(i18nContext.params, startName, op.handle.slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, op), flags);
22453
+ addParam(i18nContext.params, startName, slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, view), flags);
22356
22454
  }
22357
22455
  /**
22358
22456
  * Records an i18n param value for the closing of a template.
22359
22457
  */
22360
- function recordTemplateClose(job, op, i18nContext, i18nBlock, structuralDirective) {
22361
- const { startName, closeName } = op.i18nPlaceholder;
22458
+ function recordTemplateClose(job, view, slot, i18nPlaceholder, i18nContext, i18nBlock, structuralDirective) {
22459
+ const { startName, closeName } = i18nPlaceholder;
22362
22460
  const flags = I18nParamValueFlags.TemplateTag | I18nParamValueFlags.CloseTag;
22363
22461
  // Self-closing tags don't have a closing tag placeholder, instead the template's closing is
22364
22462
  // recorded via an additional flag on the template start value.
22365
22463
  if (closeName) {
22366
22464
  // Record the closing of the template. For the sub-template index, pass the index for the
22367
22465
  // template's view, rather than the current i18n block's index.
22368
- addParam(i18nContext.params, closeName, op.handle.slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, op), flags);
22466
+ addParam(i18nContext.params, closeName, slot, getSubTemplateIndexForTemplateTag(job, i18nBlock, view), flags);
22369
22467
  // If the template is associated with a structural directive, record the structural directive's
22370
22468
  // closing after. Since this template must be in the structural directive's view, we can just
22371
22469
  // directly use the current i18n block's sub-template index.
@@ -22378,8 +22476,8 @@ function recordTemplateClose(job, op, i18nContext, i18nBlock, structuralDirectiv
22378
22476
  * Get the subTemplateIndex for the given template op. For template ops, use the subTemplateIndex of
22379
22477
  * the child i18n block inside the template.
22380
22478
  */
22381
- function getSubTemplateIndexForTemplateTag(job, i18nOp, op) {
22382
- for (const childOp of job.views.get(op.xref).create) {
22479
+ function getSubTemplateIndexForTemplateTag(job, i18nOp, view) {
22480
+ for (const childOp of view.create) {
22383
22481
  if (childOp.kind === OpKind.I18nStart) {
22384
22482
  return childOp.subTemplateIndex;
22385
22483
  }
@@ -22596,12 +22694,20 @@ function processLexicalScope(unit, ops, savedView) {
22596
22694
  }
22597
22695
 
22598
22696
  /**
22599
- * Mapping of security contexts to sanitizer function for that context.
22697
+ * Map of security contexts to their sanitizer function.
22698
+ */
22699
+ const sanitizerFns = new Map([
22700
+ [SecurityContext.HTML, Identifiers.sanitizeHtml],
22701
+ [SecurityContext.RESOURCE_URL, Identifiers.sanitizeResourceUrl],
22702
+ [SecurityContext.SCRIPT, Identifiers.sanitizeScript],
22703
+ [SecurityContext.STYLE, Identifiers.sanitizeStyle], [SecurityContext.URL, Identifiers.sanitizeUrl]
22704
+ ]);
22705
+ /**
22706
+ * Map of security contexts to their trusted value function.
22600
22707
  */
22601
- const sanitizers = new Map([
22602
- [SecurityContext.HTML, SanitizerFn.Html], [SecurityContext.SCRIPT, SanitizerFn.Script],
22603
- [SecurityContext.STYLE, SanitizerFn.Style], [SecurityContext.URL, SanitizerFn.Url],
22604
- [SecurityContext.RESOURCE_URL, SanitizerFn.ResourceUrl]
22708
+ const trustedValueFns = new Map([
22709
+ [SecurityContext.HTML, Identifiers.trustConstantHtml],
22710
+ [SecurityContext.RESOURCE_URL, Identifiers.trustConstantResourceUrl],
22605
22711
  ]);
22606
22712
  /**
22607
22713
  * Resolves sanitization functions for ops that need them.
@@ -22609,24 +22715,61 @@ const sanitizers = new Map([
22609
22715
  function resolveSanitizers(job) {
22610
22716
  for (const unit of job.units) {
22611
22717
  const elements = createOpXrefMap(unit);
22612
- let sanitizerFn;
22718
+ // For normal element bindings we create trusted values for security sensitive constant
22719
+ // attributes. However, for host bindings we skip this step (this matches what
22720
+ // TemplateDefinitionBuilder does).
22721
+ // TODO: Is the TDB behavior correct here?
22722
+ if (job.kind !== CompilationJobKind.Host) {
22723
+ for (const op of unit.create) {
22724
+ if (op.kind === OpKind.ExtractedAttribute) {
22725
+ const trustedValueFn = trustedValueFns.get(getOnlySecurityContext(op.securityContext)) ?? null;
22726
+ op.trustedValueFn = trustedValueFn !== null ? importExpr(trustedValueFn) : null;
22727
+ }
22728
+ }
22729
+ }
22613
22730
  for (const op of unit.update) {
22614
22731
  switch (op.kind) {
22615
22732
  case OpKind.Property:
22616
22733
  case OpKind.Attribute:
22617
- sanitizerFn = sanitizers.get(op.securityContext) || null;
22618
- op.sanitizer = sanitizerFn ? new SanitizerExpr(sanitizerFn) : null;
22734
+ case OpKind.HostProperty:
22735
+ let sanitizerFn = null;
22736
+ if (Array.isArray(op.securityContext) && op.securityContext.length === 2 &&
22737
+ op.securityContext.indexOf(SecurityContext.URL) > -1 &&
22738
+ op.securityContext.indexOf(SecurityContext.RESOURCE_URL) > -1) {
22739
+ // When the host element isn't known, some URL attributes (such as "src" and "href") may
22740
+ // be part of multiple different security contexts. In this case we use special
22741
+ // sanitization function and select the actual sanitizer at runtime based on a tag name
22742
+ // that is provided while invoking sanitization function.
22743
+ sanitizerFn = Identifiers.sanitizeUrlOrResourceUrl;
22744
+ }
22745
+ else {
22746
+ sanitizerFn = sanitizerFns.get(getOnlySecurityContext(op.securityContext)) ?? null;
22747
+ }
22748
+ op.sanitizer = sanitizerFn !== null ? importExpr(sanitizerFn) : null;
22619
22749
  // If there was no sanitization function found based on the security context of an
22620
22750
  // attribute/property, check whether this attribute/property is one of the
22621
22751
  // security-sensitive <iframe> attributes (and that the current element is actually an
22622
22752
  // <iframe>).
22623
22753
  if (op.sanitizer === null) {
22624
- const ownerOp = elements.get(op.target);
22625
- if (ownerOp === undefined || !isElementOrContainerOp(ownerOp)) {
22626
- throw Error('Property should have an element-like owner');
22754
+ let isIframe = false;
22755
+ if (job.kind === CompilationJobKind.Host || op.kind === OpKind.HostProperty) {
22756
+ // Note: for host bindings defined on a directive, we do not try to find all
22757
+ // possible places where it can be matched, so we can not determine whether
22758
+ // the host element is an <iframe>. In this case, we just assume it is and append a
22759
+ // validation function, which is invoked at runtime and would have access to the
22760
+ // underlying DOM element to check if it's an <iframe> and if so - run extra checks.
22761
+ isIframe = true;
22762
+ }
22763
+ else {
22764
+ // For a normal binding we can just check if the element its on is an iframe.
22765
+ const ownerOp = elements.get(op.target);
22766
+ if (ownerOp === undefined || !isElementOrContainerOp(ownerOp)) {
22767
+ throw Error('Property should have an element-like owner');
22768
+ }
22769
+ isIframe = isIframeElement$1(ownerOp);
22627
22770
  }
22628
- if (isIframeElement$1(ownerOp) && isIframeSecuritySensitiveAttr(op.name)) {
22629
- op.sanitizer = new SanitizerExpr(SanitizerFn.IframeAttribute);
22771
+ if (isIframe && isIframeSecuritySensitiveAttr(op.name)) {
22772
+ op.sanitizer = importExpr(Identifiers.validateIframeAttribute);
22630
22773
  }
22631
22774
  }
22632
22775
  break;
@@ -22640,6 +22783,22 @@ function resolveSanitizers(job) {
22640
22783
  function isIframeElement$1(op) {
22641
22784
  return op.kind === OpKind.ElementStart && op.tag?.toLowerCase() === 'iframe';
22642
22785
  }
22786
+ /**
22787
+ * Asserts that there is only a single security context and returns it.
22788
+ */
22789
+ function getOnlySecurityContext(securityContext) {
22790
+ if (Array.isArray(securityContext)) {
22791
+ if (securityContext.length > 1) {
22792
+ // TODO: What should we do here? TDB just took the first one, but this feels like something we
22793
+ // would want to know about and create a special case for like we did for Url/ResourceUrl. My
22794
+ // guess is that, outside of the Url/ResourceUrl case, this never actually happens. If there
22795
+ // do turn out to be other cases, throwing an error until we can address it feels safer.
22796
+ throw Error(`AssertionError: Ambiguous security context`);
22797
+ }
22798
+ return securityContext[0] || SecurityContext.NONE;
22799
+ }
22800
+ return securityContext;
22801
+ }
22643
22802
 
22644
22803
  /**
22645
22804
  * When inside of a listener, we may need access to one or more enclosing views. Therefore, each
@@ -22743,6 +22902,8 @@ function allocateSlots(job) {
22743
22902
  // operation itself, so it can be emitted later.
22744
22903
  const childView = job.views.get(op.xref);
22745
22904
  op.decls = childView.decls;
22905
+ // TODO: currently we handle the decls for the RepeaterCreate empty template in the reify
22906
+ // phase. We should handle that here instead.
22746
22907
  }
22747
22908
  }
22748
22909
  }
@@ -23066,6 +23227,8 @@ function countVariables(job) {
23066
23227
  }
23067
23228
  const childView = job.views.get(op.xref);
23068
23229
  op.vars = childView.vars;
23230
+ // TODO: currently we handle the vars for the RepeaterCreate empty template in the reify
23231
+ // phase. We should handle that here instead.
23069
23232
  }
23070
23233
  }
23071
23234
  }
@@ -23587,10 +23750,10 @@ const phases = [
23587
23750
  { kind: CompilationJobKind.Tmpl, fn: emitNamespaceChanges },
23588
23751
  { kind: CompilationJobKind.Tmpl, fn: propagateI18nBlocks },
23589
23752
  { kind: CompilationJobKind.Tmpl, fn: wrapI18nIcus },
23590
- { kind: CompilationJobKind.Tmpl, fn: createI18nContexts },
23591
23753
  { kind: CompilationJobKind.Both, fn: specializeStyleBindings },
23592
23754
  { kind: CompilationJobKind.Both, fn: specializeBindings },
23593
23755
  { kind: CompilationJobKind.Both, fn: extractAttributes },
23756
+ { kind: CompilationJobKind.Tmpl, fn: createI18nContexts },
23594
23757
  { kind: CompilationJobKind.Both, fn: parseExtractedStyles },
23595
23758
  { kind: CompilationJobKind.Tmpl, fn: removeEmptyBindings },
23596
23759
  { kind: CompilationJobKind.Both, fn: collapseSingletonInterpolations },
@@ -23608,7 +23771,7 @@ const phases = [
23608
23771
  { kind: CompilationJobKind.Tmpl, fn: generateProjectionDefs },
23609
23772
  { kind: CompilationJobKind.Tmpl, fn: generateVariables },
23610
23773
  { kind: CompilationJobKind.Tmpl, fn: saveAndRestoreView },
23611
- { kind: CompilationJobKind.Tmpl, fn: deleteAnyCasts },
23774
+ { kind: CompilationJobKind.Both, fn: deleteAnyCasts },
23612
23775
  { kind: CompilationJobKind.Both, fn: resolveDollarEvent },
23613
23776
  { kind: CompilationJobKind.Tmpl, fn: generateRepeaterDerivedVars },
23614
23777
  { kind: CompilationJobKind.Tmpl, fn: generateTrackVariables },
@@ -23616,7 +23779,7 @@ const phases = [
23616
23779
  { kind: CompilationJobKind.Tmpl, fn: resolveDeferTargetNames },
23617
23780
  { kind: CompilationJobKind.Tmpl, fn: optimizeTrackFns },
23618
23781
  { kind: CompilationJobKind.Both, fn: resolveContexts },
23619
- { kind: CompilationJobKind.Tmpl, fn: resolveSanitizers }, // TODO: run in both
23782
+ { kind: CompilationJobKind.Both, fn: resolveSanitizers },
23620
23783
  { kind: CompilationJobKind.Tmpl, fn: liftLocalRefs },
23621
23784
  { kind: CompilationJobKind.Both, fn: generateNullishCoalesceExpressions },
23622
23785
  { kind: CompilationJobKind.Both, fn: expandSafeReads },
@@ -23752,6 +23915,10 @@ function emitHostBindingFunction(job) {
23752
23915
  }
23753
23916
 
23754
23917
  const compatibilityMode = CompatibilityMode.TemplateDefinitionBuilder;
23918
+ // Schema containing DOM elements and their properties.
23919
+ const domSchema = new DomElementSchemaRegistry();
23920
+ // Tag name of the `ng-template` element.
23921
+ const NG_TEMPLATE_TAG_NAME$1 = 'ng-template';
23755
23922
  /**
23756
23923
  * Process a template AST and convert it into a `ComponentCompilation` in the intermediate
23757
23924
  * representation.
@@ -23769,10 +23936,24 @@ function ingestComponent(componentName, template, constantPool, relativeContextF
23769
23936
  function ingestHostBinding(input, bindingParser, constantPool) {
23770
23937
  const job = new HostBindingCompilationJob(input.componentName, constantPool, compatibilityMode);
23771
23938
  for (const property of input.properties ?? []) {
23772
- ingestHostProperty(job, property, false);
23939
+ let bindingKind = BindingKind.Property;
23940
+ // TODO: this should really be handled in the parser.
23941
+ if (property.name.startsWith('attr.')) {
23942
+ property.name = property.name.substring('attr.'.length);
23943
+ bindingKind = BindingKind.Attribute;
23944
+ }
23945
+ if (property.isAnimation) {
23946
+ bindingKind = BindingKind.Animation;
23947
+ }
23948
+ const securityContexts = bindingParser
23949
+ .calcPossibleSecurityContexts(input.componentSelector, property.name, bindingKind === BindingKind.Attribute)
23950
+ .filter(context => context !== SecurityContext.NONE);
23951
+ ingestHostProperty(job, property, bindingKind, false, securityContexts);
23773
23952
  }
23774
23953
  for (const [name, expr] of Object.entries(input.attributes) ?? []) {
23775
- ingestHostAttribute(job, name, expr);
23954
+ const securityContexts = bindingParser.calcPossibleSecurityContexts(input.componentSelector, name, true)
23955
+ .filter(context => context !== SecurityContext.NONE);
23956
+ ingestHostAttribute(job, name, expr, securityContexts);
23776
23957
  }
23777
23958
  for (const event of input.events ?? []) {
23778
23959
  ingestHostEvent(job, event);
@@ -23781,7 +23962,7 @@ function ingestHostBinding(input, bindingParser, constantPool) {
23781
23962
  }
23782
23963
  // TODO: We should refactor the parser to use the same types and structures for host bindings as
23783
23964
  // with ordinary components. This would allow us to share a lot more ingestion code.
23784
- function ingestHostProperty(job, property, isTextAttribute) {
23965
+ function ingestHostProperty(job, property, bindingKind, isTextAttribute, securityContexts) {
23785
23966
  let expression;
23786
23967
  const ast = property.expression.ast;
23787
23968
  if (ast instanceof Interpolation$1) {
@@ -23790,26 +23971,18 @@ function ingestHostProperty(job, property, isTextAttribute) {
23790
23971
  else {
23791
23972
  expression = convertAst(ast, job, property.sourceSpan);
23792
23973
  }
23793
- let bindingKind = BindingKind.Property;
23794
- // TODO: this should really be handled in the parser.
23795
- if (property.name.startsWith('attr.')) {
23796
- property.name = property.name.substring('attr.'.length);
23797
- bindingKind = BindingKind.Attribute;
23798
- }
23799
- if (property.isAnimation) {
23800
- bindingKind = BindingKind.Animation;
23801
- }
23802
- job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, SecurityContext
23803
- .NONE /* TODO: what should we pass as security context? Passing NONE for now. */, isTextAttribute, false, /* TODO: How do Host bindings handle i18n attrs? */ null, property.sourceSpan));
23974
+ job.root.update.push(createBindingOp(job.root.xref, bindingKind, property.name, expression, null, securityContexts, isTextAttribute, false, null, /* TODO: How do Host bindings handle i18n attrs? */ null, property.sourceSpan));
23804
23975
  }
23805
- function ingestHostAttribute(job, name, value) {
23806
- const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, SecurityContext.NONE, true, false,
23976
+ function ingestHostAttribute(job, name, value, securityContexts) {
23977
+ const attrBinding = createBindingOp(job.root.xref, BindingKind.Attribute, name, value, null, securityContexts, true, false, null,
23807
23978
  /* TODO */ null,
23808
23979
  /* TODO: host attribute source spans */ null);
23809
23980
  job.root.update.push(attrBinding);
23810
23981
  }
23811
23982
  function ingestHostEvent(job, event) {
23812
- const eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null, event.targetOrPhase, true, event.sourceSpan);
23983
+ const [phase, target] = event.type === 0 /* e.ParsedEventType.Regular */ ? [null, event.targetOrPhase] :
23984
+ [event.targetOrPhase, null];
23985
+ const eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null, [], phase, target, true, event.sourceSpan);
23813
23986
  // TODO: Can this be a chain?
23814
23987
  eventBinding.handlerOps.push(createStatementOp(new ReturnStatement(convertAst(event.handler.ast, job, event.sourceSpan), event.handlerSpan)));
23815
23988
  job.root.create.push(eventBinding);
@@ -23866,8 +24039,14 @@ function ingestElement(unit, element) {
23866
24039
  const [namespaceKey, elementName] = splitNsName(element.name);
23867
24040
  const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan);
23868
24041
  unit.create.push(startOp);
23869
- ingestBindings(unit, startOp, element);
24042
+ ingestElementBindings(unit, startOp, element);
23870
24043
  ingestReferences(startOp, element);
24044
+ // Start i18n, if needed, goes after the element create and bindings, but before the nodes
24045
+ let i18nBlockId = null;
24046
+ if (element.i18n instanceof Message) {
24047
+ i18nBlockId = unit.job.allocateXrefId();
24048
+ unit.create.push(createI18nStartOp(i18nBlockId, element.i18n));
24049
+ }
23871
24050
  ingestNodes(unit, element.children);
23872
24051
  // The source span for the end op is typically the element closing tag. However, if no closing tag
23873
24052
  // exists, such as in `<input>`, we use the start source span instead. Usually the start and end
@@ -23877,9 +24056,7 @@ function ingestElement(unit, element) {
23877
24056
  const endOp = createElementEndOp(id, element.endSourceSpan ?? element.startSourceSpan);
23878
24057
  unit.create.push(endOp);
23879
24058
  // If there is an i18n message associated with this element, insert i18n start and end ops.
23880
- if (element.i18n instanceof Message) {
23881
- const i18nBlockId = unit.job.allocateXrefId();
23882
- OpList.insertAfter(createI18nStartOp(i18nBlockId, element.i18n), startOp);
24059
+ if (i18nBlockId !== null) {
23883
24060
  OpList.insertBefore(createI18nEndOp(i18nBlockId), endOp);
23884
24061
  }
23885
24062
  }
@@ -23905,7 +24082,7 @@ function ingestTemplate(unit, tmpl) {
23905
24082
  const templateKind = isPlainTemplate(tmpl) ? TemplateKind.NgTemplate : TemplateKind.Structural;
23906
24083
  const templateOp = createTemplateOp(childView.xref, templateKind, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan);
23907
24084
  unit.create.push(templateOp);
23908
- ingestBindings(unit, templateOp, tmpl);
24085
+ ingestTemplateBindings(unit, templateOp, tmpl, templateKind);
23909
24086
  ingestReferences(templateOp, tmpl);
23910
24087
  ingestNodes(childView, tmpl.children);
23911
24088
  for (const { name, value } of tmpl.variables) {
@@ -23921,7 +24098,7 @@ function ingestTemplate(unit, tmpl) {
23921
24098
  }
23922
24099
  }
23923
24100
  /**
23924
- * Ingest a literal text node from the AST into the given `ViewCompilation`.
24101
+ * Ingest a content node from the AST into the given `ViewCompilation`.
23925
24102
  */
23926
24103
  function ingestContent(unit, content) {
23927
24104
  if (content.i18n !== undefined && !(content.i18n instanceof TagPlaceholder)) {
@@ -23930,7 +24107,8 @@ function ingestContent(unit, content) {
23930
24107
  const attrs = content.attributes.flatMap(a => [a.name, a.value]);
23931
24108
  const op = createProjectionOp(unit.job.allocateXrefId(), content.selector, content.i18n, attrs, content.sourceSpan);
23932
24109
  for (const attr of content.attributes) {
23933
- ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, BindingFlags.TextValue, attr.i18n);
24110
+ const securityContext = domSchema.securityContext(content.name, attr.name, true);
24111
+ unit.update.push(createBindingOp(op.xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
23934
24112
  }
23935
24113
  unit.create.push(op);
23936
24114
  }
@@ -24045,13 +24223,16 @@ function ingestSwitchBlock(unit, switchBlock) {
24045
24223
  const conditional = createConditionalOp(firstXref, firstSlotHandle, convertAst(switchBlock.expression, unit.job, null), conditions, switchBlock.sourceSpan);
24046
24224
  unit.update.push(conditional);
24047
24225
  }
24048
- function ingestDeferView(unit, suffix, children, sourceSpan) {
24226
+ function ingestDeferView(unit, suffix, i18nMeta, children, sourceSpan) {
24227
+ if (i18nMeta !== undefined && !(i18nMeta instanceof BlockPlaceholder)) {
24228
+ throw Error('Unhandled i18n metadata type for defer block');
24229
+ }
24049
24230
  if (children === undefined) {
24050
24231
  return null;
24051
24232
  }
24052
24233
  const secondaryView = unit.job.allocateView(unit.xref);
24053
24234
  ingestNodes(secondaryView, children);
24054
- const templateOp = createTemplateOp(secondaryView.xref, TemplateKind.Block, null, `Defer${suffix}`, Namespace.HTML, undefined, sourceSpan);
24235
+ const templateOp = createTemplateOp(secondaryView.xref, TemplateKind.Block, null, `Defer${suffix}`, Namespace.HTML, i18nMeta, sourceSpan);
24055
24236
  unit.create.push(templateOp);
24056
24237
  return templateOp;
24057
24238
  }
@@ -24061,10 +24242,10 @@ function ingestDeferBlock(unit, deferBlock) {
24061
24242
  throw new Error(`AssertionError: unable to find metadata for deferred block`);
24062
24243
  }
24063
24244
  // Generate the defer main view and all secondary views.
24064
- const main = ingestDeferView(unit, '', deferBlock.children, deferBlock.sourceSpan);
24065
- const loading = ingestDeferView(unit, 'Loading', deferBlock.loading?.children, deferBlock.loading?.sourceSpan);
24066
- const placeholder = ingestDeferView(unit, 'Placeholder', deferBlock.placeholder?.children, deferBlock.placeholder?.sourceSpan);
24067
- const error = ingestDeferView(unit, 'Error', deferBlock.error?.children, deferBlock.error?.sourceSpan);
24245
+ const main = ingestDeferView(unit, '', deferBlock.i18n, deferBlock.children, deferBlock.sourceSpan);
24246
+ const loading = ingestDeferView(unit, 'Loading', deferBlock.loading?.i18n, deferBlock.loading?.children, deferBlock.loading?.sourceSpan);
24247
+ const placeholder = ingestDeferView(unit, 'Placeholder', deferBlock.placeholder?.i18n, deferBlock.placeholder?.children, deferBlock.placeholder?.sourceSpan);
24248
+ const error = ingestDeferView(unit, 'Error', deferBlock.error?.i18n, deferBlock.error?.children, deferBlock.error?.sourceSpan);
24068
24249
  // Create the main defer op, and ops for all secondary views.
24069
24250
  const deferXref = unit.job.allocateXrefId();
24070
24251
  const deferOp = createDeferOp(deferXref, main.xref, main.handle, blockMeta, deferBlock.sourceSpan);
@@ -24198,8 +24379,17 @@ function ingestForBlock(unit, forBlock) {
24198
24379
  $odd: forBlock.contextVariables.$odd.name,
24199
24380
  $implicit: forBlock.item.name,
24200
24381
  };
24382
+ if (forBlock.i18n !== undefined && !(forBlock.i18n instanceof BlockPlaceholder)) {
24383
+ throw Error('AssertionError: Unhandled i18n metadata type or @for');
24384
+ }
24385
+ if (forBlock.empty?.i18n !== undefined &&
24386
+ !(forBlock.empty.i18n instanceof BlockPlaceholder)) {
24387
+ throw Error('AssertionError: Unhandled i18n metadata type or @empty');
24388
+ }
24389
+ const i18nPlaceholder = forBlock.i18n;
24390
+ const emptyI18nPlaceholder = forBlock.empty?.i18n;
24201
24391
  const tagName = ingestControlFlowInsertionPoint(unit, repeaterView.xref, forBlock);
24202
- const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, forBlock.sourceSpan);
24392
+ const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, i18nPlaceholder, emptyI18nPlaceholder, forBlock.sourceSpan);
24203
24393
  unit.create.push(repeaterCreate);
24204
24394
  const expression = convertAst(forBlock.expression, unit.job, convertSourceSpan(forBlock.expression.span, forBlock.sourceSpan));
24205
24395
  const repeater = createRepeaterOp(repeaterCreate.xref, repeaterCreate.handle, expression, forBlock.sourceSpan);
@@ -24317,6 +24507,27 @@ function convertAst(ast, job, baseSourceSpan) {
24317
24507
  throw new Error(`Unhandled expression type "${ast.constructor.name}" in file "${baseSourceSpan?.start.file.url}"`);
24318
24508
  }
24319
24509
  }
24510
+ function convertAstWithInterpolation(job, value, i18nMeta) {
24511
+ let expression;
24512
+ if (value instanceof Interpolation$1) {
24513
+ expression = new Interpolation(value.strings, value.expressions.map(e => convertAst(e, job, null)), Object.keys(asMessage(i18nMeta)?.placeholders ?? {}));
24514
+ }
24515
+ else if (value instanceof AST) {
24516
+ expression = convertAst(value, job, null);
24517
+ }
24518
+ else {
24519
+ expression = literal(value);
24520
+ }
24521
+ return expression;
24522
+ }
24523
+ // TODO: Can we populate Template binding kinds in ingest?
24524
+ const BINDING_KINDS = new Map([
24525
+ [0 /* e.BindingType.Property */, BindingKind.Property],
24526
+ [1 /* e.BindingType.Attribute */, BindingKind.Attribute],
24527
+ [2 /* e.BindingType.Class */, BindingKind.ClassName],
24528
+ [3 /* e.BindingType.Style */, BindingKind.StyleProperty],
24529
+ [4 /* e.BindingType.Animation */, BindingKind.Animation],
24530
+ ]);
24320
24531
  /**
24321
24532
  * Checks whether the given template is a plain ng-template (as opposed to another kind of template
24322
24533
  * such as a structural directive template or control flow template). This is checked based on the
@@ -24335,149 +24546,184 @@ function convertAst(ast, job, baseSourceSpan) {
24335
24546
  * | `<ng-template *ngIf>` (structural) | null |
24336
24547
  */
24337
24548
  function isPlainTemplate(tmpl) {
24338
- return splitNsName(tmpl.tagName ?? '')[1] === 'ng-template';
24549
+ return splitNsName(tmpl.tagName ?? '')[1] === NG_TEMPLATE_TAG_NAME$1;
24339
24550
  }
24340
24551
  /**
24341
- * Process all of the bindings on an element-like structure in the template AST and convert them
24342
- * to their IR representation.
24552
+ * Ensures that the i18nMeta, if provided, is an i18n.Message.
24343
24553
  */
24344
- function ingestBindings(unit, op, element) {
24345
- let flags = BindingFlags.None;
24346
- let hasI18nAttributes = false;
24347
- if (element instanceof Template) {
24348
- flags |= BindingFlags.OnNgTemplateElement;
24349
- if (element instanceof Template && isPlainTemplate(element)) {
24350
- flags |= BindingFlags.BindingTargetsTemplate;
24351
- }
24352
- const templateAttrFlags = flags | BindingFlags.BindingTargetsTemplate | BindingFlags.IsStructuralTemplateAttribute;
24353
- for (const attr of element.templateAttrs) {
24354
- if (attr instanceof TextAttribute) {
24355
- ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, templateAttrFlags | BindingFlags.TextValue, attr.i18n);
24356
- hasI18nAttributes ||= attr.i18n !== undefined;
24357
- }
24358
- else {
24359
- ingestBinding(unit, op.xref, attr.name, attr.value, attr.type, attr.unit, attr.securityContext, attr.sourceSpan, templateAttrFlags, attr.i18n);
24360
- hasI18nAttributes ||= attr.i18n !== undefined;
24361
- }
24362
- }
24554
+ function asMessage(i18nMeta) {
24555
+ if (i18nMeta == null) {
24556
+ return null;
24557
+ }
24558
+ if (!(i18nMeta instanceof Message)) {
24559
+ throw Error(`Expected i18n meta to be a Message, but got: ${i18nMeta.constructor.name}`);
24363
24560
  }
24561
+ return i18nMeta;
24562
+ }
24563
+ /**
24564
+ * Process all of the bindings on an element in the template AST and convert them to their IR
24565
+ * representation.
24566
+ */
24567
+ function ingestElementBindings(unit, op, element) {
24568
+ let bindings = new Array();
24364
24569
  for (const attr of element.attributes) {
24365
- // This is only attribute TextLiteral bindings, such as `attr.foo="bar"`. This can never be
24366
- // `[attr.foo]="bar"` or `attr.foo="{{bar}}"`, both of which will be handled as inputs with
24367
- // `BindingType.Attribute`.
24368
- ingestBinding(unit, op.xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, flags | BindingFlags.TextValue, attr.i18n);
24369
- hasI18nAttributes ||= attr.i18n !== undefined;
24570
+ // Attribute literal bindings, such as `attr.foo="bar"`.
24571
+ const securityContext = domSchema.securityContext(element.name, attr.name, true);
24572
+ bindings.push(createBindingOp(op.xref, BindingKind.Attribute, attr.name, convertAstWithInterpolation(unit.job, attr.value, attr.i18n), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
24370
24573
  }
24371
24574
  for (const input of element.inputs) {
24372
- ingestBinding(unit, op.xref, input.name, input.value, input.type, input.unit, input.securityContext, input.sourceSpan, flags, input.i18n);
24373
- hasI18nAttributes ||= input.i18n !== undefined;
24575
+ // All dynamic bindings (both attribute and property bindings).
24576
+ bindings.push(createBindingOp(op.xref, BINDING_KINDS.get(input.type), input.name, convertAstWithInterpolation(unit.job, astOf(input.value), input.i18n), input.unit, input.securityContext, false, false, null, asMessage(input.i18n) ?? null, input.sourceSpan));
24374
24577
  }
24578
+ unit.create.push(bindings.filter((b) => b?.kind === OpKind.ExtractedAttribute));
24579
+ unit.update.push(bindings.filter((b) => b?.kind === OpKind.Binding));
24375
24580
  for (const output of element.outputs) {
24376
- let listenerOp;
24377
- if (output.type === 1 /* e.ParsedEventType.Animation */) {
24378
- if (output.phase === null) {
24379
- throw Error('Animation listener should have a phase');
24380
- }
24381
- }
24382
- if (element instanceof Template && !isPlainTemplate(element)) {
24383
- unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null, null));
24384
- continue;
24385
- }
24386
- listenerOp = createListenerOp(op.xref, op.handle, output.name, op.tag, output.phase, false, output.sourceSpan);
24387
- // if output.handler is a chain, then push each statement from the chain separately, and
24388
- // return the last one?
24389
- let handlerExprs;
24390
- let handler = output.handler;
24391
- if (handler instanceof ASTWithSource) {
24392
- handler = handler.ast;
24581
+ if (output.type === 1 /* e.ParsedEventType.Animation */ && output.phase === null) {
24582
+ throw Error('Animation listener should have a phase');
24393
24583
  }
24394
- if (handler instanceof Chain) {
24395
- handlerExprs = handler.expressions;
24584
+ unit.create.push(createListenerOp(op.xref, op.handle, output.name, op.tag, makeListenerHandlerOps(unit, output.handler, output.handlerSpan), output.phase, output.target, false, output.sourceSpan));
24585
+ }
24586
+ // If any of the bindings on this element have an i18n message, then an i18n attrs configuration
24587
+ // op is also required.
24588
+ if (bindings.some(b => b?.i18nMessage) !== null) {
24589
+ unit.create.push(createI18nAttributesOp(unit.job.allocateXrefId(), new SlotHandle(), op.xref));
24590
+ }
24591
+ }
24592
+ /**
24593
+ * Process all of the bindings on a template in the template AST and convert them to their IR
24594
+ * representation.
24595
+ */
24596
+ function ingestTemplateBindings(unit, op, template, templateKind) {
24597
+ let bindings = new Array();
24598
+ for (const attr of template.templateAttrs) {
24599
+ if (attr instanceof TextAttribute) {
24600
+ const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
24601
+ bindings.push(createTemplateBinding(unit, op.xref, 1 /* e.BindingType.Attribute */, attr.name, attr.value, null, securityContext, true, templateKind, asMessage(attr.i18n), attr.sourceSpan));
24396
24602
  }
24397
24603
  else {
24398
- handlerExprs = [handler];
24604
+ bindings.push(createTemplateBinding(unit, op.xref, attr.type, attr.name, astOf(attr.value), attr.unit, attr.securityContext, true, templateKind, asMessage(attr.i18n), attr.sourceSpan));
24605
+ }
24606
+ }
24607
+ for (const attr of template.attributes) {
24608
+ // Attribute literal bindings, such as `attr.foo="bar"`.
24609
+ const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
24610
+ bindings.push(createTemplateBinding(unit, op.xref, 1 /* e.BindingType.Attribute */, attr.name, attr.value, null, securityContext, false, templateKind, asMessage(attr.i18n), attr.sourceSpan));
24611
+ }
24612
+ for (const input of template.inputs) {
24613
+ // Dynamic bindings (both attribute and property bindings).
24614
+ bindings.push(createTemplateBinding(unit, op.xref, input.type, input.name, astOf(input.value), input.unit, input.securityContext, false, templateKind, asMessage(input.i18n), input.sourceSpan));
24615
+ }
24616
+ unit.create.push(bindings.filter((b) => b?.kind === OpKind.ExtractedAttribute));
24617
+ unit.update.push(bindings.filter((b) => b?.kind === OpKind.Binding));
24618
+ for (const output of template.outputs) {
24619
+ if (output.type === 1 /* e.ParsedEventType.Animation */ && output.phase === null) {
24620
+ throw Error('Animation listener should have a phase');
24399
24621
  }
24400
- if (handlerExprs.length === 0) {
24401
- throw new Error('Expected listener to have non-empty expression list.');
24622
+ if (templateKind === TemplateKind.NgTemplate) {
24623
+ unit.create.push(createListenerOp(op.xref, op.handle, output.name, op.tag, makeListenerHandlerOps(unit, output.handler, output.handlerSpan), output.phase, output.target, false, output.sourceSpan));
24402
24624
  }
24403
- const expressions = handlerExprs.map(expr => convertAst(expr, unit.job, output.handlerSpan));
24404
- const returnExpr = expressions.pop();
24405
- for (const expr of expressions) {
24406
- const stmtOp = createStatementOp(new ExpressionStatement(expr, expr.sourceSpan));
24407
- listenerOp.handlerOps.push(stmtOp);
24625
+ if (templateKind === TemplateKind.Structural &&
24626
+ output.type !== 1 /* e.ParsedEventType.Animation */) {
24627
+ // Animation bindings are excluded from the structural template's const array.
24628
+ const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, output.name, false);
24629
+ unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null, null, null, securityContext));
24408
24630
  }
24409
- listenerOp.handlerOps.push(createStatementOp(new ReturnStatement(returnExpr, returnExpr.sourceSpan)));
24410
- unit.create.push(listenerOp);
24411
24631
  }
24412
24632
  // TODO: Perhaps we could do this in a phase? (It likely wouldn't change the slot indices.)
24413
- if (hasI18nAttributes) {
24633
+ if (bindings.some(b => b?.i18nMessage) !== null) {
24414
24634
  unit.create.push(createI18nAttributesOp(unit.job.allocateXrefId(), new SlotHandle(), op.xref));
24415
24635
  }
24416
24636
  }
24417
- const BINDING_KINDS = new Map([
24418
- [0 /* e.BindingType.Property */, BindingKind.Property],
24419
- [1 /* e.BindingType.Attribute */, BindingKind.Attribute],
24420
- [2 /* e.BindingType.Class */, BindingKind.ClassName],
24421
- [3 /* e.BindingType.Style */, BindingKind.StyleProperty],
24422
- [4 /* e.BindingType.Animation */, BindingKind.Animation],
24423
- ]);
24424
- var BindingFlags;
24425
- (function (BindingFlags) {
24426
- BindingFlags[BindingFlags["None"] = 0] = "None";
24427
- /**
24428
- * The binding is to a static text literal and not to an expression.
24429
- */
24430
- BindingFlags[BindingFlags["TextValue"] = 1] = "TextValue";
24431
- /**
24432
- * The binding belongs to the `<ng-template>` side of a `t.Template`.
24433
- */
24434
- BindingFlags[BindingFlags["BindingTargetsTemplate"] = 2] = "BindingTargetsTemplate";
24435
- /**
24436
- * The binding is on a structural directive.
24437
- */
24438
- BindingFlags[BindingFlags["IsStructuralTemplateAttribute"] = 4] = "IsStructuralTemplateAttribute";
24439
- /**
24440
- * The binding is on a `t.Template`.
24441
- */
24442
- BindingFlags[BindingFlags["OnNgTemplateElement"] = 8] = "OnNgTemplateElement";
24443
- })(BindingFlags || (BindingFlags = {}));
24444
- function ingestBinding(view, xref, name, value, type, unit, securityContext, sourceSpan, flags, i18nMeta) {
24445
- if (value instanceof ASTWithSource) {
24446
- value = value.ast;
24447
- }
24448
- let i18nContext = null;
24449
- if (i18nMeta !== undefined) {
24450
- if (!(i18nMeta instanceof Message)) {
24451
- throw Error(`Unhandled i18n metadata type for binding: ${i18nMeta.constructor.name}`);
24637
+ /**
24638
+ * Helper to ingest an individual binding on a template, either an explicit `ng-template`, or an
24639
+ * implicit template created via structural directive.
24640
+ *
24641
+ * Bindings on templates are *extremely* tricky. I have tried to isolate all of the confusing edge
24642
+ * cases into this function, and to comment it well to document the behavior.
24643
+ *
24644
+ * Some of this behavior is intuitively incorrect, and we should consider changing it in the future.
24645
+ *
24646
+ * @param view The compilation unit for the view containing the template.
24647
+ * @param xref The xref of the template op.
24648
+ * @param type The binding type, according to the parser. This is fairly reasonable, e.g. both
24649
+ * dynamic and static attributes have e.BindingType.Attribute.
24650
+ * @param name The binding's name.
24651
+ * @param value The bindings's value, which will either be an input AST expression, or a string
24652
+ * literal. Note that the input AST expression may or may not be const -- it will only be a
24653
+ * string literal if the parser considered it a text binding.
24654
+ * @param unit If the binding has a unit (e.g. `px` for style bindings), then this is the unit.
24655
+ * @param securityContext The security context of the binding.
24656
+ * @param isStructuralTemplateAttribute Whether this binding actually applies to the structural
24657
+ * ng-template. For example, an `ngFor` would actually apply to the structural template. (Most
24658
+ * bindings on structural elements target the inner element, not the template.)
24659
+ * @param templateKind Whether this is an explicit `ng-template` or an implicit template created by
24660
+ * a structural directive. This should never be a block template.
24661
+ * @param i18nMessage The i18n metadata for the binding, if any.
24662
+ * @param sourceSpan The source span of the binding.
24663
+ * @returns An IR binding op, or null if the binding should be skipped.
24664
+ */
24665
+ function createTemplateBinding(view, xref, type, name, value, unit, securityContext, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan) {
24666
+ const isTextBinding = typeof value === 'string';
24667
+ // If this is a structural template, then several kinds of bindings should not result in an
24668
+ // update instruction.
24669
+ if (templateKind === TemplateKind.Structural) {
24670
+ if (!isStructuralTemplateAttribute &&
24671
+ (type === 0 /* e.BindingType.Property */ || type === 2 /* e.BindingType.Class */ ||
24672
+ type === 3 /* e.BindingType.Style */)) {
24673
+ // Because this binding doesn't really target the ng-template, it must be a binding on an
24674
+ // inner node of a structural template. We can't skip it entirely, because we still need it on
24675
+ // the ng-template's consts (e.g. for the purposes of directive matching). However, we should
24676
+ // not generate an update instruction for it.
24677
+ return createExtractedAttributeOp(xref, BindingKind.Property, name, null, null, i18nMessage, securityContext);
24678
+ }
24679
+ if (!isTextBinding && (type === 1 /* e.BindingType.Attribute */ || type === 4 /* e.BindingType.Animation */)) {
24680
+ // Again, this binding doesn't really target the ng-template; it actually targets the element
24681
+ // inside the structural template. In the case of non-text attribute or animation bindings,
24682
+ // the binding doesn't even show up on the ng-template const array, so we just skip it
24683
+ // entirely.
24684
+ return null;
24452
24685
  }
24453
- i18nContext = view.job.allocateXrefId();
24454
- view.create.push(createI18nContextOp(I18nContextKind.Attr, i18nContext, null, i18nMeta, null));
24455
- }
24456
- if (flags & BindingFlags.OnNgTemplateElement && !(flags & BindingFlags.BindingTargetsTemplate) &&
24457
- type === 0 /* e.BindingType.Property */) {
24458
- // This binding only exists for later const extraction, and is not an actual binding to be
24459
- // created.
24460
- view.create.push(createExtractedAttributeOp(xref, BindingKind.Property, name, null, i18nContext));
24461
- return;
24462
24686
  }
24463
- let expression;
24464
- // TODO: We could easily generate source maps for subexpressions in these cases, but
24465
- // TemplateDefinitionBuilder does not. Should we do so?
24466
- if (value instanceof Interpolation$1) {
24467
- let i18nPlaceholders = [];
24468
- if (i18nMeta !== undefined) {
24469
- i18nPlaceholders = Object.keys(i18nMeta.placeholders);
24687
+ let bindingType = BINDING_KINDS.get(type);
24688
+ if (templateKind === TemplateKind.NgTemplate) {
24689
+ // We know we are dealing with bindings directly on an explicit ng-template.
24690
+ // Static attribute bindings should be collected into the const array as k/v pairs. Property
24691
+ // bindings should result in a `property` instruction, and `AttributeMarker.Bindings` const
24692
+ // entries.
24693
+ //
24694
+ // The difficulty is with dynamic attribute, style, and class bindings. These don't really make
24695
+ // sense on an `ng-template` and should probably be parser errors. However,
24696
+ // TemplateDefinitionBuilder generates `property` instructions for them, and so we do that as
24697
+ // well.
24698
+ //
24699
+ // Note that we do have a slight behavior difference with TemplateDefinitionBuilder: although
24700
+ // TDB emits `property` instructions for dynamic attributes, styles, and classes, only styles
24701
+ // and classes also get const collected into the `AttributeMarker.Bindings` field. Dynamic
24702
+ // attribute bindings are missing from the consts entirely. We choose to emit them into the
24703
+ // consts field anyway, to avoid creating special cases for something so arcane and nonsensical.
24704
+ if (type === 2 /* e.BindingType.Class */ || type === 3 /* e.BindingType.Style */ ||
24705
+ (type === 1 /* e.BindingType.Attribute */ && !isTextBinding)) {
24706
+ // TODO: These cases should be parse errors.
24707
+ bindingType = BindingKind.Property;
24470
24708
  }
24471
- expression = new Interpolation(value.strings, value.expressions.map(expr => convertAst(expr, view.job, null)), i18nPlaceholders);
24472
24709
  }
24473
- else if (value instanceof AST) {
24474
- expression = convertAst(value, view.job, null);
24475
- }
24476
- else {
24477
- expression = value;
24710
+ return createBindingOp(xref, bindingType, name, convertAstWithInterpolation(view.job, value, i18nMessage), unit, securityContext, isTextBinding, isStructuralTemplateAttribute, templateKind, i18nMessage, sourceSpan);
24711
+ }
24712
+ function makeListenerHandlerOps(unit, handler, handlerSpan) {
24713
+ handler = astOf(handler);
24714
+ const handlerOps = new Array();
24715
+ let handlerExprs = handler instanceof Chain ? handler.expressions : [handler];
24716
+ if (handlerExprs.length === 0) {
24717
+ throw new Error('Expected listener to have non-empty expression list.');
24478
24718
  }
24479
- const kind = BINDING_KINDS.get(type);
24480
- view.update.push(createBindingOp(xref, kind, name, expression, unit, securityContext, !!(flags & BindingFlags.TextValue), !!(flags & BindingFlags.IsStructuralTemplateAttribute), i18nContext, sourceSpan));
24719
+ const expressions = handlerExprs.map(expr => convertAst(expr, unit.job, handlerSpan));
24720
+ const returnExpr = expressions.pop();
24721
+ handlerOps.push(...expressions.map(e => createStatementOp(new ExpressionStatement(e, e.sourceSpan))));
24722
+ handlerOps.push(createStatementOp(new ReturnStatement(returnExpr, returnExpr.sourceSpan)));
24723
+ return handlerOps;
24724
+ }
24725
+ function astOf(ast) {
24726
+ return ast instanceof ASTWithSource ? ast.ast : ast;
24481
24727
  }
24482
24728
  /**
24483
24729
  * Process all of the local references on an element-like structure in the template AST and
@@ -24565,11 +24811,12 @@ function ingestControlFlowInsertionPoint(unit, xref, node) {
24565
24811
  // and they can be used in directive matching (in the case of `Template.templateAttrs`).
24566
24812
  if (root !== null) {
24567
24813
  for (const attr of root.attributes) {
24568
- ingestBinding(unit, xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, BindingFlags.TextValue, attr.i18n);
24814
+ const securityContext = domSchema.securityContext(NG_TEMPLATE_TAG_NAME$1, attr.name, true);
24815
+ unit.update.push(createBindingOp(xref, BindingKind.Attribute, attr.name, literal(attr.value), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
24569
24816
  }
24570
24817
  const tagName = root instanceof Element$1 ? root.name : root.tagName;
24571
24818
  // Don't pass along `ng-template` tag name since it enables directive matching.
24572
- return tagName === 'ng-template' ? null : tagName;
24819
+ return tagName === NG_TEMPLATE_TAG_NAME$1 ? null : tagName;
24573
24820
  }
24574
24821
  return null;
24575
24822
  }
@@ -29923,14 +30170,16 @@ function createBaseDirectiveTypeParams(meta) {
29923
30170
  function getInputsTypeExpression(meta) {
29924
30171
  return literalMap(Object.keys(meta.inputs).map(key => {
29925
30172
  const value = meta.inputs[key];
29926
- return {
29927
- key,
29928
- value: literalMap([
29929
- { key: 'alias', value: literal(value.bindingPropertyName), quoted: true },
29930
- { key: 'required', value: literal(value.required), quoted: true }
29931
- ]),
29932
- quoted: true
29933
- };
30173
+ const values = [
30174
+ { key: 'alias', value: literal(value.bindingPropertyName), quoted: true },
30175
+ { key: 'required', value: literal(value.required), quoted: true },
30176
+ ];
30177
+ // TODO(legacy-partial-output-inputs): Consider always emitting this information,
30178
+ // or leaving it as is.
30179
+ if (value.isSignal) {
30180
+ values.push({ key: 'isSignal', value: literal(value.isSignal), quoted: true });
30181
+ }
30182
+ return { key, value: literalMap(values), quoted: true };
29934
30183
  }));
29935
30184
  }
29936
30185
  /**
@@ -29996,6 +30245,7 @@ function createHostBindingsFunction(hostBindingsMetadata, typeSourceSpan, bindin
29996
30245
  }
29997
30246
  const hostJob = ingestHostBinding({
29998
30247
  componentName: name,
30248
+ componentSelector: selector,
29999
30249
  properties: bindings,
30000
30250
  events: eventBindings,
30001
30251
  attributes: hostBindingsMetadata.attributes,
@@ -30306,6 +30556,18 @@ function compileStyles(styles, selector, hostSelector) {
30306
30556
  return shadowCss.shimCssText(style, selector, hostSelector);
30307
30557
  });
30308
30558
  }
30559
+ /**
30560
+ * Encapsulates a CSS stylesheet with emulated view encapsulation.
30561
+ * This allows a stylesheet to be used with an Angular component that
30562
+ * is using the `ViewEncapsulation.Emulated` mode.
30563
+ *
30564
+ * @param style The content of a CSS stylesheet.
30565
+ * @returns The encapsulated content for the style.
30566
+ */
30567
+ function encapsulateStyle(style) {
30568
+ const shadowCss = new ShadowCss();
30569
+ return shadowCss.shimCssText(style, CONTENT_ATTR, HOST_ATTR);
30570
+ }
30309
30571
  function createHostDirectivesType(meta) {
30310
30572
  if (!meta.hostDirectives?.length) {
30311
30573
  return NONE_TYPE;
@@ -31371,6 +31633,8 @@ function convertDirectiveFacadeToMetadata(facade) {
31371
31633
  bindingPropertyName: ann.alias || field,
31372
31634
  classPropertyName: field,
31373
31635
  required: ann.required || false,
31636
+ // TODO(signals): Support JIT signal inputs via decorator transform.
31637
+ isSignal: false,
31374
31638
  transformFunction: ann.transform != null ? new WrappedNodeExpr(ann.transform) : null,
31375
31639
  };
31376
31640
  }
@@ -31402,7 +31666,7 @@ function convertDeclareDirectiveFacadeToMetadata(declaration, typeSourceSpan) {
31402
31666
  type: wrapReference(declaration.type),
31403
31667
  typeSourceSpan,
31404
31668
  selector: declaration.selector ?? null,
31405
- inputs: declaration.inputs ? inputsMappingToInputMetadata(declaration.inputs) : {},
31669
+ inputs: declaration.inputs ? inputsPartialMetadataToInputMetadata(declaration.inputs) : {},
31406
31670
  outputs: declaration.outputs ?? {},
31407
31671
  host: convertHostDeclarationToMetadata(declaration.host),
31408
31672
  queries: (declaration.queries ?? []).map(convertQueryDeclarationToMetadata),
@@ -31665,28 +31929,51 @@ function isInput(value) {
31665
31929
  function isOutput(value) {
31666
31930
  return value.ngMetadataName === 'Output';
31667
31931
  }
31668
- function inputsMappingToInputMetadata(inputs) {
31669
- return Object.keys(inputs).reduce((result, key) => {
31670
- const value = inputs[key];
31671
- if (typeof value === 'string') {
31672
- result[key] = {
31673
- bindingPropertyName: value,
31674
- classPropertyName: value,
31675
- transformFunction: null,
31676
- required: false,
31677
- };
31932
+ function inputsPartialMetadataToInputMetadata(inputs) {
31933
+ return Object.keys(inputs).reduce((result, minifiedClassName) => {
31934
+ const value = inputs[minifiedClassName];
31935
+ // Handle legacy partial input output.
31936
+ if (typeof value === 'string' || Array.isArray(value)) {
31937
+ result[minifiedClassName] = parseLegacyInputPartialOutput(value);
31678
31938
  }
31679
31939
  else {
31680
- result[key] = {
31681
- bindingPropertyName: value[0],
31682
- classPropertyName: value[1],
31683
- transformFunction: value[2] ? new WrappedNodeExpr(value[2]) : null,
31684
- required: false,
31940
+ result[minifiedClassName] = {
31941
+ bindingPropertyName: value.publicName,
31942
+ classPropertyName: minifiedClassName,
31943
+ transformFunction: value.transformFunction !== null ?
31944
+ new WrappedNodeExpr(value.transformFunction) :
31945
+ null,
31946
+ required: value.isRequired,
31947
+ isSignal: value.isSignal,
31685
31948
  };
31686
31949
  }
31687
31950
  return result;
31688
31951
  }, {});
31689
31952
  }
31953
+ /**
31954
+ * Parses the legacy input partial output. For more details see `partial/directive.ts`.
31955
+ * TODO(legacy-partial-output-inputs): Remove in v18.
31956
+ */
31957
+ function parseLegacyInputPartialOutput(value) {
31958
+ if (typeof value === 'string') {
31959
+ return {
31960
+ bindingPropertyName: value,
31961
+ classPropertyName: value,
31962
+ transformFunction: null,
31963
+ required: false,
31964
+ // legacy partial output does not capture signal inputs.
31965
+ isSignal: false,
31966
+ };
31967
+ }
31968
+ return {
31969
+ bindingPropertyName: value[0],
31970
+ classPropertyName: value[1],
31971
+ transformFunction: value[2] ? new WrappedNodeExpr(value[2]) : null,
31972
+ required: false,
31973
+ // legacy partial output does not capture signal inputs.
31974
+ isSignal: false,
31975
+ };
31976
+ }
31690
31977
  function parseInputsArray(values) {
31691
31978
  return values.reduce((results, value) => {
31692
31979
  if (typeof value === 'string') {
@@ -31695,6 +31982,8 @@ function parseInputsArray(values) {
31695
31982
  bindingPropertyName,
31696
31983
  classPropertyName,
31697
31984
  required: false,
31985
+ // Signal inputs not supported for the inputs array.
31986
+ isSignal: false,
31698
31987
  transformFunction: null,
31699
31988
  };
31700
31989
  }
@@ -31703,6 +31992,8 @@ function parseInputsArray(values) {
31703
31992
  bindingPropertyName: value.alias || value.name,
31704
31993
  classPropertyName: value.name,
31705
31994
  required: value.required || false,
31995
+ // Signal inputs not supported for the inputs array.
31996
+ isSignal: false,
31706
31997
  transformFunction: value.transform != null ? new WrappedNodeExpr(value.transform) : null,
31707
31998
  };
31708
31999
  }
@@ -31755,7 +32046,7 @@ function publishFacade(global) {
31755
32046
  * @description
31756
32047
  * Entry point for all public APIs of the compiler package.
31757
32048
  */
31758
- const VERSION = new Version('17.1.0-next.3');
32049
+ const VERSION = new Version('17.1.0-next.4');
31759
32050
 
31760
32051
  class CompilerConfig {
31761
32052
  constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
@@ -33317,11 +33608,11 @@ function compileClassDebugInfo(debugInfo) {
33317
33608
  *
33318
33609
  * Do not include any prerelease in these versions as they are ignored.
33319
33610
  */
33320
- const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
33611
+ const MINIMUM_PARTIAL_LINKER_VERSION$5 = '12.0.0';
33321
33612
  function compileDeclareClassMetadata(metadata) {
33322
33613
  const definitionMap = new DefinitionMap();
33323
- definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
33324
- definitionMap.set('version', literal('17.1.0-next.3'));
33614
+ definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
33615
+ definitionMap.set('version', literal('17.1.0-next.4'));
33325
33616
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33326
33617
  definitionMap.set('type', metadata.type);
33327
33618
  definitionMap.set('decorators', metadata.decorators);
@@ -33400,14 +33691,6 @@ function compileDependency(dep) {
33400
33691
  return depMeta.toLiteralMap();
33401
33692
  }
33402
33693
 
33403
- /**
33404
- * Every time we make a breaking change to the declaration interface or partial-linker behavior, we
33405
- * must update this constant to prevent old partial-linkers from incorrectly processing the
33406
- * declaration.
33407
- *
33408
- * Do not include any prerelease in these versions as they are ignored.
33409
- */
33410
- const MINIMUM_PARTIAL_LINKER_VERSION$5 = '16.1.0';
33411
33694
  /**
33412
33695
  * Compile a directive declaration defined by the `R3DirectiveMetadata`.
33413
33696
  */
@@ -33423,13 +33706,9 @@ function compileDeclareDirectiveFromMetadata(meta) {
33423
33706
  */
33424
33707
  function createDirectiveDefinitionMap(meta) {
33425
33708
  const definitionMap = new DefinitionMap();
33426
- const hasTransformFunctions = Object.values(meta.inputs).some(input => input.transformFunction !== null);
33427
- // Note: in order to allow consuming Angular libraries that have been compiled with 16.1+ in
33428
- // Angular 16.0, we only force a minimum version of 16.1 if input transform feature as introduced
33429
- // in 16.1 is actually used.
33430
- const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
33709
+ const minVersion = getMinimumVersionForPartialOutput(meta);
33431
33710
  definitionMap.set('minVersion', literal(minVersion));
33432
- definitionMap.set('version', literal('17.1.0-next.3'));
33711
+ definitionMap.set('version', literal('17.1.0-next.4'));
33433
33712
  // e.g. `type: MyDirective`
33434
33713
  definitionMap.set('type', meta.type.value);
33435
33714
  if (meta.isStandalone) {
@@ -33442,7 +33721,8 @@ function createDirectiveDefinitionMap(meta) {
33442
33721
  if (meta.selector !== null) {
33443
33722
  definitionMap.set('selector', literal(meta.selector));
33444
33723
  }
33445
- definitionMap.set('inputs', conditionallyCreateDirectiveBindingLiteral(meta.inputs, true));
33724
+ definitionMap.set('inputs', needsNewInputPartialOutput(meta) ? createInputsPartialMetadata(meta.inputs) :
33725
+ legacyInputsPartialMetadata(meta.inputs));
33446
33726
  definitionMap.set('outputs', conditionallyCreateDirectiveBindingLiteral(meta.outputs));
33447
33727
  definitionMap.set('host', compileHostMetadata(meta.host));
33448
33728
  definitionMap.set('providers', meta.providers);
@@ -33467,6 +33747,44 @@ function createDirectiveDefinitionMap(meta) {
33467
33747
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33468
33748
  return definitionMap;
33469
33749
  }
33750
+ /**
33751
+ * Determines the minimum linker version for the partial output
33752
+ * generated for this directive.
33753
+ *
33754
+ * Every time we make a breaking change to the declaration interface or partial-linker
33755
+ * behavior, we must update the minimum versions to prevent old partial-linkers from
33756
+ * incorrectly processing the declaration.
33757
+ *
33758
+ * NOTE: Do not include any prerelease in these versions as they are ignored.
33759
+ */
33760
+ function getMinimumVersionForPartialOutput(meta) {
33761
+ // We are starting with the oldest minimum version that can work for common
33762
+ // directive partial compilation output. As we discover usages of new features
33763
+ // that require a newer partial output emit, we bump the `minVersion`. Our goal
33764
+ // is to keep libraries as much compatible with older linker versions as possible.
33765
+ let minVersion = '14.0.0';
33766
+ // Note: in order to allow consuming Angular libraries that have been compiled with 16.1+ in
33767
+ // Angular 16.0, we only force a minimum version of 16.1 if input transform feature as introduced
33768
+ // in 16.1 is actually used.
33769
+ const hasTransformFunctions = Object.values(meta.inputs).some(input => input.transformFunction !== null);
33770
+ if (hasTransformFunctions) {
33771
+ minVersion = '16.1.0';
33772
+ }
33773
+ // If there are input flags and we need the new emit, use the actual minimum version,
33774
+ // where this was introduced. i.e. in 17.1.0
33775
+ // TODO(legacy-partial-output-inputs): Remove in v18.
33776
+ if (needsNewInputPartialOutput(meta)) {
33777
+ minVersion = '17.1.0';
33778
+ }
33779
+ return minVersion;
33780
+ }
33781
+ /**
33782
+ * Gets whether the given directive needs the new input partial output structure
33783
+ * that can hold additional metadata like `isRequired`, `isSignal` etc.
33784
+ */
33785
+ function needsNewInputPartialOutput(meta) {
33786
+ return Object.values(meta.inputs).some(input => input.isSignal);
33787
+ }
33470
33788
  /**
33471
33789
  * Compiles the metadata of a single query into its partial declaration form as declared
33472
33790
  * by `R3DeclareQueryMetadata`.
@@ -33540,6 +33858,74 @@ function createHostDirectives(hostDirectives) {
33540
33858
  // otherwise we can save some bytes by using a plain array, e.g. `[{directive: HostDir}]`.
33541
33859
  return literalArr(expressions);
33542
33860
  }
33861
+ /**
33862
+ * Generates partial output metadata for inputs of a directive.
33863
+ *
33864
+ * The generated structure is expected to match `R3DeclareDirectiveFacade['inputs']`.
33865
+ */
33866
+ function createInputsPartialMetadata(inputs) {
33867
+ const keys = Object.getOwnPropertyNames(inputs);
33868
+ if (keys.length === 0) {
33869
+ return null;
33870
+ }
33871
+ return literalMap(keys.map(declaredName => {
33872
+ const value = inputs[declaredName];
33873
+ return {
33874
+ key: declaredName,
33875
+ // put quotes around keys that contain potentially unsafe characters
33876
+ quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(declaredName),
33877
+ value: literalMap([
33878
+ { key: 'classPropertyName', quoted: false, value: asLiteral(value.classPropertyName) },
33879
+ { key: 'publicName', quoted: false, value: asLiteral(value.bindingPropertyName) },
33880
+ { key: 'isSignal', quoted: false, value: asLiteral(value.isSignal) },
33881
+ { key: 'isRequired', quoted: false, value: asLiteral(value.required) },
33882
+ { key: 'transformFunction', quoted: false, value: value.transformFunction ?? NULL_EXPR },
33883
+ ])
33884
+ };
33885
+ }));
33886
+ }
33887
+ /**
33888
+ * Pre v18 legacy partial output for inputs.
33889
+ *
33890
+ * Previously, inputs did not capture metadata like `isSignal` in the partial compilation output.
33891
+ * To enable capturing such metadata, we restructured how input metadata is communicated in the
33892
+ * partial output. This would make libraries incompatible with older Angular FW versions where the
33893
+ * linker would not know how to handle this new "format". For this reason, if we know this metadata
33894
+ * does not need to be captured- we fall back to the old format. This is what this function
33895
+ * generates.
33896
+ *
33897
+ * See:
33898
+ * https://github.com/angular/angular/blob/d4b423690210872b5c32a322a6090beda30b05a3/packages/core/src/compiler/compiler_facade_interface.ts#L197-L199
33899
+ */
33900
+ function legacyInputsPartialMetadata(inputs) {
33901
+ // TODO(legacy-partial-output-inputs): Remove function in v18.
33902
+ const keys = Object.getOwnPropertyNames(inputs);
33903
+ if (keys.length === 0) {
33904
+ return null;
33905
+ }
33906
+ return literalMap(keys.map(declaredName => {
33907
+ const value = inputs[declaredName];
33908
+ const publicName = value.bindingPropertyName;
33909
+ const differentDeclaringName = publicName !== declaredName;
33910
+ let result;
33911
+ if (differentDeclaringName || value.transformFunction !== null) {
33912
+ const values = [asLiteral(publicName), asLiteral(declaredName)];
33913
+ if (value.transformFunction !== null) {
33914
+ values.push(value.transformFunction);
33915
+ }
33916
+ result = literalArr(values);
33917
+ }
33918
+ else {
33919
+ result = asLiteral(publicName);
33920
+ }
33921
+ return {
33922
+ key: declaredName,
33923
+ // put quotes around keys that contain potentially unsafe characters
33924
+ quoted: UNSAFE_OBJECT_KEY_NAME_REGEXP.test(declaredName),
33925
+ value: result,
33926
+ };
33927
+ }));
33928
+ }
33543
33929
 
33544
33930
  /**
33545
33931
  * Compile a component declaration defined by the `R3ComponentMetadata`.
@@ -33706,7 +34092,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
33706
34092
  function compileDeclareFactoryFunction(meta) {
33707
34093
  const definitionMap = new DefinitionMap();
33708
34094
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
33709
- definitionMap.set('version', literal('17.1.0-next.3'));
34095
+ definitionMap.set('version', literal('17.1.0-next.4'));
33710
34096
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33711
34097
  definitionMap.set('type', meta.type.value);
33712
34098
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -33741,7 +34127,7 @@ function compileDeclareInjectableFromMetadata(meta) {
33741
34127
  function createInjectableDefinitionMap(meta) {
33742
34128
  const definitionMap = new DefinitionMap();
33743
34129
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
33744
- definitionMap.set('version', literal('17.1.0-next.3'));
34130
+ definitionMap.set('version', literal('17.1.0-next.4'));
33745
34131
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33746
34132
  definitionMap.set('type', meta.type.value);
33747
34133
  // Only generate providedIn property if it has a non-null value
@@ -33792,7 +34178,7 @@ function compileDeclareInjectorFromMetadata(meta) {
33792
34178
  function createInjectorDefinitionMap(meta) {
33793
34179
  const definitionMap = new DefinitionMap();
33794
34180
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
33795
- definitionMap.set('version', literal('17.1.0-next.3'));
34181
+ definitionMap.set('version', literal('17.1.0-next.4'));
33796
34182
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33797
34183
  definitionMap.set('type', meta.type.value);
33798
34184
  definitionMap.set('providers', meta.providers);
@@ -33825,7 +34211,7 @@ function createNgModuleDefinitionMap(meta) {
33825
34211
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
33826
34212
  }
33827
34213
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
33828
- definitionMap.set('version', literal('17.1.0-next.3'));
34214
+ definitionMap.set('version', literal('17.1.0-next.4'));
33829
34215
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33830
34216
  definitionMap.set('type', meta.type.value);
33831
34217
  // We only generate the keys in the metadata if the arrays contain values.
@@ -33876,7 +34262,7 @@ function compileDeclarePipeFromMetadata(meta) {
33876
34262
  function createPipeDefinitionMap(meta) {
33877
34263
  const definitionMap = new DefinitionMap();
33878
34264
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
33879
- definitionMap.set('version', literal('17.1.0-next.3'));
34265
+ definitionMap.set('version', literal('17.1.0-next.4'));
33880
34266
  definitionMap.set('ngImport', importExpr(Identifiers.core));
33881
34267
  // e.g. `type: MyPipe`
33882
34268
  definitionMap.set('type', meta.type.value);
@@ -33909,5 +34295,5 @@ publishFacade(_global);
33909
34295
 
33910
34296
  // This file is not used to build this module. It is only used during editing
33911
34297
 
33912
- 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, createCssSelectorFromNode, 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 };
34298
+ 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, createCssSelectorFromNode, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, encapsulateStyle, 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 };
33913
34299
  //# sourceMappingURL=compiler.mjs.map