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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/esm2022/src/compiler.mjs +3 -3
  2. package/esm2022/src/jit_compiler_facade.mjs +6 -2
  3. package/esm2022/src/ml_parser/lexer.mjs +14 -3
  4. package/esm2022/src/output/abstract_emitter.mjs +4 -1
  5. package/esm2022/src/output/output_ast.mjs +22 -1
  6. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  7. package/esm2022/src/render3/partial/directive.mjs +1 -1
  8. package/esm2022/src/render3/partial/factory.mjs +1 -1
  9. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  10. package/esm2022/src/render3/partial/injector.mjs +1 -1
  11. package/esm2022/src/render3/partial/ng_module.mjs +1 -1
  12. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  13. package/esm2022/src/render3/r3_ast.mjs +109 -1
  14. package/esm2022/src/render3/r3_deferred_blocks.mjs +156 -0
  15. package/esm2022/src/render3/r3_deferred_triggers.mjs +275 -0
  16. package/esm2022/src/render3/r3_template_transform.mjs +40 -12
  17. package/esm2022/src/render3/view/t2_binder.mjs +61 -6
  18. package/esm2022/src/render3/view/template.mjs +17 -3
  19. package/esm2022/src/template/pipeline/ir/src/enums.mjs +21 -9
  20. package/esm2022/src/template/pipeline/ir/src/expression.mjs +4 -1
  21. package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +42 -1
  22. package/esm2022/src/template/pipeline/src/emit.mjs +8 -6
  23. package/esm2022/src/template/pipeline/src/ingest.mjs +25 -3
  24. package/esm2022/src/template/pipeline/src/instruction.mjs +35 -8
  25. package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +2 -1
  26. package/esm2022/src/template/pipeline/src/phases/chaining.mjs +11 -1
  27. package/esm2022/src/template/pipeline/src/phases/naming.mjs +38 -9
  28. package/esm2022/src/template/pipeline/src/phases/property_ordering.mjs +82 -0
  29. package/esm2022/src/template/pipeline/src/phases/reify.mjs +10 -1
  30. package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +13 -8
  31. package/esm2022/src/template_parser/binding_parser.mjs +4 -4
  32. package/esm2022/src/util.mjs +2 -8
  33. package/esm2022/src/version.mjs +1 -1
  34. package/fesm2022/compiler.mjs +1335 -456
  35. package/fesm2022/compiler.mjs.map +1 -1
  36. package/fesm2022/testing.mjs +1 -1
  37. package/index.d.ts +120 -2
  38. package/package.json +2 -2
  39. 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.4
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.
@@ -18151,10 +18510,10 @@ class _Tokenizer {
18151
18510
  this._beginToken(28 /* TokenType.BLOCK_PARAMETER */);
18152
18511
  const start = this._cursor.clone();
18153
18512
  let inQuote = null;
18513
+ let openBraces = 0;
18154
18514
  // Consume the parameter until the next semicolon or brace.
18155
18515
  // Note that we skip over semicolons/braces inside of strings.
18156
- while ((this._cursor.peek() !== $SEMICOLON && this._cursor.peek() !== $RBRACE &&
18157
- this._cursor.peek() !== $EOF) ||
18516
+ while ((this._cursor.peek() !== $SEMICOLON && this._cursor.peek() !== $EOF) ||
18158
18517
  inQuote !== null) {
18159
18518
  const char = this._cursor.peek();
18160
18519
  // Skip to the next character if it was escaped.
@@ -18167,6 +18526,17 @@ class _Tokenizer {
18167
18526
  else if (inQuote === null && isQuote(char)) {
18168
18527
  inQuote = char;
18169
18528
  }
18529
+ else if (char === $LBRACE && inQuote === null) {
18530
+ openBraces++;
18531
+ }
18532
+ else if (char === $RBRACE && inQuote === null) {
18533
+ if (openBraces === 0) {
18534
+ break;
18535
+ }
18536
+ else if (openBraces > 0) {
18537
+ openBraces--;
18538
+ }
18539
+ }
18170
18540
  this._cursor.advance();
18171
18541
  }
18172
18542
  this._endToken([this._cursor.getChars(start)]);
@@ -19904,7 +20274,7 @@ class BindingParser {
19904
20274
  this._parseAnimation(name, expression, sourceSpan, absoluteOffset, keySpan, valueSpan, targetMatchableAttrs, targetProps);
19905
20275
  }
19906
20276
  else {
19907
- this._parsePropertyAst(name, this._parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
20277
+ this._parsePropertyAst(name, this.parseBinding(expression, isHost, valueSpan || sourceSpan, absoluteOffset), sourceSpan, keySpan, valueSpan, targetMatchableAttrs, targetProps);
19908
20278
  }
19909
20279
  }
19910
20280
  parsePropertyInterpolation(name, value, sourceSpan, valueSpan, targetMatchableAttrs, targetProps, keySpan, interpolatedTokens) {
@@ -19926,11 +20296,11 @@ class BindingParser {
19926
20296
  // This will occur when a @trigger is not paired with an expression.
19927
20297
  // For animations it is valid to not have an expression since */void
19928
20298
  // states will be applied by angular when the element is attached/detached
19929
- const ast = this._parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
20299
+ const ast = this.parseBinding(expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset);
19930
20300
  targetMatchableAttrs.push([name, ast.source]);
19931
20301
  targetProps.push(new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, keySpan, valueSpan));
19932
20302
  }
19933
- _parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
20303
+ parseBinding(value, isHostBinding, sourceSpan, absoluteOffset) {
19934
20304
  const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown)').toString();
19935
20305
  try {
19936
20306
  const ast = isHostBinding ?
@@ -20207,6 +20577,415 @@ function normalizeNgContentSelect(selectAttr) {
20207
20577
  return selectAttr;
20208
20578
  }
20209
20579
 
20580
+ /** Pattern for a timing value in a trigger. */
20581
+ const TIME_PATTERN = /^\d+(ms|s)?$/;
20582
+ /** Pattern for a separator between keywords in a trigger expression. */
20583
+ const SEPARATOR_PATTERN = /^\s$/;
20584
+ /** Pairs of characters that form syntax that is comma-delimited. */
20585
+ const COMMA_DELIMITED_SYNTAX = new Map([
20586
+ [$LBRACE, $RBRACE],
20587
+ [$LBRACKET, $RBRACKET],
20588
+ [$LPAREN, $RPAREN], // Function calls
20589
+ ]);
20590
+ /** Possible types of `on` triggers. */
20591
+ var OnTriggerType;
20592
+ (function (OnTriggerType) {
20593
+ OnTriggerType["IDLE"] = "idle";
20594
+ OnTriggerType["TIMER"] = "timer";
20595
+ OnTriggerType["INTERACTION"] = "interaction";
20596
+ OnTriggerType["IMMEDIATE"] = "immediate";
20597
+ OnTriggerType["HOVER"] = "hover";
20598
+ OnTriggerType["VIEWPORT"] = "viewport";
20599
+ })(OnTriggerType || (OnTriggerType = {}));
20600
+ /** Parses a `when` deferred trigger. */
20601
+ function parseWhenTrigger({ expression, sourceSpan }, bindingParser, errors) {
20602
+ const whenIndex = expression.indexOf('when');
20603
+ // This is here just to be safe, we shouldn't enter this function
20604
+ // in the first place if a block doesn't have the "when" keyword.
20605
+ if (whenIndex === -1) {
20606
+ errors.push(new ParseError(sourceSpan, `Could not find "when" keyword in expression`));
20607
+ return null;
20608
+ }
20609
+ const start = getTriggerParametersStart(expression, whenIndex + 1);
20610
+ const parsed = bindingParser.parseBinding(expression.slice(start), false, sourceSpan, sourceSpan.start.offset + start);
20611
+ return new BoundDeferredTrigger(parsed, sourceSpan);
20612
+ }
20613
+ /** Parses an `on` trigger */
20614
+ function parseOnTrigger({ expression, sourceSpan }, errors) {
20615
+ const onIndex = expression.indexOf('on');
20616
+ // This is here just to be safe, we shouldn't enter this function
20617
+ // in the first place if a block doesn't have the "on" keyword.
20618
+ if (onIndex === -1) {
20619
+ errors.push(new ParseError(sourceSpan, `Could not find "on" keyword in expression`));
20620
+ return [];
20621
+ }
20622
+ const start = getTriggerParametersStart(expression, onIndex + 1);
20623
+ return new OnTriggerParser(expression, start, sourceSpan, errors).parse();
20624
+ }
20625
+ class OnTriggerParser {
20626
+ constructor(expression, start, span, errors) {
20627
+ this.expression = expression;
20628
+ this.start = start;
20629
+ this.span = span;
20630
+ this.errors = errors;
20631
+ this.index = 0;
20632
+ this.triggers = [];
20633
+ this.tokens = new Lexer().tokenize(expression.slice(start));
20634
+ }
20635
+ parse() {
20636
+ while (this.tokens.length > 0 && this.index < this.tokens.length) {
20637
+ const token = this.token();
20638
+ if (!token.isIdentifier()) {
20639
+ this.unexpectedToken(token);
20640
+ break;
20641
+ }
20642
+ // An identifier immediately followed by a comma or the end of
20643
+ // the expression cannot have parameters so we can exit early.
20644
+ if (this.isFollowedByOrLast($COMMA)) {
20645
+ this.consumeTrigger(token, []);
20646
+ this.advance();
20647
+ }
20648
+ else if (this.isFollowedByOrLast($LPAREN)) {
20649
+ this.advance(); // Advance to the opening paren.
20650
+ const prevErrors = this.errors.length;
20651
+ const parameters = this.consumeParameters();
20652
+ if (this.errors.length !== prevErrors) {
20653
+ break;
20654
+ }
20655
+ this.consumeTrigger(token, parameters);
20656
+ this.advance(); // Advance past the closing paren.
20657
+ }
20658
+ else if (this.index < this.tokens.length - 1) {
20659
+ this.unexpectedToken(this.tokens[this.index + 1]);
20660
+ }
20661
+ this.advance();
20662
+ }
20663
+ return this.triggers;
20664
+ }
20665
+ advance() {
20666
+ this.index++;
20667
+ }
20668
+ isFollowedByOrLast(char) {
20669
+ if (this.index === this.tokens.length - 1) {
20670
+ return true;
20671
+ }
20672
+ return this.tokens[this.index + 1].isCharacter(char);
20673
+ }
20674
+ token() {
20675
+ return this.tokens[Math.min(this.index, this.tokens.length - 1)];
20676
+ }
20677
+ consumeTrigger(identifier, parameters) {
20678
+ const startSpan = this.span.start.moveBy(this.start + identifier.index - this.tokens[0].index);
20679
+ const endSpan = startSpan.moveBy(this.token().end - identifier.index);
20680
+ const sourceSpan = new ParseSourceSpan(startSpan, endSpan);
20681
+ try {
20682
+ switch (identifier.toString()) {
20683
+ case OnTriggerType.IDLE:
20684
+ this.triggers.push(createIdleTrigger(parameters, sourceSpan));
20685
+ break;
20686
+ case OnTriggerType.TIMER:
20687
+ this.triggers.push(createTimerTrigger(parameters, sourceSpan));
20688
+ break;
20689
+ case OnTriggerType.INTERACTION:
20690
+ this.triggers.push(createInteractionTrigger(parameters, sourceSpan));
20691
+ break;
20692
+ case OnTriggerType.IMMEDIATE:
20693
+ this.triggers.push(createImmediateTrigger(parameters, sourceSpan));
20694
+ break;
20695
+ case OnTriggerType.HOVER:
20696
+ this.triggers.push(createHoverTrigger(parameters, sourceSpan));
20697
+ break;
20698
+ case OnTriggerType.VIEWPORT:
20699
+ this.triggers.push(createViewportTrigger(parameters, sourceSpan));
20700
+ break;
20701
+ default:
20702
+ throw new Error(`Unrecognized trigger type "${identifier}"`);
20703
+ }
20704
+ }
20705
+ catch (e) {
20706
+ this.error(identifier, e.message);
20707
+ }
20708
+ }
20709
+ consumeParameters() {
20710
+ const parameters = [];
20711
+ if (!this.token().isCharacter($LPAREN)) {
20712
+ this.unexpectedToken(this.token());
20713
+ return parameters;
20714
+ }
20715
+ this.advance();
20716
+ const commaDelimStack = [];
20717
+ let current = '';
20718
+ while (this.index < this.tokens.length) {
20719
+ const token = this.token();
20720
+ // Stop parsing if we've hit the end character and we're outside of a comma-delimited syntax.
20721
+ // Note that we don't need to account for strings here since the lexer already parsed them
20722
+ // into string tokens.
20723
+ if (token.isCharacter($RPAREN) && commaDelimStack.length === 0) {
20724
+ if (current.length) {
20725
+ parameters.push(current);
20726
+ }
20727
+ break;
20728
+ }
20729
+ // In the `on` microsyntax "top-level" commas (e.g. ones outside of an parameters) separate
20730
+ // the different triggers (e.g. `on idle,timer(500)`). This is problematic, because the
20731
+ // function-like syntax also implies that multiple parameters can be passed into the
20732
+ // individual trigger (e.g. `on foo(a, b)`). To avoid tripping up the parser with commas that
20733
+ // are part of other sorts of syntax (object literals, arrays), we treat anything inside
20734
+ // a comma-delimited syntax block as plain text.
20735
+ if (token.type === TokenType.Character && COMMA_DELIMITED_SYNTAX.has(token.numValue)) {
20736
+ commaDelimStack.push(COMMA_DELIMITED_SYNTAX.get(token.numValue));
20737
+ }
20738
+ if (commaDelimStack.length > 0 &&
20739
+ token.isCharacter(commaDelimStack[commaDelimStack.length - 1])) {
20740
+ commaDelimStack.pop();
20741
+ }
20742
+ // If we hit a comma outside of a comma-delimited syntax, it means
20743
+ // that we're at the top level and we're starting a new parameter.
20744
+ if (commaDelimStack.length === 0 && token.isCharacter($COMMA) && current.length > 0) {
20745
+ parameters.push(current);
20746
+ current = '';
20747
+ this.advance();
20748
+ continue;
20749
+ }
20750
+ // Otherwise treat the token as a plain text character in the current parameter.
20751
+ current += this.tokenText();
20752
+ this.advance();
20753
+ }
20754
+ if (!this.token().isCharacter($RPAREN) || commaDelimStack.length > 0) {
20755
+ this.error(this.token(), 'Unexpected end of expression');
20756
+ }
20757
+ if (this.index < this.tokens.length - 1 &&
20758
+ !this.tokens[this.index + 1].isCharacter($COMMA)) {
20759
+ this.unexpectedToken(this.tokens[this.index + 1]);
20760
+ }
20761
+ return parameters;
20762
+ }
20763
+ tokenText() {
20764
+ // Tokens have a toString already which we could use, but for string tokens it omits the quotes.
20765
+ // Eventually we could expose this information on the token directly.
20766
+ return this.expression.slice(this.start + this.token().index, this.start + this.token().end);
20767
+ }
20768
+ error(token, message) {
20769
+ const newStart = this.span.start.moveBy(this.start + token.index);
20770
+ const newEnd = newStart.moveBy(token.end - token.index);
20771
+ this.errors.push(new ParseError(new ParseSourceSpan(newStart, newEnd), message));
20772
+ }
20773
+ unexpectedToken(token) {
20774
+ this.error(token, `Unexpected token "${token}"`);
20775
+ }
20776
+ }
20777
+ function createIdleTrigger(parameters, sourceSpan) {
20778
+ if (parameters.length > 0) {
20779
+ throw new Error(`"${OnTriggerType.IDLE}" trigger cannot have parameters`);
20780
+ }
20781
+ return new IdleDeferredTrigger(sourceSpan);
20782
+ }
20783
+ function createTimerTrigger(parameters, sourceSpan) {
20784
+ if (parameters.length !== 1) {
20785
+ throw new Error(`"${OnTriggerType.TIMER}" trigger must have exactly one parameter`);
20786
+ }
20787
+ const delay = parseDeferredTime(parameters[0]);
20788
+ if (delay === null) {
20789
+ throw new Error(`Could not parse time value of trigger "${OnTriggerType.TIMER}"`);
20790
+ }
20791
+ return new TimerDeferredTrigger(delay, sourceSpan);
20792
+ }
20793
+ function createInteractionTrigger(parameters, sourceSpan) {
20794
+ if (parameters.length > 1) {
20795
+ throw new Error(`"${OnTriggerType.INTERACTION}" trigger can only have zero or one parameters`);
20796
+ }
20797
+ return new InteractionDeferredTrigger(parameters[0] ?? null, sourceSpan);
20798
+ }
20799
+ function createImmediateTrigger(parameters, sourceSpan) {
20800
+ if (parameters.length > 0) {
20801
+ throw new Error(`"${OnTriggerType.IMMEDIATE}" trigger cannot have parameters`);
20802
+ }
20803
+ return new ImmediateDeferredTrigger(sourceSpan);
20804
+ }
20805
+ function createHoverTrigger(parameters, sourceSpan) {
20806
+ if (parameters.length > 0) {
20807
+ throw new Error(`"${OnTriggerType.HOVER}" trigger cannot have parameters`);
20808
+ }
20809
+ return new HoverDeferredTrigger(sourceSpan);
20810
+ }
20811
+ function createViewportTrigger(parameters, sourceSpan) {
20812
+ // TODO: the RFC has some more potential parameters for `viewport`.
20813
+ if (parameters.length > 1) {
20814
+ throw new Error(`"${OnTriggerType.VIEWPORT}" trigger can only have zero or one parameters`);
20815
+ }
20816
+ return new ViewportDeferredTrigger(parameters[0] ?? null, sourceSpan);
20817
+ }
20818
+ /** Gets the index within an expression at which the trigger parameters start. */
20819
+ function getTriggerParametersStart(value, startPosition = 0) {
20820
+ let hasFoundSeparator = false;
20821
+ for (let i = startPosition; i < value.length; i++) {
20822
+ if (SEPARATOR_PATTERN.test(value[i])) {
20823
+ hasFoundSeparator = true;
20824
+ }
20825
+ else if (hasFoundSeparator) {
20826
+ return i;
20827
+ }
20828
+ }
20829
+ return -1;
20830
+ }
20831
+ /**
20832
+ * Parses a time expression from a deferred trigger to
20833
+ * milliseconds. Returns null if it cannot be parsed.
20834
+ */
20835
+ function parseDeferredTime(value) {
20836
+ const match = value.match(TIME_PATTERN);
20837
+ if (!match) {
20838
+ return null;
20839
+ }
20840
+ const [time, units] = match;
20841
+ return parseInt(time) * (units === 's' ? 1000 : 1);
20842
+ }
20843
+
20844
+ /** Pattern to identify a `prefetch when` trigger. */
20845
+ const PREFETCH_WHEN_PATTERN = /^prefetch\s+when\s/;
20846
+ /** Pattern to identify a `prefetch on` trigger. */
20847
+ const PREFETCH_ON_PATTERN = /^prefetch\s+on\s/;
20848
+ /** Pattern to identify a `minimum` parameter in a block. */
20849
+ const MINIMUM_PARAMETER_PATTERN = /^minimum\s/;
20850
+ /** Pattern to identify a `after` parameter in a block. */
20851
+ const AFTER_PARAMETER_PATTERN = /^after\s/;
20852
+ /** Pattern to identify a `when` parameter in a block. */
20853
+ const WHEN_PARAMETER_PATTERN = /^when\s/;
20854
+ /** Pattern to identify a `on` parameter in a block. */
20855
+ const ON_PARAMETER_PATTERN = /^on\s/;
20856
+ /** Possible types of secondary deferred blocks. */
20857
+ var SecondaryDeferredBlockType;
20858
+ (function (SecondaryDeferredBlockType) {
20859
+ SecondaryDeferredBlockType["PLACEHOLDER"] = "placeholder";
20860
+ SecondaryDeferredBlockType["LOADING"] = "loading";
20861
+ SecondaryDeferredBlockType["ERROR"] = "error";
20862
+ })(SecondaryDeferredBlockType || (SecondaryDeferredBlockType = {}));
20863
+ /** Creates a deferred block from an HTML AST node. */
20864
+ function createDeferredBlock(ast, visitor, bindingParser) {
20865
+ const errors = [];
20866
+ const [primaryBlock, ...secondaryBlocks] = ast.blocks;
20867
+ const { triggers, prefetchTriggers } = parsePrimaryTriggers(primaryBlock.parameters, bindingParser, errors);
20868
+ const { placeholder, loading, error } = parseSecondaryBlocks(secondaryBlocks, errors, visitor);
20869
+ return {
20870
+ node: new DeferredBlock(visitAll(visitor, primaryBlock.children), triggers, prefetchTriggers, placeholder, loading, error, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
20871
+ errors,
20872
+ };
20873
+ }
20874
+ function parseSecondaryBlocks(blocks, errors, visitor) {
20875
+ let placeholder = null;
20876
+ let loading = null;
20877
+ let error = null;
20878
+ for (const block of blocks) {
20879
+ try {
20880
+ switch (block.name) {
20881
+ case SecondaryDeferredBlockType.PLACEHOLDER:
20882
+ if (placeholder !== null) {
20883
+ errors.push(new ParseError(block.startSourceSpan, `"defer" block can only have one "${SecondaryDeferredBlockType.PLACEHOLDER}" block`));
20884
+ }
20885
+ else {
20886
+ placeholder = parsePlaceholderBlock(block, visitor);
20887
+ }
20888
+ break;
20889
+ case SecondaryDeferredBlockType.LOADING:
20890
+ if (loading !== null) {
20891
+ errors.push(new ParseError(block.startSourceSpan, `"defer" block can only have one "${SecondaryDeferredBlockType.LOADING}" block`));
20892
+ }
20893
+ else {
20894
+ loading = parseLoadingBlock(block, visitor);
20895
+ }
20896
+ break;
20897
+ case SecondaryDeferredBlockType.ERROR:
20898
+ if (error !== null) {
20899
+ errors.push(new ParseError(block.startSourceSpan, `"defer" block can only have one "${SecondaryDeferredBlockType.ERROR}" block`));
20900
+ }
20901
+ else {
20902
+ error = parseErrorBlock(block, visitor);
20903
+ }
20904
+ break;
20905
+ default:
20906
+ errors.push(new ParseError(block.startSourceSpan, `Unrecognized block "${block.name}"`));
20907
+ break;
20908
+ }
20909
+ }
20910
+ catch (e) {
20911
+ errors.push(new ParseError(block.startSourceSpan, e.message));
20912
+ }
20913
+ }
20914
+ return { placeholder, loading, error };
20915
+ }
20916
+ function parsePlaceholderBlock(ast, visitor) {
20917
+ let minimumTime = null;
20918
+ for (const param of ast.parameters) {
20919
+ if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
20920
+ const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
20921
+ if (parsedTime === null) {
20922
+ throw new Error(`Could not parse time value of parameter "minimum"`);
20923
+ }
20924
+ minimumTime = parsedTime;
20925
+ }
20926
+ else {
20927
+ throw new Error(`Unrecognized parameter in "${SecondaryDeferredBlockType.PLACEHOLDER}" block: "${param.expression}"`);
20928
+ }
20929
+ }
20930
+ return new DeferredBlockPlaceholder(visitAll(visitor, ast.children), minimumTime, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
20931
+ }
20932
+ function parseLoadingBlock(ast, visitor) {
20933
+ let afterTime = null;
20934
+ let minimumTime = null;
20935
+ for (const param of ast.parameters) {
20936
+ if (AFTER_PARAMETER_PATTERN.test(param.expression)) {
20937
+ const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
20938
+ if (parsedTime === null) {
20939
+ throw new Error(`Could not parse time value of parameter "after"`);
20940
+ }
20941
+ afterTime = parsedTime;
20942
+ }
20943
+ else if (MINIMUM_PARAMETER_PATTERN.test(param.expression)) {
20944
+ const parsedTime = parseDeferredTime(param.expression.slice(getTriggerParametersStart(param.expression)));
20945
+ if (parsedTime === null) {
20946
+ throw new Error(`Could not parse time value of parameter "minimum"`);
20947
+ }
20948
+ minimumTime = parsedTime;
20949
+ }
20950
+ else {
20951
+ throw new Error(`Unrecognized parameter in "${SecondaryDeferredBlockType.LOADING}" block: "${param.expression}"`);
20952
+ }
20953
+ }
20954
+ return new DeferredBlockLoading(visitAll(visitor, ast.children), afterTime, minimumTime, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
20955
+ }
20956
+ function parseErrorBlock(ast, visitor) {
20957
+ if (ast.parameters.length > 0) {
20958
+ throw new Error(`"${SecondaryDeferredBlockType.ERROR}" block cannot have parameters`);
20959
+ }
20960
+ return new DeferredBlockError(visitAll(visitor, ast.children), ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
20961
+ }
20962
+ function parsePrimaryTriggers(params, bindingParser, errors) {
20963
+ const triggers = [];
20964
+ const prefetchTriggers = [];
20965
+ for (const param of params) {
20966
+ // The lexer ignores the leading spaces so we can assume
20967
+ // that the expression starts with a keyword.
20968
+ if (WHEN_PARAMETER_PATTERN.test(param.expression)) {
20969
+ const result = parseWhenTrigger(param, bindingParser, errors);
20970
+ result !== null && triggers.push(result);
20971
+ }
20972
+ else if (ON_PARAMETER_PATTERN.test(param.expression)) {
20973
+ triggers.push(...parseOnTrigger(param, errors));
20974
+ }
20975
+ else if (PREFETCH_WHEN_PATTERN.test(param.expression)) {
20976
+ const result = parseWhenTrigger(param, bindingParser, errors);
20977
+ result !== null && prefetchTriggers.push(result);
20978
+ }
20979
+ else if (PREFETCH_ON_PATTERN.test(param.expression)) {
20980
+ prefetchTriggers.push(...parseOnTrigger(param, errors));
20981
+ }
20982
+ else {
20983
+ errors.push(new ParseError(param.sourceSpan, 'Unrecognized trigger'));
20984
+ }
20985
+ }
20986
+ return { triggers, prefetchTriggers };
20987
+ }
20988
+
20210
20989
  const BIND_NAME_REGEXP = /^(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*)$/;
20211
20990
  // Group 1 = "bind-"
20212
20991
  const KW_BIND_IDX = 1;
@@ -20330,7 +21109,16 @@ class HtmlAstToIvyAst {
20330
21109
  attributes.push(this.visitAttribute(attribute));
20331
21110
  }
20332
21111
  }
20333
- const children = visitAll(preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children);
21112
+ let children;
21113
+ if (preparsedElement.nonBindable) {
21114
+ // The `NonBindableVisitor` may need to return an array of nodes for block groups so we need
21115
+ // to flatten the array here. Avoid doing this for the `HtmlAstToIvyAst` since `flat` creates
21116
+ // a new array.
21117
+ children = visitAll(NON_BINDABLE_VISITOR, element.children).flat(Infinity);
21118
+ }
21119
+ else {
21120
+ children = visitAll(this, element.children);
21121
+ }
20334
21122
  let parsedElement;
20335
21123
  if (preparsedElement.type === PreparsedElementType.NG_CONTENT) {
20336
21124
  // `<ng-content>`
@@ -20429,14 +21217,22 @@ class HtmlAstToIvyAst {
20429
21217
  return null;
20430
21218
  }
20431
21219
  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');
21220
+ const primaryBlock = group.blocks[0];
21221
+ // The HTML parser ensures that we don't hit this case, but we have an assertion just in case.
21222
+ if (!primaryBlock) {
21223
+ this.reportError('Block group must have at least one block.', group.sourceSpan);
21224
+ return null;
21225
+ }
21226
+ if (primaryBlock.name === 'defer' && this.options.enabledBlockTypes.has(primaryBlock.name)) {
21227
+ const { node, errors } = createDeferredBlock(group, this, this.bindingParser);
21228
+ this.errors.push(...errors);
21229
+ return node;
21230
+ }
21231
+ this.reportError(`Unrecognized block "${primaryBlock.name}".`, primaryBlock.sourceSpan);
21232
+ return null;
20439
21233
  }
21234
+ visitBlock(block, context) { }
21235
+ visitBlockParameter(parameter, context) { }
20440
21236
  // convert view engine `ParsedProperty` to a format suitable for IVY
20441
21237
  extractAttributes(elementName, properties, i18nPropsMeta) {
20442
21238
  const bound = [];
@@ -20615,13 +21411,23 @@ class NonBindableVisitor {
20615
21411
  return null;
20616
21412
  }
20617
21413
  visitBlockGroup(group, context) {
20618
- throw new Error('TODO');
21414
+ const nodes = visitAll(this, group.blocks);
21415
+ // We only need to do the end tag since the start will be added as a part of the primary block.
21416
+ if (group.endSourceSpan !== null) {
21417
+ nodes.push(new Text$3(group.endSourceSpan.toString(), group.endSourceSpan));
21418
+ }
21419
+ return nodes;
20619
21420
  }
20620
21421
  visitBlock(block, context) {
20621
- throw new Error('TODO');
21422
+ return [
21423
+ // In an ngNonBindable context we treat the opening/closing tags of block as plain text.
21424
+ // This is the as if the `tokenizeBlocks` option was disabled.
21425
+ new Text$3(block.startSourceSpan.toString(), block.startSourceSpan),
21426
+ ...visitAll(this, block.children)
21427
+ ];
20622
21428
  }
20623
21429
  visitBlockParameter(parameter, context) {
20624
- throw new Error('TODO');
21430
+ return null;
20625
21431
  }
20626
21432
  }
20627
21433
  const NON_BINDABLE_VISITOR = new NonBindableVisitor();
@@ -22469,6 +23275,12 @@ class TemplateDefinitionBuilder {
22469
23275
  }
22470
23276
  return null;
22471
23277
  }
23278
+ // TODO: implement deferred block instructions.
23279
+ visitDeferredBlock(deferred) { }
23280
+ visitDeferredTrigger(trigger) { }
23281
+ visitDeferredBlockPlaceholder(block) { }
23282
+ visitDeferredBlockError(block) { }
23283
+ visitDeferredBlockLoading(block) { }
22472
23284
  allocateDataSlot() {
22473
23285
  return this._dataIndex++;
22474
23286
  }
@@ -23205,7 +24017,12 @@ function parseTemplate(template, templateUrl, options = {}) {
23205
24017
  const { interpolationConfig, preserveWhitespaces, enableI18nLegacyMessageIdFormat } = options;
23206
24018
  const bindingParser = makeBindingParser(interpolationConfig);
23207
24019
  const htmlParser = new HtmlParser();
23208
- const parseResult = htmlParser.parse(template, templateUrl, { leadingTriviaChars: LEADING_TRIVIA_CHARS, ...options, tokenizeExpansionForms: true });
24020
+ const parseResult = htmlParser.parse(template, templateUrl, {
24021
+ leadingTriviaChars: LEADING_TRIVIA_CHARS,
24022
+ ...options,
24023
+ tokenizeExpansionForms: true,
24024
+ tokenizeBlocks: options.enabledBlockTypes != null && options.enabledBlockTypes.size > 0,
24025
+ });
23209
24026
  if (!options.alwaysAttemptHtmlToR3AstConversion && parseResult.errors &&
23210
24027
  parseResult.errors.length > 0) {
23211
24028
  const parsedTemplate = {
@@ -23256,7 +24073,10 @@ function parseTemplate(template, templateUrl, options = {}) {
23256
24073
  rootNodes = visitAll(new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), rootNodes);
23257
24074
  }
23258
24075
  }
23259
- const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, { collectCommentNodes: !!options.collectCommentNodes });
24076
+ const { nodes, errors, styleUrls, styles, ngContentSelectors, commentNodes } = htmlAstToRender3Ast(rootNodes, bindingParser, {
24077
+ collectCommentNodes: !!options.collectCommentNodes,
24078
+ enabledBlockTypes: options.enabledBlockTypes || new Set(),
24079
+ });
23260
24080
  errors.push(...parseResult.errors, ...i18nMetaResult.errors);
23261
24081
  const parsedTemplate = {
23262
24082
  interpolationConfig,
@@ -24533,7 +25353,11 @@ function convertPipeDeclarationToMetadata(pipe) {
24533
25353
  function parseJitTemplate(template, typeName, sourceMapUrl, preserveWhitespaces, interpolation) {
24534
25354
  const interpolationConfig = interpolation ? InterpolationConfig.fromArray(interpolation) : DEFAULT_INTERPOLATION_CONFIG;
24535
25355
  // Parse the template and check for errors.
24536
- const parsed = parseTemplate(template, sourceMapUrl, { preserveWhitespaces, interpolationConfig });
25356
+ const parsed = parseTemplate(template, sourceMapUrl, {
25357
+ preserveWhitespaces,
25358
+ interpolationConfig,
25359
+ enabledBlockTypes: new Set(), // TODO: enable deferred blocks when testing in JIT mode.
25360
+ });
24537
25361
  if (parsed.errors !== null) {
24538
25362
  const errors = parsed.errors.map(err => err.toString()).join(', ');
24539
25363
  throw new Error(`Errors during JIT compilation of template for ${typeName}: ${errors}`);
@@ -24722,7 +25546,7 @@ function publishFacade(global) {
24722
25546
  * @description
24723
25547
  * Entry point for all public APIs of the compiler package.
24724
25548
  */
24725
- const VERSION = new Version('16.2.0-next.2');
25549
+ const VERSION = new Version('16.2.0-next.4');
24726
25550
 
24727
25551
  class CompilerConfig {
24728
25552
  constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
@@ -26267,6 +27091,21 @@ class Scope {
26267
27091
  // Declare the variable if it's not already.
26268
27092
  this.maybeDeclare(reference);
26269
27093
  }
27094
+ visitDeferredBlock(deferred) {
27095
+ deferred.children.forEach(node => node.visit(this));
27096
+ deferred.placeholder?.visit(this);
27097
+ deferred.loading?.visit(this);
27098
+ deferred.error?.visit(this);
27099
+ }
27100
+ visitDeferredBlockPlaceholder(block) {
27101
+ block.children.forEach(node => node.visit(this));
27102
+ }
27103
+ visitDeferredBlockError(block) {
27104
+ block.children.forEach(node => node.visit(this));
27105
+ }
27106
+ visitDeferredBlockLoading(block) {
27107
+ block.children.forEach(node => node.visit(this));
27108
+ }
26270
27109
  // Unused visitors.
26271
27110
  visitContent(content) { }
26272
27111
  visitBoundAttribute(attr) { }
@@ -26275,6 +27114,7 @@ class Scope {
26275
27114
  visitText(text) { }
26276
27115
  visitTextAttribute(attr) { }
26277
27116
  visitIcu(icu) { }
27117
+ visitDeferredTrigger(trigger) { }
26278
27118
  maybeDeclare(thing) {
26279
27119
  // Declare something with a name, as long as that name isn't taken.
26280
27120
  if (!this.namedEntities.has(thing.name)) {
@@ -26412,6 +27252,21 @@ class DirectiveBinder {
26412
27252
  // Recurse into the node's children.
26413
27253
  node.children.forEach(child => child.visit(this));
26414
27254
  }
27255
+ visitDeferredBlock(deferred) {
27256
+ deferred.children.forEach(child => child.visit(this));
27257
+ deferred.placeholder?.visit(this);
27258
+ deferred.loading?.visit(this);
27259
+ deferred.error?.visit(this);
27260
+ }
27261
+ visitDeferredBlockPlaceholder(block) {
27262
+ block.children.forEach(child => child.visit(this));
27263
+ }
27264
+ visitDeferredBlockError(block) {
27265
+ block.children.forEach(child => child.visit(this));
27266
+ }
27267
+ visitDeferredBlockLoading(block) {
27268
+ block.children.forEach(child => child.visit(this));
27269
+ }
26415
27270
  // Unused visitors.
26416
27271
  visitContent(content) { }
26417
27272
  visitVariable(variable) { }
@@ -26423,6 +27278,7 @@ class DirectiveBinder {
26423
27278
  visitText(text) { }
26424
27279
  visitBoundText(text) { }
26425
27280
  visitIcu(icu) { }
27281
+ visitDeferredTrigger(trigger) { }
26426
27282
  }
26427
27283
  /**
26428
27284
  * Processes a template and extract metadata about expressions and symbols within.
@@ -26460,7 +27316,7 @@ class TemplateBinder extends RecursiveAstVisitor {
26460
27316
  /**
26461
27317
  * Process a template and extract metadata about expressions and symbols within.
26462
27318
  *
26463
- * @param template the nodes of the template to process
27319
+ * @param nodes the nodes of the template to process
26464
27320
  * @param scope the `Scope` of the template being processed.
26465
27321
  * @returns three maps which contain metadata about the template: `expressions` which interprets
26466
27322
  * special `AST` nodes in expressions as pointing to references or variables declared within the
@@ -26469,14 +27325,15 @@ class TemplateBinder extends RecursiveAstVisitor {
26469
27325
  * nesting level (how many levels deep within the template structure the `Template` is), starting
26470
27326
  * at 1.
26471
27327
  */
26472
- static applyWithScope(template, scope) {
27328
+ static applyWithScope(nodes, scope) {
26473
27329
  const expressions = new Map();
26474
27330
  const symbols = new Map();
26475
27331
  const nestingLevel = new Map();
26476
27332
  const usedPipes = new Set();
27333
+ const template = nodes instanceof Template ? nodes : null;
26477
27334
  // 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);
27335
+ const binder = new TemplateBinder(expressions, symbols, usedPipes, nestingLevel, scope, template, 0);
27336
+ binder.ingest(nodes);
26480
27337
  return { expressions, symbols, nestingLevel, usedPipes };
26481
27338
  }
26482
27339
  ingest(template) {
@@ -26538,6 +27395,28 @@ class TemplateBinder extends RecursiveAstVisitor {
26538
27395
  visitBoundEvent(event) {
26539
27396
  event.handler.visit(this);
26540
27397
  }
27398
+ visitDeferredBlock(deferred) {
27399
+ deferred.triggers.forEach(this.visitNode);
27400
+ deferred.prefetchTriggers.forEach(this.visitNode);
27401
+ deferred.children.forEach(this.visitNode);
27402
+ deferred.placeholder && this.visitNode(deferred.placeholder);
27403
+ deferred.loading && this.visitNode(deferred.loading);
27404
+ deferred.error && this.visitNode(deferred.error);
27405
+ }
27406
+ visitDeferredTrigger(trigger) {
27407
+ if (trigger instanceof BoundDeferredTrigger) {
27408
+ trigger.value.visit(this);
27409
+ }
27410
+ }
27411
+ visitDeferredBlockPlaceholder(block) {
27412
+ block.children.forEach(this.visitNode);
27413
+ }
27414
+ visitDeferredBlockError(block) {
27415
+ block.children.forEach(this.visitNode);
27416
+ }
27417
+ visitDeferredBlockLoading(block) {
27418
+ block.children.forEach(this.visitNode);
27419
+ }
26541
27420
  visitBoundText(text) {
26542
27421
  text.value.visit(this);
26543
27422
  }
@@ -26676,7 +27555,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
26676
27555
  function compileDeclareClassMetadata(metadata) {
26677
27556
  const definitionMap = new DefinitionMap();
26678
27557
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
26679
- definitionMap.set('version', literal('16.2.0-next.2'));
27558
+ definitionMap.set('version', literal('16.2.0-next.4'));
26680
27559
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26681
27560
  definitionMap.set('type', metadata.type);
26682
27561
  definitionMap.set('decorators', metadata.decorators);
@@ -26779,7 +27658,7 @@ function compileDeclareDirectiveFromMetadata(meta) {
26779
27658
  function createDirectiveDefinitionMap(meta) {
26780
27659
  const definitionMap = new DefinitionMap();
26781
27660
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
26782
- definitionMap.set('version', literal('16.2.0-next.2'));
27661
+ definitionMap.set('version', literal('16.2.0-next.4'));
26783
27662
  // e.g. `type: MyDirective`
26784
27663
  definitionMap.set('type', meta.type.value);
26785
27664
  if (meta.isStandalone) {
@@ -27007,7 +27886,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
27007
27886
  function compileDeclareFactoryFunction(meta) {
27008
27887
  const definitionMap = new DefinitionMap();
27009
27888
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
27010
- definitionMap.set('version', literal('16.2.0-next.2'));
27889
+ definitionMap.set('version', literal('16.2.0-next.4'));
27011
27890
  definitionMap.set('ngImport', importExpr(Identifiers.core));
27012
27891
  definitionMap.set('type', meta.type.value);
27013
27892
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -27042,7 +27921,7 @@ function compileDeclareInjectableFromMetadata(meta) {
27042
27921
  function createInjectableDefinitionMap(meta) {
27043
27922
  const definitionMap = new DefinitionMap();
27044
27923
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
27045
- definitionMap.set('version', literal('16.2.0-next.2'));
27924
+ definitionMap.set('version', literal('16.2.0-next.4'));
27046
27925
  definitionMap.set('ngImport', importExpr(Identifiers.core));
27047
27926
  definitionMap.set('type', meta.type.value);
27048
27927
  // Only generate providedIn property if it has a non-null value
@@ -27093,7 +27972,7 @@ function compileDeclareInjectorFromMetadata(meta) {
27093
27972
  function createInjectorDefinitionMap(meta) {
27094
27973
  const definitionMap = new DefinitionMap();
27095
27974
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
27096
- definitionMap.set('version', literal('16.2.0-next.2'));
27975
+ definitionMap.set('version', literal('16.2.0-next.4'));
27097
27976
  definitionMap.set('ngImport', importExpr(Identifiers.core));
27098
27977
  definitionMap.set('type', meta.type.value);
27099
27978
  definitionMap.set('providers', meta.providers);
@@ -27126,7 +28005,7 @@ function createNgModuleDefinitionMap(meta) {
27126
28005
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
27127
28006
  }
27128
28007
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
27129
- definitionMap.set('version', literal('16.2.0-next.2'));
28008
+ definitionMap.set('version', literal('16.2.0-next.4'));
27130
28009
  definitionMap.set('ngImport', importExpr(Identifiers.core));
27131
28010
  definitionMap.set('type', meta.type.value);
27132
28011
  // We only generate the keys in the metadata if the arrays contain values.
@@ -27177,7 +28056,7 @@ function compileDeclarePipeFromMetadata(meta) {
27177
28056
  function createPipeDefinitionMap(meta) {
27178
28057
  const definitionMap = new DefinitionMap();
27179
28058
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
27180
- definitionMap.set('version', literal('16.2.0-next.2'));
28059
+ definitionMap.set('version', literal('16.2.0-next.4'));
27181
28060
  definitionMap.set('ngImport', importExpr(Identifiers.core));
27182
28061
  // e.g. `type: MyPipe`
27183
28062
  definitionMap.set('type', meta.type.value);
@@ -27210,5 +28089,5 @@ publishFacade(_global);
27210
28089
 
27211
28090
  // This file is not used to build this module. It is only used during editing
27212
28091
 
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 };
28092
+ 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
28093
  //# sourceMappingURL=compiler.mjs.map