@angular/compiler 16.2.0-next.2 → 16.2.0-next.3

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 (38) hide show
  1. package/esm2022/src/compiler.mjs +3 -3
  2. package/esm2022/src/jit_compiler_facade.mjs +6 -2
  3. package/esm2022/src/output/abstract_emitter.mjs +4 -1
  4. package/esm2022/src/output/output_ast.mjs +22 -1
  5. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  6. package/esm2022/src/render3/partial/directive.mjs +1 -1
  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_ast.mjs +109 -1
  13. package/esm2022/src/render3/r3_deferred_blocks.mjs +156 -0
  14. package/esm2022/src/render3/r3_deferred_triggers.mjs +275 -0
  15. package/esm2022/src/render3/r3_template_transform.mjs +40 -12
  16. package/esm2022/src/render3/view/t2_binder.mjs +61 -6
  17. package/esm2022/src/render3/view/template.mjs +17 -3
  18. package/esm2022/src/template/pipeline/ir/src/enums.mjs +21 -9
  19. package/esm2022/src/template/pipeline/ir/src/expression.mjs +4 -1
  20. package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +42 -1
  21. package/esm2022/src/template/pipeline/src/emit.mjs +8 -6
  22. package/esm2022/src/template/pipeline/src/ingest.mjs +25 -3
  23. package/esm2022/src/template/pipeline/src/instruction.mjs +35 -8
  24. package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +2 -1
  25. package/esm2022/src/template/pipeline/src/phases/chaining.mjs +11 -1
  26. package/esm2022/src/template/pipeline/src/phases/naming.mjs +38 -9
  27. package/esm2022/src/template/pipeline/src/phases/property_ordering.mjs +82 -0
  28. package/esm2022/src/template/pipeline/src/phases/reify.mjs +10 -1
  29. package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +13 -8
  30. package/esm2022/src/template_parser/binding_parser.mjs +4 -4
  31. package/esm2022/src/util.mjs +2 -8
  32. package/esm2022/src/version.mjs +1 -1
  33. package/fesm2022/compiler.mjs +1322 -454
  34. package/fesm2022/compiler.mjs.map +1 -1
  35. package/fesm2022/testing.mjs +1 -1
  36. package/index.d.ts +120 -2
  37. package/package.json +2 -2
  38. package/testing/index.d.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v16.2.0-next.2
2
+ * @license Angular v16.2.0-next.3
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -1621,6 +1621,24 @@ class ConditionalExpr extends Expression {
1621
1621
  return new ConditionalExpr(this.condition.clone(), this.trueCase.clone(), this.falseCase?.clone(), this.type, this.sourceSpan);
1622
1622
  }
1623
1623
  }
1624
+ class DynamicImportExpr extends Expression {
1625
+ constructor(url, sourceSpan) {
1626
+ super(null, sourceSpan);
1627
+ this.url = url;
1628
+ }
1629
+ isEquivalent(e) {
1630
+ return e instanceof DynamicImportExpr && this.url === e.url;
1631
+ }
1632
+ isConstant() {
1633
+ return false;
1634
+ }
1635
+ visitExpression(visitor, context) {
1636
+ return visitor.visitDynamicImportExpr(this, context);
1637
+ }
1638
+ clone() {
1639
+ return new DynamicImportExpr(this.url, this.sourceSpan);
1640
+ }
1641
+ }
1624
1642
  class NotExpr extends Expression {
1625
1643
  constructor(condition, sourceSpan) {
1626
1644
  super(BOOL_TYPE, sourceSpan);
@@ -2009,6 +2027,9 @@ class RecursiveAstVisitor$1 {
2009
2027
  ast.value.visitExpression(this, context);
2010
2028
  return this.visitExpression(ast, context);
2011
2029
  }
2030
+ visitDynamicImportExpr(ast, context) {
2031
+ return this.visitExpression(ast, context);
2032
+ }
2012
2033
  visitInvokeFunctionExpr(ast, context) {
2013
2034
  ast.fn.visitExpression(this, context);
2014
2035
  this.visitAllExpressions(ast.args, context);
@@ -2247,6 +2268,7 @@ var output_ast = /*#__PURE__*/Object.freeze({
2247
2268
  ExternalExpr: ExternalExpr,
2248
2269
  ExternalReference: ExternalReference,
2249
2270
  ConditionalExpr: ConditionalExpr,
2271
+ DynamicImportExpr: DynamicImportExpr,
2250
2272
  NotExpr: NotExpr,
2251
2273
  FnParam: FnParam,
2252
2274
  FunctionExpr: FunctionExpr,
@@ -2825,13 +2847,7 @@ class Version {
2825
2847
  this.patch = splits.slice(2).join('.');
2826
2848
  }
2827
2849
  }
2828
- // Check `global` first, because in Node tests both `global` and `window` may be defined and our
2829
- // `_global` variable should point to the NodeJS `global` in that case. Note: Typeof/Instanceof
2830
- // checks are considered side-effects in Terser. We explicitly mark this as side-effect free:
2831
- // https://github.com/terser/terser/issues/250.
2832
- const _global = ( /* @__PURE__ */(() => (typeof global !== 'undefined' && global) || (typeof window !== 'undefined' && window) ||
2833
- (typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
2834
- self instanceof WorkerGlobalScope && self))());
2850
+ const _global = globalThis;
2835
2851
  function newArray(size, value) {
2836
2852
  const list = [];
2837
2853
  for (let i = 0; i < size; i++) {
@@ -3313,6 +3329,9 @@ class AbstractEmitterVisitor {
3313
3329
  ctx.print(ast, `)`);
3314
3330
  return null;
3315
3331
  }
3332
+ visitDynamicImportExpr(ast, ctx) {
3333
+ ctx.print(ast, `import(${ast.url})`);
3334
+ }
3316
3335
  visitNotExpr(ast, ctx) {
3317
3336
  ctx.print(ast, '!');
3318
3337
  ast.condition.visitExpression(this, ctx);
@@ -3886,6 +3905,96 @@ class Element$1 {
3886
3905
  return visitor.visitElement(this);
3887
3906
  }
3888
3907
  }
3908
+ class DeferredTrigger {
3909
+ constructor(sourceSpan) {
3910
+ this.sourceSpan = sourceSpan;
3911
+ }
3912
+ visit(visitor) {
3913
+ return visitor.visitDeferredTrigger(this);
3914
+ }
3915
+ }
3916
+ class BoundDeferredTrigger extends DeferredTrigger {
3917
+ constructor(value, sourceSpan) {
3918
+ super(sourceSpan);
3919
+ this.value = value;
3920
+ }
3921
+ }
3922
+ class IdleDeferredTrigger extends DeferredTrigger {
3923
+ }
3924
+ class ImmediateDeferredTrigger extends DeferredTrigger {
3925
+ }
3926
+ class HoverDeferredTrigger extends DeferredTrigger {
3927
+ }
3928
+ class TimerDeferredTrigger extends DeferredTrigger {
3929
+ constructor(delay, sourceSpan) {
3930
+ super(sourceSpan);
3931
+ this.delay = delay;
3932
+ }
3933
+ }
3934
+ class InteractionDeferredTrigger extends DeferredTrigger {
3935
+ constructor(reference, sourceSpan) {
3936
+ super(sourceSpan);
3937
+ this.reference = reference;
3938
+ }
3939
+ }
3940
+ class ViewportDeferredTrigger extends DeferredTrigger {
3941
+ constructor(reference, sourceSpan) {
3942
+ super(sourceSpan);
3943
+ this.reference = reference;
3944
+ }
3945
+ }
3946
+ class DeferredBlockPlaceholder {
3947
+ constructor(children, minimumTime, sourceSpan, startSourceSpan, endSourceSpan) {
3948
+ this.children = children;
3949
+ this.minimumTime = minimumTime;
3950
+ this.sourceSpan = sourceSpan;
3951
+ this.startSourceSpan = startSourceSpan;
3952
+ this.endSourceSpan = endSourceSpan;
3953
+ }
3954
+ visit(visitor) {
3955
+ return visitor.visitDeferredBlockPlaceholder(this);
3956
+ }
3957
+ }
3958
+ class DeferredBlockLoading {
3959
+ constructor(children, afterTime, minimumTime, sourceSpan, startSourceSpan, endSourceSpan) {
3960
+ this.children = children;
3961
+ this.afterTime = afterTime;
3962
+ this.minimumTime = minimumTime;
3963
+ this.sourceSpan = sourceSpan;
3964
+ this.startSourceSpan = startSourceSpan;
3965
+ this.endSourceSpan = endSourceSpan;
3966
+ }
3967
+ visit(visitor) {
3968
+ return visitor.visitDeferredBlockLoading(this);
3969
+ }
3970
+ }
3971
+ class DeferredBlockError {
3972
+ constructor(children, sourceSpan, startSourceSpan, endSourceSpan) {
3973
+ this.children = children;
3974
+ this.sourceSpan = sourceSpan;
3975
+ this.startSourceSpan = startSourceSpan;
3976
+ this.endSourceSpan = endSourceSpan;
3977
+ }
3978
+ visit(visitor) {
3979
+ return visitor.visitDeferredBlockError(this);
3980
+ }
3981
+ }
3982
+ class DeferredBlock {
3983
+ constructor(children, triggers, prefetchTriggers, placeholder, loading, error, sourceSpan, startSourceSpan, endSourceSpan) {
3984
+ this.children = children;
3985
+ this.triggers = triggers;
3986
+ this.prefetchTriggers = prefetchTriggers;
3987
+ this.placeholder = placeholder;
3988
+ this.loading = loading;
3989
+ this.error = error;
3990
+ this.sourceSpan = sourceSpan;
3991
+ this.startSourceSpan = startSourceSpan;
3992
+ this.endSourceSpan = endSourceSpan;
3993
+ }
3994
+ visit(visitor) {
3995
+ return visitor.visitDeferredBlock(this);
3996
+ }
3997
+ }
3889
3998
  class Template {
3890
3999
  constructor(
3891
4000
  // tagName is the name of the container element, if applicable.
@@ -3973,6 +4082,23 @@ class RecursiveVisitor$1 {
3973
4082
  visitAll$1(this, template.references);
3974
4083
  visitAll$1(this, template.variables);
3975
4084
  }
4085
+ visitDeferredBlock(deferred) {
4086
+ visitAll$1(this, deferred.triggers);
4087
+ visitAll$1(this, deferred.prefetchTriggers);
4088
+ visitAll$1(this, deferred.children);
4089
+ deferred.placeholder?.visit(this);
4090
+ deferred.loading?.visit(this);
4091
+ deferred.error?.visit(this);
4092
+ }
4093
+ visitDeferredBlockPlaceholder(block) {
4094
+ visitAll$1(this, block.children);
4095
+ }
4096
+ visitDeferredBlockError(block) {
4097
+ visitAll$1(this, block.children);
4098
+ }
4099
+ visitDeferredBlockLoading(block) {
4100
+ visitAll$1(this, block.children);
4101
+ }
3976
4102
  visitContent(content) { }
3977
4103
  visitVariable(variable) { }
3978
4104
  visitReference(reference) { }
@@ -3982,6 +4108,7 @@ class RecursiveVisitor$1 {
3982
4108
  visitText(text) { }
3983
4109
  visitBoundText(text) { }
3984
4110
  visitIcu(icu) { }
4111
+ visitDeferredTrigger(trigger) { }
3985
4112
  }
3986
4113
  function visitAll$1(visitor, nodes) {
3987
4114
  const result = [];
@@ -8685,38 +8812,50 @@ var OpKind;
8685
8812
  * An operation to bind an expression to a style property of an element.
8686
8813
  */
8687
8814
  OpKind[OpKind["StyleProp"] = 14] = "StyleProp";
8815
+ /**
8816
+ * An operation to bind an expression to a class property of an element.
8817
+ */
8818
+ OpKind[OpKind["ClassProp"] = 15] = "ClassProp";
8688
8819
  /**
8689
8820
  * An operation to bind an expression to the styles of an element.
8690
8821
  */
8691
- OpKind[OpKind["StyleMap"] = 15] = "StyleMap";
8822
+ OpKind[OpKind["StyleMap"] = 16] = "StyleMap";
8823
+ /**
8824
+ * An operation to bind an expression to the classes of an element.
8825
+ */
8826
+ OpKind[OpKind["ClassMap"] = 17] = "ClassMap";
8692
8827
  /**
8693
8828
  * An operation to interpolate text into a property binding.
8694
8829
  */
8695
- OpKind[OpKind["InterpolateProperty"] = 16] = "InterpolateProperty";
8830
+ OpKind[OpKind["InterpolateProperty"] = 18] = "InterpolateProperty";
8696
8831
  /**
8697
8832
  * An operation to interpolate text into a style property binding.
8698
8833
  */
8699
- OpKind[OpKind["InterpolateStyleProp"] = 17] = "InterpolateStyleProp";
8834
+ OpKind[OpKind["InterpolateStyleProp"] = 19] = "InterpolateStyleProp";
8700
8835
  /**
8701
8836
  * An operation to interpolate text into a style mapping.
8702
8837
  */
8703
- OpKind[OpKind["InterpolateStyleMap"] = 18] = "InterpolateStyleMap";
8838
+ OpKind[OpKind["InterpolateStyleMap"] = 20] = "InterpolateStyleMap";
8839
+ /**
8840
+ * An operation to interpolate text into a class mapping.
8841
+ */
8842
+ OpKind[OpKind["InterpolateClassMap"] = 21] = "InterpolateClassMap";
8704
8843
  /**
8705
8844
  * An operation to advance the runtime's implicit slot context during the update phase of a view.
8706
8845
  */
8707
- OpKind[OpKind["Advance"] = 19] = "Advance";
8846
+ OpKind[OpKind["Advance"] = 22] = "Advance";
8708
8847
  /**
8709
8848
  * An operation to instantiate a pipe.
8710
8849
  */
8711
- OpKind[OpKind["Pipe"] = 20] = "Pipe";
8850
+ OpKind[OpKind["Pipe"] = 23] = "Pipe";
8712
8851
  /**
8713
8852
  * An operation to associate an attribute with an element.
8714
8853
  */
8715
- OpKind[OpKind["Attribute"] = 21] = "Attribute";
8854
+ OpKind[OpKind["Attribute"] = 24] = "Attribute";
8716
8855
  /**
8717
8856
  * An operation to interpolate text into an attribute binding.
8718
8857
  */
8719
- OpKind[OpKind["InterpolateAttribute"] = 22] = "InterpolateAttribute";
8858
+ OpKind[OpKind["InterpolateAttribute"] = 25] = "InterpolateAttribute";
8720
8859
  })(OpKind || (OpKind = {}));
8721
8860
  /**
8722
8861
  * Distinguishes different kinds of IR expressions.
@@ -9454,11 +9593,14 @@ function transformExpressionsInOp(op, transform, flags) {
9454
9593
  case OpKind.Property:
9455
9594
  case OpKind.StyleProp:
9456
9595
  case OpKind.StyleMap:
9596
+ case OpKind.ClassProp:
9597
+ case OpKind.ClassMap:
9457
9598
  op.expression = transformExpressionsInExpression(op.expression, transform, flags);
9458
9599
  break;
9459
9600
  case OpKind.InterpolateProperty:
9460
9601
  case OpKind.InterpolateStyleProp:
9461
9602
  case OpKind.InterpolateStyleMap:
9603
+ case OpKind.InterpolateClassMap:
9462
9604
  case OpKind.InterpolateText:
9463
9605
  for (let i = 0; i < op.expressions.length; i++) {
9464
9606
  op.expressions[i] = transformExpressionsInExpression(op.expressions[i], transform, flags);
@@ -9977,6 +10119,20 @@ function createStylePropOp(xref, name, expression, unit) {
9977
10119
  ...NEW_OP,
9978
10120
  };
9979
10121
  }
10122
+ /**
10123
+ * Create a `ClassPropOp`.
10124
+ */
10125
+ function createClassPropOp(xref, name, expression) {
10126
+ return {
10127
+ kind: OpKind.ClassProp,
10128
+ target: xref,
10129
+ name,
10130
+ expression,
10131
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
10132
+ ...TRAIT_CONSUMES_VARS,
10133
+ ...NEW_OP,
10134
+ };
10135
+ }
9980
10136
  /** Create a `StyleMapOp`. */
9981
10137
  function createStyleMapOp(xref, expression) {
9982
10138
  return {
@@ -9988,6 +10144,19 @@ function createStyleMapOp(xref, expression) {
9988
10144
  ...NEW_OP,
9989
10145
  };
9990
10146
  }
10147
+ /**
10148
+ * Create a `ClassMapOp`.
10149
+ */
10150
+ function createClassMapOp(xref, expression) {
10151
+ return {
10152
+ kind: OpKind.ClassMap,
10153
+ target: xref,
10154
+ expression,
10155
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
10156
+ ...TRAIT_CONSUMES_VARS,
10157
+ ...NEW_OP,
10158
+ };
10159
+ }
9991
10160
  /**
9992
10161
  * Create an `AttributeOp`.
9993
10162
  */
@@ -10062,6 +10231,20 @@ function createInterpolateStyleMapOp(xref, strings, expressions) {
10062
10231
  ...NEW_OP,
10063
10232
  };
10064
10233
  }
10234
+ /**
10235
+ * Create a `InterpolateStyleMap`.
10236
+ */
10237
+ function createInterpolateClassMapOp(xref, strings, expressions) {
10238
+ return {
10239
+ kind: OpKind.InterpolateClassMap,
10240
+ target: xref,
10241
+ strings,
10242
+ expressions,
10243
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
10244
+ ...TRAIT_CONSUMES_VARS,
10245
+ ...NEW_OP,
10246
+ };
10247
+ }
10065
10248
  /**
10066
10249
  * Create an `AdvanceOp`.
10067
10250
  */
@@ -10119,25 +10302,30 @@ function phaseVarCounting(cpl) {
10119
10302
  function varsUsedByOp(op) {
10120
10303
  switch (op.kind) {
10121
10304
  case OpKind.Property:
10122
- case OpKind.StyleProp:
10123
- case OpKind.StyleMap:
10124
- // Property bindings use 1 variable slot.
10125
- return 1;
10126
10305
  case OpKind.Attribute:
10127
- // Attribute bindings use 1 variable slot.
10306
+ // Property & attribute bindings use 1 variable slot.
10128
10307
  return 1;
10308
+ case OpKind.StyleProp:
10309
+ case OpKind.ClassProp:
10310
+ case OpKind.StyleMap:
10311
+ case OpKind.ClassMap:
10312
+ // Style & class bindings use 2 variable slots.
10313
+ return 2;
10129
10314
  case OpKind.InterpolateText:
10130
10315
  // `ir.InterpolateTextOp`s use a variable slot for each dynamic expression.
10131
10316
  return op.expressions.length;
10132
10317
  case OpKind.InterpolateProperty:
10133
- case OpKind.InterpolateStyleProp:
10134
- case OpKind.InterpolateStyleMap:
10135
10318
  // `ir.InterpolatePropertyOp`s use a variable slot for each dynamic expression, plus one for
10136
10319
  // the result.
10137
10320
  return 1 + op.expressions.length;
10138
10321
  case OpKind.InterpolateAttribute:
10139
10322
  // One variable slot for each dynamic expression, plus one for the result.
10140
10323
  return 1 + op.expressions.length;
10324
+ case OpKind.InterpolateStyleProp:
10325
+ case OpKind.InterpolateStyleMap:
10326
+ case OpKind.InterpolateClassMap:
10327
+ // One variable slot for each dynamic expression, plus two for binding the result.
10328
+ return 2 + op.expressions.length;
10141
10329
  default:
10142
10330
  throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
10143
10331
  }
@@ -10257,6 +10445,7 @@ function populateElementAttributes(view, compatibility) {
10257
10445
  ownerOp.attributes.add(op.bindingKind, op.name, null);
10258
10446
  break;
10259
10447
  case OpKind.StyleProp:
10448
+ case OpKind.ClassProp:
10260
10449
  ownerOp = lookupElement(elements, op.target);
10261
10450
  assertIsElementAttributes(ownerOp.attributes);
10262
10451
  // The old compiler treated empty style bindings as regular bindings for the purpose of
@@ -10284,6 +10473,16 @@ const CHAINABLE = new Set([
10284
10473
  Identifiers.property,
10285
10474
  Identifiers.styleProp,
10286
10475
  Identifiers.attribute,
10476
+ Identifiers.stylePropInterpolate1,
10477
+ Identifiers.stylePropInterpolate2,
10478
+ Identifiers.stylePropInterpolate3,
10479
+ Identifiers.stylePropInterpolate4,
10480
+ Identifiers.stylePropInterpolate5,
10481
+ Identifiers.stylePropInterpolate6,
10482
+ Identifiers.stylePropInterpolate7,
10483
+ Identifiers.stylePropInterpolate8,
10484
+ Identifiers.stylePropInterpolateV,
10485
+ Identifiers.classProp,
10287
10486
  Identifiers.elementContainerStart,
10288
10487
  Identifiers.elementContainerEnd,
10289
10488
  Identifiers.elementContainer,
@@ -10426,87 +10625,238 @@ function phaseEmptyElements(cpl) {
10426
10625
  }
10427
10626
 
10428
10627
  /**
10429
- * Generate `ir.AdvanceOp`s in between `ir.UpdateOp`s that ensure the runtime's implicit slot
10430
- * context will be advanced correctly.
10628
+ * Finds all unresolved safe read expressions, and converts them into the appropriate output AST
10629
+ * reads, guarded by null checks.
10431
10630
  */
10432
- function phaseGenerateAdvance(cpl) {
10631
+ function phaseExpandSafeReads(cpl, compatibility) {
10433
10632
  for (const [_, view] of cpl.views) {
10434
- // First build a map of all of the declarations in the view that have assigned slots.
10435
- const slotMap = new Map();
10436
- for (const op of view.create) {
10437
- if (!hasConsumesSlotTrait(op)) {
10438
- continue;
10439
- }
10440
- else if (op.slot === null) {
10441
- throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
10442
- }
10443
- slotMap.set(op.xref, op.slot);
10444
- }
10445
- // Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
10446
- // the runtime's implicit slot counter will be set to the correct slot before executing each
10447
- // update operation which depends on it.
10448
- //
10449
- // To do that, we track what the runtime's slot counter will be through the update operations.
10450
- let slotContext = 0;
10451
- for (const op of view.update) {
10452
- if (!hasDependsOnSlotContextTrait(op)) {
10453
- // `op` doesn't depend on the slot counter, so it can be skipped.
10454
- continue;
10455
- }
10456
- else if (!slotMap.has(op.target)) {
10457
- // We expect ops that _do_ depend on the slot counter to point at declarations that exist in
10458
- // the `slotMap`.
10459
- throw new Error(`AssertionError: reference to unknown slot for var ${op.target}`);
10460
- }
10461
- const slot = slotMap.get(op.target);
10462
- // Does the slot counter need to be adjusted?
10463
- if (slotContext !== slot) {
10464
- // If so, generate an `ir.AdvanceOp` to advance the counter.
10465
- const delta = slot - slotContext;
10466
- if (delta < 0) {
10467
- throw new Error(`AssertionError: slot counter should never need to move backwards`);
10468
- }
10469
- OpList.insertBefore(createAdvanceOp(delta), op);
10470
- slotContext = slot;
10471
- }
10633
+ for (const op of view.ops()) {
10634
+ transformExpressionsInOp(op, e => safeTransform(e, { cpl, compatibility }), VisitorContextFlag.None);
10635
+ transformExpressionsInOp(op, ternaryTransform, VisitorContextFlag.None);
10472
10636
  }
10473
10637
  }
10474
10638
  }
10475
-
10476
- function phaseNullishCoalescing(cpl) {
10477
- for (const view of cpl.views.values()) {
10478
- for (const op of view.ops()) {
10479
- transformExpressionsInOp(op, expr => {
10480
- if (!(expr instanceof BinaryOperatorExpr) ||
10481
- expr.operator !== BinaryOperator.NullishCoalesce) {
10482
- return expr;
10483
- }
10484
- const assignment = new AssignTemporaryExpr(expr.lhs.clone(), cpl.allocateXrefId());
10485
- const read = new ReadTemporaryExpr(assignment.xref);
10486
- // TODO: When not in compatibility mode for TemplateDefinitionBuilder, we can just emit
10487
- // `t != null` instead of including an undefined check as well.
10488
- return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.And, new BinaryOperatorExpr(BinaryOperator.NotIdentical, assignment, NULL_EXPR), new BinaryOperatorExpr(BinaryOperator.NotIdentical, read, new LiteralExpr(undefined))), read.clone(), expr.rhs);
10489
- }, VisitorContextFlag.None);
10490
- }
10639
+ // A lookup set of all the expression kinds that require a temporary variable to be generated.
10640
+ const requiresTemporary = [
10641
+ InvokeFunctionExpr, LiteralArrayExpr, LiteralMapExpr, SafeInvokeFunctionExpr,
10642
+ PipeBindingExpr
10643
+ ].map(e => e.constructor.name);
10644
+ function needsTemporaryInSafeAccess(e) {
10645
+ // TODO: We probably want to use an expression visitor to recursively visit all descendents.
10646
+ // However, that would potentially do a lot of extra work (because it cannot short circuit), so we
10647
+ // implement the logic ourselves for now.
10648
+ if (e instanceof UnaryOperatorExpr) {
10649
+ return needsTemporaryInSafeAccess(e.expr);
10650
+ }
10651
+ else if (e instanceof BinaryOperatorExpr) {
10652
+ return needsTemporaryInSafeAccess(e.lhs) || needsTemporaryInSafeAccess(e.rhs);
10653
+ }
10654
+ else if (e instanceof ConditionalExpr) {
10655
+ if (e.falseCase && needsTemporaryInSafeAccess(e.falseCase))
10656
+ return true;
10657
+ return needsTemporaryInSafeAccess(e.condition) || needsTemporaryInSafeAccess(e.trueCase);
10658
+ }
10659
+ else if (e instanceof NotExpr) {
10660
+ return needsTemporaryInSafeAccess(e.condition);
10661
+ }
10662
+ else if (e instanceof AssignTemporaryExpr) {
10663
+ return needsTemporaryInSafeAccess(e.expr);
10664
+ }
10665
+ else if (e instanceof ReadPropExpr) {
10666
+ return needsTemporaryInSafeAccess(e.receiver);
10491
10667
  }
10668
+ else if (e instanceof ReadKeyExpr) {
10669
+ return needsTemporaryInSafeAccess(e.receiver) || needsTemporaryInSafeAccess(e.index);
10670
+ }
10671
+ // TODO: Switch to a method which is exhaustive of newly added expression subtypes.
10672
+ return e instanceof InvokeFunctionExpr || e instanceof LiteralArrayExpr ||
10673
+ e instanceof LiteralMapExpr || e instanceof SafeInvokeFunctionExpr ||
10674
+ e instanceof PipeBindingExpr;
10492
10675
  }
10493
-
10494
- /**
10495
- * Generate a preamble sequence for each view creation block and listener function which declares
10496
- * any variables that be referenced in other operations in the block.
10497
- *
10498
- * Variables generated include:
10499
- * * a saved view context to be used to restore the current view in event listeners.
10500
- * * the context of the restored view within event listener handlers.
10501
- * * context variables from the current view as well as all parent views (including the root
10502
- * context if needed).
10503
- * * local references from elements within the current view and any lexical parents.
10504
- *
10505
- * Variables are generated here unconditionally, and may optimized away in future operations if it
10506
- * turns out their values (and any side effects) are unused.
10507
- */
10508
- function phaseGenerateVariables(cpl) {
10509
- recursivelyProcessView(cpl.root, /* there is no parent scope for the root view */ null);
10676
+ function temporariesIn(e) {
10677
+ const temporaries = new Set();
10678
+ // TODO: Although it's not currently supported by the transform helper, we should be able to
10679
+ // short-circuit exploring the tree to do less work. In particular, we don't have to penetrate
10680
+ // into the subexpressions of temporary assignments.
10681
+ transformExpressionsInExpression(e, e => {
10682
+ if (e instanceof AssignTemporaryExpr) {
10683
+ temporaries.add(e.xref);
10684
+ }
10685
+ return e;
10686
+ }, VisitorContextFlag.None);
10687
+ return temporaries;
10688
+ }
10689
+ function eliminateTemporaryAssignments(e, tmps, ctx) {
10690
+ // TODO: We can be more efficient than the transform helper here. We don't need to visit any
10691
+ // descendents of temporary assignments.
10692
+ transformExpressionsInExpression(e, e => {
10693
+ if (e instanceof AssignTemporaryExpr && tmps.has(e.xref)) {
10694
+ const read = new ReadTemporaryExpr(e.xref);
10695
+ // `TemplateDefinitionBuilder` has the (accidental?) behavior of generating assignments of
10696
+ // temporary variables to themselves. This happens because some subexpression that the
10697
+ // temporary refers to, possibly through nested temporaries, has a function call. We copy that
10698
+ // behavior here.
10699
+ return ctx.compatibility ? new AssignTemporaryExpr(read, read.xref) : read;
10700
+ }
10701
+ return e;
10702
+ }, VisitorContextFlag.None);
10703
+ return e;
10704
+ }
10705
+ /**
10706
+ * Creates a safe ternary guarded by the input expression, and with a body generated by the provided
10707
+ * callback on the input expression. Generates a temporary variable assignment if needed, and
10708
+ * deduplicates nested temporary assignments if needed.
10709
+ */
10710
+ function safeTernaryWithTemporary(guard, body, ctx) {
10711
+ let result;
10712
+ if (needsTemporaryInSafeAccess(guard)) {
10713
+ const xref = ctx.cpl.allocateXrefId();
10714
+ result = [new AssignTemporaryExpr(guard, xref), new ReadTemporaryExpr(xref)];
10715
+ }
10716
+ else {
10717
+ result = [guard, guard.clone()];
10718
+ // Consider an expression like `a?.[b?.c()]?.d`. The `b?.c()` will be transformed first,
10719
+ // introducing a temporary assignment into the key. Then, as part of expanding the `?.d`. That
10720
+ // assignment will be duplicated into both the guard and expression sides. We de-duplicate it,
10721
+ // by transforming it from an assignment into a read on the expression side.
10722
+ eliminateTemporaryAssignments(result[1], temporariesIn(result[0]), ctx);
10723
+ }
10724
+ return new SafeTernaryExpr(result[0], body(result[1]));
10725
+ }
10726
+ function isSafeAccessExpression(e) {
10727
+ return e instanceof SafePropertyReadExpr || e instanceof SafeKeyedReadExpr;
10728
+ }
10729
+ function isUnsafeAccessExpression(e) {
10730
+ return e instanceof ReadPropExpr || e instanceof ReadKeyExpr ||
10731
+ e instanceof InvokeFunctionExpr;
10732
+ }
10733
+ function isAccessExpression(e) {
10734
+ return isSafeAccessExpression(e) || isUnsafeAccessExpression(e);
10735
+ }
10736
+ function deepestSafeTernary(e) {
10737
+ if (isAccessExpression(e) && e.receiver instanceof SafeTernaryExpr) {
10738
+ let st = e.receiver;
10739
+ while (st.expr instanceof SafeTernaryExpr) {
10740
+ st = st.expr;
10741
+ }
10742
+ return st;
10743
+ }
10744
+ return null;
10745
+ }
10746
+ // TODO: When strict compatibility with TemplateDefinitionBuilder is not required, we can use `&&`
10747
+ // instead to save some code size.
10748
+ function safeTransform(e, ctx) {
10749
+ if (e instanceof SafeInvokeFunctionExpr) {
10750
+ // TODO: Implement safe function calls in a subsequent commit.
10751
+ return new InvokeFunctionExpr(e.receiver, e.args);
10752
+ }
10753
+ if (!isAccessExpression(e)) {
10754
+ return e;
10755
+ }
10756
+ const dst = deepestSafeTernary(e);
10757
+ if (dst) {
10758
+ if (e instanceof InvokeFunctionExpr) {
10759
+ dst.expr = dst.expr.callFn(e.args);
10760
+ return e.receiver;
10761
+ }
10762
+ if (e instanceof ReadPropExpr) {
10763
+ dst.expr = dst.expr.prop(e.name);
10764
+ return e.receiver;
10765
+ }
10766
+ if (e instanceof ReadKeyExpr) {
10767
+ dst.expr = dst.expr.key(e.index);
10768
+ return e.receiver;
10769
+ }
10770
+ if (e instanceof SafePropertyReadExpr) {
10771
+ dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.prop(e.name), ctx);
10772
+ return e.receiver;
10773
+ }
10774
+ if (e instanceof SafeKeyedReadExpr) {
10775
+ dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.key(e.index), ctx);
10776
+ return e.receiver;
10777
+ }
10778
+ }
10779
+ else {
10780
+ if (e instanceof SafePropertyReadExpr) {
10781
+ return safeTernaryWithTemporary(e.receiver, (r) => r.prop(e.name), ctx);
10782
+ }
10783
+ if (e instanceof SafeKeyedReadExpr) {
10784
+ return safeTernaryWithTemporary(e.receiver, (r) => r.key(e.index), ctx);
10785
+ }
10786
+ }
10787
+ return e;
10788
+ }
10789
+ function ternaryTransform(e) {
10790
+ if (!(e instanceof SafeTernaryExpr)) {
10791
+ return e;
10792
+ }
10793
+ return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.Equals, e.guard, NULL_EXPR), NULL_EXPR, e.expr);
10794
+ }
10795
+
10796
+ /**
10797
+ * Generate `ir.AdvanceOp`s in between `ir.UpdateOp`s that ensure the runtime's implicit slot
10798
+ * context will be advanced correctly.
10799
+ */
10800
+ function phaseGenerateAdvance(cpl) {
10801
+ for (const [_, view] of cpl.views) {
10802
+ // First build a map of all of the declarations in the view that have assigned slots.
10803
+ const slotMap = new Map();
10804
+ for (const op of view.create) {
10805
+ if (!hasConsumesSlotTrait(op)) {
10806
+ continue;
10807
+ }
10808
+ else if (op.slot === null) {
10809
+ throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
10810
+ }
10811
+ slotMap.set(op.xref, op.slot);
10812
+ }
10813
+ // Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
10814
+ // the runtime's implicit slot counter will be set to the correct slot before executing each
10815
+ // update operation which depends on it.
10816
+ //
10817
+ // To do that, we track what the runtime's slot counter will be through the update operations.
10818
+ let slotContext = 0;
10819
+ for (const op of view.update) {
10820
+ if (!hasDependsOnSlotContextTrait(op)) {
10821
+ // `op` doesn't depend on the slot counter, so it can be skipped.
10822
+ continue;
10823
+ }
10824
+ else if (!slotMap.has(op.target)) {
10825
+ // We expect ops that _do_ depend on the slot counter to point at declarations that exist in
10826
+ // the `slotMap`.
10827
+ throw new Error(`AssertionError: reference to unknown slot for var ${op.target}`);
10828
+ }
10829
+ const slot = slotMap.get(op.target);
10830
+ // Does the slot counter need to be adjusted?
10831
+ if (slotContext !== slot) {
10832
+ // If so, generate an `ir.AdvanceOp` to advance the counter.
10833
+ const delta = slot - slotContext;
10834
+ if (delta < 0) {
10835
+ throw new Error(`AssertionError: slot counter should never need to move backwards`);
10836
+ }
10837
+ OpList.insertBefore(createAdvanceOp(delta), op);
10838
+ slotContext = slot;
10839
+ }
10840
+ }
10841
+ }
10842
+ }
10843
+
10844
+ /**
10845
+ * Generate a preamble sequence for each view creation block and listener function which declares
10846
+ * any variables that be referenced in other operations in the block.
10847
+ *
10848
+ * Variables generated include:
10849
+ * * a saved view context to be used to restore the current view in event listeners.
10850
+ * * the context of the restored view within event listener handlers.
10851
+ * * context variables from the current view as well as all parent views (including the root
10852
+ * context if needed).
10853
+ * * local references from elements within the current view and any lexical parents.
10854
+ *
10855
+ * Variables are generated here unconditionally, and may optimized away in future operations if it
10856
+ * turns out their values (and any side effects) are unused.
10857
+ */
10858
+ function phaseGenerateVariables(cpl) {
10859
+ recursivelyProcessView(cpl.root, /* there is no parent scope for the root view */ null);
10510
10860
  }
10511
10861
  /**
10512
10862
  * Process the given `ViewCompilation` and generate preambles for it and any listeners that it
@@ -10647,18 +10997,97 @@ function serializeLocalRefs(refs) {
10647
10997
  return literalArr(constRefs);
10648
10998
  }
10649
10999
 
11000
+ /**
11001
+ * Parses string representation of a style and converts it into object literal.
11002
+ *
11003
+ * @param value string representation of style as used in the `style` attribute in HTML.
11004
+ * Example: `color: red; height: auto`.
11005
+ * @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
11006
+ * 'auto']`
11007
+ */
11008
+ function parse(value) {
11009
+ // we use a string array here instead of a string map
11010
+ // because a string-map is not guaranteed to retain the
11011
+ // order of the entries whereas a string array can be
11012
+ // constructed in a [key, value, key, value] format.
11013
+ const styles = [];
11014
+ let i = 0;
11015
+ let parenDepth = 0;
11016
+ let quote = 0 /* Char.QuoteNone */;
11017
+ let valueStart = 0;
11018
+ let propStart = 0;
11019
+ let currentProp = null;
11020
+ while (i < value.length) {
11021
+ const token = value.charCodeAt(i++);
11022
+ switch (token) {
11023
+ case 40 /* Char.OpenParen */:
11024
+ parenDepth++;
11025
+ break;
11026
+ case 41 /* Char.CloseParen */:
11027
+ parenDepth--;
11028
+ break;
11029
+ case 39 /* Char.QuoteSingle */:
11030
+ // valueStart needs to be there since prop values don't
11031
+ // have quotes in CSS
11032
+ if (quote === 0 /* Char.QuoteNone */) {
11033
+ quote = 39 /* Char.QuoteSingle */;
11034
+ }
11035
+ else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
11036
+ quote = 0 /* Char.QuoteNone */;
11037
+ }
11038
+ break;
11039
+ case 34 /* Char.QuoteDouble */:
11040
+ // same logic as above
11041
+ if (quote === 0 /* Char.QuoteNone */) {
11042
+ quote = 34 /* Char.QuoteDouble */;
11043
+ }
11044
+ else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
11045
+ quote = 0 /* Char.QuoteNone */;
11046
+ }
11047
+ break;
11048
+ case 58 /* Char.Colon */:
11049
+ if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
11050
+ currentProp = hyphenate(value.substring(propStart, i - 1).trim());
11051
+ valueStart = i;
11052
+ }
11053
+ break;
11054
+ case 59 /* Char.Semicolon */:
11055
+ if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
11056
+ const styleVal = value.substring(valueStart, i - 1).trim();
11057
+ styles.push(currentProp, styleVal);
11058
+ propStart = i;
11059
+ valueStart = 0;
11060
+ currentProp = null;
11061
+ }
11062
+ break;
11063
+ }
11064
+ }
11065
+ if (currentProp && valueStart) {
11066
+ const styleVal = value.slice(valueStart).trim();
11067
+ styles.push(currentProp, styleVal);
11068
+ }
11069
+ return styles;
11070
+ }
11071
+ function hyphenate(value) {
11072
+ return value
11073
+ .replace(/[a-z][A-Z]/g, v => {
11074
+ return v.charAt(0) + '-' + v.charAt(1);
11075
+ })
11076
+ .toLowerCase();
11077
+ }
11078
+
10650
11079
  /**
10651
11080
  * Generate names for functions and variables across all views.
10652
11081
  *
10653
11082
  * This includes propagating those names into any `ir.ReadVariableExpr`s of those variables, so that
10654
11083
  * the reads can be emitted correctly.
10655
11084
  */
10656
- function phaseNaming(cpl) {
10657
- addNamesToView(cpl.root, cpl.componentName, { index: 0 });
11085
+ function phaseNaming(cpl, compatibility) {
11086
+ addNamesToView(cpl.root, cpl.componentName, { index: 0 }, compatibility);
10658
11087
  }
10659
- function addNamesToView(view, baseName, state) {
11088
+ function addNamesToView(view, baseName, state, compatibility) {
10660
11089
  if (view.fnName === null) {
10661
- view.fnName = `${baseName}_Template`;
11090
+ view.fnName = sanitizeIdentifier(`${baseName}_Template`);
10662
11091
  }
10663
11092
  // Keep track of the names we assign to variables in the view. We'll need to propagate these
10664
11093
  // into reads of those variables afterwards.
@@ -10672,7 +11101,8 @@ function addNamesToView(view, baseName, state) {
10672
11101
  if (op.slot === null) {
10673
11102
  throw new Error(`Expected a slot to be assigned`);
10674
11103
  }
10675
- op.handlerFnName = `${view.fnName}_${op.tag}_${op.name}_${op.slot}_listener`;
11104
+ op.handlerFnName =
11105
+ sanitizeIdentifier(`${view.fnName}_${op.tag}_${op.name}_${op.slot}_listener`);
10676
11106
  }
10677
11107
  break;
10678
11108
  case OpKind.Variable:
@@ -10683,9 +11113,19 @@ function addNamesToView(view, baseName, state) {
10683
11113
  if (op.slot === null) {
10684
11114
  throw new Error(`Expected slot to be assigned`);
10685
11115
  }
10686
- // TODO: properly escape the tag name.
10687
- const safeTagName = op.tag.replace('-', '_');
10688
- addNamesToView(childView, `${baseName}_${safeTagName}_${op.slot}`, state);
11116
+ addNamesToView(childView, `${baseName}_${op.tag}_${op.slot}`, state, compatibility);
11117
+ break;
11118
+ case OpKind.StyleProp:
11119
+ case OpKind.InterpolateStyleProp:
11120
+ op.name = normalizeStylePropName(op.name);
11121
+ if (compatibility) {
11122
+ op.name = stripImportant(op.name);
11123
+ }
11124
+ break;
11125
+ case OpKind.ClassProp:
11126
+ if (compatibility) {
11127
+ op.name = stripImportant(op.name);
11128
+ }
10689
11129
  break;
10690
11130
  }
10691
11131
  }
@@ -10716,6 +11156,22 @@ function getVariableName(variable, state) {
10716
11156
  }
10717
11157
  return variable.name;
10718
11158
  }
11159
+ /**
11160
+ * Normalizes a style prop name by hyphenating it (unless its a CSS variable).
11161
+ */
11162
+ function normalizeStylePropName(name) {
11163
+ return name.startsWith('--') ? name : hyphenate(name);
11164
+ }
11165
+ /**
11166
+ * Strips `!important` out of the given style or class name.
11167
+ */
11168
+ function stripImportant(name) {
11169
+ const importantIndex = name.indexOf('!important');
11170
+ if (importantIndex > -1) {
11171
+ return name.substring(0, importantIndex);
11172
+ }
11173
+ return name;
11174
+ }
10719
11175
 
10720
11176
  /**
10721
11177
  * Merges logically sequential `NextContextExpr` operations.
@@ -10801,6 +11257,24 @@ function phaseNgContainer(cpl) {
10801
11257
  }
10802
11258
  }
10803
11259
 
11260
+ function phaseNullishCoalescing(cpl) {
11261
+ for (const view of cpl.views.values()) {
11262
+ for (const op of view.ops()) {
11263
+ transformExpressionsInOp(op, expr => {
11264
+ if (!(expr instanceof BinaryOperatorExpr) ||
11265
+ expr.operator !== BinaryOperator.NullishCoalesce) {
11266
+ return expr;
11267
+ }
11268
+ const assignment = new AssignTemporaryExpr(expr.lhs.clone(), cpl.allocateXrefId());
11269
+ const read = new ReadTemporaryExpr(assignment.xref);
11270
+ // TODO: When not in compatibility mode for TemplateDefinitionBuilder, we can just emit
11271
+ // `t != null` instead of including an undefined check as well.
11272
+ return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.And, new BinaryOperatorExpr(BinaryOperator.NotIdentical, assignment, NULL_EXPR), new BinaryOperatorExpr(BinaryOperator.NotIdentical, read, new LiteralExpr(undefined))), read.clone(), expr.rhs);
11273
+ }, VisitorContextFlag.None);
11274
+ }
11275
+ }
11276
+ }
11277
+
10804
11278
  function phasePipeCreation(cpl) {
10805
11279
  for (const view of cpl.views.values()) {
10806
11280
  processPipeBindingsInView(view);
@@ -10867,6 +11341,80 @@ function phasePipeVariadic(cpl) {
10867
11341
  }
10868
11342
  }
10869
11343
 
11344
+ /**
11345
+ * Defines the groups based on `OpKind` that ops will be divided into. Ops will be collected into
11346
+ * groups, then optionally transformed, before recombining the groups in the order defined here.
11347
+ */
11348
+ const ORDERING = [
11349
+ { kinds: new Set([OpKind.StyleMap, OpKind.InterpolateStyleMap]), transform: keepLast },
11350
+ { kinds: new Set([OpKind.ClassMap, OpKind.InterpolateClassMap]), transform: keepLast },
11351
+ { kinds: new Set([OpKind.StyleProp, OpKind.InterpolateStyleProp]) },
11352
+ { kinds: new Set([OpKind.ClassProp]) },
11353
+ { kinds: new Set([OpKind.InterpolateProperty]) },
11354
+ { kinds: new Set([OpKind.Property]) },
11355
+ { kinds: new Set([OpKind.Attribute, OpKind.InterpolateAttribute]) },
11356
+ ];
11357
+ /**
11358
+ * The set of all op kinds we handle in the reordering phase.
11359
+ */
11360
+ const handledOpKinds = new Set(ORDERING.flatMap(group => [...group.kinds]));
11361
+ /**
11362
+ * Reorders property and attribute ops according to the following ordering:
11363
+ * 1. styleMap & styleMapInterpolate (drops all but the last op in the group)
11364
+ * 2. classMap & classMapInterpolate (drops all but the last op in the group)
11365
+ * 3. styleProp & stylePropInterpolate (ordering preserved within group)
11366
+ * 4. classProp (ordering preserved within group)
11367
+ * 5. propertyInterpolate (ordering preserved within group)
11368
+ * 6. property (ordering preserved within group)
11369
+ * 7. attribute & attributeInterpolate (ordering preserve within group)
11370
+ */
11371
+ function phasePropertyOrdering(cpl) {
11372
+ for (const [_, view] of cpl.views) {
11373
+ let opsToOrder = [];
11374
+ for (const op of view.update) {
11375
+ if (handledOpKinds.has(op.kind)) {
11376
+ // Pull out ops that need o be ordered.
11377
+ opsToOrder.push(op);
11378
+ OpList.remove(op);
11379
+ }
11380
+ else {
11381
+ // When we encounter an op that shouldn't be reordered, put the ones we've pulled so far
11382
+ // back in the correct order.
11383
+ for (const orderedOp of reorder(opsToOrder)) {
11384
+ OpList.insertBefore(orderedOp, op);
11385
+ }
11386
+ opsToOrder = [];
11387
+ }
11388
+ }
11389
+ // If we still have ops pulled at the end, put them back in the correct order.
11390
+ for (const orderedOp of reorder(opsToOrder)) {
11391
+ view.update.push(orderedOp);
11392
+ }
11393
+ }
11394
+ }
11395
+ /**
11396
+ * Reorders the given list of ops according to the ordering defined by `ORDERING`.
11397
+ */
11398
+ function reorder(ops) {
11399
+ // Break the ops list into groups based on OpKind.
11400
+ const groups = Array.from(ORDERING, () => new Array());
11401
+ for (const op of ops) {
11402
+ const groupIndex = ORDERING.findIndex(o => o.kinds.has(op.kind));
11403
+ groups[groupIndex].push(op);
11404
+ }
11405
+ // Reassemble the groups into a single list, in the correct order.
11406
+ return groups.flatMap((group, i) => {
11407
+ const transform = ORDERING[i].transform;
11408
+ return transform ? transform(group) : group;
11409
+ });
11410
+ }
11411
+ /**
11412
+ * Keeps only the last op in a list of ops.
11413
+ */
11414
+ function keepLast(ops) {
11415
+ return ops.slice(ops.length - 1);
11416
+ }
11417
+
10870
11418
  function phasePureFunctionExtraction(cpl) {
10871
11419
  for (const view of cpl.views.values()) {
10872
11420
  for (const op of view.ops()) {
@@ -11066,9 +11614,15 @@ function styleProp(name, expression, unit) {
11066
11614
  }
11067
11615
  return call(Identifiers.styleProp, args);
11068
11616
  }
11617
+ function classProp(name, expression) {
11618
+ return call(Identifiers.classProp, [literal(name), expression]);
11619
+ }
11069
11620
  function styleMap(expression) {
11070
11621
  return call(Identifiers.styleMap, [expression]);
11071
11622
  }
11623
+ function classMap(expression) {
11624
+ return call(Identifiers.classMap, [expression]);
11625
+ }
11072
11626
  const PIPE_BINDINGS = [
11073
11627
  Identifiers.pipeBind1,
11074
11628
  Identifiers.pipeBind2,
@@ -11131,6 +11685,10 @@ function styleMapInterpolate(strings, expressions) {
11131
11685
  const interpolationArgs = collateInterpolationArgs(strings, expressions);
11132
11686
  return callVariadicInstruction(STYLE_MAP_INTERPOLATE_CONFIG, [], interpolationArgs);
11133
11687
  }
11688
+ function classMapInterpolate(strings, expressions) {
11689
+ const interpolationArgs = collateInterpolationArgs(strings, expressions);
11690
+ return callVariadicInstruction(CLASS_MAP_INTERPOLATE_CONFIG, [], interpolationArgs);
11691
+ }
11134
11692
  function pureFunction(varOffset, fn, args) {
11135
11693
  return callVariadicInstructionExpr(PURE_FUNCTION_CONFIG, [
11136
11694
  literal(varOffset),
@@ -11212,7 +11770,7 @@ const PROPERTY_INTERPOLATE_CONFIG = {
11212
11770
  */
11213
11771
  const STYLE_PROP_INTERPOLATE_CONFIG = {
11214
11772
  constant: [
11215
- null,
11773
+ Identifiers.styleProp,
11216
11774
  Identifiers.stylePropInterpolate1,
11217
11775
  Identifiers.stylePropInterpolate2,
11218
11776
  Identifiers.stylePropInterpolate3,
@@ -11227,9 +11785,6 @@ const STYLE_PROP_INTERPOLATE_CONFIG = {
11227
11785
  if (n % 2 === 0) {
11228
11786
  throw new Error(`Expected odd number of arguments`);
11229
11787
  }
11230
- if (n < 3) {
11231
- throw new Error(`Expected at least 3 arguments`);
11232
- }
11233
11788
  return (n - 1) / 2;
11234
11789
  },
11235
11790
  };
@@ -11261,7 +11816,7 @@ const ATTRIBUTE_INTERPOLATE_CONFIG = {
11261
11816
  */
11262
11817
  const STYLE_MAP_INTERPOLATE_CONFIG = {
11263
11818
  constant: [
11264
- null,
11819
+ Identifiers.styleMap,
11265
11820
  Identifiers.styleMapInterpolate1,
11266
11821
  Identifiers.styleMapInterpolate2,
11267
11822
  Identifiers.styleMapInterpolate3,
@@ -11276,8 +11831,28 @@ const STYLE_MAP_INTERPOLATE_CONFIG = {
11276
11831
  if (n % 2 === 0) {
11277
11832
  throw new Error(`Expected odd number of arguments`);
11278
11833
  }
11279
- if (n < 3) {
11280
- throw new Error(`Expected at least 3 arguments`);
11834
+ return (n - 1) / 2;
11835
+ },
11836
+ };
11837
+ /**
11838
+ * `InterpolationConfig` for the `classMapInterpolate` instruction.
11839
+ */
11840
+ const CLASS_MAP_INTERPOLATE_CONFIG = {
11841
+ constant: [
11842
+ Identifiers.classMap,
11843
+ Identifiers.classMapInterpolate1,
11844
+ Identifiers.classMapInterpolate2,
11845
+ Identifiers.classMapInterpolate3,
11846
+ Identifiers.classMapInterpolate4,
11847
+ Identifiers.classMapInterpolate5,
11848
+ Identifiers.classMapInterpolate6,
11849
+ Identifiers.classMapInterpolate7,
11850
+ Identifiers.classMapInterpolate8,
11851
+ ],
11852
+ variable: Identifiers.classMapInterpolateV,
11853
+ mapping: n => {
11854
+ if (n % 2 === 0) {
11855
+ throw new Error(`Expected odd number of arguments`);
11281
11856
  }
11282
11857
  return (n - 1) / 2;
11283
11858
  },
@@ -11396,9 +11971,15 @@ function reifyUpdateOperations(_view, ops) {
11396
11971
  case OpKind.StyleProp:
11397
11972
  OpList.replace(op, styleProp(op.name, op.expression, op.unit));
11398
11973
  break;
11974
+ case OpKind.ClassProp:
11975
+ OpList.replace(op, classProp(op.name, op.expression));
11976
+ break;
11399
11977
  case OpKind.StyleMap:
11400
11978
  OpList.replace(op, styleMap(op.expression));
11401
11979
  break;
11980
+ case OpKind.ClassMap:
11981
+ OpList.replace(op, classMap(op.expression));
11982
+ break;
11402
11983
  case OpKind.InterpolateProperty:
11403
11984
  OpList.replace(op, propertyInterpolate(op.name, op.strings, op.expressions));
11404
11985
  break;
@@ -11408,6 +11989,9 @@ function reifyUpdateOperations(_view, ops) {
11408
11989
  case OpKind.InterpolateStyleMap:
11409
11990
  OpList.replace(op, styleMapInterpolate(op.strings, op.expressions));
11410
11991
  break;
11992
+ case OpKind.InterpolateClassMap:
11993
+ OpList.replace(op, classMapInterpolate(op.strings, op.expressions));
11994
+ break;
11411
11995
  case OpKind.InterpolateText:
11412
11996
  OpList.replace(op, textInterpolate(op.strings, op.expressions));
11413
11997
  break;
@@ -11765,27 +12349,71 @@ function phaseSlotAllocation(cpl) {
11765
12349
  // We do expect to find a slot allocated for everything which might be referenced.
11766
12350
  throw new Error(`AssertionError: no slot allocated for ${OpKind[op.kind]} target ${op.target}`);
11767
12351
  }
11768
- op.slot = slotMap.get(op.target);
12352
+ op.slot = slotMap.get(op.target);
12353
+ }
12354
+ // Process all `ir.Expression`s within this view, and look for `usesSlotIndexExprTrait`.
12355
+ visitExpressionsInOp(op, expr => {
12356
+ if (!isIrExpression(expr)) {
12357
+ return;
12358
+ }
12359
+ if (!hasUsesSlotIndexTrait(expr) || expr.slot !== null) {
12360
+ return;
12361
+ }
12362
+ // The `UsesSlotIndexExprTrait` indicates that this expression references something declared
12363
+ // in this component template by its slot index. Use the `target` `ir.XrefId` to find the
12364
+ // allocated slot for that declaration in `slotMap`.
12365
+ if (!slotMap.has(expr.target)) {
12366
+ // We do expect to find a slot allocated for everything which might be referenced.
12367
+ throw new Error(`AssertionError: no slot allocated for ${expr.constructor.name} target ${expr.target}`);
12368
+ }
12369
+ // Record the allocated slot on the expression.
12370
+ expr.slot = slotMap.get(expr.target);
12371
+ });
12372
+ }
12373
+ }
12374
+ }
12375
+
12376
+ /**
12377
+ * Find all assignments and usages of temporary variables, which are linked to each other with cross
12378
+ * references. Generate names for each cross-reference, and add a `DeclareVarStmt` to initialize
12379
+ * them at the beginning of the update block.
12380
+ *
12381
+ * TODO: Sometimes, it will be possible to reuse names across different subexpressions. For example,
12382
+ * in the double keyed read `a?.[f()]?.[f()]`, the two function calls have non-overlapping scopes.
12383
+ * Implement an algorithm for reuse.
12384
+ */
12385
+ function phaseTemporaryVariables(cpl) {
12386
+ for (const view of cpl.views.values()) {
12387
+ let opCount = 0;
12388
+ let generatedStatements = [];
12389
+ for (const op of view.ops()) {
12390
+ let count = 0;
12391
+ let xrefs = new Set();
12392
+ let defs = new Map();
12393
+ visitExpressionsInOp(op, expr => {
12394
+ if (expr instanceof ReadTemporaryExpr || expr instanceof AssignTemporaryExpr) {
12395
+ xrefs.add(expr.xref);
12396
+ }
12397
+ });
12398
+ for (const xref of xrefs) {
12399
+ // TODO: Exactly replicate the naming scheme used by `TemplateDefinitionBuilder`. It seems
12400
+ // to rely on an expression index instead of an op index.
12401
+ defs.set(xref, `tmp_${opCount}_${count++}`);
11769
12402
  }
11770
- // Process all `ir.Expression`s within this view, and look for `usesSlotIndexExprTrait`.
11771
12403
  visitExpressionsInOp(op, expr => {
11772
- if (!isIrExpression(expr)) {
11773
- return;
11774
- }
11775
- if (!hasUsesSlotIndexTrait(expr) || expr.slot !== null) {
11776
- return;
11777
- }
11778
- // The `UsesSlotIndexExprTrait` indicates that this expression references something declared
11779
- // in this component template by its slot index. Use the `target` `ir.XrefId` to find the
11780
- // allocated slot for that declaration in `slotMap`.
11781
- if (!slotMap.has(expr.target)) {
11782
- // We do expect to find a slot allocated for everything which might be referenced.
11783
- throw new Error(`AssertionError: no slot allocated for ${expr.constructor.name} target ${expr.target}`);
12404
+ if (expr instanceof ReadTemporaryExpr || expr instanceof AssignTemporaryExpr) {
12405
+ const name = defs.get(expr.xref);
12406
+ if (name === undefined) {
12407
+ throw new Error('Found xref with unassigned name');
12408
+ }
12409
+ expr.name = name;
11784
12410
  }
11785
- // Record the allocated slot on the expression.
11786
- expr.slot = slotMap.get(expr.target);
11787
12411
  });
12412
+ generatedStatements.push(...Array.from(defs.values())
12413
+ .map(name => createStatementOp(new DeclareVarStmt(name))));
12414
+ opCount++;
11788
12415
  }
12416
+ view.update.prepend(generatedStatements);
11789
12417
  }
11790
12418
  }
11791
12419
 
@@ -12152,225 +12780,12 @@ function allowConservativeInlining(decl, target) {
12152
12780
  }
12153
12781
  }
12154
12782
 
12155
- /**
12156
- * Finds all unresolved safe read expressions, and converts them into the appropriate output AST
12157
- * reads, guarded by null checks.
12158
- */
12159
- function phaseExpandSafeReads(cpl, compatibility) {
12160
- for (const [_, view] of cpl.views) {
12161
- for (const op of view.ops()) {
12162
- transformExpressionsInOp(op, e => safeTransform(e, { cpl, compatibility }), VisitorContextFlag.None);
12163
- transformExpressionsInOp(op, ternaryTransform, VisitorContextFlag.None);
12164
- }
12165
- }
12166
- }
12167
- // A lookup set of all the expression kinds that require a temporary variable to be generated.
12168
- const requiresTemporary = [
12169
- InvokeFunctionExpr, LiteralArrayExpr, LiteralMapExpr, SafeInvokeFunctionExpr,
12170
- PipeBindingExpr
12171
- ].map(e => e.constructor.name);
12172
- function needsTemporaryInSafeAccess(e) {
12173
- // TODO: We probably want to use an expression visitor to recursively visit all descendents.
12174
- // However, that would potentially do a lot of extra work (because it cannot short circuit), so we
12175
- // implement the logic ourselves for now.
12176
- if (e instanceof UnaryOperatorExpr) {
12177
- return needsTemporaryInSafeAccess(e.expr);
12178
- }
12179
- else if (e instanceof BinaryOperatorExpr) {
12180
- return needsTemporaryInSafeAccess(e.lhs) || needsTemporaryInSafeAccess(e.rhs);
12181
- }
12182
- else if (e instanceof ConditionalExpr) {
12183
- if (e.falseCase && needsTemporaryInSafeAccess(e.falseCase))
12184
- return true;
12185
- return needsTemporaryInSafeAccess(e.condition) || needsTemporaryInSafeAccess(e.trueCase);
12186
- }
12187
- else if (e instanceof NotExpr) {
12188
- return needsTemporaryInSafeAccess(e.condition);
12189
- }
12190
- else if (e instanceof AssignTemporaryExpr) {
12191
- return needsTemporaryInSafeAccess(e.expr);
12192
- }
12193
- else if (e instanceof ReadPropExpr) {
12194
- return needsTemporaryInSafeAccess(e.receiver);
12195
- }
12196
- else if (e instanceof ReadKeyExpr) {
12197
- return needsTemporaryInSafeAccess(e.receiver) || needsTemporaryInSafeAccess(e.index);
12198
- }
12199
- // TODO: Switch to a method which is exhaustive of newly added expression subtypes.
12200
- return e instanceof InvokeFunctionExpr || e instanceof LiteralArrayExpr ||
12201
- e instanceof LiteralMapExpr || e instanceof SafeInvokeFunctionExpr ||
12202
- e instanceof PipeBindingExpr;
12203
- }
12204
- function temporariesIn(e) {
12205
- const temporaries = new Set();
12206
- // TODO: Although it's not currently supported by the transform helper, we should be able to
12207
- // short-circuit exploring the tree to do less work. In particular, we don't have to penetrate
12208
- // into the subexpressions of temporary assignments.
12209
- transformExpressionsInExpression(e, e => {
12210
- if (e instanceof AssignTemporaryExpr) {
12211
- temporaries.add(e.xref);
12212
- }
12213
- return e;
12214
- }, VisitorContextFlag.None);
12215
- return temporaries;
12216
- }
12217
- function eliminateTemporaryAssignments(e, tmps, ctx) {
12218
- // TODO: We can be more efficient than the transform helper here. We don't need to visit any
12219
- // descendents of temporary assignments.
12220
- transformExpressionsInExpression(e, e => {
12221
- if (e instanceof AssignTemporaryExpr && tmps.has(e.xref)) {
12222
- const read = new ReadTemporaryExpr(e.xref);
12223
- // `TemplateDefinitionBuilder` has the (accidental?) behavior of generating assignments of
12224
- // temporary variables to themselves. This happens because some subexpression that the
12225
- // temporary refers to, possibly through nested temporaries, has a function call. We copy that
12226
- // behavior here.
12227
- return ctx.compatibility ? new AssignTemporaryExpr(read, read.xref) : read;
12228
- }
12229
- return e;
12230
- }, VisitorContextFlag.None);
12231
- return e;
12232
- }
12233
- /**
12234
- * Creates a safe ternary guarded by the input expression, and with a body generated by the provided
12235
- * callback on the input expression. Generates a temporary variable assignment if needed, and
12236
- * deduplicates nested temporary assignments if needed.
12237
- */
12238
- function safeTernaryWithTemporary(guard, body, ctx) {
12239
- let result;
12240
- if (needsTemporaryInSafeAccess(guard)) {
12241
- const xref = ctx.cpl.allocateXrefId();
12242
- result = [new AssignTemporaryExpr(guard, xref), new ReadTemporaryExpr(xref)];
12243
- }
12244
- else {
12245
- result = [guard, guard.clone()];
12246
- // Consider an expression like `a?.[b?.c()]?.d`. The `b?.c()` will be transformed first,
12247
- // introducing a temporary assignment into the key. Then, as part of expanding the `?.d`. That
12248
- // assignment will be duplicated into both the guard and expression sides. We de-duplicate it,
12249
- // by transforming it from an assignment into a read on the expression side.
12250
- eliminateTemporaryAssignments(result[1], temporariesIn(result[0]), ctx);
12251
- }
12252
- return new SafeTernaryExpr(result[0], body(result[1]));
12253
- }
12254
- function isSafeAccessExpression(e) {
12255
- return e instanceof SafePropertyReadExpr || e instanceof SafeKeyedReadExpr;
12256
- }
12257
- function isUnsafeAccessExpression(e) {
12258
- return e instanceof ReadPropExpr || e instanceof ReadKeyExpr ||
12259
- e instanceof InvokeFunctionExpr;
12260
- }
12261
- function isAccessExpression(e) {
12262
- return isSafeAccessExpression(e) || isUnsafeAccessExpression(e);
12263
- }
12264
- function deepestSafeTernary(e) {
12265
- if (isAccessExpression(e) && e.receiver instanceof SafeTernaryExpr) {
12266
- let st = e.receiver;
12267
- while (st.expr instanceof SafeTernaryExpr) {
12268
- st = st.expr;
12269
- }
12270
- return st;
12271
- }
12272
- return null;
12273
- }
12274
- // TODO: When strict compatibility with TemplateDefinitionBuilder is not required, we can use `&&`
12275
- // instead to save some code size.
12276
- function safeTransform(e, ctx) {
12277
- if (e instanceof SafeInvokeFunctionExpr) {
12278
- // TODO: Implement safe function calls in a subsequent commit.
12279
- return new InvokeFunctionExpr(e.receiver, e.args);
12280
- }
12281
- if (!isAccessExpression(e)) {
12282
- return e;
12283
- }
12284
- const dst = deepestSafeTernary(e);
12285
- if (dst) {
12286
- if (e instanceof InvokeFunctionExpr) {
12287
- dst.expr = dst.expr.callFn(e.args);
12288
- return e.receiver;
12289
- }
12290
- if (e instanceof ReadPropExpr) {
12291
- dst.expr = dst.expr.prop(e.name);
12292
- return e.receiver;
12293
- }
12294
- if (e instanceof ReadKeyExpr) {
12295
- dst.expr = dst.expr.key(e.index);
12296
- return e.receiver;
12297
- }
12298
- if (e instanceof SafePropertyReadExpr) {
12299
- dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.prop(e.name), ctx);
12300
- return e.receiver;
12301
- }
12302
- if (e instanceof SafeKeyedReadExpr) {
12303
- dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.key(e.index), ctx);
12304
- return e.receiver;
12305
- }
12306
- }
12307
- else {
12308
- if (e instanceof SafePropertyReadExpr) {
12309
- return safeTernaryWithTemporary(e.receiver, (r) => r.prop(e.name), ctx);
12310
- }
12311
- if (e instanceof SafeKeyedReadExpr) {
12312
- return safeTernaryWithTemporary(e.receiver, (r) => r.key(e.index), ctx);
12313
- }
12314
- }
12315
- return e;
12316
- }
12317
- function ternaryTransform(e) {
12318
- if (!(e instanceof SafeTernaryExpr)) {
12319
- return e;
12320
- }
12321
- return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.Equals, e.guard, NULL_EXPR), NULL_EXPR, e.expr);
12322
- }
12323
-
12324
- /**
12325
- * Find all assignments and usages of temporary variables, which are linked to each other with cross
12326
- * references. Generate names for each cross-reference, and add a `DeclareVarStmt` to initialize
12327
- * them at the beginning of the update block.
12328
- *
12329
- * TODO: Sometimes, it will be possible to reuse names across different subexpressions. For example,
12330
- * in the double keyed read `a?.[f()]?.[f()]`, the two function calls have non-overlapping scopes.
12331
- * Implement an algorithm for reuse.
12332
- */
12333
- function phaseTemporaryVariables(cpl) {
12334
- for (const view of cpl.views.values()) {
12335
- let opCount = 0;
12336
- let generatedStatements = [];
12337
- for (const op of view.ops()) {
12338
- let count = 0;
12339
- let xrefs = new Set();
12340
- let defs = new Map();
12341
- visitExpressionsInOp(op, expr => {
12342
- if (expr instanceof ReadTemporaryExpr || expr instanceof AssignTemporaryExpr) {
12343
- xrefs.add(expr.xref);
12344
- }
12345
- });
12346
- for (const xref of xrefs) {
12347
- // TODO: Exactly replicate the naming scheme used by `TemplateDefinitionBuilder`. It seems
12348
- // to rely on an expression index instead of an op index.
12349
- defs.set(xref, `tmp_${opCount}_${count++}`);
12350
- }
12351
- visitExpressionsInOp(op, expr => {
12352
- if (expr instanceof ReadTemporaryExpr || expr instanceof AssignTemporaryExpr) {
12353
- const name = defs.get(expr.xref);
12354
- if (name === undefined) {
12355
- throw new Error('Found xref with unassigned name');
12356
- }
12357
- expr.name = name;
12358
- }
12359
- });
12360
- generatedStatements.push(...Array.from(defs.values())
12361
- .map(name => createStatementOp(new DeclareVarStmt(name))));
12362
- opCount++;
12363
- }
12364
- view.update.prepend(generatedStatements);
12365
- }
12366
- }
12367
-
12368
12783
  /**
12369
12784
  * Run all transformation phases in the correct order against a `ComponentCompilation`. After this
12370
12785
  * processing, the compilation should be in a state where it can be emitted via `emitTemplateFn`.s
12371
12786
  */
12372
12787
  function transformTemplate(cpl) {
12373
- phaseAttributeExtraction(cpl, true);
12788
+ phaseAttributeExtraction(cpl, /* compatibility */ true);
12374
12789
  phasePipeCreation(cpl);
12375
12790
  phasePipeVariadic(cpl);
12376
12791
  phasePureLiteralStructures(cpl);
@@ -12386,13 +12801,14 @@ function transformTemplate(cpl) {
12386
12801
  phaseSlotAllocation(cpl);
12387
12802
  phaseVarCounting(cpl);
12388
12803
  phaseGenerateAdvance(cpl);
12389
- phaseNaming(cpl);
12804
+ phaseNaming(cpl, /* compatibility */ true);
12390
12805
  phaseVariableOptimization(cpl, { conservative: true });
12391
12806
  phaseMergeNextContext(cpl);
12392
12807
  phaseNgContainer(cpl);
12393
12808
  phaseEmptyElements(cpl);
12394
12809
  phasePureFunctionExtraction(cpl);
12395
12810
  phaseAlignPipeVariadicVarOffset(cpl);
12811
+ phasePropertyOrdering(cpl);
12396
12812
  phaseReify(cpl);
12397
12813
  phaseChaining(cpl);
12398
12814
  }
@@ -12828,6 +13244,12 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, uni
12828
13244
  }
12829
13245
  view.update.push(createInterpolateStyleMapOp(xref, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
12830
13246
  }
13247
+ else if (name === 'class') {
13248
+ if (bindingKind !== ElementAttributeKind.Binding) {
13249
+ throw Error('Unexpected class binding on ng-template');
13250
+ }
13251
+ view.update.push(createInterpolateClassMapOp(xref, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
13252
+ }
12831
13253
  else {
12832
13254
  view.update.push(createInterpolatePropertyOp(xref, bindingKind, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
12833
13255
  }
@@ -12845,8 +13267,11 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, uni
12845
13267
  const attributeInterpolate = createInterpolateAttributeOp(xref, bindingKind, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl)));
12846
13268
  view.update.push(attributeInterpolate);
12847
13269
  break;
13270
+ case 2 /* e.BindingType.Class */:
13271
+ throw Error('Unexpected interpolation in class property binding');
13272
+ // TODO: implement remaining binding types.
13273
+ case 4 /* e.BindingType.Animation */:
12848
13274
  default:
12849
- // TODO: implement remaining binding types.
12850
13275
  throw Error(`Interpolated property binding type not handled: ${type}`);
12851
13276
  }
12852
13277
  }
@@ -12860,6 +13285,12 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, uni
12860
13285
  }
12861
13286
  view.update.push(createStyleMapOp(xref, convertAst(value, view.tpl)));
12862
13287
  }
13288
+ else if (name === 'class') {
13289
+ if (bindingKind !== ElementAttributeKind.Binding) {
13290
+ throw Error('Unexpected class binding on ng-template');
13291
+ }
13292
+ view.update.push(createClassMapOp(xref, convertAst(value, view.tpl)));
13293
+ }
12863
13294
  else {
12864
13295
  view.update.push(createPropertyOp(xref, bindingKind, name, convertAst(value, view.tpl)));
12865
13296
  }
@@ -12877,8 +13308,15 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, uni
12877
13308
  const attrOp = createAttributeOp(xref, bindingKind, name, convertAst(value, view.tpl));
12878
13309
  view.update.push(attrOp);
12879
13310
  break;
13311
+ case 2 /* e.BindingType.Class */:
13312
+ if (bindingKind !== ElementAttributeKind.Binding) {
13313
+ throw Error('Unexpected class binding on ng-template');
13314
+ }
13315
+ view.update.push(createClassPropOp(xref, name, convertAst(value, view.tpl)));
13316
+ break;
13317
+ // TODO: implement remaining binding types.
13318
+ case 4 /* e.BindingType.Animation */:
12880
13319
  default:
12881
- // TODO: implement remaining binding types.
12882
13320
  throw Error(`Property binding type not handled: ${type}`);
12883
13321
  }
12884
13322
  }
@@ -12907,85 +13345,6 @@ function assertIsArray(value) {
12907
13345
 
12908
13346
  const USE_TEMPLATE_PIPELINE = false;
12909
13347
 
12910
- /**
12911
- * Parses string representation of a style and converts it into object literal.
12912
- *
12913
- * @param value string representation of style as used in the `style` attribute in HTML.
12914
- * Example: `color: red; height: auto`.
12915
- * @returns An array of style property name and value pairs, e.g. `['color', 'red', 'height',
12916
- * 'auto']`
12917
- */
12918
- function parse(value) {
12919
- // we use a string array here instead of a string map
12920
- // because a string-map is not guaranteed to retain the
12921
- // order of the entries whereas a string array can be
12922
- // constructed in a [key, value, key, value] format.
12923
- const styles = [];
12924
- let i = 0;
12925
- let parenDepth = 0;
12926
- let quote = 0 /* Char.QuoteNone */;
12927
- let valueStart = 0;
12928
- let propStart = 0;
12929
- let currentProp = null;
12930
- while (i < value.length) {
12931
- const token = value.charCodeAt(i++);
12932
- switch (token) {
12933
- case 40 /* Char.OpenParen */:
12934
- parenDepth++;
12935
- break;
12936
- case 41 /* Char.CloseParen */:
12937
- parenDepth--;
12938
- break;
12939
- case 39 /* Char.QuoteSingle */:
12940
- // valueStart needs to be there since prop values don't
12941
- // have quotes in CSS
12942
- if (quote === 0 /* Char.QuoteNone */) {
12943
- quote = 39 /* Char.QuoteSingle */;
12944
- }
12945
- else if (quote === 39 /* Char.QuoteSingle */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
12946
- quote = 0 /* Char.QuoteNone */;
12947
- }
12948
- break;
12949
- case 34 /* Char.QuoteDouble */:
12950
- // same logic as above
12951
- if (quote === 0 /* Char.QuoteNone */) {
12952
- quote = 34 /* Char.QuoteDouble */;
12953
- }
12954
- else if (quote === 34 /* Char.QuoteDouble */ && value.charCodeAt(i - 1) !== 92 /* Char.BackSlash */) {
12955
- quote = 0 /* Char.QuoteNone */;
12956
- }
12957
- break;
12958
- case 58 /* Char.Colon */:
12959
- if (!currentProp && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
12960
- currentProp = hyphenate(value.substring(propStart, i - 1).trim());
12961
- valueStart = i;
12962
- }
12963
- break;
12964
- case 59 /* Char.Semicolon */:
12965
- if (currentProp && valueStart > 0 && parenDepth === 0 && quote === 0 /* Char.QuoteNone */) {
12966
- const styleVal = value.substring(valueStart, i - 1).trim();
12967
- styles.push(currentProp, styleVal);
12968
- propStart = i;
12969
- valueStart = 0;
12970
- currentProp = null;
12971
- }
12972
- break;
12973
- }
12974
- }
12975
- if (currentProp && valueStart) {
12976
- const styleVal = value.slice(valueStart).trim();
12977
- styles.push(currentProp, styleVal);
12978
- }
12979
- return styles;
12980
- }
12981
- function hyphenate(value) {
12982
- return value
12983
- .replace(/[a-z][A-Z]/g, v => {
12984
- return v.charAt(0) + '-' + v.charAt(1);
12985
- })
12986
- .toLowerCase();
12987
- }
12988
-
12989
13348
  const IMPORTANT_FLAG = '!important';
12990
13349
  /**
12991
13350
  * Minimum amount of binding slots required in the runtime for style/class bindings.
@@ -19904,7 +20263,7 @@ class BindingParser {
19904
20263
  this._parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
19905
20264
  }
19906
20265
  else {
19907
- this._parsePropertyAst(name, this._parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
20266
+ this._parsePropertyAst(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
19908
20267
  }
19909
20268
  }
19910
20269
  parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs, targetProps, keySpan, interpolatedTokens) {
@@ -19926,11 +20285,11 @@ class BindingParser {
19926
20285
  // This will occur when a @trigger is not paired with an expression.
19927
20286
  // For animations it is valid to not have an expression since */void
19928
20287
  // states will be applied by angular when the element is attached/detached
19929
- const ast = this._parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
20288
+ const ast = this.parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
19930
20289
  targetMatchableAttrs.push([name, ast.source]);
19931
20290
  targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
19932
20291
  }
19933
- _parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
20292
+ parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
19934
20293
  const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown)').toString();
19935
20294
  try {
19936
20295
  const ast = isHostBinding ?
@@ -20207,6 +20566,415 @@ function normalizeNgContentSelect(selectAttr) {
20207
20566
  return selectAttr;
20208
20567
  }
20209
20568
 
20569
+ /** Pattern for a timing value in a trigger. */
20570
+ const TIME_PATTERN = /^\d+(ms|s)?$/;
20571
+ /** Pattern for a separator between keywords in a trigger expression. */
20572
+ const SEPARATOR_PATTERN = /^\s$/;
20573
+ /** Pairs of characters that form syntax that is comma-delimited. */
20574
+ const COMMA_DELIMITED_SYNTAX = new Map([
20575
+ [$LBRACE, $RBRACE],
20576
+ [$LBRACKET, $RBRACKET],
20577
+ [$LPAREN, $RPAREN], // Function calls
20578
+ ]);
20579
+ /** Possible types of `on` triggers. */
20580
+ var OnTriggerType;
20581
+ (function (OnTriggerType) {
20582
+ OnTriggerType["IDLE"] = "idle";
20583
+ OnTriggerType["TIMER"] = "timer";
20584
+ OnTriggerType["INTERACTION"] = "interaction";
20585
+ OnTriggerType["IMMEDIATE"] = "immediate";
20586
+ OnTriggerType["HOVER"] = "hover";
20587
+ OnTriggerType["VIEWPORT"] = "viewport";
20588
+ })(OnTriggerType || (OnTriggerType = {}));
20589
+ /** Parses a `when` deferred trigger. */
20590
+ function parseWhenTrigger({ expression, sourceSpan }, bindingParser, errors) {
20591
+ const whenIndex = expression.indexOf('when');
20592
+ // This is here just to be safe, we shouldn't enter this function
20593
+ // in the first place if a block doesn't have the "when" keyword.
20594
+ if (whenIndex === -1) {
20595
+ errors.push(new ParseError(sourceSpan, `Could not find "when" keyword in expression`));
20596
+ return null;
20597
+ }
20598
+ const start = getTriggerParametersStart(expression, whenIndex + 1);
20599
+ const parsed = bindingParser.parseBinding(expression.slice(start), false, sourceSpan, sourceSpan.start.offset + start);
20600
+ return new BoundDeferredTrigger(parsed, sourceSpan);
20601
+ }
20602
+ /** Parses an `on` trigger */
20603
+ function parseOnTrigger({ expression, sourceSpan }, errors) {
20604
+ const onIndex = expression.indexOf('on');
20605
+ // This is here just to be safe, we shouldn't enter this function
20606
+ // in the first place if a block doesn't have the "on" keyword.
20607
+ if (onIndex === -1) {
20608
+ errors.push(new ParseError(sourceSpan, `Could not find "on" keyword in expression`));
20609
+ return [];
20610
+ }
20611
+ const start = getTriggerParametersStart(expression, onIndex + 1);
20612
+ return new OnTriggerParser(expression, start, sourceSpan, errors).parse();
20613
+ }
20614
+ class OnTriggerParser {
20615
+ constructor(expression, start, span, errors) {
20616
+ this.expression = expression;
20617
+ this.start = start;
20618
+ this.span = span;
20619
+ this.errors = errors;
20620
+ this.index = 0;
20621
+ this.triggers = [];
20622
+ this.tokens = new Lexer().tokenize(expression.slice(start));
20623
+ }
20624
+ parse() {
20625
+ while (this.tokens.length > 0 && this.index < this.tokens.length) {
20626
+ const token = this.token();
20627
+ if (!token.isIdentifier()) {
20628
+ this.unexpectedToken(token);
20629
+ break;
20630
+ }
20631
+ // An identifier immediately followed by a comma or the end of
20632
+ // the expression cannot have parameters so we can exit early.
20633
+ if (this.isFollowedByOrLast($COMMA)) {
20634
+ this.consumeTrigger(token, []);
20635
+ this.advance();
20636
+ }
20637
+ else if (this.isFollowedByOrLast($LPAREN)) {
20638
+ this.advance(); // Advance to the opening paren.
20639
+ const prevErrors = this.errors.length;
20640
+ const parameters = this.consumeParameters();
20641
+ if (this.errors.length !== prevErrors) {
20642
+ break;
20643
+ }
20644
+ this.consumeTrigger(token, parameters);
20645
+ this.advance(); // Advance past the closing paren.
20646
+ }
20647
+ else if (this.index < this.tokens.length - 1) {
20648
+ this.unexpectedToken(this.tokens[this.index + 1]);
20649
+ }
20650
+ this.advance();
20651
+ }
20652
+ return this.triggers;
20653
+ }
20654
+ advance() {
20655
+ this.index++;
20656
+ }
20657
+ isFollowedByOrLast(char) {
20658
+ if (this.index === this.tokens.length - 1) {
20659
+ return true;
20660
+ }
20661
+ return this.tokens[this.index + 1].isCharacter(char);
20662
+ }
20663
+ token() {
20664
+ return this.tokens[Math.min(this.index, this.tokens.length - 1)];
20665
+ }
20666
+ consumeTrigger(identifier, parameters) {
20667
+ const startSpan = this.span.start.moveBy(this.start + identifier.index - this.tokens[0].index);
20668
+ const endSpan = startSpan.moveBy(this.token().end - identifier.index);
20669
+ const sourceSpan = new ParseSourceSpan(startSpan, endSpan);
20670
+ try {
20671
+ switch (identifier.toString()) {
20672
+ case OnTriggerType.IDLE:
20673
+ this.triggers.push(createIdleTrigger(parameters, sourceSpan));
20674
+ break;
20675
+ case OnTriggerType.TIMER:
20676
+ this.triggers.push(createTimerTrigger(parameters, sourceSpan));
20677
+ break;
20678
+ case OnTriggerType.INTERACTION:
20679
+ this.triggers.push(createInteractionTrigger(parameters, sourceSpan));
20680
+ break;
20681
+ case OnTriggerType.IMMEDIATE:
20682
+ this.triggers.push(createImmediateTrigger(parameters, sourceSpan));
20683
+ break;
20684
+ case OnTriggerType.HOVER:
20685
+ this.triggers.push(createHoverTrigger(parameters, sourceSpan));
20686
+ break;
20687
+ case OnTriggerType.VIEWPORT:
20688
+ this.triggers.push(createViewportTrigger(parameters, sourceSpan));
20689
+ break;
20690
+ default:
20691
+ throw new Error(`Unrecognized trigger type "${identifier}"`);
20692
+ }
20693
+ }
20694
+ catch (e) {
20695
+ this.error(identifier, e.message);
20696
+ }
20697
+ }
20698
+ consumeParameters() {
20699
+ const parameters = [];
20700
+ if (!this.token().isCharacter($LPAREN)) {
20701
+ this.unexpectedToken(this.token());
20702
+ return parameters;
20703
+ }
20704
+ this.advance();
20705
+ const commaDelimStack = [];
20706
+ let current = '';
20707
+ while (this.index < this.tokens.length) {
20708
+ const token = this.token();
20709
+ // Stop parsing if we've hit the end character and we're outside of a comma-delimited syntax.
20710
+ // Note that we don't need to account for strings here since the lexer already parsed them
20711
+ // into string tokens.
20712
+ if (token.isCharacter($RPAREN) && commaDelimStack.length === 0) {
20713
+ if (current.length) {
20714
+ parameters.push(current);
20715
+ }
20716
+ break;
20717
+ }
20718
+ // In the `on` microsyntax "top-level" commas (e.g. ones outside of an parameters) separate
20719
+ // the different triggers (e.g. `on idle,timer(500)`). This is problematic, because the
20720
+ // function-like syntax also implies that multiple parameters can be passed into the
20721
+ // individual trigger (e.g. `on foo(a, b)`). To avoid tripping up the parser with commas that
20722
+ // are part of other sorts of syntax (object literals, arrays), we treat anything inside
20723
+ // a comma-delimited syntax block as plain text.
20724
+ if (token.type === TokenType.Character && COMMA_DELIMITED_SYNTAX.has(token.numValue)) {
20725
+ commaDelimStack.push(COMMA_DELIMITED_SYNTAX.get(token.numValue));
20726
+ }
20727
+ if (commaDelimStack.length > 0 &&
20728
+ token.isCharacter(commaDelimStack[commaDelimStack.length - 1])) {
20729
+ commaDelimStack.pop();
20730
+ }
20731
+ // If we hit a comma outside of a comma-delimited syntax, it means
20732
+ // that we're at the top level and we're starting a new parameter.
20733
+ if (commaDelimStack.length === 0 && token.isCharacter($COMMA) && current.length > 0) {
20734
+ parameters.push(current);
20735
+ current = '';
20736
+ this.advance();
20737
+ continue;
20738
+ }
20739
+ // Otherwise treat the token as a plain text character in the current parameter.
20740
+ current += this.tokenText();
20741
+ this.advance();
20742
+ }
20743
+ if (!this.token().isCharacter($RPAREN) || commaDelimStack.length > 0) {
20744
+ this.error(this.token(), 'Unexpected end of expression');
20745
+ }
20746
+ if (this.index < this.tokens.length - 1 &&
20747
+ !this.tokens[this.index + 1].isCharacter($COMMA)) {
20748
+ this.unexpectedToken(this.tokens[this.index + 1]);
20749
+ }
20750
+ return parameters;
20751
+ }
20752
+ tokenText() {
20753
+ // Tokens have a toString already which we could use, but for string tokens it omits the quotes.
20754
+ // Eventually we could expose this information on the token directly.
20755
+ return this.expression.slice(this.start + this.token().index, this.start + this.token().end);
20756
+ }
20757
+ error(token, message) {
20758
+ const newStart = this.span.start.moveBy(this.start + token.index);
20759
+ const newEnd = newStart.moveBy(token.end - token.index);
20760
+ this.errors.push(new ParseError(new ParseSourceSpan(newStart, newEnd), message));
20761
+ }
20762
+ unexpectedToken(token) {
20763
+ this.error(token, `Unexpected token "${token}"`);
20764
+ }
20765
+ }
20766
+ function createIdleTrigger(parameters, sourceSpan) {
20767
+ if (parameters.length > 0) {
20768
+ throw new Error(`"${OnTriggerType.IDLE}" trigger cannot have parameters`);
20769
+ }
20770
+ return new IdleDeferredTrigger(sourceSpan);
20771
+ }
20772
+ function createTimerTrigger(parameters, sourceSpan) {
20773
+ if (parameters.length !== 1) {
20774
+ throw new Error(`"${OnTriggerType.TIMER}" trigger must have exactly one parameter`);
20775
+ }
20776
+ const delay = parseDeferredTime(parameters[0]);
20777
+ if (delay === null) {
20778
+ throw new Error(`Could not parse time value of trigger "${OnTriggerType.TIMER}"`);
20779
+ }
20780
+ return new TimerDeferredTrigger(delay, sourceSpan);
20781
+ }
20782
+ function createInteractionTrigger(parameters, sourceSpan) {
20783
+ if (parameters.length > 1) {
20784
+ throw new Error(`"${OnTriggerType.INTERACTION}" trigger can only have zero or one parameters`);
20785
+ }
20786
+ return new InteractionDeferredTrigger(parameters[0] ?? null, sourceSpan);
20787
+ }
20788
+ function createImmediateTrigger(parameters, sourceSpan) {
20789
+ if (parameters.length > 0) {
20790
+ throw new Error(`"${OnTriggerType.IMMEDIATE}" trigger cannot have parameters`);
20791
+ }
20792
+ return new ImmediateDeferredTrigger(sourceSpan);
20793
+ }
20794
+ function createHoverTrigger(parameters, sourceSpan) {
20795
+ if (parameters.length > 0) {
20796
+ throw new Error(`"${OnTriggerType.HOVER}" trigger cannot have parameters`);
20797
+ }
20798
+ return new HoverDeferredTrigger(sourceSpan);
20799
+ }
20800
+ function createViewportTrigger(parameters, sourceSpan) {
20801
+ // TODO: the RFC has some more potential parameters for `viewport`.
20802
+ if (parameters.length > 1) {
20803
+ throw new Error(`"${OnTriggerType.VIEWPORT}" trigger can only have zero or one parameters`);
20804
+ }
20805
+ return new ViewportDeferredTrigger(parameters[0] ?? null, sourceSpan);
20806
+ }
20807
+ /** Gets the index within an expression at which the trigger parameters start. */
20808
+ function getTriggerParametersStart(value, startPosition = 0) {
20809
+ let hasFoundSeparator = false;
20810
+ for (let i = startPosition; i < value.length; i++) {
20811
+ if (SEPARATOR_PATTERN.test(value[i])) {
20812
+ hasFoundSeparator = true;
20813
+ }
20814
+ else if (hasFoundSeparator) {
20815
+ return i;
20816
+ }
20817
+ }
20818
+ return -1;
20819
+ }
20820
+ /**
20821
+ * Parses a time expression from a deferred trigger to
20822
+ * milliseconds. Returns null if it cannot be parsed.
20823
+ */
20824
+ function parseDeferredTime(value) {
20825
+ const match = value.match(TIME_PATTERN);
20826
+ if (!match) {
20827
+ return null;
20828
+ }
20829
+ const [time, units] = match;
20830
+ return parseInt(time) * (units === 's' ? 1000 : 1);
20831
+ }
20832
+
20833
+ /** Pattern to identify a `prefetch when` trigger. */
20834
+ const PREFETCH_WHEN_PATTERN = /^prefetch\s+when\s/;
20835
+ /** Pattern to identify a `prefetch on` trigger. */
20836
+ const PREFETCH_ON_PATTERN = /^prefetch\s+on\s/;
20837
+ /** Pattern to identify a `minimum` parameter in a block. */
20838
+ const MINIMUM_PARAMETER_PATTERN = /^minimum\s/;
20839
+ /** Pattern to identify a `after` parameter in a block. */
20840
+ const AFTER_PARAMETER_PATTERN = /^after\s/;
20841
+ /** Pattern to identify a `when` parameter in a block. */
20842
+ const WHEN_PARAMETER_PATTERN = /^when\s/;
20843
+ /** Pattern to identify a `on` parameter in a block. */
20844
+ const ON_PARAMETER_PATTERN = /^on\s/;
20845
+ /** Possible types of secondary deferred blocks. */
20846
+ var SecondaryDeferredBlockType;
20847
+ (function (SecondaryDeferredBlockType) {
20848
+ SecondaryDeferredBlockType["PLACEHOLDER"] = "placeholder";
20849
+ SecondaryDeferredBlockType["LOADING"] = "loading";
20850
+ SecondaryDeferredBlockType["ERROR"] = "error";
20851
+ })(SecondaryDeferredBlockType || (SecondaryDeferredBlockType = {}));
20852
+ /** Creates a deferred block from an HTML AST node. */
20853
+ function createDeferredBlock(ast, visitor, bindingParser) {
20854
+ const errors = [];
20855
+ const [primaryBlock, ...secondaryBlocks] = ast.blocks;
20856
+ const { triggers, prefetchTriggers } = parsePrimaryTriggers(primaryBlock.parameters, bindingParser, errors);
20857
+ const { placeholder, loading, error } = parseSecondaryBlocks(secondaryBlocks, errors, visitor);
20858
+ return {
20859
+ node: new DeferredBlock(visitAll(visitor, primaryBlock.children), triggers, prefetchTriggers, placeholder, loading, error, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
20860
+ errors,
20861
+ };
20862
+ }
20863
+ function parseSecondaryBlocks(blocks, errors, visitor) {
20864
+ let placeholder = null;
20865
+ let loading = null;
20866
+ let error = null;
20867
+ for (const block of blocks) {
20868
+ try {
20869
+ switch (block.name) {
20870
+ case SecondaryDeferredBlockType.PLACEHOLDER:
20871
+ if (placeholder !== null) {
20872
+ errors.push(new ParseError(block.startSourceSpan, `"defer" block can only have one "${SecondaryDeferredBlockType.PLACEHOLDER}" block`));
20873
+ }
20874
+ else {
20875
+ placeholder = parsePlaceholderBlock(block, visitor);
20876
+ }
20877
+ break;
20878
+ case SecondaryDeferredBlockType.LOADING:
20879
+ if (loading !== null) {
20880
+ errors.push(new ParseError(block.startSourceSpan, `"defer" block can only have one "${SecondaryDeferredBlockType.LOADING}" block`));
20881
+ }
20882
+ else {
20883
+ loading = parseLoadingBlock(block, visitor);
20884
+ }
20885
+ break;
20886
+ case SecondaryDeferredBlockType.ERROR:
20887
+ if (error !== null) {
20888
+ errors.push(new ParseError(block.startSourceSpan, `"defer" block can only have one "${SecondaryDeferredBlockType.ERROR}" block`));
20889
+ }
20890
+ else {
20891
+ error = parseErrorBlock(block, visitor);
20892
+ }
20893
+ break;
20894
+ default:
20895
+ errors.push(new ParseError(block.startSourceSpan, `Unrecognized block "${block.name}"`));
20896
+ break;
20897
+ }
20898
+ }
20899
+ catch (e) {
20900
+ errors.push(new ParseError(block.startSourceSpan, e.message));
20901
+ }
20902
+ }
20903
+ return { placeholder, loading, error };
20904
+ }
20905
+ function parsePlaceholderBlock(ast, visitor) {
20906
+ let minimumTime = null;
20907
+ for (const param of ast.parameters) {
20908
+ if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
20909
+ const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
20910
+ if (parsedTime === null) {
20911
+ throw new Error(`Could not parse time value of parameter "minimum"`);
20912
+ }
20913
+ minimumTime = parsedTime;
20914
+ }
20915
+ else {
20916
+ throw new Error(`Unrecognized parameter in "${SecondaryDeferredBlockType.PLACEHOLDER}" block: "${param.expression}"`);
20917
+ }
20918
+ }
20919
+ return new DeferredBlockPlaceholder(visitAll(visitor, ast.children), minimumTime, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
20920
+ }
20921
+ function parseLoadingBlock(ast, visitor) {
20922
+ let afterTime = null;
20923
+ let minimumTime = null;
20924
+ for (const param of ast.parameters) {
20925
+ if (AFTER_PARAMETER_PATTERN.test(param.expression)) {
20926
+ const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
20927
+ if (parsedTime === null) {
20928
+ throw new Error(`Could not parse time value of parameter "after"`);
20929
+ }
20930
+ afterTime = parsedTime;
20931
+ }
20932
+ else if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
20933
+ const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
20934
+ if (parsedTime === null) {
20935
+ throw new Error(`Could not parse time value of parameter "minimum"`);
20936
+ }
20937
+ minimumTime = parsedTime;
20938
+ }
20939
+ else {
20940
+ throw new Error(`Unrecognized parameter in "${SecondaryDeferredBlockType.LOADING}" block: "${param.expression}"`);
20941
+ }
20942
+ }
20943
+ return new DeferredBlockLoading(visitAll(visitor, ast.children), afterTime, minimumTime, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
20944
+ }
20945
+ function parseErrorBlock(ast, visitor) {
20946
+ if (ast.parameters.length > 0) {
20947
+ throw new Error(`"${SecondaryDeferredBlockType.ERROR}" block cannot have parameters`);
20948
+ }
20949
+ return new DeferredBlockError(visitAll(visitor, ast.children), ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
20950
+ }
20951
+ function parsePrimaryTriggers(params, bindingParser, errors) {
20952
+ const triggers = [];
20953
+ const prefetchTriggers = [];
20954
+ for (const param of params) {
20955
+ // The lexer ignores the leading spaces so we can assume
20956
+ // that the expression starts with a keyword.
20957
+ if (WHEN_PARAMETER_PATTERN.test(param.expression)) {
20958
+ const result = parseWhenTrigger(param, bindingParser, errors);
20959
+ result !== null && triggers.push(result);
20960
+ }
20961
+ else if (ON_PARAMETER_PATTERN.test(param.expression)) {
20962
+ triggers.push(...parseOnTrigger(param, errors));
20963
+ }
20964
+ else if (PREFETCH_WHEN_PATTERN.test(param.expression)) {
20965
+ const result = parseWhenTrigger(param, bindingParser, errors);
20966
+ result !== null && prefetchTriggers.push(result);
20967
+ }
20968
+ else if (PREFETCH_ON_PATTERN.test(param.expression)) {
20969
+ prefetchTriggers.push(...parseOnTrigger(param, errors));
20970
+ }
20971
+ else {
20972
+ errors.push(new ParseError(param.sourceSpan, 'Unrecognized trigger'));
20973
+ }
20974
+ }
20975
+ return { triggers, prefetchTriggers };
20976
+ }
20977
+
20210
20978
  const BIND_NAME_REGEXP = /^(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*)$/;
20211
20979
  // Group 1 = "bind-"
20212
20980
  const KW_BIND_IDX = 1;
@@ -20330,7 +21098,16 @@ class HtmlAstToIvyAst {
20330
21098
  attributes.push(this.visitAttribute(attribute));
20331
21099
  }
20332
21100
  }
20333
- const children = visitAll(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children);
21101
+ let children;
21102
+ if (preparsedElement.nonBindable) {
21103
+ // The `NonBindableVisitor` may need to return an array of nodes for block groups so we need
21104
+ // to flatten the array here. Avoid doing this for the `HtmlAstToIvyAst` since `flat` creates
21105
+ // a new array.
21106
+ children = visitAll(NON_BINDABLE_VISITOR, element.children).flat(Infinity);
21107
+ }
21108
+ else {
21109
+ children = visitAll(this, element.children);
21110
+ }
20334
21111
  let parsedElement;
20335
21112
  if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
20336
21113
  // `<ng-content>`
@@ -20429,14 +21206,22 @@ class HtmlAstToIvyAst {
20429
21206
  return null;
20430
21207
  }
20431
21208
  visitBlockGroup(group, context) {
20432
- throw new Error('TODO');
20433
- }
20434
- visitBlock(block, context) {
20435
- throw new Error('TODO');
20436
- }
20437
- visitBlockParameter(parameter, context) {
20438
- throw new Error('TODO');
21209
+ const primaryBlock = group.blocks[0];
21210
+ // The HTML parser ensures that we don't hit this case, but we have an assertion just in case.
21211
+ if (!primaryBlock) {
21212
+ this.reportError('Block group must have at least one block.', group.sourceSpan);
21213
+ return null;
21214
+ }
21215
+ if (primaryBlock.name === 'defer' && this.options.enabledBlockTypes.has(primaryBlock.name)) {
21216
+ const { node, errors } = createDeferredBlock(group, this, this.bindingParser);
21217
+ this.errors.push(...errors);
21218
+ return node;
21219
+ }
21220
+ this.reportError(`Unrecognized block "${primaryBlock.name}".`, primaryBlock.sourceSpan);
21221
+ return null;
20439
21222
  }
21223
+ visitBlock(block, context) { }
21224
+ visitBlockParameter(parameter, context) { }
20440
21225
  // convert view engine `ParsedProperty` to a format suitable for IVY
20441
21226
  extractAttributes(elementName, properties, i18nPropsMeta) {
20442
21227
  const bound = [];
@@ -20615,13 +21400,23 @@ class NonBindableVisitor {
20615
21400
  return null;
20616
21401
  }
20617
21402
  visitBlockGroup(group, context) {
20618
- throw new Error('TODO');
21403
+ const nodes = visitAll(this, group.blocks);
21404
+ // We only need to do the end tag since the start will be added as a part of the primary block.
21405
+ if (group.endSourceSpan !== null) {
21406
+ nodes.push(new Text$3(group.endSourceSpan.toString(), group.endSourceSpan));
21407
+ }
21408
+ return nodes;
20619
21409
  }
20620
21410
  visitBlock(block, context) {
20621
- throw new Error('TODO');
21411
+ return [
21412
+ // In an ngNonBindable context we treat the opening/closing tags of block as plain text.
21413
+ // This is the as if the `tokenizeBlocks` option was disabled.
21414
+ new Text$3(block.startSourceSpan.toString(), block.startSourceSpan),
21415
+ ...visitAll(this, block.children)
21416
+ ];
20622
21417
  }
20623
21418
  visitBlockParameter(parameter, context) {
20624
- throw new Error('TODO');
21419
+ return null;
20625
21420
  }
20626
21421
  }
20627
21422
  const NON_BINDABLE_VISITOR = new NonBindableVisitor();
@@ -22469,6 +23264,12 @@ class TemplateDefinitionBuilder {
22469
23264
  }
22470
23265
  return null;
22471
23266
  }
23267
+ // TODO: implement deferred block instructions.
23268
+ visitDeferredBlock(deferred) { }
23269
+ visitDeferredTrigger(trigger) { }
23270
+ visitDeferredBlockPlaceholder(block) { }
23271
+ visitDeferredBlockError(block) { }
23272
+ visitDeferredBlockLoading(block) { }
22472
23273
  allocateDataSlot() {
22473
23274
  return this._dataIndex++;
22474
23275
  }
@@ -23205,7 +24006,12 @@ function parseTemplate(template, templateUrl, options = {}) {
23205
24006
  const { interpolationConfig, preserveWhitespaces, enableI18nLegacyMessageIdFormat } = options;
23206
24007
  const bindingParser = makeBindingParser(interpolationConfig);
23207
24008
  const htmlParser = new HtmlParser();
23208
- const parseResult = htmlParser.parse(template, templateUrl, { leadingTriviaChars: LEADING_TRIVIA_CHARS, ...options, tokenizeExpansionForms: true });
24009
+ const parseResult = htmlParser.parse(template, templateUrl, {
24010
+ leadingTriviaChars: LEADING_TRIVIA_CHARS,
24011
+ ...options,
24012
+ tokenizeExpansionForms: true,
24013
+ tokenizeBlocks: options.enabledBlockTypes != null && options.enabledBlockTypes.size > 0,
24014
+ });
23209
24015
  if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
23210
24016
  parseResult.errors.length > 0) {
23211
24017
  const parsedTemplate = {
@@ -23256,7 +24062,10 @@ function parseTemplate(template, templateUrl, options = {}) {
23256
24062
  rootNodes = visitAll(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
23257
24063
  }
23258
24064
  }
23259
- const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, { collectCommentNodes: !!options.collectCommentNodes });
24065
+ const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, {
24066
+ collectCommentNodes: !!options.collectCommentNodes,
24067
+ enabledBlockTypes: options.enabledBlockTypes || new Set(),
24068
+ });
23260
24069
  errors.push(...parseResult.errors, ...i18nMetaResult.errors);
23261
24070
  const parsedTemplate = {
23262
24071
  interpolationConfig,
@@ -24533,7 +25342,11 @@ function convertPipeDeclarationToMetadata(pipe) {
24533
25342
  function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces, interpolation) {
24534
25343
  const interpolationConfig = interpolation ? InterpolationConfig.fromArray(interpolation) : DEFAULT_INTERPOLATION_CONFIG;
24535
25344
  // Parse the template and check for errors.
24536
- const parsed = parseTemplate(template, sourceMapUrl, { preserveWhitespaces, interpolationConfig });
25345
+ const parsed = parseTemplate(template, sourceMapUrl, {
25346
+ preserveWhitespaces,
25347
+ interpolationConfig,
25348
+ enabledBlockTypes: new Set(), // TODO: enable deferred blocks when testing in JIT mode.
25349
+ });
24537
25350
  if (parsed.errors !== null) {
24538
25351
  const errors = parsed.errors.map(err => err.toString()).join(', ');
24539
25352
  throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`);
@@ -24722,7 +25535,7 @@ function publishFacade(global) {
24722
25535
  * @description
24723
25536
  * Entry point for all public APIs of the compiler package.
24724
25537
  */
24725
- const VERSION = new Version('16.2.0-next.2');
25538
+ const VERSION = new Version('16.2.0-next.3');
24726
25539
 
24727
25540
  class CompilerConfig {
24728
25541
  constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
@@ -26267,6 +27080,21 @@ class Scope {
26267
27080
  // Declare the variable if it's not already.
26268
27081
  this.maybeDeclare(reference);
26269
27082
  }
27083
+ visitDeferredBlock(deferred) {
27084
+ deferred.children.forEach(node => node.visit(this));
27085
+ deferred.placeholder?.visit(this);
27086
+ deferred.loading?.visit(this);
27087
+ deferred.error?.visit(this);
27088
+ }
27089
+ visitDeferredBlockPlaceholder(block) {
27090
+ block.children.forEach(node => node.visit(this));
27091
+ }
27092
+ visitDeferredBlockError(block) {
27093
+ block.children.forEach(node => node.visit(this));
27094
+ }
27095
+ visitDeferredBlockLoading(block) {
27096
+ block.children.forEach(node => node.visit(this));
27097
+ }
26270
27098
  // Unused visitors.
26271
27099
  visitContent(content) { }
26272
27100
  visitBoundAttribute(attr) { }
@@ -26275,6 +27103,7 @@ class Scope {
26275
27103
  visitText(text) { }
26276
27104
  visitTextAttribute(attr) { }
26277
27105
  visitIcu(icu) { }
27106
+ visitDeferredTrigger(trigger) { }
26278
27107
  maybeDeclare(thing) {
26279
27108
  // Declare something with a name, as long as that name isn't taken.
26280
27109
  if (!this.namedEntities.has(thing.name)) {
@@ -26412,6 +27241,21 @@ class DirectiveBinder {
26412
27241
  // Recurse into the node's children.
26413
27242
  node.children.forEach(child => child.visit(this));
26414
27243
  }
27244
+ visitDeferredBlock(deferred) {
27245
+ deferred.children.forEach(child => child.visit(this));
27246
+ deferred.placeholder?.visit(this);
27247
+ deferred.loading?.visit(this);
27248
+ deferred.error?.visit(this);
27249
+ }
27250
+ visitDeferredBlockPlaceholder(block) {
27251
+ block.children.forEach(child => child.visit(this));
27252
+ }
27253
+ visitDeferredBlockError(block) {
27254
+ block.children.forEach(child => child.visit(this));
27255
+ }
27256
+ visitDeferredBlockLoading(block) {
27257
+ block.children.forEach(child => child.visit(this));
27258
+ }
26415
27259
  // Unused visitors.
26416
27260
  visitContent(content) { }
26417
27261
  visitVariable(variable) { }
@@ -26423,6 +27267,7 @@ class DirectiveBinder {
26423
27267
  visitText(text) { }
26424
27268
  visitBoundText(text) { }
26425
27269
  visitIcu(icu) { }
27270
+ visitDeferredTrigger(trigger) { }
26426
27271
  }
26427
27272
  /**
26428
27273
  * Processes a template and extract metadata about expressions and symbols within.
@@ -26460,7 +27305,7 @@ class TemplateBinder extends RecursiveAstVisitor {
26460
27305
  /**
26461
27306
  * Process a template and extract metadata about expressions and symbols within.
26462
27307
  *
26463
- * @param template the nodes of the template to process
27308
+ * @param nodes the nodes of the template to process
26464
27309
  * @param scope the `Scope` of the template being processed.
26465
27310
  * @returns three maps which contain metadata about the template: `expressions` which interprets
26466
27311
  * special `AST` nodes in expressions as pointing to references or variables declared within the
@@ -26469,14 +27314,15 @@ class TemplateBinder extends RecursiveAstVisitor {
26469
27314
  * nesting level (how many levels deep within the template structure the `Template` is), starting
26470
27315
  * at 1.
26471
27316
  */
26472
- static applyWithScope(template, scope) {
27317
+ static applyWithScope(nodes, scope) {
26473
27318
  const expressions = new Map();
26474
27319
  const symbols = new Map();
26475
27320
  const nestingLevel = new Map();
26476
27321
  const usedPipes = new Set();
27322
+ const template = nodes instanceof Template ? nodes : null;
26477
27323
  // The top-level template has nesting level 0.
26478
- const binder = new TemplateBinder(expressions, symbols, usedPipes, nestingLevel, scope, template instanceof Template ? template : null, 0);
26479
- binder.ingest(template);
27324
+ const binder = new TemplateBinder(expressions, symbols, usedPipes, nestingLevel, scope, template, 0);
27325
+ binder.ingest(nodes);
26480
27326
  return { expressions, symbols, nestingLevel, usedPipes };
26481
27327
  }
26482
27328
  ingest(template) {
@@ -26538,6 +27384,28 @@ class TemplateBinder extends RecursiveAstVisitor {
26538
27384
  visitBoundEvent(event) {
26539
27385
  event.handler.visit(this);
26540
27386
  }
27387
+ visitDeferredBlock(deferred) {
27388
+ deferred.triggers.forEach(this.visitNode);
27389
+ deferred.prefetchTriggers.forEach(this.visitNode);
27390
+ deferred.children.forEach(this.visitNode);
27391
+ deferred.placeholder && this.visitNode(deferred.placeholder);
27392
+ deferred.loading && this.visitNode(deferred.loading);
27393
+ deferred.error && this.visitNode(deferred.error);
27394
+ }
27395
+ visitDeferredTrigger(trigger) {
27396
+ if (trigger instanceof BoundDeferredTrigger) {
27397
+ trigger.value.visit(this);
27398
+ }
27399
+ }
27400
+ visitDeferredBlockPlaceholder(block) {
27401
+ block.children.forEach(this.visitNode);
27402
+ }
27403
+ visitDeferredBlockError(block) {
27404
+ block.children.forEach(this.visitNode);
27405
+ }
27406
+ visitDeferredBlockLoading(block) {
27407
+ block.children.forEach(this.visitNode);
27408
+ }
26541
27409
  visitBoundText(text) {
26542
27410
  text.value.visit(this);
26543
27411
  }
@@ -26676,7 +27544,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
26676
27544
  function compileDeclareClassMetadata(metadata) {
26677
27545
  const definitionMap = new DefinitionMap();
26678
27546
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
26679
- definitionMap.set('version', literal('16.2.0-next.2'));
27547
+ definitionMap.set('version', literal('16.2.0-next.3'));
26680
27548
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26681
27549
  definitionMap.set('type', metadata.type);
26682
27550
  definitionMap.set('decorators', metadata.decorators);
@@ -26779,7 +27647,7 @@ function compileDeclareDirectiveFromMetadata(meta) {
26779
27647
  function createDirectiveDefinitionMap(meta) {
26780
27648
  const definitionMap = new DefinitionMap();
26781
27649
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
26782
- definitionMap.set('version', literal('16.2.0-next.2'));
27650
+ definitionMap.set('version', literal('16.2.0-next.3'));
26783
27651
  // e.g. `type: MyDirective`
26784
27652
  definitionMap.set('type', meta.type.value);
26785
27653
  if (meta.isStandalone) {
@@ -27007,7 +27875,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
27007
27875
  function compileDeclareFactoryFunction(meta) {
27008
27876
  const definitionMap = new DefinitionMap();
27009
27877
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
27010
- definitionMap.set('version', literal('16.2.0-next.2'));
27878
+ definitionMap.set('version', literal('16.2.0-next.3'));
27011
27879
  definitionMap.set('ngImport', importExpr(Identifiers.core));
27012
27880
  definitionMap.set('type', meta.type.value);
27013
27881
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -27042,7 +27910,7 @@ function compileDeclareInjectableFromMetadata(meta) {
27042
27910
  function createInjectableDefinitionMap(meta) {
27043
27911
  const definitionMap = new DefinitionMap();
27044
27912
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
27045
- definitionMap.set('version', literal('16.2.0-next.2'));
27913
+ definitionMap.set('version', literal('16.2.0-next.3'));
27046
27914
  definitionMap.set('ngImport', importExpr(Identifiers.core));
27047
27915
  definitionMap.set('type', meta.type.value);
27048
27916
  // Only generate providedIn property if it has a non-null value
@@ -27093,7 +27961,7 @@ function compileDeclareInjectorFromMetadata(meta) {
27093
27961
  function createInjectorDefinitionMap(meta) {
27094
27962
  const definitionMap = new DefinitionMap();
27095
27963
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
27096
- definitionMap.set('version', literal('16.2.0-next.2'));
27964
+ definitionMap.set('version', literal('16.2.0-next.3'));
27097
27965
  definitionMap.set('ngImport', importExpr(Identifiers.core));
27098
27966
  definitionMap.set('type', meta.type.value);
27099
27967
  definitionMap.set('providers', meta.providers);
@@ -27126,7 +27994,7 @@ function createNgModuleDefinitionMap(meta) {
27126
27994
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
27127
27995
  }
27128
27996
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
27129
- definitionMap.set('version', literal('16.2.0-next.2'));
27997
+ definitionMap.set('version', literal('16.2.0-next.3'));
27130
27998
  definitionMap.set('ngImport', importExpr(Identifiers.core));
27131
27999
  definitionMap.set('type', meta.type.value);
27132
28000
  // We only generate the keys in the metadata if the arrays contain values.
@@ -27177,7 +28045,7 @@ function compileDeclarePipeFromMetadata(meta) {
27177
28045
  function createPipeDefinitionMap(meta) {
27178
28046
  const definitionMap = new DefinitionMap();
27179
28047
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
27180
- definitionMap.set('version', literal('16.2.0-next.2'));
28048
+ definitionMap.set('version', literal('16.2.0-next.3'));
27181
28049
  definitionMap.set('ngImport', importExpr(Identifiers.core));
27182
28050
  // e.g. `type: MyPipe`
27183
28051
  definitionMap.set('type', meta.type.value);
@@ -27210,5 +28078,5 @@ publishFacade(_global);
27210
28078
 
27211
28079
  // This file is not used to build this module. It is only used during editing
27212
28080
 
27213
- export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockGroup, 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, 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, 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, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, Element$1 as TmplAstElement, Icu$1 as TmplAstIcu, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, Variable as TmplAstVariable, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
28081
+ export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockGroup, 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, 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, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, _ParseAST, compileClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
27214
28082
  //# sourceMappingURL=compiler.mjs.map