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

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 (50) hide show
  1. package/esm2022/src/compiler.mjs +2 -2
  2. package/esm2022/src/expression_parser/ast.mjs +1 -1
  3. package/esm2022/src/i18n/extractor_merger.mjs +8 -1
  4. package/esm2022/src/i18n/i18n_parser.mjs +12 -1
  5. package/esm2022/src/i18n/serializers/xliff.mjs +7 -1
  6. package/esm2022/src/i18n/serializers/xliff2.mjs +7 -1
  7. package/esm2022/src/i18n/serializers/xtb.mjs +7 -1
  8. package/esm2022/src/jit_compiler_facade.mjs +3 -2
  9. package/esm2022/src/ml_parser/ast.mjs +46 -1
  10. package/esm2022/src/ml_parser/html_whitespaces.mjs +10 -1
  11. package/esm2022/src/ml_parser/icu_ast_expander.mjs +10 -1
  12. package/esm2022/src/ml_parser/lexer.mjs +93 -4
  13. package/esm2022/src/ml_parser/parser.mjs +129 -32
  14. package/esm2022/src/ml_parser/tokens.mjs +1 -1
  15. package/esm2022/src/ml_parser/xml_parser.mjs +4 -3
  16. package/esm2022/src/output/output_ast.mjs +9 -1
  17. package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
  18. package/esm2022/src/render3/partial/directive.mjs +1 -1
  19. package/esm2022/src/render3/partial/factory.mjs +1 -1
  20. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  21. package/esm2022/src/render3/partial/injector.mjs +1 -1
  22. package/esm2022/src/render3/partial/ng_module.mjs +6 -3
  23. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  24. package/esm2022/src/render3/r3_module_compiler.mjs +69 -27
  25. package/esm2022/src/render3/r3_template_transform.mjs +19 -1
  26. package/esm2022/src/render3/view/i18n/meta.mjs +12 -1
  27. package/esm2022/src/shadow_css.mjs +2 -2
  28. package/esm2022/src/template/pipeline/ir/src/enums.mjs +37 -5
  29. package/esm2022/src/template/pipeline/ir/src/expression.mjs +101 -10
  30. package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +70 -1
  31. package/esm2022/src/template/pipeline/src/emit.mjs +4 -2
  32. package/esm2022/src/template/pipeline/src/ingest.mjs +53 -4
  33. package/esm2022/src/template/pipeline/src/instruction.mjs +128 -13
  34. package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +32 -6
  35. package/esm2022/src/template/pipeline/src/phases/chaining.mjs +3 -1
  36. package/esm2022/src/template/pipeline/src/phases/expand_safe_reads.mjs +102 -10
  37. package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +1 -6
  38. package/esm2022/src/template/pipeline/src/phases/nullish_coalescing.mjs +6 -5
  39. package/esm2022/src/template/pipeline/src/phases/reify.mjs +29 -1
  40. package/esm2022/src/template/pipeline/src/phases/resolve_names.mjs +8 -1
  41. package/esm2022/src/template/pipeline/src/phases/save_restore_view.mjs +32 -19
  42. package/esm2022/src/template/pipeline/src/phases/temporary_variables.mjs +53 -0
  43. package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +11 -1
  44. package/esm2022/src/version.mjs +1 -1
  45. package/fesm2022/compiler.mjs +1091 -156
  46. package/fesm2022/compiler.mjs.map +1 -1
  47. package/fesm2022/testing.mjs +1 -1
  48. package/index.d.ts +113 -15
  49. package/package.json +2 -2
  50. package/testing/index.d.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v16.2.0-next.0
2
+ * @license Angular v16.2.0-next.2
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -1339,6 +1339,10 @@ class InvokeFunctionExpr extends Expression {
1339
1339
  this.args = args;
1340
1340
  this.pure = pure;
1341
1341
  }
1342
+ // An alias for fn, which allows other logic to handle calls and property reads together.
1343
+ get receiver() {
1344
+ return this.fn;
1345
+ }
1342
1346
  isEquivalent(e) {
1343
1347
  return e instanceof InvokeFunctionExpr && this.fn.isEquivalent(e.fn) &&
1344
1348
  areAllEquivalent(this.args, e.args) && this.pure === e.pure;
@@ -1721,6 +1725,10 @@ class ReadPropExpr extends Expression {
1721
1725
  this.receiver = receiver;
1722
1726
  this.name = name;
1723
1727
  }
1728
+ // An alias for name, which allows other logic to handle property reads and keyed reads together.
1729
+ get index() {
1730
+ return this.name;
1731
+ }
1724
1732
  isEquivalent(e) {
1725
1733
  return e instanceof ReadPropExpr && this.receiver.isEquivalent(e.receiver) &&
1726
1734
  this.name === e.name;
@@ -5717,31 +5725,49 @@ var R3SelectorScopeMode;
5717
5725
  */
5718
5726
  R3SelectorScopeMode[R3SelectorScopeMode["Omit"] = 2] = "Omit";
5719
5727
  })(R3SelectorScopeMode || (R3SelectorScopeMode = {}));
5728
+ /**
5729
+ * The type of the NgModule meta data.
5730
+ * - Global: Used for full and partial compilation modes which mainly includes R3References.
5731
+ * - Local: Used for the local compilation mode which mainly includes the raw expressions as appears
5732
+ * in the NgModule decorator.
5733
+ */
5734
+ var R3NgModuleMetadataKind;
5735
+ (function (R3NgModuleMetadataKind) {
5736
+ R3NgModuleMetadataKind[R3NgModuleMetadataKind["Global"] = 0] = "Global";
5737
+ R3NgModuleMetadataKind[R3NgModuleMetadataKind["Local"] = 1] = "Local";
5738
+ })(R3NgModuleMetadataKind || (R3NgModuleMetadataKind = {}));
5720
5739
  /**
5721
5740
  * Construct an `R3NgModuleDef` for the given `R3NgModuleMetadata`.
5722
5741
  */
5723
5742
  function compileNgModule(meta) {
5724
- const { type: moduleType, bootstrap, declarations, imports, exports, schemas, containsForwardDecls, selectorScopeMode, id } = meta;
5725
5743
  const statements = [];
5726
5744
  const definitionMap = new DefinitionMap();
5727
- definitionMap.set('type', moduleType.value);
5728
- if (bootstrap.length > 0) {
5729
- definitionMap.set('bootstrap', refsToArray(bootstrap, containsForwardDecls));
5745
+ definitionMap.set('type', meta.type.value);
5746
+ // Assign bootstrap definition
5747
+ if (meta.kind === R3NgModuleMetadataKind.Global) {
5748
+ if (meta.bootstrap.length > 0) {
5749
+ definitionMap.set('bootstrap', refsToArray(meta.bootstrap, meta.containsForwardDecls));
5750
+ }
5730
5751
  }
5731
- if (selectorScopeMode === R3SelectorScopeMode.Inline) {
5752
+ else {
5753
+ if (meta.bootstrapExpression) {
5754
+ definitionMap.set('bootstrap', meta.bootstrapExpression);
5755
+ }
5756
+ }
5757
+ if (meta.selectorScopeMode === R3SelectorScopeMode.Inline) {
5732
5758
  // If requested to emit scope information inline, pass the `declarations`, `imports` and
5733
5759
  // `exports` to the `ɵɵdefineNgModule()` call directly.
5734
- if (declarations.length > 0) {
5735
- definitionMap.set('declarations', refsToArray(declarations, containsForwardDecls));
5760
+ if (meta.declarations.length > 0) {
5761
+ definitionMap.set('declarations', refsToArray(meta.declarations, meta.containsForwardDecls));
5736
5762
  }
5737
- if (imports.length > 0) {
5738
- definitionMap.set('imports', refsToArray(imports, containsForwardDecls));
5763
+ if (meta.imports.length > 0) {
5764
+ definitionMap.set('imports', refsToArray(meta.imports, meta.containsForwardDecls));
5739
5765
  }
5740
- if (exports.length > 0) {
5741
- definitionMap.set('exports', refsToArray(exports, containsForwardDecls));
5766
+ if (meta.exports.length > 0) {
5767
+ definitionMap.set('exports', refsToArray(meta.exports, meta.containsForwardDecls));
5742
5768
  }
5743
5769
  }
5744
- else if (selectorScopeMode === R3SelectorScopeMode.SideEffect) {
5770
+ else if (meta.selectorScopeMode === R3SelectorScopeMode.SideEffect) {
5745
5771
  // In this mode, scope information is not passed into `ɵɵdefineNgModule` as it
5746
5772
  // would prevent tree-shaking of the declarations, imports and exports references. Instead, it's
5747
5773
  // patched onto the NgModule definition with a `ɵɵsetNgModuleScope` call that's guarded by the
@@ -5754,14 +5780,14 @@ function compileNgModule(meta) {
5754
5780
  else {
5755
5781
  // Selector scope emit was not requested, so skip it.
5756
5782
  }
5757
- if (schemas !== null && schemas.length > 0) {
5758
- definitionMap.set('schemas', literalArr(schemas.map(ref => ref.value)));
5783
+ if (meta.schemas !== null && meta.schemas.length > 0) {
5784
+ definitionMap.set('schemas', literalArr(meta.schemas.map(ref => ref.value)));
5759
5785
  }
5760
- if (id !== null) {
5761
- definitionMap.set('id', id);
5786
+ if (meta.id !== null) {
5787
+ definitionMap.set('id', meta.id);
5762
5788
  // Generate a side-effectful call to register this NgModule by its id, as per the semantics of
5763
5789
  // NgModule ids.
5764
- statements.push(importExpr(Identifiers.registerNgModuleType).callFn([moduleType.value, id]).toStmt());
5790
+ statements.push(importExpr(Identifiers.registerNgModuleType).callFn([meta.type.value, meta.id]).toStmt());
5765
5791
  }
5766
5792
  const expression = importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()], undefined, true);
5767
5793
  const type = createNgModuleType(meta);
@@ -5794,7 +5820,11 @@ function compileNgModuleDeclarationExpression(meta) {
5794
5820
  }
5795
5821
  return importExpr(Identifiers.defineNgModule).callFn([definitionMap.toLiteralMap()]);
5796
5822
  }
5797
- function createNgModuleType({ type: moduleType, declarations, exports, imports, includeImportTypes, publicDeclarationTypes }) {
5823
+ function createNgModuleType(meta) {
5824
+ if (meta.kind === R3NgModuleMetadataKind.Local) {
5825
+ return new ExpressionType(meta.type.value);
5826
+ }
5827
+ const { type: moduleType, declarations, exports, imports, includeImportTypes, publicDeclarationTypes } = meta;
5798
5828
  return new ExpressionType(importExpr(Identifiers.NgModuleDeclaration, [
5799
5829
  new ExpressionType(moduleType.type),
5800
5830
  publicDeclarationTypes === null ? tupleTypeOf(declarations) :
@@ -5810,16 +5840,36 @@ function createNgModuleType({ type: moduleType, declarations, exports, imports,
5810
5840
  * symbols to become tree-shakeable.
5811
5841
  */
5812
5842
  function generateSetNgModuleScopeCall(meta) {
5813
- const { type: moduleType, declarations, imports, exports, containsForwardDecls } = meta;
5814
5843
  const scopeMap = new DefinitionMap();
5815
- if (declarations.length > 0) {
5816
- scopeMap.set('declarations', refsToArray(declarations, containsForwardDecls));
5844
+ if (meta.kind === R3NgModuleMetadataKind.Global) {
5845
+ if (meta.declarations.length > 0) {
5846
+ scopeMap.set('declarations', refsToArray(meta.declarations, meta.containsForwardDecls));
5847
+ }
5817
5848
  }
5818
- if (imports.length > 0) {
5819
- scopeMap.set('imports', refsToArray(imports, containsForwardDecls));
5849
+ else {
5850
+ if (meta.declarationsExpression) {
5851
+ scopeMap.set('declarations', meta.declarationsExpression);
5852
+ }
5853
+ }
5854
+ if (meta.kind === R3NgModuleMetadataKind.Global) {
5855
+ if (meta.imports.length > 0) {
5856
+ scopeMap.set('imports', refsToArray(meta.imports, meta.containsForwardDecls));
5857
+ }
5858
+ }
5859
+ else {
5860
+ if (meta.importsExpression) {
5861
+ scopeMap.set('imports', meta.importsExpression);
5862
+ }
5820
5863
  }
5821
- if (exports.length > 0) {
5822
- scopeMap.set('exports', refsToArray(exports, containsForwardDecls));
5864
+ if (meta.kind === R3NgModuleMetadataKind.Global) {
5865
+ if (meta.exports.length > 0) {
5866
+ scopeMap.set('exports', refsToArray(meta.exports, meta.containsForwardDecls));
5867
+ }
5868
+ }
5869
+ else {
5870
+ if (meta.exportsExpression) {
5871
+ scopeMap.set('exports', meta.exportsExpression);
5872
+ }
5823
5873
  }
5824
5874
  if (Object.keys(scopeMap.values).length === 0) {
5825
5875
  return null;
@@ -5827,7 +5877,7 @@ function generateSetNgModuleScopeCall(meta) {
5827
5877
  // setNgModuleScope(...)
5828
5878
  const fnCall = new InvokeFunctionExpr(
5829
5879
  /* fn */ importExpr(Identifiers.setNgModuleScope),
5830
- /* args */ [moduleType.value, scopeMap.toLiteralMap()]);
5880
+ /* args */ [meta.type.value, scopeMap.toLiteralMap()]);
5831
5881
  // (ngJitMode guard) && setNgModuleScope(...)
5832
5882
  const guardedCall = jitOnlyGuardedExpression(fnCall);
5833
5883
  // function() { (ngJitMode guard) && setNgModuleScope(...); }
@@ -5915,7 +5965,7 @@ class ASTWithName extends AST {
5915
5965
  this.nameSpan = nameSpan;
5916
5966
  }
5917
5967
  }
5918
- class EmptyExpr extends AST {
5968
+ class EmptyExpr$1 extends AST {
5919
5969
  visit(visitor, context = null) {
5920
5970
  // do nothing
5921
5971
  }
@@ -7348,7 +7398,7 @@ class DefaultLocalResolver {
7348
7398
  }
7349
7399
  class BuiltinFunctionCall extends Call {
7350
7400
  constructor(span, sourceSpan, args, converter) {
7351
- super(span, sourceSpan, new EmptyExpr(span, sourceSpan), args, null);
7401
+ super(span, sourceSpan, new EmptyExpr$1(span, sourceSpan), args, null);
7352
7402
  this.converter = converter;
7353
7403
  }
7354
7404
  }
@@ -7946,7 +7996,7 @@ class ShadowCss {
7946
7996
  }
7947
7997
  else if (rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') ||
7948
7998
  rule.selector.startsWith('@document') || rule.selector.startsWith('@layer') ||
7949
- rule.selector.startsWith('@container')) {
7999
+ rule.selector.startsWith('@container') || rule.selector.startsWith('@scope')) {
7950
8000
  content = this._scopeSelectors(rule.content, scopeSelector, hostSelector);
7951
8001
  }
7952
8002
  else if (rule.selector.startsWith('@font-face') || rule.selector.startsWith('@page')) {
@@ -8631,22 +8681,42 @@ var OpKind;
8631
8681
  * An operation to bind an expression to a property of an element.
8632
8682
  */
8633
8683
  OpKind[OpKind["Property"] = 13] = "Property";
8684
+ /**
8685
+ * An operation to bind an expression to a style property of an element.
8686
+ */
8687
+ OpKind[OpKind["StyleProp"] = 14] = "StyleProp";
8688
+ /**
8689
+ * An operation to bind an expression to the styles of an element.
8690
+ */
8691
+ OpKind[OpKind["StyleMap"] = 15] = "StyleMap";
8634
8692
  /**
8635
8693
  * An operation to interpolate text into a property binding.
8636
8694
  */
8637
- OpKind[OpKind["InterpolateProperty"] = 14] = "InterpolateProperty";
8695
+ OpKind[OpKind["InterpolateProperty"] = 16] = "InterpolateProperty";
8696
+ /**
8697
+ * An operation to interpolate text into a style property binding.
8698
+ */
8699
+ OpKind[OpKind["InterpolateStyleProp"] = 17] = "InterpolateStyleProp";
8700
+ /**
8701
+ * An operation to interpolate text into a style mapping.
8702
+ */
8703
+ OpKind[OpKind["InterpolateStyleMap"] = 18] = "InterpolateStyleMap";
8638
8704
  /**
8639
8705
  * An operation to advance the runtime's implicit slot context during the update phase of a view.
8640
8706
  */
8641
- OpKind[OpKind["Advance"] = 15] = "Advance";
8707
+ OpKind[OpKind["Advance"] = 19] = "Advance";
8642
8708
  /**
8643
8709
  * An operation to instantiate a pipe.
8644
8710
  */
8645
- OpKind[OpKind["Pipe"] = 16] = "Pipe";
8711
+ OpKind[OpKind["Pipe"] = 20] = "Pipe";
8646
8712
  /**
8647
8713
  * An operation to associate an attribute with an element.
8648
8714
  */
8649
- OpKind[OpKind["Attribute"] = 17] = "Attribute";
8715
+ OpKind[OpKind["Attribute"] = 21] = "Attribute";
8716
+ /**
8717
+ * An operation to interpolate text into an attribute binding.
8718
+ */
8719
+ OpKind[OpKind["InterpolateAttribute"] = 22] = "InterpolateAttribute";
8650
8720
  })(OpKind || (OpKind = {}));
8651
8721
  /**
8652
8722
  * Distinguishes different kinds of IR expressions.
@@ -8717,6 +8787,18 @@ var ExpressionKind;
8717
8787
  * An intermediate expression that will be expanded from a safe read into an explicit ternary.
8718
8788
  */
8719
8789
  ExpressionKind[ExpressionKind["SafeTernaryExpr"] = 15] = "SafeTernaryExpr";
8790
+ /**
8791
+ * An empty expression that will be stipped before generating the final output.
8792
+ */
8793
+ ExpressionKind[ExpressionKind["EmptyExpr"] = 16] = "EmptyExpr";
8794
+ /*
8795
+ * An assignment to a temporary variable.
8796
+ */
8797
+ ExpressionKind[ExpressionKind["AssignTemporaryExpr"] = 17] = "AssignTemporaryExpr";
8798
+ /**
8799
+ * A reference to a temporary variable.
8800
+ */
8801
+ ExpressionKind[ExpressionKind["ReadTemporaryExpr"] = 18] = "ReadTemporaryExpr";
8720
8802
  })(ExpressionKind || (ExpressionKind = {}));
8721
8803
  /**
8722
8804
  * Distinguishes between different kinds of `SemanticVariable`s.
@@ -9184,7 +9266,13 @@ class SafePropertyReadExpr extends ExpressionBase {
9184
9266
  this.name = name;
9185
9267
  this.kind = ExpressionKind.SafePropertyRead;
9186
9268
  }
9187
- visitExpression(visitor, context) { }
9269
+ // An alias for name, which allows other logic to handle property reads and keyed reads together.
9270
+ get index() {
9271
+ return this.name;
9272
+ }
9273
+ visitExpression(visitor, context) {
9274
+ this.receiver.visitExpression(visitor, context);
9275
+ }
9188
9276
  isEquivalent() {
9189
9277
  return false;
9190
9278
  }
@@ -9205,7 +9293,10 @@ class SafeKeyedReadExpr extends ExpressionBase {
9205
9293
  this.index = index;
9206
9294
  this.kind = ExpressionKind.SafeKeyedRead;
9207
9295
  }
9208
- visitExpression(visitor, context) { }
9296
+ visitExpression(visitor, context) {
9297
+ this.receiver.visitExpression(visitor, context);
9298
+ this.index.visitExpression(visitor, context);
9299
+ }
9209
9300
  isEquivalent() {
9210
9301
  return false;
9211
9302
  }
@@ -9227,7 +9318,12 @@ class SafeInvokeFunctionExpr extends ExpressionBase {
9227
9318
  this.args = args;
9228
9319
  this.kind = ExpressionKind.SafeInvokeFunction;
9229
9320
  }
9230
- visitExpression(visitor, context) { }
9321
+ visitExpression(visitor, context) {
9322
+ this.receiver.visitExpression(visitor, context);
9323
+ for (const a of this.args) {
9324
+ a.visitExpression(visitor, context);
9325
+ }
9326
+ }
9231
9327
  isEquivalent() {
9232
9328
  return false;
9233
9329
  }
@@ -9251,7 +9347,10 @@ class SafeTernaryExpr extends ExpressionBase {
9251
9347
  this.expr = expr;
9252
9348
  this.kind = ExpressionKind.SafeTernaryExpr;
9253
9349
  }
9254
- visitExpression(visitor, context) { }
9350
+ visitExpression(visitor, context) {
9351
+ this.guard.visitExpression(visitor, context);
9352
+ this.expr.visitExpression(visitor, context);
9353
+ }
9255
9354
  isEquivalent() {
9256
9355
  return false;
9257
9356
  }
@@ -9266,6 +9365,70 @@ class SafeTernaryExpr extends ExpressionBase {
9266
9365
  return new SafeTernaryExpr(this.guard.clone(), this.expr.clone());
9267
9366
  }
9268
9367
  }
9368
+ class EmptyExpr extends ExpressionBase {
9369
+ constructor() {
9370
+ super(...arguments);
9371
+ this.kind = ExpressionKind.EmptyExpr;
9372
+ }
9373
+ visitExpression(visitor, context) { }
9374
+ isEquivalent(e) {
9375
+ return e instanceof EmptyExpr;
9376
+ }
9377
+ isConstant() {
9378
+ return true;
9379
+ }
9380
+ clone() {
9381
+ return new EmptyExpr();
9382
+ }
9383
+ transformInternalExpressions() { }
9384
+ }
9385
+ class AssignTemporaryExpr extends ExpressionBase {
9386
+ constructor(expr, xref) {
9387
+ super();
9388
+ this.expr = expr;
9389
+ this.xref = xref;
9390
+ this.kind = ExpressionKind.AssignTemporaryExpr;
9391
+ this.name = null;
9392
+ }
9393
+ visitExpression(visitor, context) {
9394
+ this.expr.visitExpression(visitor, context);
9395
+ }
9396
+ isEquivalent() {
9397
+ return false;
9398
+ }
9399
+ isConstant() {
9400
+ return false;
9401
+ }
9402
+ transformInternalExpressions(transform, flags) {
9403
+ this.expr = transformExpressionsInExpression(this.expr, transform, flags);
9404
+ }
9405
+ clone() {
9406
+ const a = new AssignTemporaryExpr(this.expr, this.xref);
9407
+ a.name = this.name;
9408
+ return a;
9409
+ }
9410
+ }
9411
+ class ReadTemporaryExpr extends ExpressionBase {
9412
+ constructor(xref) {
9413
+ super();
9414
+ this.xref = xref;
9415
+ this.kind = ExpressionKind.ReadTemporaryExpr;
9416
+ this.name = null;
9417
+ }
9418
+ visitExpression(visitor, context) { }
9419
+ isEquivalent() {
9420
+ return this.xref === this.xref;
9421
+ }
9422
+ isConstant() {
9423
+ return false;
9424
+ }
9425
+ transformInternalExpressions(transform, flags) { }
9426
+ clone() {
9427
+ const r = new ReadTemporaryExpr(this.xref);
9428
+ r.name = this.name;
9429
+ return r;
9430
+ }
9431
+ }
9269
9432
  /**
9270
9433
  * Visits all `Expression`s in the AST of `op` with the `visitor` function.
9271
9434
  */
@@ -9289,9 +9452,14 @@ var VisitorContextFlag;
9289
9452
  function transformExpressionsInOp(op, transform, flags) {
9290
9453
  switch (op.kind) {
9291
9454
  case OpKind.Property:
9455
+ case OpKind.StyleProp:
9456
+ case OpKind.StyleMap:
9292
9457
  op.expression = transformExpressionsInExpression(op.expression, transform, flags);
9293
9458
  break;
9294
9459
  case OpKind.InterpolateProperty:
9460
+ case OpKind.InterpolateStyleProp:
9461
+ case OpKind.InterpolateStyleMap:
9462
+ case OpKind.InterpolateText:
9295
9463
  for (let i = 0; i < op.expressions.length; i++) {
9296
9464
  op.expressions[i] = transformExpressionsInExpression(op.expressions[i], transform, flags);
9297
9465
  }
@@ -9301,17 +9469,17 @@ function transformExpressionsInOp(op, transform, flags) {
9301
9469
  break;
9302
9470
  case OpKind.Attribute:
9303
9471
  if (op.value) {
9304
- transformExpressionsInExpression(op.value, transform, flags);
9472
+ op.value = transformExpressionsInExpression(op.value, transform, flags);
9305
9473
  }
9306
9474
  break;
9307
- case OpKind.Variable:
9308
- op.initializer = transformExpressionsInExpression(op.initializer, transform, flags);
9309
- break;
9310
- case OpKind.InterpolateText:
9475
+ case OpKind.InterpolateAttribute:
9311
9476
  for (let i = 0; i < op.expressions.length; i++) {
9312
9477
  op.expressions[i] = transformExpressionsInExpression(op.expressions[i], transform, flags);
9313
9478
  }
9314
9479
  break;
9480
+ case OpKind.Variable:
9481
+ op.initializer = transformExpressionsInExpression(op.initializer, transform, flags);
9482
+ break;
9315
9483
  case OpKind.Listener:
9316
9484
  for (const innerOp of op.handlerOps) {
9317
9485
  transformExpressionsInOp(innerOp, transform, flags | VisitorContextFlag.InChildOperation);
@@ -9409,6 +9577,11 @@ function transformExpressionsInStatement(stmt, transform, flags) {
9409
9577
  else if (stmt instanceof ReturnStatement) {
9410
9578
  stmt.value = transformExpressionsInExpression(stmt.value, transform, flags);
9411
9579
  }
9580
+ else if (stmt instanceof DeclareVarStmt) {
9581
+ if (stmt.value !== undefined) {
9582
+ stmt.value = transformExpressionsInExpression(stmt.value, transform, flags);
9583
+ }
9584
+ }
9412
9585
  else {
9413
9586
  throw new Error(`Unhandled statement kind: ${stmt.constructor.name}`);
9414
9587
  }
@@ -9791,6 +9964,30 @@ function createPropertyOp(xref, bindingKind, name, expression) {
9791
9964
  ...NEW_OP,
9792
9965
  };
9793
9966
  }
9967
+ /** Create a `StylePropOp`. */
9968
+ function createStylePropOp(xref, name, expression, unit) {
9969
+ return {
9970
+ kind: OpKind.StyleProp,
9971
+ target: xref,
9972
+ name,
9973
+ expression,
9974
+ unit,
9975
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
9976
+ ...TRAIT_CONSUMES_VARS,
9977
+ ...NEW_OP,
9978
+ };
9979
+ }
9980
+ /** Create a `StyleMapOp`. */
9981
+ function createStyleMapOp(xref, expression) {
9982
+ return {
9983
+ kind: OpKind.StyleMap,
9984
+ target: xref,
9985
+ expression,
9986
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
9987
+ ...TRAIT_CONSUMES_VARS,
9988
+ ...NEW_OP,
9989
+ };
9990
+ }
9794
9991
  /**
9795
9992
  * Create an `AttributeOp`.
9796
9993
  */
@@ -9801,6 +9998,8 @@ function createAttributeOp(target, attributeKind, name, value) {
9801
9998
  attributeKind,
9802
9999
  name,
9803
10000
  value,
10001
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
10002
+ ...TRAIT_CONSUMES_VARS,
9804
10003
  ...NEW_OP,
9805
10004
  };
9806
10005
  }
@@ -9820,6 +10019,49 @@ function createInterpolatePropertyOp(xref, bindingKind, name, strings, expressio
9820
10019
  ...NEW_OP,
9821
10020
  };
9822
10021
  }
10022
+ function createInterpolateAttributeOp(target, attributeKind, name, strings, expressions) {
10023
+ return {
10024
+ kind: OpKind.InterpolateAttribute,
10025
+ target: target,
10026
+ attributeKind,
10027
+ name,
10028
+ strings,
10029
+ expressions,
10030
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
10031
+ ...TRAIT_CONSUMES_VARS,
10032
+ ...NEW_OP,
10033
+ };
10034
+ }
10035
+ /**
10036
+ * Create a `InterpolateStyleProp`.
10037
+ */
10038
+ function createInterpolateStylePropOp(xref, name, strings, expressions, unit) {
10039
+ return {
10040
+ kind: OpKind.InterpolateStyleProp,
10041
+ target: xref,
10042
+ name,
10043
+ strings,
10044
+ expressions,
10045
+ unit,
10046
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
10047
+ ...TRAIT_CONSUMES_VARS,
10048
+ ...NEW_OP,
10049
+ };
10050
+ }
10051
+ /**
10052
+ * Create a `InterpolateStyleMap`.
10053
+ */
10054
+ function createInterpolateStyleMapOp(xref, strings, expressions) {
10055
+ return {
10056
+ kind: OpKind.InterpolateStyleMap,
10057
+ target: xref,
10058
+ strings,
10059
+ expressions,
10060
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
10061
+ ...TRAIT_CONSUMES_VARS,
10062
+ ...NEW_OP,
10063
+ };
10064
+ }
9823
10065
  /**
9824
10066
  * Create an `AdvanceOp`.
9825
10067
  */
@@ -9877,15 +10119,25 @@ function phaseVarCounting(cpl) {
9877
10119
  function varsUsedByOp(op) {
9878
10120
  switch (op.kind) {
9879
10121
  case OpKind.Property:
10122
+ case OpKind.StyleProp:
10123
+ case OpKind.StyleMap:
9880
10124
  // Property bindings use 1 variable slot.
9881
10125
  return 1;
10126
+ case OpKind.Attribute:
10127
+ // Attribute bindings use 1 variable slot.
10128
+ return 1;
9882
10129
  case OpKind.InterpolateText:
9883
10130
  // `ir.InterpolateTextOp`s use a variable slot for each dynamic expression.
9884
10131
  return op.expressions.length;
9885
10132
  case OpKind.InterpolateProperty:
10133
+ case OpKind.InterpolateStyleProp:
10134
+ case OpKind.InterpolateStyleMap:
9886
10135
  // `ir.InterpolatePropertyOp`s use a variable slot for each dynamic expression, plus one for
9887
10136
  // the result.
9888
10137
  return 1 + op.expressions.length;
10138
+ case OpKind.InterpolateAttribute:
10139
+ // One variable slot for each dynamic expression, plus one for the result.
10140
+ return 1 + op.expressions.length;
9889
10141
  default:
9890
10142
  throw new Error(`Unhandled op: ${OpKind[op.kind]}`);
9891
10143
  }
@@ -9935,6 +10187,15 @@ function phaseAlignPipeVariadicVarOffset(cpl) {
9935
10187
  }
9936
10188
  }
9937
10189
 
10190
+ /**
10191
+ * Find all attribute and binding ops, and collect them into the ElementAttribute structures.
10192
+ * In cases where no instruction needs to be generated for the attribute or binding, it is removed.
10193
+ */
10194
+ function phaseAttributeExtraction(cpl, compatibility) {
10195
+ for (const [_, view] of cpl.views) {
10196
+ populateElementAttributes(view, compatibility);
10197
+ }
10198
+ }
9938
10199
  /**
9939
10200
  * Looks up an element in the given map by xref ID.
9940
10201
  */
@@ -9946,13 +10207,14 @@ function lookupElement(elements, xref) {
9946
10207
  return el;
9947
10208
  }
9948
10209
  /**
9949
- * Find all attribute and binding ops, and collect them into the ElementAttribute structures.
9950
- * In cases where no instruction needs to be generated for the attribute or binding, it is removed.
10210
+ * Removes the op if its expression is empty.
9951
10211
  */
9952
- function phaseAttributeExtraction(cpl, compatibility) {
9953
- for (const [_, view] of cpl.views) {
9954
- populateElementAttributes(view, compatibility);
10212
+ function removeIfExpressionIsEmpty(op, expression) {
10213
+ if (expression instanceof EmptyExpr) {
10214
+ OpList.remove(op);
10215
+ return true;
9955
10216
  }
10217
+ return false;
9956
10218
  }
9957
10219
  /**
9958
10220
  * Populates the ElementAttributes map for the given view, and removes ops for any bindings that do
@@ -9972,6 +10234,8 @@ function populateElementAttributes(view, compatibility) {
9972
10234
  case OpKind.Attribute:
9973
10235
  ownerOp = lookupElement(elements, op.target);
9974
10236
  assertIsElementAttributes(ownerOp.attributes);
10237
+ // The old compiler only extracted string constants, so we emulate that behavior in
10238
+ // compaitiblity mode, otherwise we optimize more aggressively.
9975
10239
  let extractable = compatibility ?
9976
10240
  (op.value instanceof LiteralExpr && typeof op.value.value === 'string') :
9977
10241
  (op.value.isConstant());
@@ -9982,11 +10246,25 @@ function populateElementAttributes(view, compatibility) {
9982
10246
  }
9983
10247
  break;
9984
10248
  case OpKind.Property:
10249
+ ownerOp = lookupElement(elements, op.target);
10250
+ assertIsElementAttributes(ownerOp.attributes);
10251
+ removeIfExpressionIsEmpty(op, op.expression);
10252
+ ownerOp.attributes.add(op.bindingKind, op.name, null);
10253
+ break;
9985
10254
  case OpKind.InterpolateProperty:
9986
10255
  ownerOp = lookupElement(elements, op.target);
9987
10256
  assertIsElementAttributes(ownerOp.attributes);
9988
10257
  ownerOp.attributes.add(op.bindingKind, op.name, null);
9989
10258
  break;
10259
+ case OpKind.StyleProp:
10260
+ ownerOp = lookupElement(elements, op.target);
10261
+ assertIsElementAttributes(ownerOp.attributes);
10262
+ // The old compiler treated empty style bindings as regular bindings for the purpose of
10263
+ // directive matching. That behavior is incorrect, but we emulate it in compatibility mode.
10264
+ if (removeIfExpressionIsEmpty(op, op.expression) && compatibility) {
10265
+ ownerOp.attributes.add(ElementAttributeKind.Binding, op.name, null);
10266
+ }
10267
+ break;
9990
10268
  case OpKind.Listener:
9991
10269
  ownerOp = lookupElement(elements, op.target);
9992
10270
  assertIsElementAttributes(ownerOp.attributes);
@@ -10004,6 +10282,8 @@ const CHAINABLE = new Set([
10004
10282
  Identifiers.elementStart,
10005
10283
  Identifiers.elementEnd,
10006
10284
  Identifiers.property,
10285
+ Identifiers.styleProp,
10286
+ Identifiers.attribute,
10007
10287
  Identifiers.elementContainerStart,
10008
10288
  Identifiers.elementContainerEnd,
10009
10289
  Identifiers.elementContainer,
@@ -10201,10 +10481,11 @@ function phaseNullishCoalescing(cpl) {
10201
10481
  expr.operator !== BinaryOperator.NullishCoalesce) {
10202
10482
  return expr;
10203
10483
  }
10204
- // TODO: We need to unconditionally emit a temporary variable to match
10205
- // TemplateDefinitionBuilder. (We could also emit one conditionally when not in
10206
- // compatibility mode.)
10207
- return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.And, new BinaryOperatorExpr(BinaryOperator.NotIdentical, expr.lhs, NULL_EXPR), new BinaryOperatorExpr(BinaryOperator.NotIdentical, expr.lhs, new LiteralExpr(undefined))), expr.lhs, expr.rhs);
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);
10208
10489
  }, VisitorContextFlag.None);
10209
10490
  }
10210
10491
  }
@@ -10237,11 +10518,6 @@ function phaseGenerateVariables(cpl) {
10237
10518
  function recursivelyProcessView(view, parentScope) {
10238
10519
  // Extract a `Scope` from this view.
10239
10520
  const scope = getScopeForView(view, parentScope);
10240
- // Embedded views require an operation to save/restore the view context.
10241
- if (view.parent !== null) {
10242
- // Start the view creation block with an operation to save the current view context. This may be
10243
- // used to restore the view context in any listeners that may be present.
10244
- }
10245
10521
  for (const op of view.create) {
10246
10522
  switch (op.kind) {
10247
10523
  case OpKind.Template:
@@ -10780,6 +11056,19 @@ function property(name, expression) {
10780
11056
  expression,
10781
11057
  ]);
10782
11058
  }
11059
+ function attribute(name, expression) {
11060
+ return call(Identifiers.attribute, [literal(name), expression]);
11061
+ }
11062
+ function styleProp(name, expression, unit) {
11063
+ const args = [literal(name), expression];
11064
+ if (unit !== null) {
11065
+ args.push(literal(unit));
11066
+ }
11067
+ return call(Identifiers.styleProp, args);
11068
+ }
11069
+ function styleMap(expression) {
11070
+ return call(Identifiers.styleMap, [expression]);
11071
+ }
10783
11072
  const PIPE_BINDINGS = [
10784
11073
  Identifiers.pipeBind1,
10785
11074
  Identifiers.pipeBind2,
@@ -10823,6 +11112,35 @@ function textInterpolate(strings, expressions) {
10823
11112
  return callVariadicInstruction(TEXT_INTERPOLATE_CONFIG, [], interpolationArgs);
10824
11113
  }
10825
11114
  function propertyInterpolate(name, strings, expressions) {
11115
+ const interpolationArgs = collateInterpolationArgs(strings, expressions);
11116
+ return callVariadicInstruction(PROPERTY_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs);
11117
+ }
11118
+ function attributeInterpolate(name, strings, expressions) {
11119
+ const interpolationArgs = collateInterpolationArgs(strings, expressions);
11120
+ return callVariadicInstruction(ATTRIBUTE_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs);
11121
+ }
11122
+ function stylePropInterpolate(name, strings, expressions, unit) {
11123
+ const interpolationArgs = collateInterpolationArgs(strings, expressions);
11124
+ const extraArgs = [];
11125
+ if (unit !== null) {
11126
+ extraArgs.push(literal(unit));
11127
+ }
11128
+ return callVariadicInstruction(STYLE_PROP_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs, extraArgs);
11129
+ }
11130
+ function styleMapInterpolate(strings, expressions) {
11131
+ const interpolationArgs = collateInterpolationArgs(strings, expressions);
11132
+ return callVariadicInstruction(STYLE_MAP_INTERPOLATE_CONFIG, [], interpolationArgs);
11133
+ }
11134
+ function pureFunction(varOffset, fn, args) {
11135
+ return callVariadicInstructionExpr(PURE_FUNCTION_CONFIG, [
11136
+ literal(varOffset),
11137
+ fn,
11138
+ ], args);
11139
+ }
11140
+ /**
11141
+ * Collates the string an expression arguments for an interpolation instruction.
11142
+ */
11143
+ function collateInterpolationArgs(strings, expressions) {
10826
11144
  if (strings.length < 1 || expressions.length !== strings.length - 1) {
10827
11145
  throw new Error(`AssertionError: expected specific shape of args for strings/expressions in interpolation`);
10828
11146
  }
@@ -10838,13 +11156,7 @@ function propertyInterpolate(name, strings, expressions) {
10838
11156
  // idx points at the last string.
10839
11157
  interpolationArgs.push(literal(strings[idx]));
10840
11158
  }
10841
- return callVariadicInstruction(PROPERTY_INTERPOLATE_CONFIG, [literal(name)], interpolationArgs);
10842
- }
10843
- function pureFunction(varOffset, fn, args) {
10844
- return callVariadicInstructionExpr(PURE_FUNCTION_CONFIG, [
10845
- literal(varOffset),
10846
- fn,
10847
- ], args);
11159
+ return interpolationArgs;
10848
11160
  }
10849
11161
  function call(instruction, args) {
10850
11162
  return createStatementOp(importExpr(instruction).callFn(args).toStmt());
@@ -10895,6 +11207,81 @@ const PROPERTY_INTERPOLATE_CONFIG = {
10895
11207
  return (n - 1) / 2;
10896
11208
  },
10897
11209
  };
11210
+ /**
11211
+ * `InterpolationConfig` for the `stylePropInterpolate` instruction.
11212
+ */
11213
+ const STYLE_PROP_INTERPOLATE_CONFIG = {
11214
+ constant: [
11215
+ null,
11216
+ Identifiers.stylePropInterpolate1,
11217
+ Identifiers.stylePropInterpolate2,
11218
+ Identifiers.stylePropInterpolate3,
11219
+ Identifiers.stylePropInterpolate4,
11220
+ Identifiers.stylePropInterpolate5,
11221
+ Identifiers.stylePropInterpolate6,
11222
+ Identifiers.stylePropInterpolate7,
11223
+ Identifiers.stylePropInterpolate8,
11224
+ ],
11225
+ variable: Identifiers.stylePropInterpolateV,
11226
+ mapping: n => {
11227
+ if (n % 2 === 0) {
11228
+ throw new Error(`Expected odd number of arguments`);
11229
+ }
11230
+ if (n < 3) {
11231
+ throw new Error(`Expected at least 3 arguments`);
11232
+ }
11233
+ return (n - 1) / 2;
11234
+ },
11235
+ };
11236
+ /**
11237
+ * `InterpolationConfig` for the `attributeInterpolate` instruction.
11238
+ */
11239
+ const ATTRIBUTE_INTERPOLATE_CONFIG = {
11240
+ constant: [
11241
+ Identifiers.attribute,
11242
+ Identifiers.attributeInterpolate1,
11243
+ Identifiers.attributeInterpolate2,
11244
+ Identifiers.attributeInterpolate3,
11245
+ Identifiers.attributeInterpolate4,
11246
+ Identifiers.attributeInterpolate5,
11247
+ Identifiers.attributeInterpolate6,
11248
+ Identifiers.attributeInterpolate7,
11249
+ Identifiers.attributeInterpolate8,
11250
+ ],
11251
+ variable: Identifiers.attributeInterpolateV,
11252
+ mapping: n => {
11253
+ if (n % 2 === 0) {
11254
+ throw new Error(`Expected odd number of arguments`);
11255
+ }
11256
+ return (n - 1) / 2;
11257
+ },
11258
+ };
11259
+ /**
11260
+ * `InterpolationConfig` for the `styleMapInterpolate` instruction.
11261
+ */
11262
+ const STYLE_MAP_INTERPOLATE_CONFIG = {
11263
+ constant: [
11264
+ null,
11265
+ Identifiers.styleMapInterpolate1,
11266
+ Identifiers.styleMapInterpolate2,
11267
+ Identifiers.styleMapInterpolate3,
11268
+ Identifiers.styleMapInterpolate4,
11269
+ Identifiers.styleMapInterpolate5,
11270
+ Identifiers.styleMapInterpolate6,
11271
+ Identifiers.styleMapInterpolate7,
11272
+ Identifiers.styleMapInterpolate8,
11273
+ ],
11274
+ variable: Identifiers.styleMapInterpolateV,
11275
+ mapping: n => {
11276
+ if (n % 2 === 0) {
11277
+ throw new Error(`Expected odd number of arguments`);
11278
+ }
11279
+ if (n < 3) {
11280
+ throw new Error(`Expected at least 3 arguments`);
11281
+ }
11282
+ return (n - 1) / 2;
11283
+ },
11284
+ };
10898
11285
  const PURE_FUNCTION_CONFIG = {
10899
11286
  constant: [
10900
11287
  Identifiers.pureFunction0,
@@ -10910,22 +11297,26 @@ const PURE_FUNCTION_CONFIG = {
10910
11297
  variable: Identifiers.pureFunctionV,
10911
11298
  mapping: n => n,
10912
11299
  };
10913
- function callVariadicInstructionExpr(config, baseArgs, interpolationArgs) {
11300
+ function callVariadicInstructionExpr(config, baseArgs, interpolationArgs, extraArgs = []) {
10914
11301
  const n = config.mapping(interpolationArgs.length);
10915
11302
  if (n < config.constant.length) {
10916
11303
  // Constant calling pattern.
10917
- return importExpr(config.constant[n]).callFn([...baseArgs, ...interpolationArgs]);
11304
+ return importExpr(config.constant[n]).callFn([
11305
+ ...baseArgs, ...interpolationArgs, ...extraArgs
11306
+ ]);
10918
11307
  }
10919
11308
  else if (config.variable !== null) {
10920
11309
  // Variable calling pattern.
10921
- return importExpr(config.variable).callFn([...baseArgs, literalArr(interpolationArgs)]);
11310
+ return importExpr(config.variable).callFn([
11311
+ ...baseArgs, literalArr(interpolationArgs), ...extraArgs
11312
+ ]);
10922
11313
  }
10923
11314
  else {
10924
11315
  throw new Error(`AssertionError: unable to call variadic function`);
10925
11316
  }
10926
11317
  }
10927
- function callVariadicInstruction(config, baseArgs, interpolationArgs) {
10928
- return createStatementOp(callVariadicInstructionExpr(config, baseArgs, interpolationArgs).toStmt());
11318
+ function callVariadicInstruction(config, baseArgs, interpolationArgs, extraArgs = []) {
11319
+ return createStatementOp(callVariadicInstructionExpr(config, baseArgs, interpolationArgs, extraArgs).toStmt());
10929
11320
  }
10930
11321
 
10931
11322
  /**
@@ -11002,12 +11393,30 @@ function reifyUpdateOperations(_view, ops) {
11002
11393
  case OpKind.Property:
11003
11394
  OpList.replace(op, property(op.name, op.expression));
11004
11395
  break;
11396
+ case OpKind.StyleProp:
11397
+ OpList.replace(op, styleProp(op.name, op.expression, op.unit));
11398
+ break;
11399
+ case OpKind.StyleMap:
11400
+ OpList.replace(op, styleMap(op.expression));
11401
+ break;
11005
11402
  case OpKind.InterpolateProperty:
11006
11403
  OpList.replace(op, propertyInterpolate(op.name, op.strings, op.expressions));
11007
11404
  break;
11405
+ case OpKind.InterpolateStyleProp:
11406
+ OpList.replace(op, stylePropInterpolate(op.name, op.strings, op.expressions, op.unit));
11407
+ break;
11408
+ case OpKind.InterpolateStyleMap:
11409
+ OpList.replace(op, styleMapInterpolate(op.strings, op.expressions));
11410
+ break;
11008
11411
  case OpKind.InterpolateText:
11009
11412
  OpList.replace(op, textInterpolate(op.strings, op.expressions));
11010
11413
  break;
11414
+ case OpKind.Attribute:
11415
+ OpList.replace(op, attribute(op.name, op.value));
11416
+ break;
11417
+ case OpKind.InterpolateAttribute:
11418
+ OpList.replace(op, attributeInterpolate(op.name, op.strings, op.expressions));
11419
+ break;
11011
11420
  case OpKind.Variable:
11012
11421
  if (op.variable.name === null) {
11013
11422
  throw new Error(`AssertionError: unnamed variable ${op.xref}`);
@@ -11047,6 +11456,16 @@ function reifyIrExpression(expr) {
11047
11456
  throw new Error(`Read of unnamed variable ${expr.xref}`);
11048
11457
  }
11049
11458
  return variable(expr.name);
11459
+ case ExpressionKind.ReadTemporaryExpr:
11460
+ if (expr.name === null) {
11461
+ throw new Error(`Read of unnamed temporary ${expr.xref}`);
11462
+ }
11463
+ return variable(expr.name);
11464
+ case ExpressionKind.AssignTemporaryExpr:
11465
+ if (expr.name === null) {
11466
+ throw new Error(`Assign of unnamed temporary ${expr.xref}`);
11467
+ }
11468
+ return variable(expr.name).set(expr.expr);
11050
11469
  case ExpressionKind.PureFunctionExpr:
11051
11470
  if (expr.fn === null) {
11052
11471
  throw new Error(`AssertionError: expected PureFunctions to have been extracted`);
@@ -11234,14 +11653,17 @@ function processLexicalScope(view, ops, savedView) {
11234
11653
  }
11235
11654
  }, VisitorContextFlag.None);
11236
11655
  }
11656
+ for (const op of ops) {
11657
+ visitExpressionsInOp(op, expr => {
11658
+ if (expr instanceof LexicalReadExpr) {
11659
+ throw new Error(`AssertionError: no lexical reads should remain, but found read of ${expr.name}`);
11660
+ }
11661
+ });
11662
+ }
11237
11663
  }
11238
11664
 
11239
11665
  function phaseSaveRestoreView(cpl) {
11240
11666
  for (const view of cpl.views.values()) {
11241
- if (view === cpl.root) {
11242
- // Save/restore operations are not necessary for the root view.
11243
- continue;
11244
- }
11245
11667
  view.create.prepend([
11246
11668
  createVariableOp(view.tpl.allocateXrefId(), {
11247
11669
  kind: SemanticVariableKind.SavedView,
@@ -11253,22 +11675,39 @@ function phaseSaveRestoreView(cpl) {
11253
11675
  if (op.kind !== OpKind.Listener) {
11254
11676
  continue;
11255
11677
  }
11256
- op.handlerOps.prepend([
11257
- createVariableOp(view.tpl.allocateXrefId(), {
11258
- kind: SemanticVariableKind.Context,
11259
- name: null,
11260
- view: view.xref,
11261
- }, new RestoreViewExpr(view.xref)),
11262
- ]);
11263
- // The "restore view" operation in listeners requires a call to `resetView` to reset the
11264
- // context prior to returning from the listener operation. Find any `return` statements in
11265
- // the listener body and wrap them in a call to reset the view.
11266
- for (const handlerOp of op.handlerOps) {
11267
- if (handlerOp.kind === OpKind.Statement &&
11268
- handlerOp.statement instanceof ReturnStatement) {
11269
- handlerOp.statement.value = new ResetViewExpr(handlerOp.statement.value);
11678
+ // Embedded views always need the save/restore view operation.
11679
+ let needsRestoreView = view !== cpl.root;
11680
+ if (!needsRestoreView) {
11681
+ for (const handlerOp of op.handlerOps) {
11682
+ visitExpressionsInOp(handlerOp, expr => {
11683
+ if (expr instanceof ReferenceExpr) {
11684
+ // Listeners that reference() a local ref need the save/restore view operation.
11685
+ needsRestoreView = true;
11686
+ }
11687
+ });
11270
11688
  }
11271
11689
  }
11690
+ if (needsRestoreView) {
11691
+ addSaveRestoreViewOperationToListener(view, op);
11692
+ }
11693
+ }
11694
+ }
11695
+ }
11696
+ function addSaveRestoreViewOperationToListener(view, op) {
11697
+ op.handlerOps.prepend([
11698
+ createVariableOp(view.tpl.allocateXrefId(), {
11699
+ kind: SemanticVariableKind.Context,
11700
+ name: null,
11701
+ view: view.xref,
11702
+ }, new RestoreViewExpr(view.xref)),
11703
+ ]);
11704
+ // The "restore view" operation in listeners requires a call to `resetView` to reset the
11705
+ // context prior to returning from the listener operation. Find any `return` statements in
11706
+ // the listener body and wrap them in a call to reset the view.
11707
+ for (const handlerOp of op.handlerOps) {
11708
+ if (handlerOp.kind === OpKind.Statement &&
11709
+ handlerOp.statement instanceof ReturnStatement) {
11710
+ handlerOp.statement.value = new ResetViewExpr(handlerOp.statement.value);
11272
11711
  }
11273
11712
  }
11274
11713
  }
@@ -11717,19 +12156,107 @@ function allowConservativeInlining(decl, target) {
11717
12156
  * Finds all unresolved safe read expressions, and converts them into the appropriate output AST
11718
12157
  * reads, guarded by null checks.
11719
12158
  */
11720
- function phaseExpandSafeReads(cpl) {
12159
+ function phaseExpandSafeReads(cpl, compatibility) {
11721
12160
  for (const [_, view] of cpl.views) {
11722
12161
  for (const op of view.ops()) {
11723
- transformExpressionsInOp(op, safeTransform, VisitorContextFlag.None);
12162
+ transformExpressionsInOp(op, e => safeTransform(e, { cpl, compatibility }), VisitorContextFlag.None);
11724
12163
  transformExpressionsInOp(op, ternaryTransform, VisitorContextFlag.None);
11725
12164
  }
11726
12165
  }
11727
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
+ }
11728
12254
  function isSafeAccessExpression(e) {
11729
12255
  return e instanceof SafePropertyReadExpr || e instanceof SafeKeyedReadExpr;
11730
12256
  }
11731
12257
  function isUnsafeAccessExpression(e) {
11732
- return e instanceof ReadPropExpr || e instanceof ReadKeyExpr;
12258
+ return e instanceof ReadPropExpr || e instanceof ReadKeyExpr ||
12259
+ e instanceof InvokeFunctionExpr;
11733
12260
  }
11734
12261
  function isAccessExpression(e) {
11735
12262
  return isSafeAccessExpression(e) || isUnsafeAccessExpression(e);
@@ -11745,8 +12272,8 @@ function deepestSafeTernary(e) {
11745
12272
  return null;
11746
12273
  }
11747
12274
  // TODO: When strict compatibility with TemplateDefinitionBuilder is not required, we can use `&&`
11748
- // instead.
11749
- function safeTransform(e) {
12275
+ // instead to save some code size.
12276
+ function safeTransform(e, ctx) {
11750
12277
  if (e instanceof SafeInvokeFunctionExpr) {
11751
12278
  // TODO: Implement safe function calls in a subsequent commit.
11752
12279
  return new InvokeFunctionExpr(e.receiver, e.args);
@@ -11756,6 +12283,10 @@ function safeTransform(e) {
11756
12283
  }
11757
12284
  const dst = deepestSafeTernary(e);
11758
12285
  if (dst) {
12286
+ if (e instanceof InvokeFunctionExpr) {
12287
+ dst.expr = dst.expr.callFn(e.args);
12288
+ return e.receiver;
12289
+ }
11759
12290
  if (e instanceof ReadPropExpr) {
11760
12291
  dst.expr = dst.expr.prop(e.name);
11761
12292
  return e.receiver;
@@ -11765,20 +12296,20 @@ function safeTransform(e) {
11765
12296
  return e.receiver;
11766
12297
  }
11767
12298
  if (e instanceof SafePropertyReadExpr) {
11768
- dst.expr = new SafeTernaryExpr(dst.expr.clone(), dst.expr.prop(e.name));
12299
+ dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.prop(e.name), ctx);
11769
12300
  return e.receiver;
11770
12301
  }
11771
12302
  if (e instanceof SafeKeyedReadExpr) {
11772
- dst.expr = new SafeTernaryExpr(dst.expr.clone(), dst.expr.key(e.index));
12303
+ dst.expr = safeTernaryWithTemporary(dst.expr, (r) => r.key(e.index), ctx);
11773
12304
  return e.receiver;
11774
12305
  }
11775
12306
  }
11776
12307
  else {
11777
12308
  if (e instanceof SafePropertyReadExpr) {
11778
- return new SafeTernaryExpr(e.receiver.clone(), e.receiver.prop(e.name));
12309
+ return safeTernaryWithTemporary(e.receiver, (r) => r.prop(e.name), ctx);
11779
12310
  }
11780
12311
  if (e instanceof SafeKeyedReadExpr) {
11781
- return new SafeTernaryExpr(e.receiver.clone(), e.receiver.key(e.index));
12312
+ return safeTernaryWithTemporary(e.receiver, (r) => r.key(e.index), ctx);
11782
12313
  }
11783
12314
  }
11784
12315
  return e;
@@ -11790,6 +12321,50 @@ function ternaryTransform(e) {
11790
12321
  return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.Equals, e.guard, NULL_EXPR), NULL_EXPR, e.expr);
11791
12322
  }
11792
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
+
11793
12368
  /**
11794
12369
  * Run all transformation phases in the correct order against a `ComponentCompilation`. After this
11795
12370
  * processing, the compilation should be in a state where it can be emitted via `emitTemplateFn`.s
@@ -11806,7 +12381,8 @@ function transformTemplate(cpl) {
11806
12381
  phaseLocalRefs(cpl);
11807
12382
  phaseConstCollection(cpl);
11808
12383
  phaseNullishCoalescing(cpl);
11809
- phaseExpandSafeReads(cpl);
12384
+ phaseExpandSafeReads(cpl, true);
12385
+ phaseTemporaryVariables(cpl);
11810
12386
  phaseSlotAllocation(cpl);
11811
12387
  phaseVarCounting(cpl);
11812
12388
  phaseGenerateAdvance(cpl);
@@ -12180,6 +12756,9 @@ function convertAst(ast, cpl) {
12180
12756
  else if (ast instanceof SafeCall) {
12181
12757
  return new SafeInvokeFunctionExpr(convertAst(ast.receiver, cpl), ast.args.map(a => convertAst(a, cpl)));
12182
12758
  }
12759
+ else if (ast instanceof EmptyExpr$1) {
12760
+ return new EmptyExpr();
12761
+ }
12183
12762
  else {
12184
12763
  throw new Error(`Unhandled expression type: ${ast.constructor.name}`);
12185
12764
  }
@@ -12200,6 +12779,9 @@ function ingestBindings(view, op, element) {
12200
12779
  }
12201
12780
  }
12202
12781
  for (const attr of element.attributes) {
12782
+ // This is only attribute TextLiteral bindings, such as `attr.foo="bar'`. This can never be
12783
+ // `[attr.foo]="bar"` or `attr.foo="{{bar}}"`, both of which will be handled as inputs with
12784
+ // `BindingType.Attribute`.
12203
12785
  view.update.push(createAttributeOp(op.xref, ElementAttributeKind.Attribute, attr.name, literal(attr.value)));
12204
12786
  }
12205
12787
  for (const input of element.inputs) {
@@ -12233,14 +12815,35 @@ function ingestBindings(view, op, element) {
12233
12815
  view.create.push(listenerOp);
12234
12816
  }
12235
12817
  }
12236
- function ingestPropertyBinding(view, xref, bindingKind, { name, value, type }) {
12818
+ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type, unit }) {
12237
12819
  if (value instanceof ASTWithSource) {
12238
12820
  value = value.ast;
12239
12821
  }
12240
12822
  if (value instanceof Interpolation) {
12241
12823
  switch (type) {
12242
12824
  case 0 /* e.BindingType.Property */:
12243
- view.update.push(createInterpolatePropertyOp(xref, bindingKind, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
12825
+ if (name === 'style') {
12826
+ if (bindingKind !== ElementAttributeKind.Binding) {
12827
+ throw Error('Unexpected style binding on ng-template');
12828
+ }
12829
+ view.update.push(createInterpolateStyleMapOp(xref, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
12830
+ }
12831
+ else {
12832
+ view.update.push(createInterpolatePropertyOp(xref, bindingKind, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl))));
12833
+ }
12834
+ break;
12835
+ case 3 /* e.BindingType.Style */:
12836
+ if (bindingKind !== ElementAttributeKind.Binding) {
12837
+ throw Error('Unexpected style binding on ng-template');
12838
+ }
12839
+ view.update.push(createInterpolateStylePropOp(xref, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl)), unit));
12840
+ break;
12841
+ case 1 /* e.BindingType.Attribute */:
12842
+ if (bindingKind !== ElementAttributeKind.Binding) {
12843
+ throw new Error('Attribute bindings on templates are not expected to be valid');
12844
+ }
12845
+ const attributeInterpolate = createInterpolateAttributeOp(xref, bindingKind, name, value.strings, value.expressions.map(expr => convertAst(expr, view.tpl)));
12846
+ view.update.push(attributeInterpolate);
12244
12847
  break;
12245
12848
  default:
12246
12849
  // TODO: implement remaining binding types.
@@ -12250,7 +12853,29 @@ function ingestPropertyBinding(view, xref, bindingKind, { name, value, type }) {
12250
12853
  else {
12251
12854
  switch (type) {
12252
12855
  case 0 /* e.BindingType.Property */:
12253
- view.update.push(createPropertyOp(xref, bindingKind, name, convertAst(value, view.tpl)));
12856
+ // Bindings to [style] are mapped to their own special instruction.
12857
+ if (name === 'style') {
12858
+ if (bindingKind !== ElementAttributeKind.Binding) {
12859
+ throw Error('Unexpected style binding on ng-template');
12860
+ }
12861
+ view.update.push(createStyleMapOp(xref, convertAst(value, view.tpl)));
12862
+ }
12863
+ else {
12864
+ view.update.push(createPropertyOp(xref, bindingKind, name, convertAst(value, view.tpl)));
12865
+ }
12866
+ break;
12867
+ case 3 /* e.BindingType.Style */:
12868
+ if (bindingKind !== ElementAttributeKind.Binding) {
12869
+ throw Error('Unexpected style binding on ng-template');
12870
+ }
12871
+ view.update.push(createStylePropOp(xref, name, convertAst(value, view.tpl), unit));
12872
+ break;
12873
+ case 1 /* e.BindingType.Attribute */:
12874
+ if (bindingKind !== ElementAttributeKind.Binding) {
12875
+ throw new Error('Attribute bindings on templates are not expected to be valid');
12876
+ }
12877
+ const attrOp = createAttributeOp(xref, bindingKind, name, convertAst(value, view.tpl));
12878
+ view.update.push(attrOp);
12254
12879
  break;
12255
12880
  default:
12256
12881
  // TODO: implement remaining binding types.
@@ -12887,7 +13512,7 @@ function isEmptyExpression(ast) {
12887
13512
  if (ast instanceof ASTWithSource) {
12888
13513
  ast = ast.ast;
12889
13514
  }
12890
- return ast instanceof EmptyExpr;
13515
+ return ast instanceof EmptyExpr$1;
12891
13516
  }
12892
13517
 
12893
13518
  var TokenType;
@@ -13792,7 +14417,7 @@ class _ParseAST {
13792
14417
  // We have no expressions so create an empty expression that spans the entire input length
13793
14418
  const artificialStart = this.offset;
13794
14419
  const artificialEnd = this.offset + this.input.length;
13795
- return new EmptyExpr(this.span(artificialStart, artificialEnd), this.sourceSpan(artificialStart, artificialEnd));
14420
+ return new EmptyExpr$1(this.span(artificialStart, artificialEnd), this.sourceSpan(artificialStart, artificialEnd));
13796
14421
  }
13797
14422
  if (exprs.length == 1)
13798
14423
  return exprs[0];
@@ -13853,7 +14478,7 @@ class _ParseAST {
13853
14478
  const end = this.inputIndex;
13854
14479
  const expression = this.input.substring(start, end);
13855
14480
  this.error(`Conditional expression ${expression} requires all 3 expressions`);
13856
- no = new EmptyExpr(this.span(start), this.sourceSpan(start));
14481
+ no = new EmptyExpr$1(this.span(start), this.sourceSpan(start));
13857
14482
  }
13858
14483
  else {
13859
14484
  no = this.parsePipe();
@@ -14078,15 +14703,15 @@ class _ParseAST {
14078
14703
  }
14079
14704
  else if (this.next.isPrivateIdentifier()) {
14080
14705
  this._reportErrorForPrivateIdentifier(this.next, null);
14081
- return new EmptyExpr(this.span(start), this.sourceSpan(start));
14706
+ return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
14082
14707
  }
14083
14708
  else if (this.index >= this.tokens.length) {
14084
14709
  this.error(`Unexpected end of expression: ${this.input}`);
14085
- return new EmptyExpr(this.span(start), this.sourceSpan(start));
14710
+ return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
14086
14711
  }
14087
14712
  else {
14088
14713
  this.error(`Unexpected token ${this.next}`);
14089
- return new EmptyExpr(this.span(start), this.sourceSpan(start));
14714
+ return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
14090
14715
  }
14091
14716
  }
14092
14717
  parseExpressionList(terminator) {
@@ -14147,7 +14772,7 @@ class _ParseAST {
14147
14772
  if (isSafe) {
14148
14773
  if (this.consumeOptionalAssignment()) {
14149
14774
  this.error('The \'?.\' operator cannot be used in the assignment');
14150
- receiver = new EmptyExpr(this.span(start), this.sourceSpan(start));
14775
+ receiver = new EmptyExpr$1(this.span(start), this.sourceSpan(start));
14151
14776
  }
14152
14777
  else {
14153
14778
  receiver = new SafePropertyRead(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id);
@@ -14157,7 +14782,7 @@ class _ParseAST {
14157
14782
  if (this.consumeOptionalAssignment()) {
14158
14783
  if (!(this.parseFlags & 1 /* ParseFlags.Action */)) {
14159
14784
  this.error('Bindings cannot contain assignments');
14160
- return new EmptyExpr(this.span(start), this.sourceSpan(start));
14785
+ return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
14161
14786
  }
14162
14787
  const value = this.parseConditional();
14163
14788
  receiver = new PropertyWrite(this.span(start), this.sourceSpan(start), nameSpan, readReceiver, id, value);
@@ -14287,7 +14912,7 @@ class _ParseAST {
14287
14912
  return this.withContext(ParseContextFlags.Writable, () => {
14288
14913
  this.rbracketsExpected++;
14289
14914
  const key = this.parsePipe();
14290
- if (key instanceof EmptyExpr) {
14915
+ if (key instanceof EmptyExpr$1) {
14291
14916
  this.error(`Key access cannot be empty`);
14292
14917
  }
14293
14918
  this.rbracketsExpected--;
@@ -14305,7 +14930,7 @@ class _ParseAST {
14305
14930
  return isSafe ? new SafeKeyedRead(this.span(start), this.sourceSpan(start), receiver, key) :
14306
14931
  new KeyedRead(this.span(start), this.sourceSpan(start), receiver, key);
14307
14932
  }
14308
- return new EmptyExpr(this.span(start), this.sourceSpan(start));
14933
+ return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
14309
14934
  });
14310
14935
  }
14311
14936
  /**
@@ -14600,6 +15225,39 @@ class Comment {
14600
15225
  return visitor.visitComment(this, context);
14601
15226
  }
14602
15227
  }
15228
+ class BlockGroup {
15229
+ constructor(blocks, sourceSpan, startSourceSpan, endSourceSpan = null) {
15230
+ this.blocks = blocks;
15231
+ this.sourceSpan = sourceSpan;
15232
+ this.startSourceSpan = startSourceSpan;
15233
+ this.endSourceSpan = endSourceSpan;
15234
+ }
15235
+ visit(visitor, context) {
15236
+ return visitor.visitBlockGroup(this, context);
15237
+ }
15238
+ }
15239
+ class Block {
15240
+ constructor(name, parameters, children, sourceSpan, startSourceSpan, endSourceSpan = null) {
15241
+ this.name = name;
15242
+ this.parameters = parameters;
15243
+ this.children = children;
15244
+ this.sourceSpan = sourceSpan;
15245
+ this.startSourceSpan = startSourceSpan;
15246
+ this.endSourceSpan = endSourceSpan;
15247
+ }
15248
+ visit(visitor, context) {
15249
+ return visitor.visitBlock(this, context);
15250
+ }
15251
+ }
15252
+ class BlockParameter {
15253
+ constructor(expression, sourceSpan) {
15254
+ this.expression = expression;
15255
+ this.sourceSpan = sourceSpan;
15256
+ }
15257
+ visit(visitor, context) {
15258
+ return visitor.visitBlockParameter(this, context);
15259
+ }
15260
+ }
14603
15261
  function visitAll(visitor, nodes, context = null) {
14604
15262
  const result = [];
14605
15263
  const visit = visitor.visit ?
@@ -14630,6 +15288,18 @@ class RecursiveVisitor {
14630
15288
  });
14631
15289
  }
14632
15290
  visitExpansionCase(ast, context) { }
15291
+ visitBlockGroup(ast, context) {
15292
+ this.visitChildren(context, visit => {
15293
+ visit(ast.blocks);
15294
+ });
15295
+ }
15296
+ visitBlock(block, context) {
15297
+ this.visitChildren(context, visit => {
15298
+ visit(block.parameters);
15299
+ visit(block.children);
15300
+ });
15301
+ }
15302
+ visitBlockParameter(ast, context) { }
14633
15303
  visitChildren(context, cb) {
14634
15304
  let results = [];
14635
15305
  let t = this;
@@ -17382,8 +18052,8 @@ class _Tokenizer {
17382
18052
  this._cursor = options.escapedString ? new EscapedCharacterCursor(_file, range) :
17383
18053
  new PlainCharacterCursor(_file, range);
17384
18054
  this._preserveLineEndings = options.preserveLineEndings || false;
17385
- this._escapedString = options.escapedString || false;
17386
18055
  this._i18nNormalizeLineEndingsInICUs = options.i18nNormalizeLineEndingsInICUs || false;
18056
+ this._tokenizeBlocks = options.tokenizeBlocks || false;
17387
18057
  try {
17388
18058
  this._cursor.init();
17389
18059
  }
@@ -17424,6 +18094,15 @@ class _Tokenizer {
17424
18094
  this._consumeTagOpen(start);
17425
18095
  }
17426
18096
  }
18097
+ else if (this._tokenizeBlocks && this._attemptStr('{#')) {
18098
+ this._consumeBlockGroupOpen(start);
18099
+ }
18100
+ else if (this._tokenizeBlocks && this._attemptStr('{/')) {
18101
+ this._consumeBlockGroupClose(start);
18102
+ }
18103
+ else if (this._tokenizeBlocks && this._attemptStr('{:')) {
18104
+ this._consumeBlock(start);
18105
+ }
17427
18106
  else if (!(this._tokenizeIcu && this._tokenizeExpansionForm())) {
17428
18107
  // In (possibly interpolated) text the end of the text is given by `isTextEnd()`, while
17429
18108
  // the premature end of an interpolation is given by the start of a new HTML element.
@@ -17437,6 +18116,64 @@ class _Tokenizer {
17437
18116
  this._beginToken(24 /* TokenType.EOF */);
17438
18117
  this._endToken([]);
17439
18118
  }
18119
+ _consumeBlockGroupOpen(start) {
18120
+ this._beginToken(25 /* TokenType.BLOCK_GROUP_OPEN_START */, start);
18121
+ const nameCursor = this._cursor.clone();
18122
+ this._attemptCharCodeUntilFn(code => !isBlockNameChar(code));
18123
+ this._endToken([this._cursor.getChars(nameCursor)]);
18124
+ this._consumeBlockParameters();
18125
+ this._beginToken(26 /* TokenType.BLOCK_GROUP_OPEN_END */);
18126
+ this._requireCharCode($RBRACE);
18127
+ this._endToken([]);
18128
+ }
18129
+ _consumeBlockGroupClose(start) {
18130
+ this._beginToken(27 /* TokenType.BLOCK_GROUP_CLOSE */, start);
18131
+ const nameCursor = this._cursor.clone();
18132
+ this._attemptCharCodeUntilFn(code => !isBlockNameChar(code));
18133
+ const name = this._cursor.getChars(nameCursor);
18134
+ this._requireCharCode($RBRACE);
18135
+ this._endToken([name]);
18136
+ }
18137
+ _consumeBlock(start) {
18138
+ this._beginToken(29 /* TokenType.BLOCK_OPEN_START */, start);
18139
+ const nameCursor = this._cursor.clone();
18140
+ this._attemptCharCodeUntilFn(code => !isBlockNameChar(code));
18141
+ this._endToken([this._cursor.getChars(nameCursor)]);
18142
+ this._consumeBlockParameters();
18143
+ this._beginToken(30 /* TokenType.BLOCK_OPEN_END */);
18144
+ this._requireCharCode($RBRACE);
18145
+ this._endToken([]);
18146
+ }
18147
+ _consumeBlockParameters() {
18148
+ // Trim the whitespace until the first parameter.
18149
+ this._attemptCharCodeUntilFn(isBlockParameterChar);
18150
+ while (this._cursor.peek() !== $RBRACE && this._cursor.peek() !== $EOF) {
18151
+ this._beginToken(28 /* TokenType.BLOCK_PARAMETER */);
18152
+ const start = this._cursor.clone();
18153
+ let inQuote = null;
18154
+ // Consume the parameter until the next semicolon or brace.
18155
+ // 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) ||
18158
+ inQuote !== null) {
18159
+ const char = this._cursor.peek();
18160
+ // Skip to the next character if it was escaped.
18161
+ if (char === $BACKSLASH) {
18162
+ this._cursor.advance();
18163
+ }
18164
+ else if (char === inQuote) {
18165
+ inQuote = null;
18166
+ }
18167
+ else if (inQuote === null && isQuote(char)) {
18168
+ inQuote = char;
18169
+ }
18170
+ this._cursor.advance();
18171
+ }
18172
+ this._endToken([this._cursor.getChars(start)]);
18173
+ // Skip to the next parameter.
18174
+ this._attemptCharCodeUntilFn(isBlockParameterChar);
18175
+ }
18176
+ }
17440
18177
  /**
17441
18178
  * @returns whether an ICU token has been created
17442
18179
  * @internal
@@ -17770,7 +18507,6 @@ class _Tokenizer {
17770
18507
  this._endToken(prefixAndName);
17771
18508
  }
17772
18509
  _consumeAttributeValue() {
17773
- let value;
17774
18510
  if (this._cursor.peek() === $SQ || this._cursor.peek() === $DQ) {
17775
18511
  const quoteChar = this._cursor.peek();
17776
18512
  this._consumeQuote(quoteChar);
@@ -17959,7 +18695,7 @@ class _Tokenizer {
17959
18695
  return this._processCarriageReturns(end.getChars(start));
17960
18696
  }
17961
18697
  _isTextEnd() {
17962
- if (this._isTagStart() || this._cursor.peek() === $EOF) {
18698
+ if (this._isTagStart() || this._isBlockStart() || this._cursor.peek() === $EOF) {
17963
18699
  return true;
17964
18700
  }
17965
18701
  if (this._tokenizeIcu && !this._inInterpolation) {
@@ -17992,6 +18728,23 @@ class _Tokenizer {
17992
18728
  }
17993
18729
  return false;
17994
18730
  }
18731
+ _isBlockStart() {
18732
+ if (this._tokenizeBlocks && this._cursor.peek() === $LBRACE) {
18733
+ const tmp = this._cursor.clone();
18734
+ // Check that the cursor is on a `{#`, `{/` or `{:`.
18735
+ tmp.advance();
18736
+ const next = tmp.peek();
18737
+ if (next !== $BANG && next !== $SLASH && next !== $COLON) {
18738
+ return false;
18739
+ }
18740
+ // If it is, also verify that the next character is a valid block identifier.
18741
+ tmp.advance();
18742
+ if (isBlockNameChar(tmp.peek())) {
18743
+ return true;
18744
+ }
18745
+ }
18746
+ return false;
18747
+ }
17995
18748
  _readUntil(char) {
17996
18749
  const start = this._cursor.clone();
17997
18750
  this._attemptUntilChar(char);
@@ -18047,6 +18800,12 @@ function compareCharCodeCaseInsensitive(code1, code2) {
18047
18800
  function toUpperCaseCharCode(code) {
18048
18801
  return code >= $a && code <= $z ? code - $a + $A : code;
18049
18802
  }
18803
+ function isBlockNameChar(code) {
18804
+ return isAsciiLetter(code) || isDigit(code) || code === $_;
18805
+ }
18806
+ function isBlockParameterChar(code) {
18807
+ return code !== $SEMICOLON && isNotWhitespace(code);
18808
+ }
18050
18809
  function mergeTextTokens(srcTokens) {
18051
18810
  const dstTokens = [];
18052
18811
  let lastDstToken = undefined;
@@ -18334,7 +19093,7 @@ class _TreeBuilder {
18334
19093
  this.tokens = tokens;
18335
19094
  this.getTagDefinition = getTagDefinition;
18336
19095
  this._index = -1;
18337
- this._elementStack = [];
19096
+ this._containerStack = [];
18338
19097
  this.rootNodes = [];
18339
19098
  this.errors = [];
18340
19099
  this._advance();
@@ -18364,6 +19123,18 @@ class _TreeBuilder {
18364
19123
  else if (this._peek.type === 19 /* TokenType.EXPANSION_FORM_START */) {
18365
19124
  this._consumeExpansion(this._advance());
18366
19125
  }
19126
+ else if (this._peek.type === 25 /* TokenType.BLOCK_GROUP_OPEN_START */) {
19127
+ this._closeVoidElement();
19128
+ this._consumeBlockGroupOpen(this._advance());
19129
+ }
19130
+ else if (this._peek.type === 29 /* TokenType.BLOCK_OPEN_START */) {
19131
+ this._closeVoidElement();
19132
+ this._consumeBlock(this._advance(), 30 /* TokenType.BLOCK_OPEN_END */);
19133
+ }
19134
+ else if (this._peek.type === 27 /* TokenType.BLOCK_GROUP_CLOSE */) {
19135
+ this._closeVoidElement();
19136
+ this._consumeBlockGroupClose(this._advance());
19137
+ }
18367
19138
  else {
18368
19139
  // Skip all other tokens...
18369
19140
  this._advance();
@@ -18480,7 +19251,12 @@ class _TreeBuilder {
18480
19251
  const startSpan = token.sourceSpan;
18481
19252
  let text = token.parts[0];
18482
19253
  if (text.length > 0 && text[0] === '\n') {
18483
- const parent = this._getParentElement();
19254
+ const parent = this._getContainer();
19255
+ // This is unlikely to happen, but we have an assertion just in case.
19256
+ if (parent instanceof BlockGroup) {
19257
+ this.errors.push(TreeError.create(null, startSpan, 'Text cannot be placed directly inside of a block group.'));
19258
+ return null;
19259
+ }
18484
19260
  if (parent != null && parent.children.length === 0 &&
18485
19261
  this.getTagDefinition(parent.name).ignoreFirstLf) {
18486
19262
  text = text.substring(1);
@@ -18511,9 +19287,9 @@ class _TreeBuilder {
18511
19287
  }
18512
19288
  }
18513
19289
  _closeVoidElement() {
18514
- const el = this._getParentElement();
18515
- if (el && this.getTagDefinition(el.name).isVoid) {
18516
- this._elementStack.pop();
19290
+ const el = this._getContainer();
19291
+ if (el instanceof Element && this.getTagDefinition(el.name).isVoid) {
19292
+ this._containerStack.pop();
18517
19293
  }
18518
19294
  }
18519
19295
  _consumeStartTag(startTagToken) {
@@ -18522,7 +19298,7 @@ class _TreeBuilder {
18522
19298
  while (this._peek.type === 14 /* TokenType.ATTR_NAME */) {
18523
19299
  attrs.push(this._consumeAttr(this._advance()));
18524
19300
  }
18525
- const fullName = this._getElementFullName(prefix, name, this._getParentElement());
19301
+ const fullName = this._getElementFullName(prefix, name, this._getClosestParentElement());
18526
19302
  let selfClosing = false;
18527
19303
  // Note: There could have been a tokenizer error
18528
19304
  // so that we don't get a token for the end tag...
@@ -18543,33 +19319,34 @@ class _TreeBuilder {
18543
19319
  // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
18544
19320
  const startSpan = new ParseSourceSpan(startTagToken.sourceSpan.start, end, startTagToken.sourceSpan.fullStart);
18545
19321
  const el = new Element(fullName, attrs, [], span, startSpan, undefined);
18546
- this._pushElement(el);
19322
+ const parentEl = this._getContainer();
19323
+ this._pushContainer(el, parentEl instanceof Element &&
19324
+ this.getTagDefinition(parentEl.name).isClosedByChild(el.name));
18547
19325
  if (selfClosing) {
18548
19326
  // Elements that are self-closed have their `endSourceSpan` set to the full span, as the
18549
19327
  // element start tag also represents the end tag.
18550
- this._popElement(fullName, span);
19328
+ this._popContainer(fullName, Element, span);
18551
19329
  }
18552
19330
  else if (startTagToken.type === 4 /* TokenType.INCOMPLETE_TAG_OPEN */) {
18553
19331
  // We already know the opening tag is not complete, so it is unlikely it has a corresponding
18554
19332
  // close tag. Let's optimistically parse it as a full element and emit an error.
18555
- this._popElement(fullName, null);
19333
+ this._popContainer(fullName, Element, null);
18556
19334
  this.errors.push(TreeError.create(fullName, span, `Opening tag "${fullName}" not terminated.`));
18557
19335
  }
18558
19336
  }
18559
- _pushElement(el) {
18560
- const parentEl = this._getParentElement();
18561
- if (parentEl && this.getTagDefinition(parentEl.name).isClosedByChild(el.name)) {
18562
- this._elementStack.pop();
19337
+ _pushContainer(node, isClosedByChild) {
19338
+ if (isClosedByChild) {
19339
+ this._containerStack.pop();
18563
19340
  }
18564
- this._addToParent(el);
18565
- this._elementStack.push(el);
19341
+ this._addToParent(node);
19342
+ this._containerStack.push(node);
18566
19343
  }
18567
19344
  _consumeEndTag(endTagToken) {
18568
- const fullName = this._getElementFullName(endTagToken.parts[0], endTagToken.parts[1], this._getParentElement());
19345
+ const fullName = this._getElementFullName(endTagToken.parts[0], endTagToken.parts[1], this._getClosestParentElement());
18569
19346
  if (this.getTagDefinition(fullName).isVoid) {
18570
19347
  this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, `Void elements do not have end tags "${endTagToken.parts[1]}"`));
18571
19348
  }
18572
- else if (!this._popElement(fullName, endTagToken.sourceSpan)) {
19349
+ else if (!this._popContainer(fullName, Element, endTagToken.sourceSpan)) {
18573
19350
  const errMsg = `Unexpected closing tag "${fullName}". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags`;
18574
19351
  this.errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg));
18575
19352
  }
@@ -18580,20 +19357,23 @@ class _TreeBuilder {
18580
19357
  * not have a closing tag (for example, this happens when an incomplete
18581
19358
  * opening tag is recovered).
18582
19359
  */
18583
- _popElement(fullName, endSourceSpan) {
19360
+ _popContainer(fullName, expectedType, endSourceSpan) {
18584
19361
  let unexpectedCloseTagDetected = false;
18585
- for (let stackIndex = this._elementStack.length - 1; stackIndex >= 0; stackIndex--) {
18586
- const el = this._elementStack[stackIndex];
18587
- if (el.name === fullName) {
19362
+ for (let stackIndex = this._containerStack.length - 1; stackIndex >= 0; stackIndex--) {
19363
+ const node = this._containerStack[stackIndex];
19364
+ const name = node instanceof BlockGroup ? node.blocks[0]?.name : node.name;
19365
+ if (name === fullName && node instanceof expectedType) {
18588
19366
  // Record the parse span with the element that is being closed. Any elements that are
18589
19367
  // removed from the element stack at this point are closed implicitly, so they won't get
18590
19368
  // an end source span (as there is no explicit closing element).
18591
- el.endSourceSpan = endSourceSpan;
18592
- el.sourceSpan.end = endSourceSpan !== null ? endSourceSpan.end : el.sourceSpan.end;
18593
- this._elementStack.splice(stackIndex, this._elementStack.length - stackIndex);
19369
+ node.endSourceSpan = endSourceSpan;
19370
+ node.sourceSpan.end = endSourceSpan !== null ? endSourceSpan.end : node.sourceSpan.end;
19371
+ this._containerStack.splice(stackIndex, this._containerStack.length - stackIndex);
18594
19372
  return !unexpectedCloseTagDetected;
18595
19373
  }
18596
- if (!this.getTagDefinition(el.name).closedByParent) {
19374
+ // Blocks are self-closing while block groups and (most times) elements are not.
19375
+ if (node instanceof BlockGroup ||
19376
+ node instanceof Element && !this.getTagDefinition(node.name).closedByParent) {
18597
19377
  // Note that we encountered an unexpected close tag but continue processing the element
18598
19378
  // stack so we can assign an `endSourceSpan` if there is a corresponding start tag for this
18599
19379
  // end tag in the stack.
@@ -18652,16 +19432,92 @@ class _TreeBuilder {
18652
19432
  new ParseSourceSpan(valueStartSpan.start, valueEnd, valueStartSpan.fullStart);
18653
19433
  return new Attribute(fullName, value, new ParseSourceSpan(attrName.sourceSpan.start, attrEnd, attrName.sourceSpan.fullStart), attrName.sourceSpan, valueSpan, valueTokens.length > 0 ? valueTokens : undefined, undefined);
18654
19434
  }
18655
- _getParentElement() {
18656
- return this._elementStack.length > 0 ? this._elementStack[this._elementStack.length - 1] : null;
19435
+ _consumeBlockGroupOpen(token) {
19436
+ const end = this._peek.sourceSpan.fullStart;
19437
+ const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
19438
+ // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
19439
+ const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
19440
+ const blockGroup = new BlockGroup([], span, startSpan, null);
19441
+ this._pushContainer(blockGroup, false);
19442
+ const implicitBlock = this._consumeBlock(token, 26 /* TokenType.BLOCK_GROUP_OPEN_END */);
19443
+ // Block parameters are consumed as a part of the implicit block so we need to expand the
19444
+ // start source span once the block is parsed to include the full opening tag.
19445
+ startSpan.end = implicitBlock.startSourceSpan.end;
19446
+ }
19447
+ _consumeBlock(token, closeToken) {
19448
+ // The start of a block implicitly closes the previous block.
19449
+ this._conditionallyClosePreviousBlock();
19450
+ const parameters = [];
19451
+ while (this._peek.type === 28 /* TokenType.BLOCK_PARAMETER */) {
19452
+ const paramToken = this._advance();
19453
+ parameters.push(new BlockParameter(paramToken.parts[0], paramToken.sourceSpan));
19454
+ }
19455
+ if (this._peek.type === closeToken) {
19456
+ this._advance();
19457
+ }
19458
+ const end = this._peek.sourceSpan.fullStart;
19459
+ const span = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
19460
+ // Create a separate `startSpan` because `span` will be modified when there is an `end` span.
19461
+ const startSpan = new ParseSourceSpan(token.sourceSpan.start, end, token.sourceSpan.fullStart);
19462
+ const block = new Block(token.parts[0], parameters, [], span, startSpan);
19463
+ const parent = this._getContainer();
19464
+ if (!(parent instanceof BlockGroup)) {
19465
+ this.errors.push(TreeError.create(block.name, block.sourceSpan, 'Blocks can only be placed inside of block groups.'));
19466
+ }
19467
+ else {
19468
+ parent.blocks.push(block);
19469
+ this._containerStack.push(block);
19470
+ }
19471
+ return block;
19472
+ }
19473
+ _consumeBlockGroupClose(token) {
19474
+ const name = token.parts[0];
19475
+ const previousContainer = this._getContainer();
19476
+ // Blocks are implcitly closed by the block group.
19477
+ this._conditionallyClosePreviousBlock();
19478
+ if (!this._popContainer(name, BlockGroup, token.sourceSpan)) {
19479
+ const context = previousContainer instanceof Element ?
19480
+ `There is an unclosed "${previousContainer.name}" HTML tag named that may have to be closed first.` :
19481
+ `The block may have been closed earlier.`;
19482
+ this.errors.push(TreeError.create(name, token.sourceSpan, `Unexpected closing block "${name}". ${context}`));
19483
+ }
19484
+ }
19485
+ _conditionallyClosePreviousBlock() {
19486
+ const container = this._getContainer();
19487
+ if (container instanceof Block) {
19488
+ // Blocks don't have an explicit closing tag, they're closed either by the next block or
19489
+ // the end of the block group. Infer the end span from the last child node.
19490
+ const lastChild = container.children.length ? container.children[container.children.length - 1] : null;
19491
+ const endSpan = lastChild === null ?
19492
+ null :
19493
+ new ParseSourceSpan(lastChild.sourceSpan.end, lastChild.sourceSpan.end);
19494
+ this._popContainer(container.name, Block, endSpan);
19495
+ }
19496
+ }
19497
+ _getContainer() {
19498
+ return this._containerStack.length > 0 ? this._containerStack[this._containerStack.length - 1] :
19499
+ null;
19500
+ }
19501
+ _getClosestParentElement() {
19502
+ for (let i = this._containerStack.length - 1; i > -1; i--) {
19503
+ if (this._containerStack[i] instanceof Element) {
19504
+ return this._containerStack[i];
19505
+ }
19506
+ }
19507
+ return null;
18657
19508
  }
18658
19509
  _addToParent(node) {
18659
- const parent = this._getParentElement();
18660
- if (parent != null) {
18661
- parent.children.push(node);
19510
+ const parent = this._getContainer();
19511
+ if (parent === null) {
19512
+ this.rootNodes.push(node);
19513
+ }
19514
+ else if (parent instanceof BlockGroup) {
19515
+ // Due to how parsing is set up, we're unlikely to hit this code path, but we
19516
+ // have the assertion here just in case and to satisfy the type checker.
19517
+ this.errors.push(TreeError.create(null, node.sourceSpan, 'Block groups can only contain blocks.'));
18662
19518
  }
18663
19519
  else {
18664
- this.rootNodes.push(node);
19520
+ parent.children.push(node);
18665
19521
  }
18666
19522
  }
18667
19523
  _getElementFullName(prefix, localName, parentElement) {
@@ -18775,6 +19631,15 @@ class WhitespaceVisitor {
18775
19631
  visitExpansionCase(expansionCase, context) {
18776
19632
  return expansionCase;
18777
19633
  }
19634
+ visitBlockGroup(group, context) {
19635
+ return new BlockGroup(visitAllWithSiblings(this, group.blocks), group.sourceSpan, group.startSourceSpan, group.endSourceSpan);
19636
+ }
19637
+ visitBlock(block, context) {
19638
+ return new Block(block.name, block.parameters, visitAllWithSiblings(this, block.children), block.sourceSpan, block.startSourceSpan);
19639
+ }
19640
+ visitBlockParameter(parameter, context) {
19641
+ return parameter;
19642
+ }
18778
19643
  }
18779
19644
  function createWhitespaceProcessedTextToken({ type, parts, sourceSpan }) {
18780
19645
  return { type, parts: [processWhitespace(parts[0])], sourceSpan };
@@ -19184,7 +20049,7 @@ class BindingParser {
19184
20049
  if (ast) {
19185
20050
  this._reportExpressionParserErrors(ast.errors, sourceSpan);
19186
20051
  }
19187
- if (!ast || ast.ast instanceof EmptyExpr) {
20052
+ if (!ast || ast.ast instanceof EmptyExpr$1) {
19188
20053
  this._reportError(`Empty expressions are not allowed`, sourceSpan);
19189
20054
  return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo, absoluteOffset);
19190
20055
  }
@@ -19563,6 +20428,15 @@ class HtmlAstToIvyAst {
19563
20428
  }
19564
20429
  return null;
19565
20430
  }
20431
+ 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');
20439
+ }
19566
20440
  // convert view engine `ParsedProperty` to a format suitable for IVY
19567
20441
  extractAttributes(elementName, properties, i18nPropsMeta) {
19568
20442
  const bound = [];
@@ -19740,6 +20614,15 @@ class NonBindableVisitor {
19740
20614
  visitExpansionCase(expansionCase) {
19741
20615
  return null;
19742
20616
  }
20617
+ visitBlockGroup(group, context) {
20618
+ throw new Error('TODO');
20619
+ }
20620
+ visitBlock(block, context) {
20621
+ throw new Error('TODO');
20622
+ }
20623
+ visitBlockParameter(parameter, context) {
20624
+ throw new Error('TODO');
20625
+ }
19743
20626
  }
19744
20627
  const NON_BINDABLE_VISITOR = new NonBindableVisitor();
19745
20628
  function normalizeAttributeName(attrName) {
@@ -20187,6 +21070,17 @@ class _I18nVisitor {
20187
21070
  visitExpansionCase(_icuCase, _context) {
20188
21071
  throw new Error('Unreachable code');
20189
21072
  }
21073
+ visitBlockGroup(group, context) {
21074
+ const children = visitAll(this, group.blocks, context);
21075
+ const node = new Container(children, group.sourceSpan);
21076
+ return context.visitNodeFn(group, node);
21077
+ }
21078
+ visitBlock(block, context) {
21079
+ const children = visitAll(this, block.children, context);
21080
+ const node = new Container(children, block.sourceSpan);
21081
+ return context.visitNodeFn(block, node);
21082
+ }
21083
+ visitBlockParameter(_parameter, _context) { }
20190
21084
  /**
20191
21085
  * Convert, text and interpolated tokens up into text and placeholder pieces.
20192
21086
  *
@@ -20433,6 +21327,17 @@ class I18nMetaVisitor {
20433
21327
  visitExpansionCase(expansionCase) {
20434
21328
  return expansionCase;
20435
21329
  }
21330
+ visitBlockGroup(group, context) {
21331
+ visitAll(this, group.blocks, context);
21332
+ return group;
21333
+ }
21334
+ visitBlock(block, context) {
21335
+ visitAll(this, block.children, context);
21336
+ return block;
21337
+ }
21338
+ visitBlockParameter(parameter, context) {
21339
+ return parameter;
21340
+ }
20436
21341
  /**
20437
21342
  * Parse the general form `meta` passed into extract the explicit metadata needed to create a
20438
21343
  * `Message`.
@@ -23305,6 +24210,7 @@ class CompilerFacadeImpl {
23305
24210
  }
23306
24211
  compileNgModule(angularCoreEnv, sourceMapUrl, facade) {
23307
24212
  const meta = {
24213
+ kind: R3NgModuleMetadataKind.Global,
23308
24214
  type: wrapReference(facade.type),
23309
24215
  bootstrap: facade.bootstrap.map(wrapReference),
23310
24216
  declarations: facade.declarations.map(wrapReference),
@@ -23816,7 +24722,7 @@ function publishFacade(global) {
23816
24722
  * @description
23817
24723
  * Entry point for all public APIs of the compiler package.
23818
24724
  */
23819
- const VERSION = new Version('16.2.0-next.0');
24725
+ const VERSION = new Version('16.2.0-next.2');
23820
24726
 
23821
24727
  class CompilerConfig {
23822
24728
  constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
@@ -24037,6 +24943,13 @@ class _Visitor {
24037
24943
  visitAttribute(attribute, context) {
24038
24944
  throw new Error('unreachable code');
24039
24945
  }
24946
+ visitBlockGroup(group, context) {
24947
+ visitAll(this, group.blocks, context);
24948
+ }
24949
+ visitBlock(block, context) {
24950
+ visitAll(this, block.children, context);
24951
+ }
24952
+ visitBlockParameter(parameter, context) { }
24040
24953
  _init(mode, interpolationConfig) {
24041
24954
  this._mode = mode;
24042
24955
  this._inI18nBlock = false;
@@ -24249,8 +25162,9 @@ class XmlParser extends Parser {
24249
25162
  constructor() {
24250
25163
  super(getXmlTagDefinition);
24251
25164
  }
24252
- parse(source, url, options) {
24253
- return super.parse(source, url, options);
25165
+ parse(source, url, options = {}) {
25166
+ // Blocks aren't supported in an XML context.
25167
+ return super.parse(source, url, { ...options, tokenizeBlocks: false });
24254
25168
  }
24255
25169
  }
24256
25170
 
@@ -24434,6 +25348,9 @@ class XliffParser {
24434
25348
  visitComment(comment, context) { }
24435
25349
  visitExpansion(expansion, context) { }
24436
25350
  visitExpansionCase(expansionCase, context) { }
25351
+ visitBlockGroup(group, context) { }
25352
+ visitBlock(block, context) { }
25353
+ visitBlockParameter(parameter, context) { }
24437
25354
  _addError(node, message) {
24438
25355
  this._errors.push(new I18nError(node.sourceSpan, message));
24439
25356
  }
@@ -24484,6 +25401,9 @@ class XmlToI18n$2 {
24484
25401
  }
24485
25402
  visitComment(comment, context) { }
24486
25403
  visitAttribute(attribute, context) { }
25404
+ visitBlockGroup(group, context) { }
25405
+ visitBlock(block, context) { }
25406
+ visitBlockParameter(parameter, context) { }
24487
25407
  _addError(node, message) {
24488
25408
  this._errors.push(new I18nError(node.sourceSpan, message));
24489
25409
  }
@@ -24707,6 +25627,9 @@ class Xliff2Parser {
24707
25627
  visitComment(comment, context) { }
24708
25628
  visitExpansion(expansion, context) { }
24709
25629
  visitExpansionCase(expansionCase, context) { }
25630
+ visitBlockGroup(group, context) { }
25631
+ visitBlock(block, context) { }
25632
+ visitBlockParameter(parameter, context) { }
24710
25633
  _addError(node, message) {
24711
25634
  this._errors.push(new I18nError(node.sourceSpan, message));
24712
25635
  }
@@ -24774,6 +25697,9 @@ class XmlToI18n$1 {
24774
25697
  }
24775
25698
  visitComment(comment, context) { }
24776
25699
  visitAttribute(attribute, context) { }
25700
+ visitBlockGroup(group, context) { }
25701
+ visitBlock(block, context) { }
25702
+ visitBlockParameter(parameter, context) { }
24777
25703
  _addError(node, message) {
24778
25704
  this._errors.push(new I18nError(node.sourceSpan, message));
24779
25705
  }
@@ -24908,6 +25834,9 @@ class XtbParser {
24908
25834
  visitComment(comment, context) { }
24909
25835
  visitExpansion(expansion, context) { }
24910
25836
  visitExpansionCase(expansionCase, context) { }
25837
+ visitBlockGroup(group, context) { }
25838
+ visitBlock(block, context) { }
25839
+ visitBlockParameter(block, context) { }
24911
25840
  _addError(node, message) {
24912
25841
  this._errors.push(new I18nError(node.sourceSpan, message));
24913
25842
  }
@@ -24956,6 +25885,9 @@ class XmlToI18n {
24956
25885
  }
24957
25886
  visitComment(comment, context) { }
24958
25887
  visitAttribute(attribute, context) { }
25888
+ visitBlockGroup(group, context) { }
25889
+ visitBlock(block, context) { }
25890
+ visitBlockParameter(block, context) { }
24959
25891
  _addError(node, message) {
24960
25892
  this._errors.push(new I18nError(node.sourceSpan, message));
24961
25893
  }
@@ -25744,7 +26676,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
25744
26676
  function compileDeclareClassMetadata(metadata) {
25745
26677
  const definitionMap = new DefinitionMap();
25746
26678
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
25747
- definitionMap.set('version', literal('16.2.0-next.0'));
26679
+ definitionMap.set('version', literal('16.2.0-next.2'));
25748
26680
  definitionMap.set('ngImport', importExpr(Identifiers.core));
25749
26681
  definitionMap.set('type', metadata.type);
25750
26682
  definitionMap.set('decorators', metadata.decorators);
@@ -25847,7 +26779,7 @@ function compileDeclareDirectiveFromMetadata(meta) {
25847
26779
  function createDirectiveDefinitionMap(meta) {
25848
26780
  const definitionMap = new DefinitionMap();
25849
26781
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
25850
- definitionMap.set('version', literal('16.2.0-next.0'));
26782
+ definitionMap.set('version', literal('16.2.0-next.2'));
25851
26783
  // e.g. `type: MyDirective`
25852
26784
  definitionMap.set('type', meta.type.value);
25853
26785
  if (meta.isStandalone) {
@@ -26075,7 +27007,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
26075
27007
  function compileDeclareFactoryFunction(meta) {
26076
27008
  const definitionMap = new DefinitionMap();
26077
27009
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
26078
- definitionMap.set('version', literal('16.2.0-next.0'));
27010
+ definitionMap.set('version', literal('16.2.0-next.2'));
26079
27011
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26080
27012
  definitionMap.set('type', meta.type.value);
26081
27013
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -26110,7 +27042,7 @@ function compileDeclareInjectableFromMetadata(meta) {
26110
27042
  function createInjectableDefinitionMap(meta) {
26111
27043
  const definitionMap = new DefinitionMap();
26112
27044
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
26113
- definitionMap.set('version', literal('16.2.0-next.0'));
27045
+ definitionMap.set('version', literal('16.2.0-next.2'));
26114
27046
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26115
27047
  definitionMap.set('type', meta.type.value);
26116
27048
  // Only generate providedIn property if it has a non-null value
@@ -26161,7 +27093,7 @@ function compileDeclareInjectorFromMetadata(meta) {
26161
27093
  function createInjectorDefinitionMap(meta) {
26162
27094
  const definitionMap = new DefinitionMap();
26163
27095
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
26164
- definitionMap.set('version', literal('16.2.0-next.0'));
27096
+ definitionMap.set('version', literal('16.2.0-next.2'));
26165
27097
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26166
27098
  definitionMap.set('type', meta.type.value);
26167
27099
  definitionMap.set('providers', meta.providers);
@@ -26190,8 +27122,11 @@ function compileDeclareNgModuleFromMetadata(meta) {
26190
27122
  */
26191
27123
  function createNgModuleDefinitionMap(meta) {
26192
27124
  const definitionMap = new DefinitionMap();
27125
+ if (meta.kind === R3NgModuleMetadataKind.Local) {
27126
+ throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
27127
+ }
26193
27128
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
26194
- definitionMap.set('version', literal('16.2.0-next.0'));
27129
+ definitionMap.set('version', literal('16.2.0-next.2'));
26195
27130
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26196
27131
  definitionMap.set('type', meta.type.value);
26197
27132
  // We only generate the keys in the metadata if the arrays contain values.
@@ -26242,7 +27177,7 @@ function compileDeclarePipeFromMetadata(meta) {
26242
27177
  function createPipeDefinitionMap(meta) {
26243
27178
  const definitionMap = new DefinitionMap();
26244
27179
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
26245
- definitionMap.set('version', literal('16.2.0-next.0'));
27180
+ definitionMap.set('version', literal('16.2.0-next.2'));
26246
27181
  definitionMap.set('ngImport', importExpr(Identifiers.core));
26247
27182
  // e.g. `type: MyPipe`
26248
27183
  definitionMap.set('type', meta.type.value);
@@ -26275,5 +27210,5 @@ publishFacade(_global);
26275
27210
 
26276
27211
  // This file is not used to build this module. It is only used during editing
26277
27212
 
26278
- export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, 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, 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, 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 };
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 };
26279
27214
  //# sourceMappingURL=compiler.mjs.map